0% found this document useful (0 votes)
93 views

Massachusetts Institute of Technology Department of Electrical Engineering and Computer Science

This document describes a student project to design an RFID spoofing system using an FPGA. It provides background on RFID technology and MIT's access control system. The document then outlines the project goals and describes the design of modules for spoofing RFID signals and reading legitimate tags. It discusses the development of a graphical user interface and issues encountered with debugging.

Uploaded by

Marcelo Delgado
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
93 views

Massachusetts Institute of Technology Department of Electrical Engineering and Computer Science

This document describes a student project to design an RFID spoofing system using an FPGA. It provides background on RFID technology and MIT's access control system. The document then outlines the project goals and describes the design of modules for spoofing RFID signals and reading legitimate tags. It discusses the development of a graphical user interface and issues encountered with debugging.

Uploaded by

Marcelo Delgado
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Massachusetts Institute of Technology

Department of Electrical Engineering and Computer Science

Instructors: Gim Hom and Joe Steinmyer


Project Supervisor: Mike Wang
Fall 2019

6.111 Digital Systems Laboratory

FPGA RFID Utility – Final Report

Hannah Field and Miles Dai

December 11, 2019


Contents
1 Overview 1

2 Background 1
2.1 Data Transmission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.2 Data Packet Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

3 Goals 3
3.1 Commitment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3.2 Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3.3 Stretch Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

4 Spoofing (Hannah) 3
4.1 Analog Frontend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.1.1 Inductors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.1.2 Modulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4.1.3 Phase-locked Pulse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.2 Spoofing Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.2.1 Phase-Locked Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.2.2 Mosfet Control Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

5 Reading (Miles) 6
5.1 Analog Frontend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
5.2 Reading Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
5.2.1 Pulse Gen Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
5.2.2 Parser Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5.2.3 Read FSM Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

6 Graphical User Interface (Hannah) 9


6.1 Spoof GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
6.2 Read GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
6.3 Implementation Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

7 Portable System (Miles) 10


7.1 User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
7.2 Flash Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

8 Challenges 11
8.1 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

9 Future Work 11
9.1 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

10 Appendix 11
10.1 Top Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
10.1.1 top_level.sv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
10.2 GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
10.2.1 rfid_gui.sv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
10.2.2 bits_to_ascii.sv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
10.2.3 cstringdisplay.v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
10.3 Spoofing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
10.3.1 spoofer.sv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
10.3.2 debounce.sv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
10.4 Reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1 Overview
In the fields of corporate and building security, contactless smartcards and proximity cards
are the dominant form of access control. Indeed, Radio Frequency Identification (RFID) is
the cornerstone of MIT’s access control system. In recent years, non-contact forms of payment
using Near-Field Communication (NFC) have also been growing in popularity. In our project,
we would like to explore the security of this system by investigating the signals transmitted
from these devices and attempting to replicate them.

2 Background
RFID is a subset of more general non-contact credential systems. In particular, MIT pri-
marily uses passive RFID in the low frequency band, with card readers broadcasting 125kHz
signals. Passive here refers to the fact that the signal sent by the card reader is sufficient to
power the onboard circuitry that is used to transmit the ID data.
RFID cards come in a variety of flavors. The onboard IC can be read-only, read-write, or
write-once, read-many (WORM). Read-only cards have the ID number baked into the circuitry.
Read-write cards allow for a card reader to edit the information on the card. WORM cards
allow the end user to write to the card once, after which it becomes read-only.

2.1 Data Transmission


Embedded within each ID card is a wire coil connected to an integrated circuit. This wire
loop picks up the AC signal emitted by the card reader and rectifies it to provide power to the
IC. The purpose of the IC is to effectively modulate the impedance across the ends of the coil.
Because the coil in the card acts as the secondary of a transformer (with the card reader being
the primary), the impedance changes in the card are reflected across the air gap and can be
detected by the card reader.
The particular brand of ID card used by MIT uses binary phase-shift keying (BPSK) to
encode data. The card reader provides the 125 kHz carrier frequency which the onboard IC in
the card uses to superimpose a 62.5kHz data signal. This data signal is then phase shifted to
send information.

Figure 1: A 62.5kHz signal (green) superimposed on top of a 125kHz carrier (red). The result
(purple) is alternating “high” and “low” peaks.

The ICs on the MIT ID cards send one bit every 16 cycles of the 62.5 kHz wave. If the

1
current bit is different from the previous bit, then the IC will cause a phase shift in the 62.5
kHz signal. This looks like two consecutive high or low peaks in the carrier waveform.

Figure 2: A phase-shifted signal (green) superimposed on the 125kHz carrier (red) to produce
the purple waveform. The result (purple) is two high or low peaks at the location of phase
shift.

There are essentially three ways to emit a spoofed signal. The first is to record the coil’s
response to an ID card, and store some number of samples using an ADC. The downsides to
this approach are that it requires (1) a lot of memory, (2) a faster ADC than that on the Nexys
4 DDR, and (3) inability to spoof ID cards not already in the system.
A second approach is to recreate the 62.5 kHz signal. This method circumvents all of
the issues exhibited by the previous approach. Unfortunately, generating this discontinuous
signal would prove difficult, and questions of timing synchronization between the incoming and
spoofed signal arise.
The last method and, in particular, the approach we take in this project is to spoof the
superposition signal. In this approach, we modulate the natural response of a receive coil to
the incoming 125 kHz signal. This method provides a clean solution to the problem of time
synchronization; the circuitry is discussed in section 4.

2.2 Data Packet Structure


The data packet sent by the MIT ID is of a constant structure. Because the password
is static and there is no acknowledgement protocol with the reader, it is relatively simple to
reverse engineer the structure of the data packet that is sent. In the table below, the bits are
sent from LSB to MSB. That is, the 30 zeros are sent first followed by bit 30 all the way to 224.

Bits Length Description


[29:0] 30 All 0’s; synchronization
[51:30] 22 MIT constant bits
[84:52] 33 Personal bits
[224:85] 139 Constant bits

Based on examining multiple ID cards, it is possible to determine that only bits 52 through
84 change between cards. These, we believe are the bits that are being modified to produce
unique identifiers.

2
3 Goals
3.1 Commitment
• Read module: this module will take raw analog input from the card reading coil and
translate that into bits. Proof of goal: display bits on VGA screen.

• Spoof module: this module will simulate the PSK 62.5kHz signal generated by the ID
card. This can be demonstrated by viewing the resulting waveform on an oscilloscope
and compared to the response of an actual ID card. Proof of goal: View phase shifted
waveform and incoming waveform on oscilloscope.

• Basic Deliverable: Upload code to two FPGA’s, and show the spoofed signal is correctly
read.

3.2 Goals
• SD Card Interface: Each time a new ID is read, offer the option to save it to an SD card.
Then, select ID numbers from the SD card to playback as a spoofed signal. Index into
the SD card via switches.

• VGA Interface: Add visual navigation for the SD card. Display a list of ID numbers
stored on the SD card. Scroll through them with the up and down buttons. Use the
center button to select an ID to playback.

3.3 Stretch Goals


• Program Cards: Reverse engineer the programming protocol by reading the bits from the
Arduino programmer.

• All Systems Go: Read Joe or Jim’s ID card onto the SD card, and spoof their ID to open
the 38-6 lab doors.

4 Spoofing (Hannah)
The spoofed signal is achieved by modulating a receive coil’s impedance via the use of a
mosfet shorted accross the coil. In this manner, the superposition of the 125 kHz card reader
signal and the 62.5 kHz data signal is simulated by consecutively turning on and off the mosfet.
The key aspect of the spoofing system is that a phase-locked pulse is generated from the
incoming signal. This phase-locked pulse is effectively used as the clock for turning on and off
the mosfet, allowing the spoofed signal to phase align with the incoming signal from the card
reader. We suspect this is a necessary feature for our spoofed signal to be recognized by MIT
card readers.

4.1 Analog Frontend


4.1.1 Inductors
The inductors are hand-wound with approximately 20-turns and encompass a roughly 2-
inch diameter. These inductors had inductances in the tens-of-micro-Henry range. We found
that we had the best results using standard lab wire. One test with a 1000x larger milli-Henry
range inductor made from magnet wire performed worse as a receive coil, which we believe is

3
Figure 3: Analog frontend for the spoofer module. System consists of (1) a mosfet (IRF740)
for modulating the incoming signal (represented by the 20 Vpp oscillatory source) (2) op-amp
(TLV2371) to ensure the signal will sizable relative to the 3.3 V rails (3) comparator with
hysteresis (MAX941) to generate a phase-locked pulse.

due to it’s higher resistance. Based on measurements, MIT card readers appear to output a 20
Vpp signal. This transfers to roughly 1-2 Vpp on our inductor coils.

