Massachusetts Institute of Technology Department of Electrical Engineering and Computer Science
Massachusetts Institute of Technology Department of Electrical Engineering and Computer Science
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
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.
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.
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.
• 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.
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.
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).
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.
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.
bit_ready id_ready_out
comparator_in pulse_gen pulse parser read_fsm
current_bit id_bits_out [193:0]
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.
consecutive
IDLE TRIGGERED 1 CONST1 22 bits PERSONAL 33 bits CONST2
bits
139 bits
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].
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.
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.
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
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
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
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
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
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
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 //
////////////////////////////////////////////////////////////////////////////////
320
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
10.2.2 bits_to_ascii.sv
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