4.1.2 Modulation
The modulation is accomplished by an IRF740 N-Channel mosfet in parallel with the receive
coil. An additional capacitor is added in parallel to act as a low-pass filter. A rough estimate
of the capacitor value can be made to ensure that the cutoff frequency 2π√1LC ≈ 1 MHz. This
value of cutoff frequency is above the 125 kHz necessary for the signal to exist without too
much damping but is also low enough to remove the rapid periodic high-frequency oscillation
in the system. Experimentally, 33 nF worked well.

Figure 4: Clean spoofed signal. The filtering capacitor removes all high-frequency content.

4
4.1.3 Phase-locked Pulse
The phase-locked pulse is computed with an op-amp and comparator acting upon the
receive-side coil voltage. The first iteration of the analog setup incorporated a potentiome-
ter to set the hysteresis of the comparator. This effectively allowed for analog control of the
relative phase at which the mosfet would be turned on or off. Interestingly, the spoofed signal
with the greatest voltage differentiation between peaks was generated by switching the mosfet
at approximately 270 degrees before the expected maximum in the signal. Figure 5 depicts all
the analog signals for the basic system, which effectively corresponds to transmitting a single
bit.

Figure 5: Oscilloscope output of all analog front-end signals. Yellow: mosfet control. Blue:
spoofed signal out. Pink: op-amp output. Green: phase-locked pulse.

4.2 Spoofing Module

Figure 6: Spoof module block diagram.

The spoofing module accomplishes two tasks: (1) buffering and debouncing the card_reader_in
signal so that it is reliable and (2) computing the state of mosfet_control_out.

5
4.2.1 Phase-Locked Clock
The main difficulty for the spoof module is to generate a reliable signal for card_reader_in
so that the mosfet may use that signal as a pseudo-clock. If any edge of the analog card_reader_in
signal is missed, the mosfet state will remain unchanged, causing the entire rest of the trans-
mission to be faulty.
The most significant improvement in error rate came from a 3 wide buffer in of the card_reader_in
signal. The remaining errors were improved by debouncing. With the module’s actual logic
clock of 100 MHz, each clock cycle is 10 ns. Thus, an individual high or low peak of the 125
kHz signal lasts for 400 clock cycles. Experimentally, debouncing over 5 clock cycles led to
a near-zero error rate in the signal. Anything much more than that was too stringent of a
condition and resulted in missed edges.
Debugging of this module with the ILA was crucial: (1) the testbench simulations were
correct without either of these features implemented and (2) the oscilloscope could not pick
up on the instabilities in the FPGA from the noisy signal that caused it to fail. Of great
significance was the ability to select a number of frames for the ILA to trigger on (at the small
cost of fewer data points per window).

4.2.2 Mosfet Control Logic

Figure 7: FSM for spoof module logic.

The mosfet control logic first alternates the mosfet on and off for 32 cycles of a 125 kHz
wave. Since the spoof module should cyclically spoof the given bit stream, a pointer is used to
maintain the location of the currently transmitted bit. After the 32 cycles, the module checks
whether a bit shift occurs in the bit stream and flips the mosfet state accordingly. If no bit
shift occurs then the on off behavior continues as before. Otherwise, the bit shift is represented
by maintaining the current state of the mosfet for an additional cycle.

5 Reading (Miles)
Reading the stored data on the card requires first energizing the ID card with a 125 kHz
signal. This is picked up by a coil embedded in the card which is attached to an integrated
circuit that is able to change the impedance across the coil. In order to create a reader, we use
a signal generator connected to a transmit coil made up of 15-20 turns of 22 AWG wire in an
approximately 3-inch diameter loop to simulate a card reader. Another identical coil was made
to act as the receive coil. The voltage across this shows the signal being sent from the card.

5.1 Analog Frontend


The most straightforward way of capturing the changing voltage on the receive coil is to feed
the signal into the on-board ADC. However, the ADC has a maximum sampling rate of 1 Mbps.
The incoming carrier wave is at 125 kHz which corresponds to 8 samples per cycle. This is
insufficient to determine the small differences in amplitude required to decode the modulation.

6
Instead, an analog frontend is used to preprocess this signal. First, a notch filter tuned
to 125 kHz increases the amplitude difference between consecutive peaks. This signal is then
amplified, and a comparator is set to trigger on each high peak. The comparator pulses can be
polled by a digital pin at 100 MHz and phase shifts can be determined by the timing between
the pulses.

+3.3V +3.3V

V+
51k
V+ 10k
TLV2371
L1
34pF LM311
20 Vpp
V- comparator_out
V-
+3.3V
47mH

18k
10k
81k

Figure 8: Analog frontend for the reader module. The transmit coil is represented by the
primary of L1 and the receive coil is the secondary.

Because we are also using a hand-wound coil to spoof the signal, there is very different
coupling between the spoof coil and the coil in the ID card. As a result, we need to adjust
the potentiometer to change the comparator threshold since the voltage on the recieve coil will
vary depending on the coupling.

5.2 Reading Module


The job of the Reading Module is to accept the raw input from the analog frontend and
output the 194-bit ID number that is stored on the card. The reader should signal to the next
module when the ID is ready to be read with a flag.
Reader

bit_ready id_ready_out
comparator_in pulse_gen pulse parser read_fsm
current_bit id_bits_out [193:0]

Figure 9: Reader module block diagram.

5.2.1 Pulse Gen Module


The goal of the pulse_gen module is to synchronize the pulses from the LM311 comparator
and convert them into pulses of one clock cycle for the downstream modules.
Because this is the first module to receive the raw input, it needs to make special consid-
erations for the analog nature of the signal. Even though the comparator is fast, it still has a

7
fall time1 the of about 100 ns. With the FPGA’s 100 MHz clock, this is still around 10 clock
cycles in which the comparator is at an intermediate voltage. As a result, it is necessary for
this module to prevent metastability problems. This is done by shifting the data through a
four-stage shift register. The pulse_gen module only outputs a pulse when it detects that all
four values in the shift register agree on the logic level.

5.2.2 Parser Module


The role of the parser module is to decode the pulses received from the comparator into
bits. The integrated circuit in the ID card transmits one bit every 16 cycles of the 62.5 kHz
wave. If the current bit to be sent differs from the last bit (i.e. there is a bit flip), then the
IC will cause a phase shift in the 62.5 kHz signal which looks like two consecutive high or low
peaks in the 125 kHz carrier. The parser counts the clock cycles between pulses to determine
if a phase shift has occurred (i.e. the duration between the pulses is either too high or too
low). If so, it flips the value on current_bit. Every 16 cycles, it raises the bit_ready line to
signal that a bit has been sent. Subsequent modules then know that a valid bit is visible on
current_bit.

5.2.3 Read FSM Module

consecutive
IDLE TRIGGERED 1 CONST1 22 bits PERSONAL 33 bits CONST2
bits

139 bits

Figure 10: ID Bits decode FSM.

The read FSM represents the highest level of abstraction in decoding the ID number. This
module effectively receives a stream of bits from the parser and needs to figure out where in
the transmitted ID it is. A finite state machine accepts the incoming bits and uses the known
structure of the data packet to parse the bits.
In IDLE state, the module waits until it detects a consecutive sequence of 27 transmissions
of the same bit. This matches up with the 30 zeros sent out at the beginning and indicates
to the FSM that an ID transition is about to begin. After 27 zeros or ones are detected, the
system waits for the first one. The first one indicates the start of the first group of constant
bits. The state machine starts recording bits at this point and raises the id_ready_out flag
once it transitions from CONST2 back to IDLE.
Another benefit of knowing the structure of the data is that it allows the FSM to check the
incoming bits for known segments of data. For example, it is known that the first 22 bits sent
by every MIT card is 1000001110011000010110. We can use this in the state machine to reject
data packets that do not match this sequence since noise in the system can cause spurious bit
flips. Only after the entire 194-bit bus is filled does the FSM raise the id_ready_out flag to
signal to the downstream module that a valid ID has been loaded.
1
We use the falling edge of the comparator because the LM311 is an open collector device. Thus it relies on
the 10k pullup resistor shown in Figure 8 to create the rising edge which makes it much slower than the falling
edge.

8
6 Graphical User Interface (Hannah)
The goal of the GUI module is to provide a way for users to interact with the RFID system.
The user may switch between SPOOF and READ mode via the use of a sw[15].

6.1 Spoof GUI

Figure 11: GUI display for the spoof module.

In SPOOF mode, users are provided with a glance of the first 55 bits (personal + MIT bits)
stored in the 16 BRAM locations shared between the READ and SPOOF modules. Using the
up and down buttons, they may scroll through the contents. The selected entry is automatically
spoofed.

6.2 Read GUI


In READ mode, users are provided with a live update of the most recent bits read from the
Reading FSM. Furthermore, since the read system requires tuning of a physical potentiometer,
this mode provides feedback such as “MIT ID” or “ID Not Recognized” so that the user may be
able to tune the hardware without an external oscilloscope. This feedback is given by checking
whether the first 22 bits match the 22 MIT bits hardcoded into the module itself. Finally, users
may use the sw[4:0] to select a location in BRAM to which they may save the entire 194 long
sequence of bits.

6.3 Implementation Details


The main ability to display text on the screen is provided by the module cstringdisplay.v
written by I. Chuang and C. Terman. This module takes in the ascii code for up to 64 characters
to be displayed in a single line on the display. The font is provided by a COE file.

9
Figure 12: GUI display for the read module.

The module bits_to_ascii.sv adds the ability to convert arbitrary sequences of bits to
ascii code so that it may be displayed on the screen in the READ and SPOOF module. Other
text on the screen uses hard-coded ascii valuese.

7 Portable System (Miles)


One of the goals for this project was to create a device that could be held up to a card
reader to spoof an RFID card. This required portability which was not easy with the Nexys
A7 DDR boards. Instead, we switched to a CMOD A7 board from Digilent which contains an
Artix-7 FPGA in a more portable form factor. This allowed us to power the entire system from
a portable power bank and bring the device to a wall-mounted card reader.
Most of the code from the main project was transferred directly to the CMOD A7 with the
exception of the graphics handlers. The only other major modification made was to change
some of the constants since the Artix-7 uses a 20 MHz clock. There are fewer clock cycles
between comparator pulses, so some counting constants need to be changed.

7.1 User Interface


The CMOD A7 board is much more limited in user interface components. For our project,
in order to allow the user to select between the read and spoof modes of operation, we installed
a row of DIP switches with pullup resistors which could be connected to the GPIO pins. We
also took advantage of the two onboard LED lights and pushbuttons to indicate when to record
an id number and when the ID number read matched the MIT constant.

7.2 Flash Memory


The volatile nature of the FPGA causes challenges when making this device portable. Be-
cause the programmed bitstream disappears on each reboot, it is necessary to write the desired
bitstream into non-volatile flash memory so that it can be loaded into the FPGA during start

10
up. We were able to take advantage of the CMOD A7’s onboard Quad SPI Flash memory. We
were able to follow detailed instructions2 to generate a binary file that could be written to the
flash memory. Then, on each power up, the FPGA looks first for stored bitstreams in the flash
memory.

8 Challenges
8.1 Debugging
Because this project relies on interfacing between the digital logic and the analog frontend,
the integrated logic analyzer (ILA) proved invaluable. However, one challenge was the difficulty
in debugging some of the larger state machines. The ILA has limited memory and the data
packets takes tens of milliseconds to send. There was a lot of dead time between sending every
two bits that was taking up ILA memory depth. We were able to use more complex triggering
and the multiple sample features to trigger every time a bit is sent and and to only capture a
few samples after each trigger since it only takes one clock cycle to send a bit.
At a higher level, another challenge with debugging was the ability to verify correctness of
the bits that we were reading off the cards. Because the ID card is a black box system, we had
no way of knowing if we were reading or spoofing the bits correctly. We had to carefully verify
each module we built and trust that it was working correctly to debug downstream modules.
The only confirmation we would get is when we were able to use the system to open a door
successfully.

9 Future Work
9.1 Security
Since its use as an authentication mechanism, RFID has received criticism for its security.
Some additional security concerns specific to the MIT system reside in the generation of the
personal bits. Additional analysis can be done to see if there are any patterns or ranges that
the bits span. This would potentially narrow the scope for a brute force attack on the card
readers.
Because the RFID cards use static passwords, they are vulnerable to the exact kind of
spoofing replay attack we have demonstrated in this project. One improvement we can use
to mitigate this attack vector is the use of a one-time password (OTP). Because the card is a
passive system, it would first have to communicate with the card reader to generate the OTP.
With our system, we can implement a handshake and acknowledgement protocol and have the
card FPGA calculate a hash function with a private key along with the acknowledgement data
to generate a unique password per session.

10 Appendix
10.1 Top Level
10.1.1 top_level.sv

1 module top_level (
2 input clk_100mhz ,
2
https://reference.digilentinc.com/learn/programmable-logic/tutorials/cmod-a7-programming-guide/start

11
3 input [1:0] ja ,
4 output logic [0:0] jb ,
5 input [15:0] sw ,
6 logic btnc , // reset
7 logic btnd , // record
8 logic btnu , btnl , btnr , // unassigned
9 output [3:0] vga_r ,
10 output [3:0] vga_b ,
11 output [3:0] vga_g ,
12 output vga_hs ,
13 output vga_vs ,
14 output logic [15:0] led
15 );
16

17 logic record_btn ;
18 assign record_btn = btnd ;
19
20 // Declare BRAM
21 logic [3:0] addr ;
22 logic [193:0] data_to_bram ;
23 logic [193:0] data_from_bram ;
24 logic bram_write ;
25 blk_mem_gen_0 bit_bram (. addra ( addr ) , . clka ( clk_100mhz ) ,
26 . dina ( data_to_bram ) ,
27 . douta ( data_from_bram ) ,
28 . ena (1) , . wea ( bram_write ) ) ;
29
30 // Reader
31 logic id_ready ;
32 logic [193:0] id_bits ;
33 reader card_reader (. comparator_in ( ja [0]) ,
34 . clk_in ( clk_100mhz ) ,
35 . reset_in ( sw [15]) , // activate reader when sw [15] is
low
36 . id_bits_out ( id_bits ) ,
37 . id_ready_out ( id_ready ) ) ;
38

39 // record id_recorder (. addr ( addr ) ,


40 // . record_in ( record_btn ) ,
41 // . id_bits_in ( id_bits ) ,
42 // . id_ready_in ( id_ready ) ,
43 // . clk_in ( clk_100mhz ) ,
44 // . reset_in ( sw [15]) ,
45 // . data_to_bram_out ( data_to_bram ) ,
46 // . bram_write_out ( bram_write ) ) ;
47 // Spoofer
48 logic [193:0] bits_to_spoof ;
49 spoofer id_spoofer ( . card_reader_in ( ja [1]) ,
50 . card_bits_in ( bits_to_spoof ) ,
51 . clk_in ( clk_100mhz ) ,
52 . reset_in (! sw [15]) , // activate spoofer when sw [15]
is high
53 . mosfet_ co nt rol _o ut ( jb [0]) ) ;
54 // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
55 // GUI
56 // create 65 mhz system clock , happens to match 1024 x 768 XVGA timing
57 wire clk_65mhz ;
58 clk_wiz_0 clkdivider (. clk_in1 ( clk_100mhz ) , . clk_out1 ( clk_65mhz ) , . reset
(0) ) ;
59

12
60 wire [10:0] hcount ; // pixel on current line
61 wire [9:0] vcount ; // line number
62 wire hsync , vsync ;
63 wire [11:0] pixel ;
64 reg [11:0] rgb ;
65 wire blank ;
66 xvga xvga1 (. vclock_in ( clk_65mhz ) ,. hcount_out ( hcount ) ,. vcount_out ( vcount )
,
67 . hsync_out ( hsync ) ,. vsync_out ( vsync ) ,. blank_out ( blank ) ) ;
68
69
70 // btnc button is user reset
71 logic reset ;
72 debounce_65mhz db1 (. reset_in (0) ,. clock_in ( clk_65mhz ) ,. noisy_in ( btnc ) ,.
clean_out ( reset ) ) ;
73
74 // UP and DOWN and LEFT and RIGHT for menu interface
75 wire up , down , left , right ;
76 debounce_65mhz db2 (. reset_in ( reset ) ,. clock_in ( clk_65mhz ) ,. noisy_in ( btnu )
,. clean_out ( up ) ) ;
77 debounce_65mhz db3 (. reset_in ( reset ) ,. clock_in ( clk_65mhz ) ,. noisy_in ( btnd )
,. clean_out ( down ) ) ;
78 debounce_65mhz db4 (. reset_in ( reset ) ,. clock_in ( clk_65mhz ) ,. noisy_in ( btnl )
,. clean_out ( left ) ) ;
79 debounce_65mhz db5 (. reset_in ( reset ) ,. clock_in ( clk_65mhz ) ,. noisy_in ( btnr )
,. clean_out ( right ) ) ;
80
81 wire spoof_switch ;
82 debounce_65mhz db6 (. reset_in ( reset ) ,. clock_in ( clk_65mhz ) ,. noisy_in ( sw
[15]) ,. clean_out ( spoof_switch ) ) ;
83

84 wire phsync , pvsync , pblank ;


85 rfid_gui gui (. vclock_in ( clk_65mhz ) ,. reset_in ( reset ) ,
86 . up_in ( up ) ,. down_in ( down ) ,. left_in ( left ) , . right_in ( right ) ,
. is_spoof_display ( spoof_switch ) ,
87 . hcount_in ( hcount ) ,. vcount_in ( vcount ) ,
88 . hsync_in ( hsync ) ,. vsync_in ( vsync ) ,. blank_in ( blank ) ,
89 . phsync_out ( phsync ) ,. pvsync_out ( pvsync ) ,. pblank_out ( pblank )
,. pixel_out ( pixel ) ,
90 . save_addr ( sw [3:0]) ,
91 . read_module_bits ( id_bits ) ,
92 . data_to_bram ( data_to_bram ) ,
93 . data_from_bram ( data_from_bram ) ,
94 . addr ( addr ) ,
95 . write_to_bram ( bram_write ) ,
96 . bits_to_spoof_ou t ( bits_to_spoof ) ) ;
97
98 reg b , hs , vs ;
99 always_ff @ ( posedge clk_65mhz ) begin
100 hs <= phsync ;
101 vs <= pvsync ;
102 b <= pblank ;
103 rgb <= pixel ;
104 end
105

106 // the following lines are required for the Nexys4 VGA circuit - do not
change
107 assign vga_r = ~ b ? rgb [11:8]: 0;
108 assign vga_g = ~ b ? rgb [7:4] : 0;
109 assign vga_b = ~ b ? rgb [3:0] : 0;

13
110
111 assign vga_hs = ~ hs ;
112 assign vga_vs = ~ vs ;
113
114 // Debug
115 assign led [15:0] = sw [14] ? data_from_bram [38:23] : bits_to_spoof
[45:30];
116
117 endmodule

10.2 GUI
10.2.1 rfid_gui.sv

1 //
//////////////////////////////////////////////////////////////////////////////

2 //
3 // RFID GUI
4 //
5 // sw [15] == 1 for SPOOF ; 0 for READ
6 //
//////////////////////////////////////////////////////////////////////////////

7
8 module rfid_gui (
9 input vclock_in , // 65 MHz clock
10 input reset_in , // 1 to initialize module
11 input up_in , //
12 input down_in , //
13 input left_in ,
14 input right_in ,
15 input is_spoof_display , // connected to sw [15]
16 input [3:0] save_addr , // connected to sw [3:0] , location to save
bits to in bram
17 input [193:0] read_module_bits ,
18
19 input [10:0] hcount_in , // horizontal index of current pixel (0..1023)
20 input [9:0] vcount_in , // vertical index of current pixel (0..767)
21 input hsync_in , // XVGA horizontal sync signal ( active low )
22 input vsync_in , // XVGA vertical sync signal ( active low )
23 input blank_in , // XVGA blanking (1 means output black pixel )
24
25 output phsync_out , // pong game ’ s horizontal sync
26 output pvsync_out , // pong game ’ s vertical sync
27 output pblank_out , // pong game ’ s blanking
28 output logic [11:0] pixel_out , // pong game ’ s pixel // r =11:8 , g =7:4 , b
=3:0
29 input [193:0] data_from_bram ,
30 output logic [193:0] data_to_bram ,
31 output logic [3:0] addr ,
32 output logic write_to_bram ,
33 output logic [193:0] bits_to_spoof _out
34 );
35
36 assign phsync_out = hsync_in ;
37 assign pvsync_out = vsync_in ;
38 assign pblank_out = blank_in ;
39
40 // ///// BIT CODE THINGS /////////
41 parameter MIT_BITS = 22 ’ b0 11 0 1 0 0 0 0 1 1 0 0 1 1 1 0 0 0 0 0 1 ;

14
42
43 // /////
44 // ///// Pulse UI Buttons //////////
45 logic up_pulse ;
46 pulse_65mhz my_up_pulse (. clock_in ( vclock_in ) , . signal_in ( up_in ) , .
pulse_out ( up_pulse ) ) ;
47 logic down_pulse ;
48 pulse_65mhz my_down_pulse (. clock_in ( vclock_in ) , . signal_in ( down_in ) , .
pulse_out ( down_pulse ) ) ;
49 logic left_pulse ;
50 pulse_65mhz my_left_pulse (. clock_in ( vclock_in ) , . signal_in ( left_in ) , .
pulse_out ( left_pulse ) ) ;
51 logic right_pulse ;
52 pulse_65mhz my_right_pulse (. clock_in ( vclock_in ) , . signal_in ( right_in ) , .
pulse_out ( right_pulse ) ) ;
53 // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
54
55 parameter BITS_IN_BRAM = 194;
56 logic [ BITS_IN_BRAM -1:0] ascii_module_in ;
57 logic [8* BITS_IN_BRAM -1: 0] ascii_module_out ;
58 bits_to_ascii my_bits_to_ascii (. bits_in ( ascii_module_in ) , . ascii_out (
ascii_module_out ) ) ;
59
60
61 // /// SWITCHES TO NUMBER ////
62 logic [15:0] save_addr_ascii ;
63
64 // //// FONT MODULE ///////
65 logic [64*8 -1:0] char_string ;
66 logic [10:0] string_start_x ;
67 logic [9:0] string_start_y ;
68 logic [6:0] line_number ; // can fit 32 lines on the screen but line_number
will count up to the blank vsync interval
69 assign line_number = vcount_in /24; // text heigh is 24 pixels so line
number is module 24
70 assign string_start_y = line_number * 24;
71 logic coe_pixel_out ;
72 parameter CHARS_PER_LINE = 64; // at most 64 characters per line
73 c ha r _ st r ing_display read_spoo f_d is pl ay (. vclock ( vclock_in ) , . hcount (
hcount_in ) , . vcount ( vcount_in ) , . pixel ( coe_pixel_out ) , . cstring (
char_string ) , . cx ( string_start_x ) , . cy ( string_start_y ) ) ;
74 // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
75

76 // / / / / / / / / / / / / / / / / / / / / / / / / / /
77 // //// ASCII
78 // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
79 parameter SPOOF_ASCII = 40 ’ b 0 1 0 1 0 0 1 1 0 1 0 1 0 0 0 0 0 1 0 0 1 1 1 1 0 1 0 0 1 1 1 1 0 1 0 0 0 1 1 0 ;
80 parameter READ_ASCII = 32 ’ b 0 1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 ;
81 parameter ASCII_0 = 8 ’ b00110000 ;
82 parameter ASCII_1 = 8 ’ b00110001 ;
83 parameter ASCII_SPACE = 8 ’ b00100000 ;
84 parameter ASCII_COLON = 8 ’ b00111010 ;
85 parameter ASCII_BITS_TEXT = 48 ’
b 0 1 1 0 0 0 1 0 0 1 1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 1 1 1 0 0 1 1 0 0 1 1 1 0 1 0 0 0 1 0 0 0 0 0 ; // " bits : "
86 parameter ASCII_ID = 32 ’ b 0 1 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 1 0 0 0 0 0 ; // " ID : "
87 parameter ASCII_NOT_REC = 112 ’
b0110111001101111011101000010000001110010011001010110001101101111011001110110111001
; // " not recognized "
88 parameter ASCII_MIT = 24 ’ b 0 1 0 0 1 1 0 1 0 1 0 0 1 0 0 1 0 1 0 1 0 1 0 0 ; // " MIT "
89 parameter ASCII_POUND = 16 ’ b00 100011001 00000 ; // "# "

15
90 parameter ASCII_EMPTY = 40 ’ b 0 1 1 0 0 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 0 0 0 0 1 1 1 0 1 0 0 0 1 1 1 1 0 0 1 ; //
" empty "
91 parameter ASCII_SAVE_AS = 112 ’
b0111001101100001011101100110010100100000010010010100010000100000011000010111001100
; // " save ID as #: "
92 // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
93
94 // logic old_hsync_in ;
95
96 logic [3:0] selected_id ; // 16 IDs in bram to select from using up and
down arrow keys
97 logic [3:0] displayed_id ;
98 logic verbose_mode ;
99

100 always_ff @ ( posedge vclock_in ) begin


101
102 // / CLOCKED SPOOF LOGIC
103 if ( is_spoof_display == 1) begin
104 write_to_bram <= 0;
105 ascii_module_in <= data_from_bram ;
106 addr <= displayed_id ; // will change as hcount and vcount change
107
108 if ( displayed_id == selected_id ) begin
109 bits_to_spoof_out <= data_from_bram ;
110 end
111 if ( reset_in ) begin
112 string_start_x <= 0;
113 selected_id <= 0;
114 verbose_mode <= 0;
115
116 // keep track of state of selected ID
117 end else if ( up_pulse ) begin
118 if ( selected_id > 0) selected_id <= selected_id - 1;
119 end else if ( down_pulse ) begin
120 if ( selected_id < 15) selected_id <= selected_id + 1;
121
122 end else if ( right_pulse ) begin
123 verbose_mode <= 1;
124 end else if ( left_pulse ) begin
125 verbose_mode <= 0;
126 end
127
128 if ( line_number == 0) begin
129 pixel_out = 12 ’ hFFF * coe_pixel_out ;
130 end else if ((2* selected_id +1) == line_number ) begin
131 pixel_out = ~(12 ’ hFFF * coe_pixel_out ) ;
132 end
133 else begin
134 pixel_out = 12 ’ hFFF * coe_pixel_out ;
135 end
136
137 // /// CLOCKED READ LOGIC
138
139 end else begin
140 ascii_module_in <= read_module_bits ;
141 addr <= save_addr ;
142 // save_addr switches to ascii
143 case ( save_addr )
144 4 ’ b0000 : save_addr_ascii <= ASCII_0 +8 ’ d0 ;
145 4 ’ b0001 : save_addr_ascii <= ASCII_0 +8 ’ d1 ;

16
146 4 ’ b0010 : save_addr_ascii <= ASCII_0 +8 ’ d2 ;
147 4 ’ b0011 : save_addr_ascii <= ASCII_0 +8 ’ d3 ;
148 4 ’ b0100 : save_addr_ascii <= ASCII_0 +8 ’ d4 ;
149 4 ’ b0101 : save_addr_ascii <= ASCII_0 +8 ’ d5 ;
150 4 ’ b0110 : save_addr_ascii <= ASCII_0 +8 ’ d6 ;
151 4 ’ b0111 : save_addr_ascii <= ASCII_0 +8 ’ d7 ;
152 4 ’ b1000 : save_addr_ascii <= ASCII_0 +8 ’ d8 ;
153 4 ’ b1001 : save_addr_ascii <= ASCII_0 +8 ’ d9 ;
154 4 ’ b1010 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d0 };
155 4 ’ b1011 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d1 };
156 4 ’ b1100 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d2 };
157 4 ’ b1101 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d3 };
158 4 ’ b1110 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d4 };
159 4 ’ b1111 : save_addr_ascii <= { ASCII_1 , ASCII_0 +8 ’ d5 };
160 endcase
161
162 if ( right_pulse == 1) begin // write to bram
163 write_to_bram <= 1;
164 end else begin // don ’ t write to bram , just display
165 write_to_bram <= 0;
166 if (( line_number == 7) & ( right_in == 1) ) begin
167 pixel_out = ~(12 ’ hFFF * coe_pixel_out ) ;
168 end else begin
169 pixel_out = 12 ’ hFFF * coe_pixel_out ;
170 end
171 end
172
173 end
174
175 end
176

177 // combinational logic determines


178 // 1) based on line number , what text should be ,
179 // 2) what the color of pixel_out should be by feeding char_string
through cstringdisplay . v to produce coe_pixel_out
180 // 3) pixel_out based on coe_pixel_out
181 // uses combinational logic on hcount_in and vcount_into determine what
the element to be displayed is
182
183 always_comb begin
184 // //////// // SPOOF DISPLAY //////////////
185 if ( is_spoof_display == 1) begin
186 // generate ascii for each line -- display rom text on odd lines
in non verbose mode
187 displayed_id = ( line_number - 1) >> 1; // which ID is currently
displayed
188
189
190 // ascii_module
191
192 // ascii string to display
193 case ( line_number )
194 0: char_string = SPOOF_ASCII ;
195 1: char_string = { ASCII_0 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
196 3: char_string = { ASCII_0 +8 ’ d1 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
197 5: char_string = { ASCII_0 +8 ’ d2 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
198 7: char_string = { ASCII_0 +8 ’ d3 , ASCII_COLON , ASCII_SPACE ,

17
ascii_module_out [55*8 -1:0]};
199 9: char_string = { ASCII_0 +8 ’ d4 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
200 11: char_string = { ASCII_0 +8 ’ d5 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
201 13: char_string = { ASCII_0 +8 ’ d6 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
202 15: char_string = { ASCII_0 +8 ’ d7 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
203 17: char_string = { ASCII_0 +8 ’ d8 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
204 19: char_string = { ASCII_0 +8 ’ d9 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
205 21: char_string = { ASCII_1 , ASCII_0 , ASCII_COLON , ASCII_SPACE ,
ascii_module_out [55*8 -1:0]};
206 23: char_string = { ASCII_1 , ASCII_0 +8 ’ d1 , ASCII_COLON ,
ASCII_SPACE , ascii_module_out [55*8 -1:0]};
207 25: char_string = { ASCII_1 , ASCII_0 +8 ’ d2 , ASCII_COLON ,
ASCII_SPACE , ascii_module_out [55*8 -1:0]};
208 27: char_string = { ASCII_1 , ASCII_0 +8 ’ d3 , ASCII_COLON ,
ASCII_SPACE , ascii_module_out [55*8 -1:0]};
209 29: char_string = { ASCII_1 , ASCII_0 +8 ’ d4 , ASCII_COLON ,
ASCII_SPACE , ascii_module_out [55*8 -1:0]};
210 31: char_string = { ASCII_1 , ASCII_0 +8 ’ d5 , ASCII_COLON ,
ASCII_SPACE , ascii_module_out [55*8 -1:0]};
211 default : char_string = 0;
212 endcase
213
214 end
215
216

217 // ////// is_spoof_display ==0 for READ DISPLAY ///////////


218 else begin
219
220 // ascii
221
222 data_to_bram = read_module_bits ;
223 // // display
224 case ( line_number )
225 0: char_string = READ_ASCII ;
226 3: char_string = { ASCII_BITS_TEXT , ascii_module_out
[55*8 -1:0]}; // print out 22 MIT and 33 personal from left to right
227 5: begin
228 if ( read_module_bits [21:0] == MIT_BITS ) begin
229 char_string = { ASCII_ID , ASCII_MIT }; // add
information about whether the ID is mit , unidentified or stored in the
bram
230 end else begin
231 char_string = { ASCII_ID , ASCII_NOT_REC };
232 end
233 end
234 7: char_string = { ASCII_SAVE_AS , save_addr_ascii };
235 default : char_string = 0;
236 endcase
237 end
238
239
240 end
241
242

18
243 // ila_0 myila (. clk ( vclock_in ) , . probe0 ( hsync_in ) , . probe1 ( vsync_in ) , .
probe2 ( hcount_in ) , . probe3 ( pixel_out ) , . probe4 ( puck_center_x ) , . probe5 (
puck_center_y ) ) ;
244
245 endmodule
246
247 module synchronize #( parameter NSYNC = 3) // number of sync flops .
must be >= 2
248 ( input clk , in ,
249 output reg out ) ;
250
251 reg [ NSYNC -2:0] sync ;
252
253 always_ff @ ( posedge clk )
254 begin
255 { out , sync } <= { sync [ NSYNC -2:0] , in };
256 end
257 endmodule
258
259 //
/////////////////////////////////////////////////////////////////////////////

260 //
261 // Rising Edge Pulse
262 //
263 //
/////////////////////////////////////////////////////////////////////////////

264
265 module pulse_65mhz ( input clock_in , input signal_in , output pulse_out ) ;
266

267 logic old_signal_in ;


268 assign pulse_out = ( old_signal_in == 0) & ( signal_in == 1) ;
269 always_ff @ ( posedge clock_in ) begin
270 old_signal_in <= signal_in ;
271 end
272 endmodule
273
274
275
276 //
/////////////////////////////////////////////////////////////////////////////

277 //
278 // Pushbutton Debounce Module ( video version - 24 bits )
279 //
280 //
/////////////////////////////////////////////////////////////////////////////

281
282 module debounce_65mhz ( input reset_in , clock_in , noisy_in ,
283 output reg clean_out ) ;
284
285 reg [19:0] count ;
286 reg new_input ;
287
288 always_ff @ ( posedge clock_in )
289 if ( reset_in ) begin
290 new_input <= noisy_in ;
291 clean_out <= noisy_in ;

19
292 count <= 0; end
293 else if ( noisy_in != new_input ) begin new_input <= noisy_in ; count <= 0;
end
294 else if ( count == 1000000) clean_out <= new_input ;
295 else count <= count +1;
296
297
298 endmodule
299
300 //
////////////////////////////////////////////////////////////////////////////////

301 // Update : 8/8/2019 GH


302 // Create Date : 10/02/2015 02:05:19 AM
303 // Module Name : xvga
304 //
305 // xvga : Generate VGA display signals (1024 x 768 @ 60 Hz )
306 //
307 // ---- HORIZONTAL ----- ------ VERTICAL
-----
308 // Active Active
309 // Freq Video FP Sync BP Video FP Sync
BP
310 // 640 x480 , 60 Hz 25.175 640 16 96 48 480 11 2
31
311 // 800 x600 , 60 Hz 40.000 800 40 128 88 600 1 4
23
312 // 1024 x768 , 60 Hz 65.000 1024 24 136 160 768 3 6
29
313 // 1280 x1024 , 60 Hz 108.00 1280 48 112 248 768 1 3
38
314 // 1280 x720p 60 Hz 75.25 1280 72 80 216 720 3 5
30
315 // 1920 x1080 60 Hz 148.5 1920 88 44 148 1080 4 5
36
316 //
317 // change the clock frequency , front porches , sync ’s , and back porches to
create
318 // other screen resolutions
319 //
//////////////////////////////////////////////////////////////////////////////

320

321 module xvga ( input vclock_in ,


322 output reg [10:0] hcount_out , // pixel number on current line
323 output reg [9:0] vcount_out , // line number
324 output reg vsync_out , hsync_out ,
325 output reg blank_out ) ;
326

327 parameter DISPLAY_WIDTH = 1024; // display width


328 parameter DISPLAY_HEIGHT = 768; // number of lines
329
330 parameter H_FP = 24; // horizontal front porch
331 parameter H_SYNC_PULSE = 136; // horizontal sync
332 parameter H_BP = 160; // horizontal back porch
333
334 parameter V_FP = 3; // vertical front porch
335 parameter V_SYNC_PULSE = 6; // vertical sync
336 parameter V_BP = 29; // vertical back porch
337

20
338 // horizontal : 1344 pixels total
339 // display 1024 pixels per line
340 reg hblank , vblank ;
341 wire hsyncon , hsyncoff , hreset , hblankon ;
342 assign hblankon = ( hcount_out == ( DISPLAY_WIDTH -1) ) ;
343 assign hsyncon = ( hcount_out == ( DISPLAY_WIDTH + H_FP - 1) ) ; // 1047
344 assign hsyncoff = ( hcount_out == ( DISPLAY_WIDTH + H_FP + H_SYNC_PULSE -
1) ) ; // 1183
345 assign hreset = ( hcount_out == ( DISPLAY_WIDTH + H_FP + H_SYNC_PULSE +
H_BP - 1) ) ; // 1343
346
347 // vertical : 806 lines total
348 // display 768 lines
349 wire vsyncon , vsyncoff , vreset , vblankon ;
350 assign vblankon = hreset & ( vcount_out == ( DISPLAY_HEIGHT - 1) ) ; // 767
351 assign vsyncon = hreset & ( vcount_out == ( DISPLAY_HEIGHT + V_FP - 1) ) ;
// 771
352 assign vsyncoff = hreset & ( vcount_out == ( DISPLAY_HEIGHT + V_FP +
V_SYNC_PULSE - 1) ) ; // 777
353 assign vreset = hreset & ( vcount_out == ( DISPLAY_HEIGHT + V_FP +
V_SYNC_PULSE + V_BP - 1) ) ; // 805
354
355 // sync and blanking
356 wire next_hblank , next_vblank ;
357 assign next_hblank = hreset ? 0 : hblankon ? 1 : hblank ;
358 assign next_vblank = vreset ? 0 : vblankon ? 1 : vblank ;
359 always_ff @ ( posedge vclock_in ) begin
360 hcount_out <= hreset ? 0 : hcount_out + 1;
361 hblank <= next_hblank ;
362 hsync_out <= hsyncon ? 0 : hsyncoff ? 1 : hsync_out ; // active low
363

364 vcount_out <= hreset ? ( vreset ? 0 : vcount_out + 1) : vcount_out ;


365 vblank <= next_vblank ;
366 vsync_out <= vsyncon ? 0 : vsyncoff ? 1 : vsync_out ; // active low
367
368 blank_out <= next_vblank | ( next_hblank & ~ hreset ) ;
369 end
370 endmodule

10.2.2 bits_to_ascii.sv

1 // converts entire 194 bits into ascii . later on , can index in


2 module bits_to_ascii (
3 input logic [193:0] bits_in ,
4 output logic [8*194 -1:0] ascii_out
5 );
6
7 parameter ASCII_0 = 8 ’ b00110000 ;
8 parameter ASCII_1 = 8 ’ b00110001 ;
9 parameter MAX_BITS = 194; // at most 64 characters per line
10
11 always @ (*) begin
12 for ( int n =0 ; n < MAX_BITS ; n ++) begin
13 ascii_out [8* n +: 8] <= ( bits_in [ n ] == 1) ? ASCII_1 : ASCII_0 ;
14 end
15 end
16

17 endmodule

10.2.3 cstringdisplay.v

21
1 //
2 // File : cstringdisp . v
3 // Date : 24 - Oct -05
4 // Author : I . Chuang , C . Terman
5 //
6 // Display an ASCII encoded character string in a video window at some
7 // specified x , y pixel location .
8 //
9 // INPUTS :
10 //
11 // vclock - video pixel clock
12 // hcount - horizontal ( x ) location of current pixel
13 // vcount - vertical ( y ) location of current pixel
14 // cstring - character string to display (8 bit ASCII for each char )
15 // cx , cy - pixel location ( upper left corner ) to display string at
16 //
17 // OUTPUT :
18 //
19 // pixel - video pixel value to display at current location
20 //
21 // PARAMETERS :
22 //
23 // NCHAR - number of characters in string to display
24 // NCHAR_BITS - number of bits to specify NCHAR
25 //
26 // pixel should be OR ’ ed ( or XOR ’ ed ) to your video data for display .
27 //
28 // Each character is 8 x12 , but pixels are doubled horizontally and
vertically
29 // so fonts are magnified 2 x . On an XGA screen (1024 x768 ) you can fit
30 // 64 x 32 such characters .
31 //
32 // Needs font_rom . v and font_rom . ngo
33 //
34 // For different fonts , you can change font_rom . For different string
35 // display colors , change the assignment to cpixel .
36

37
38 //
////////////////////////////////////////////////////////////////////////////

39 //
40 // video character string display
41 //
42 //
////////////////////////////////////////////////////////////////////////////

43
44 module c h ar _string_display ( vclock , hcount , vcount , pixel , cstring , cx , cy ) ;
45
46 parameter NCHAR = 64; // number of 8 - bit characters in cstring
47 parameter NCHAR_BITS = 6; // number of bits in NCHAR
48
49 input vclock ; // 65 MHz clock
50 input [10:0] hcount ; // horizontal index of current pixel (0..1023)
51 input [9:0] vcount ; // vertical index of current pixel (0..767)
52 output [2:0] pixel ; // char display ’ s pixel
53 input [ NCHAR *8 -1:0] cstring ; // character string to display
54 input [10:0] cx ;
55 input [9:0] cy ;

22
56
57 // 1 line x 8 character display (8 x 12 pixel - sized characters )
58
59 wire [10:0] hoff = ( hcount +2) -1 - cx ; // " prefetch " 2 clock cycles
60 wire [9:0] voff = vcount - cy ;
61 wire [ NCHAR_BITS -1:0] column = NCHAR -1 - hoff [ NCHAR_BITS -1+4:4]; // <
NCHAR
62 wire [2:0] h = hoff [3:1]; // 0 .. 7
63 wire [3:0] v = voff [4:1]; // 0 .. 11
64
65 // look up character to display ( from character string )
66 reg [7:0] char ;
67 integer n ;
68 always @ (*)
69 for ( n =0 ; n <8 ; n = n +1 ) // 8 bits per character ( ASCII )
70 char [ n ] <= cstring [ column *8+ n ];
71
72 // look up raster row from font rom
73 wire reverse = char [7];
74 wire [10:0] font_addr = char [6:0]*12 + v ; // 12 bytes per character
75 wire [7:0] font_byte ;
76 font_rom f (
77 . clka ( vclock ) ,
78 . addra ( font_addr ) ,
79 . douta ( font_byte ) ) ;
80
81 // generate character pixel if we ’ re in the right h , v area
82 wire [2:0] cpixel = ( font_byte [7 - h ] ^ reverse ) ? 7 : 0;
83 wire dispflag = (( hcount > cx ) & ( vcount >= cy ) & ( hcount <= cx + NCHAR *16)
84 & ( vcount < cy + 24) ) ;
85 wire [2:0] pixel = dispflag ? cpixel : 0;
86
87 endmodule

10.3 Spoofing
10.3.1 spoofer.sv

1 module spoofer (
2 input clk_in ,
3 input reset_in , // center button for reset
4 input card_reader_in , // ready - signal from incoming 125 kHz wave
5 input [193:0] card_bits_in , // data bits to spoof ([193:0])
6 output logic mosfet_contr ol _o ut // mosfet state
7 );
8
9 // mosfet output signal
10 logic spoof_out ; // mosfet state
11 assign mosfet_control_out = spoof_out ;
12
13 parameter NUM_BITS = 224;
14 logic [ NUM_BITS -1: 0] data_in ;
15 assign data_in = {30 ’ b0 , card_bits_in }; // prepend 30 zeros to the front
of the data bits
16 logic [ NUM_BITS -1:0] cyclic_data_in ;
17
18 logic [4:0] cycles_per_bit_c o u n t ; // 5 bits so 32 cycles per bit
19
20 logic [3:0] card_reader_buffe r ; // incoming data
21 logic card_reader_noisy ; // buffered
22 logic card_reader_clean ; // buffered and debounced

23
23 debounce c a r d _ r e a d e r _ n o i s y _ d e b o u n c e (. reset_in ( reset_in ) , . clock_in (
clk_in ) , . noisy_in ( card_reader _noisy ) ,
24 . clean_out ( card _reader_ clean ) ) ;
25 logic card_reader_pulse ; // true on rising edge
26 pulse m y_card_reader_pulse (. clock ( clk_in ) , . signal ( card _reader_ clean ) ,
. pulsed_signal ( card_reader_pulse ) ) ; // pulse the clean debounced signal
27
28 logic [7:0] current_bit_loc ;
29 parameter MAX_LOC = 223;
30 logic currentBit ; // MSB of cyclic_data_in
31 logic previousBit ; // previous MSB of cyclic_data_in
32 assign currentBit = data_in [ current_bit_loc ];
33
34 always_ff @ ( posedge clk_in ) begin
35 if ( reset_in ) begin // reset and initialize
36 spoof_out <= 0;
37 cycles_per_bit_count <= 1;
38 previousBit <= currentBit ;
39 card_reader_buffer <= 4 ’ b0 ;
40 card_reader_noisy <= 0;
41 current_bit_loc <= 0;
42 end
43
44 else begin
45 if ( card_reader_pulse ) begin // determine spoof_out
46 if ( cycles_per_b i t _ c o u n t == 0) begin // move to next bit
47
48 // if bit flip from previous to current , phase shift
implies spoof_out remains the same
49 spoof_out <= ( previousBit != currentBit ) ? spoof_out : !
spoof_out ;
50
51 // get the next bit and bit shift cyclic_data_in
52 previousBit <= currentBit ;
53 current_bit_loc <= ( current_bit_loc == MAX_LOC ) ? 0:
current_bit_loc + 1; // bit shifting cyclic_data_in will pop the MSB
54 end
55
56 else begin
57 spoof_out <= ! spoof_out ;
58 end
59
60 cycles_per_bit_c o u n t <= c y c l es _ p e r _ b i t _ c o u n t + 1;
61 end
62
63 card_reader_noisy <= ( ca rd _r ea der _b uf fer >> 3) ;
64 card_reader_buffer <= ( ca rd_ re ad er_ bu ff er << 1) + card_reader_in
;
65 end
66 end
67
68 endmodule
69
70
71 // module spoof_module (
72 // input clk_100mhz ,
73 // input logic btnc , // center button for reset
74 // input logic [0:0] ja , // card_reader_in : ready - signal from
incoming 125 kHz wave
75 // output logic [0:0] jb // spoof_out : mosfet state

24
76 // );
77

78
79 // // mosfet output signal
80 // logic spoof_out ; // mosfet state
81 // assign jb = spoof_out ;
82
83 // logic [29:0] consecutive_bits ;
84 // assign consecutive_bits = 30 ’ b0 ;
85
86 // logic [21:0] constant_bits ;
87 // assign constant_bits = 22 ’ b 1 0 0 0 0 0 1 1 1 0 0 1 1 0 0 0 0 1 0 1 1 0 ;
88
89 // logic [32:0] personal_bits ;
90 // assign personal_bits = 33 ’ b 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 0 1 1 1 1 ; // hannah
91 // // // 33 ’ b 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 1 1 1 1 0 1 0 0 // miles
92
93 // logic [138:0] trash_bits ;
94 // assign trash_bits = 139 ’
b0101100010101101010000011001011100010110111001100011010101011101011110010010001000
;
95
96 // parameter NUM_BITS = 224;
97 // logic [ NUM_BITS -1: 0] data_in ;
98 // assign data_in = { consecutive_bits , constant_bits , personal_bits ,
trash_bits };
99 // logic [ NUM_BITS -1:0] cyclic_data_in ;
100
101 // logic [2:0] cycles_per_bit _ c o u n t ; //5 bits so 32 cycles per bit
102
103 // logic [3:0] card_reader_buf fer ; // incoming data
104 // logic card_reader_noisy ; // buffered
105 // logic card_reader_clean ; // buffered and debounced
106 // debounce c a r d _ r e a d e r _ n o i s y _ d e b o u n c e (. reset_in ( btnc ) , . clock_in (
clk_100mhz ) , . noisy_in ( card_rea der_nois y ) ,
107 // . clean_out ( card _reader_ clean ) ) ;
108 // logic card_reader_pulse ; // true on rising edge
109 // pulse my_card_reader_pulse (. clock ( clk_100mhz ) , . signal (
card_ reader_clean ) , . pulsed_signal ( ca rd_reade r_pulse ) ) ; // pulse the clean
debounced signal
110
111 // logic currentBit ; // MSB of cyclic_data_in
112 // logic previousBit ; // previous MSB of cyclic_data_in
113 // assign currentBit = btnc ? ( data_in >> ( NUM_BITS - 1) ) : (
cyclic_data_in >> ( NUM_BITS - 1) ) ;
114
115 // always_ff @ ( posedge clk_100mhz ) begin
116 // if ( btnc ) begin // reset and initialize
117 // cyclic_data_in <= data_in ;
118 // spoof_out <= 0;
119 // cycles_per_bit_cou n t <= 1;
120 // previousBit <= currentBit ;
121 // card_reader_buffer <= 4 ’ b0 ;
122 // card_reader_noisy <= 0;
123 // end
124
125 // else begin
126 // if ( card_reader_pulse ) begin // determine spoof_out
127 // if ( cycles_per _ b i t _ c o u nt == 0) begin // move to next bit
128

25
129 // // if bit flip from previous to current , phase shift
implies spoof_out remains the same
130 // spoof_out <= ( previousBit != currentBit ) ? spoof_out :
! spoof_out ;
131
132 // // get the next bit and bit shift cyclic_data_in
133 // previousBit <= currentBit ;
134 // cyclic_data_in <= ( cyclic_data_in << 1) + currentBit ;
// bit shifting cyclic_data_in will pop the MSB
135 // end
136
137 // else begin
138 // spoof_out <= ! spoof_out ;
139 // end
140
141 // cycles_per_bit _ c o u n t <= c y c l e s _ p e r _ b i t _ c o u nt + 1;
142 // end
143
144 // card_reader_noisy <= ( c ar d_ rea de r_ buf fe r >> 3) ;
145 // card_reader_buffer <= ( c ar d_ rea de r_ buf fe r << 1) + ja ;
146 // end
147 // end
148
149 // endmodule

10.3.2 debounce.sv

1 module pulse (
2 input clock ,
3 input signal ,
4 output pulsed_signal
5 );
6

7 logic old_signal ;
8 assign pulsed_signal = ( old_signal == 0) & ( signal == 1) ;
9
10 always_ff @ ( posedge clock ) begin
11 old_signal <= signal ;
12 end
13
14 endmodule
15
16
17
18 module debounce ( input reset_in , clock_in , noisy_in ,
19 output logic clean_out ) ;
20
21 logic [4:0] count ;
22 logic new_input ;
23
24 always_ff @ ( posedge clock_in )
25 if ( reset_in ) begin
26 new_input <= noisy_in ;
27 clean_out <= noisy_in ;
28 count <= 0; end
29 else if ( noisy_in != new_input ) begin new_input <= noisy_in ; count <= 0;
end
30 else if ( count >= 5) clean_out <= new_input ;
31 else count <= count +1;
32
33 endmodule

26
10.4 Reading
1 module reader (
2 input comparator_in ,
3 input clk_in ,
4 input reset_in ,
5 input [3:0] addr_in ,
6 input record_in ,
7 output logic [193:0] id_bits_out ,
8 output logic id_ready_out
9 );
10 logic pulse ;
11 logic bit_ready ;
12 logic current_bit ;
13 pulse_gen comparator_cleanup (. comparator_in ( comparator_in ) ,
14 . clk_in ( clk_in ) ,
15 . reset_in ( reset_in ) ,
16 . pulse_out ( pulse ) ) ;
17 parser comparator_parser (. pulse_in ( pulse ) ,
18 . clk_in ( clk_in ) ,
19 . reset_in ( reset_in ) ,
20 . bit_ready_out ( bit_ready ) ,
21 . current_bit_out ( current_bit ) ) ;
22 read_fsm fsm (. bit_ready_in ( bit_ready ) ,
23 . sent_bit_in ( current_bit ) ,
24 . reset_in ( reset_in ) ,
25 . clk_in ( clk_in ) ,
26 . id_out ( id_bits_out ) ,
27 . id_ready_out ( id_ready_out ) ) ;
28
29 endmodule
30
31 module record (
32 input [3:0] addr ,
33 input record_in , // Signal to record
34 input [193:0] id_bits_in , // id number to record
35 input id_ready_in , // id number ready signal from the reader module
36 input clk_in ,
37 input reset_in ,
38 output logic [193:0] data_to_bram_out ,
39 output logic bram_write_out
40 );
41 // Continuously stores IDs being emitted from the reader module and
stores in internal register
42 // This allows for instantaneous recording when the button is pressed .
43 parameter S_IDLE = 0;
44 parameter S_RECORD = 1;
45
46 logic state = S_IDLE ;
47 logic [193:0] last_valid_id_ num = 0;
48
49 always_ff @ ( posedge clk_in ) begin
50 case ( state )
51 S_IDLE : begin
52 bram_write_out <= 0; // ensure one cycle pulse
53 if ( record_in ) begin
54 state <= S_RECORD ;
55 end
56 if ( id_ready_in ) begin
57 last_valid_id _num <= id_bits_in ;

27
58 end
59 end
60 S_RECORD : begin
61 data_to_bram_out <= las t_valid_ id_num ;
62 bram_write_out <= 1;
63 state <= S_IDLE ;
64 end
65 default : begin
66 state <= S_IDLE ;
67 bram_write_out <= 0;
68 last_valid_id_num <= 0;
69 end
70 endcase
71 end
72 endmodule
73
74 /*
75 parser receives the raw pulse data from the comparator and determines if a
bit has been sent
76 */
77 module parser (
78 input pulse_in , // Assumed to be a single clock cycle pulse
79 input clk_in ,
80 input reset_in ,
81 output logic bit_ready_out ,
82 output logic current_bit_out
83 );
84 parameter RFID_FREQ = 125000; // This needs to be tuned depending on the
coil for optimal performance
85
86 parameter PULSE_PER_BIT = 16;
87 // parameter CYCLES_PER_PULSE = 2 * 100000000 / RFID_FREQ ; //1600; // 1 /
62.5 kHz * 100 MHz = 1600 clock cycles per pulse
88 parameter CYCLES_PER_PULSE = 1600;
89 parameter CYCLE_COUNT_ERROR = 100; // allowable tolerance on the period
90 logic [4:0] pulse_count ; // count the number of pulses detected
91 logic [11:0] cycle_count ; // longest expected duration between pulses is
2400 cycles (1.5 * period )
92
93 // Every 16 pulses , output one bit
94 always_ff @ ( posedge clk_in ) begin
95 if ( bit_ready_out ) begin
96 bit_ready_out <= 0; // ensure bit_ready_out is one pulse wide
97 end
98 if ( pulse_in ) begin
99 // Check for phase shift
100 if ( cycle_count > CYCLES_PER_PULSE + CYC LE_COUNT_ ERROR ||
101 cycle_count < CYCLES_PER_PULSE - CYCL E_COUNT_ ERROR ) begin
102 current_bit_out <= current_bit_out ^ 1 ’ b1 ; // toggle
current_bit_out
103 end
104 // Check if a bit has been sent
105 if ( pulse_count == PULSE_PER_BIT - 1) begin
106 pulse_count <= 0;
107 bit_ready_out <= 1; // tell next module that a bit is ready
to be read
108 end else begin
109 pulse_count <= pulse_count + 1;
110 end
111 cycle_count <= 0;

28
112 end else begin
113 cycle_count <= cycle_count + 1;
114 end
115
116 if ( reset_in ) begin
117 pulse_count <= 0;
118 current_bit_out <= 0;
119 bit_ready_out <= 0;
120 end
121 end
122
123 endmodule
124
125 /* Receives the output from the comparator . Needs to create a sharp
transistion and an output pulse with one clock cycle width */
126 module pulse_gen (
127 input comparator_in ,
128 input clk_in ,
129 input reset_in ,
130 output logic pulse_out
131 );
132 logic prev_input ;
133 logic [4:0] input_buffer ;
134 always_ff @ ( posedge clk_in ) begin
135 if ( pulse_out ) begin
136 pulse_out <= 0; // Guarantee one - cycle long pulse
137 end
138 input_buffer <= { comparator_in , input_buffer [4:1]};
139 // Wait until the entire buffer agrees before accepting the bit
since the comparator is slow
140 if ( input_buffer == 5 ’ b11111 || input_buffer == 0) begin
141 prev_input <= input_buffer [0];
142 // Check for falling edge
143 if ( input_buffer [0] == 0 && prev_input == 1) begin
144 pulse_out <= 1;
145 end
146 end
147 if ( reset_in ) begin
148 pulse_out <= 0;
149 prev_input <= 0;
150 end
151 end
152 endmodule
153
154 module read_fsm ( input bit_ready_in ,
155 input sent_bit_in ,
156 input clk_in ,
157 input reset_in ,
158 output logic [193:0] id_out ,
159 output logic id_ready_out ) ;
160
161 // Hyperparameters
162 parameter CONSEC_BIT_THRESHO L D = 25; // Detect 25 consecutive bits
before transitioning to triggered
163 parameter NUM_CONST_1 = 22;
164 parameter NUM_PERSONAL = 33;
165 parameter NUM_CONST_2 = 139;
166
167 // States
168 parameter S_IDLE = 0;

29
169 parameter S_TRIGGERED = 1;
170 parameter S_CONSTANT_1 = 2;
171 parameter S_PERSONAL = 3;
172 parameter S_CONSTANT_2 = 4;
173
174 logic [2:0] state = S_IDLE ;
175 logic parity = 0; // There ’ s a chance all the bits are flipped . XOR
inputs with this parity bit to fix this
176 logic input_bit ;
177 assign input_bit = parity ^ sent_bit_in ;
178 logic prev_bit ;
179 logic [7:0] bit_count ;
180
181 always_ff @ ( posedge clk_in ) begin
182 if ( reset_in ) begin
183 state <= S_IDLE ;
184 prev_bit <= 0;
185 bit_count <= 0;
186 parity <= 0;
187 id_ready_out <= 0;
188 id_out <= 0;
189 end else if ( bit_ready_in ) begin
190 case ( state )
191 S_IDLE : begin
192 // Look for consecutive string of same bit
193 id_ready_out <= 0; // Clear the bit if already set from
a previous run
194 bit_count <= input_bit == prev_bit ? bit_count + 1 : 0;
195 prev_bit <= input_bit ;
196 if ( bit_count > C O N S E C _ B I T _ T H R ES H O L D ) begin
197 state <= S_TRIGGERED ;
198 if ( input_bit == 1) begin
199 // If a string of ones is detected , flip parity
bit ( we are backwards )
200 parity <= 1;
201 end
202 end
203 end
204 S_TRIGGERED : begin
205 // Wait for first one
206 if ( input_bit == 1) begin
207 id_out [0] <= 1;
208 bit_count <= 1;
209 state <= S_CONSTANT_1 ;
210 end
211 end
212 S_CONSTANT_1 : begin
213 if ( bit_count == 11 && id_out [9:0] != 10 ’ b0111000001 )
begin // invalid , reject
214 state <= S_IDLE ;
215 bit_count <= 0;
216 parity <= 0;
217 prev_bit <= 0;
218 end
219 id_out [ bit_count ] <= input_bit ;
220 bit_count <= bit_count + 1;
221 if ( bit_count == NUM_CONST_1 - 1) begin
222 state <= S_PERSONAL ;
223 end
224 end

30
225 S_PERSONAL : begin
226 id_out [ bit_count ] <= input_bit ;
227 bit_count <= bit_count + 1;
228 if ( bit_count == NUM_PERSONAL + NUM_CONST_1 - 1) begin
229 state <= S_CONSTANT_2 ;
230 end
231 end
232 S_CONSTANT_2 : begin
233 id_out [ bit_count ] <= input_bit ;
234 bit_count <= bit_count + 1;
235 if ( bit_count == NUM_PERSONAL + NUM_CONST_1 + NUM_CONST_2
- 1) begin
236 state <= S_IDLE ;
237 id_ready_out <= 1;
238 bit_count <= 0;
239 parity <= 0;
240 prev_bit <= 0;
241 end
242 end
243 default :
244 state <= S_IDLE ;
245 endcase
246 end
247 end
248 endmodule

31

You might also like