proxmark3/fpga/hi_flite.v

371 lines
12 KiB
Coq
Raw Normal View History

2020-01-12 07:19:12 +08:00
/*
2020-01-13 00:30:29 +08:00
This code demodulates and modulates signal as described in ISO/IEC 18092.
2020-01-12 07:19:12 +08:00
That includes packets used for Felica, NFC Tag 3, etc. (which do overlap)
2020-01-13 00:30:29 +08:00
simple envelope following algorithm is used (modification of fail0verflow LF one)
2020-01-12 07:19:12 +08:00
is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave)
2017-10-21 02:27:44 +08:00
2020-01-12 07:19:12 +08:00
Speeds supported: only 212 kbps (fc/64) for now. Todo: 414 kbps
2020-01-13 00:30:29 +08:00
though for reader, the selection has to come from ARM. modulation waits for market sprocket -doesn't really mean anything
2017-10-21 02:27:44 +08:00
2020-01-13 00:30:29 +08:00
mod_type: bits 210:
2020-01-12 07:19:12 +08:00
bit 2 : reader drive/power on/off
bit 1 : speed bit, 0 : 212, 1 :424
bit 0 : listen or modulate
*/
module hi_flite(
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg,
2020-01-12 07:19:12 +08:00
mod_type
2019-07-31 04:47:23 +08:00
);
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
2020-01-12 07:19:12 +08:00
input [2:0] mod_type;
assign dbg=0;
2020-01-12 07:19:12 +08:00
wire power = mod_type[2];
wire speed = mod_type[1];
wire disabl = mod_type[0];
2017-10-21 02:27:44 +08:00
// Most off, oe4 for modulation;
2019-07-31 04:47:23 +08:00
// Trying reader emulation (would presumably just require switching power on, but I am not sure)
assign pwr_lo = 1'b0;
2017-10-21 02:27:44 +08:00
2020-01-12 07:19:12 +08:00
// 512x64/fc -wait before ts0, 32768 ticks
// tslot: 256*64/fc
assign adc_clk = ck_1356meg;
///heuristic values for initial thresholds. seem to work OK
2020-01-12 07:19:12 +08:00
`define imin 70 // (13'd256)
`define imax 180 // (-13'd256)
`define ithrmin 91 // -13'd8
`define ithrmax 160 // 13'd8
2017-10-21 02:27:44 +08:00
`define min_bitdelay_212 8
//minimum values and corresponding thresholds
reg [8:0] curmin=`imin;
2019-07-31 04:47:23 +08:00
reg [8:0] curminthres=`ithrmin;
reg [8:0] curmaxthres=`ithrmax;
reg [8:0] curmax=`imax;
//signal state, 1-not modulated, 0 -modulated
reg after_hysteresis = 1'b1;
//state machine for envelope tracking
reg [1:0] state=1'd0;
//lower edge detected, trying to detect first bit of SYNC (b24d, 1011001001001101)
reg try_sync=1'b0;
//detected first sync bit, phase frozen
reg did_sync=0;
2020-01-12 07:19:12 +08:00
`define bithalf_212 32 // half-bit length for 212 kbit
`define bitmlen_212 63 // bit transition edge
2020-01-12 07:19:12 +08:00
`define bithalf_424 16 // half-bit length for 212 kbit
`define bitmlen_424 31 // bit transition edge
2017-10-21 02:27:44 +08:00
2020-01-12 07:19:12 +08:00
wire [7:0] bithalf = speed ? `bithalf_424 : `bithalf_212;
wire [7:0] bitmlen = speed ? `bitmlen_424 : `bitmlen_212;
//ssp clock and current values
reg ssp_clk;
reg ssp_frame;
2020-01-12 07:19:12 +08:00
reg curbit = 1'b0;
2020-01-12 07:19:12 +08:00
reg [7:0] fccount = 8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected
2020-01-12 07:19:12 +08:00
reg [7:0] tsinceedge = 8'd0;// ticks from last edge, desync if the valye is too large
2020-01-12 07:19:12 +08:00
reg zero = 1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it
//ssp counter for transfer and framing
2020-01-12 07:19:12 +08:00
reg [8:0] ssp_cnt = 9'd0;
always @(posedge adc_clk)
ssp_cnt <= (ssp_cnt + 1);
2017-10-21 02:27:44 +08:00
//maybe change it so that ARM sends preamble as well.
2019-07-31 04:47:23 +08:00
//then: ready bits sent to ARM, 8 bits sent from ARM (all ones), then preamble (all zeros, presumably) - which starts modulation
always @(negedge adc_clk)
begin
//count fc/64 - transfer bits to ARM at the rate they are received
2020-01-12 07:19:12 +08:00
if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed && (ssp_cnt[4:0] == 5'b00000)))
begin
2019-07-31 04:47:23 +08:00
ssp_clk <= 1'b1;
ssp_din <= curbit;
end
2019-07-31 04:47:23 +08:00
if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000))
ssp_clk <= 1'b0;
//create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason
2019-07-31 04:47:23 +08:00
// took me a day to figure THAT out.
2020-01-12 07:19:12 +08:00
if(( (~speed) && (ssp_cnt[8:0] == 9'd31)) || (speed && ssp_cnt[7:0] == 8'd15))
begin
2019-07-31 04:47:23 +08:00
ssp_frame <= 1'b1;
end
2020-01-12 07:19:12 +08:00
if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111)) || (speed &&ssp_cnt[7:0] == 8'b101111) )
begin
2019-07-31 04:47:23 +08:00
ssp_frame <= 1'b0;
end
end
//send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise)
2020-01-12 07:19:12 +08:00
reg ssp_din;
//previous signal value, mostly to detect SYNC
2020-01-12 07:19:12 +08:00
reg prv = 1'b1;
2020-01-12 07:19:12 +08:00
// for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry.
2020-01-13 00:30:29 +08:00
reg[7:0] mid = 8'd128;
// set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...)
// start sending over 1s on ssp->arm when we start sending preamble
2020-01-12 07:19:12 +08:00
// reg sending = 1'b0; // are we actively modulating?
reg [11:0] bit_counts = 12'd0; // for timeslots. only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those?
2017-10-21 02:27:44 +08:00
//we need some way to flush bit_counts triggers on mod_type changes don't compile
reg dlay;
2020-01-12 07:19:12 +08:00
always @(negedge adc_clk) // every data ping?
begin
2019-07-31 04:47:23 +08:00
//envelope follow code...
////////////
2020-01-12 07:19:12 +08:00
if (fccount == bitmlen)
2019-07-31 04:47:23 +08:00
begin
2020-01-12 07:19:12 +08:00
if ((~try_sync) && (adc_d < curminthres) && disabl )
2017-10-21 02:27:44 +08:00
begin
2020-01-12 07:19:12 +08:00
fccount <= 1;
2017-10-21 02:27:44 +08:00
end
else
begin
2020-01-12 07:19:12 +08:00
fccount <= 0;
2019-07-31 04:47:23 +08:00
end
2020-01-12 07:19:12 +08:00
dlay <= ssp_dout;
if (bit_counts > 768) // should be over ts0 now, without ARM interference... stop counting...
2019-07-31 04:47:23 +08:00
begin
2020-01-12 07:19:12 +08:00
bit_counts <= 0;
2017-10-21 02:27:44 +08:00
end
else
2020-01-12 07:19:12 +08:00
if (power)
bit_counts <= 0;
2017-10-21 02:27:44 +08:00
else
2020-01-12 07:19:12 +08:00
bit_counts <= bit_counts + 1;
2017-10-21 02:27:44 +08:00
end
else
2019-07-31 04:47:23 +08:00
begin
2020-01-12 07:19:12 +08:00
if((~try_sync) && (adc_d < curminthres) && disabl)
2017-10-21 02:27:44 +08:00
begin
2020-01-12 07:19:12 +08:00
fccount <= 1;
2017-10-21 02:27:44 +08:00
end
else
begin
2020-01-12 07:19:12 +08:00
fccount <= fccount + 1;
2019-07-31 04:47:23 +08:00
end
2017-10-21 02:27:44 +08:00
end
2019-07-31 04:47:23 +08:00
2020-01-12 07:19:12 +08:00
// rising edge
if (adc_d > curmaxthres)
begin
case (state)
0: begin
2020-01-12 07:19:12 +08:00
curmax <= adc_d > `imax? adc_d : `imax;
state <= 2;
end
1: begin
2020-01-12 07:19:12 +08:00
curminthres <= ((curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4)); //threshold: 0.1875 max + 0.8125 min
curmaxthres <= ((curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
curmax <= adc_d > 155 ? adc_d : 155; // to hopefully prevent overflow from spikes going up to 255
state <= 2;
end
2: begin
2020-01-12 07:19:12 +08:00
if (adc_d > curmax)
curmax <= adc_d;
2019-07-31 04:47:23 +08:00
end
default:
begin
2019-07-31 04:47:23 +08:00
end
endcase
2020-01-12 07:19:12 +08:00
after_hysteresis <= 1'b1;
if(try_sync)
2020-01-12 07:19:12 +08:00
tsinceedge <= 0;
end
else if (adc_d<curminthres) //falling edge
2019-07-31 04:47:23 +08:00
begin
case (state)
0: begin
2020-01-12 07:19:12 +08:00
curmin <= adc_d<`imin? adc_d :`imin;
state <= 1;
end
1: begin
if (adc_d<curmin)
2019-07-31 04:47:23 +08:00
curmin <= adc_d;
end
2: begin
2020-01-12 07:19:12 +08:00
curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
curmin <= adc_d < `imin ? adc_d : `imin;
state <= 1;
2019-07-31 04:47:23 +08:00
end
default:
begin
2019-07-31 04:47:23 +08:00
end
endcase
2020-01-12 07:19:12 +08:00
after_hysteresis <= 0;
2019-07-31 04:47:23 +08:00
if (~try_sync ) //begin modulation, lower edge...
begin
2020-01-12 07:19:12 +08:00
try_sync <= 1;
fccount <= 1;
2020-01-12 07:19:12 +08:00
did_sync <= 0;
curbit <= 0;
mid <= 8'd127;
tsinceedge <= 0;
prv <= 1;
2019-07-31 04:47:23 +08:00
end
else
begin
2020-01-12 07:19:12 +08:00
tsinceedge <= 0;
end
end
else //stable state, low or high
begin
2020-01-12 07:19:12 +08:00
curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
state <= 0;
2019-07-31 04:47:23 +08:00
if (try_sync )
begin
2020-01-12 07:19:12 +08:00
if (tsinceedge >= (128))
begin
2019-07-31 04:47:23 +08:00
//we might need to start counting... assuming ARM wants to reply to the frame.
2020-01-12 07:19:12 +08:00
bit_counts <= 1;// i think? 128 is about 2 bits passed... but 1 also works
try_sync <= 0;
did_sync <= 0;//desync
curmin <= `imin; //reset envelope
curmax <= `imax;
curminthres <= `ithrmin;
curmaxthres <= `ithrmax;
prv <= 1;
tsinceedge <= 0;
after_hysteresis <= 1'b1;
curbit <= 0;
mid <= 8'd128;
end
else
2020-01-12 07:19:12 +08:00
tsinceedge <= (tsinceedge + 1);
end
2019-07-31 04:47:23 +08:00
end
2020-01-12 07:19:12 +08:00
if (try_sync && tsinceedge < 128)
begin
//detect bits in their middle ssp sampling is in sync, so it would sample all bits in order
2020-01-12 07:19:12 +08:00
if (fccount == bithalf)
begin
2020-01-12 07:19:12 +08:00
if ((~did_sync) && ((prv == 1 && (mid > 128))||(prv == 0 && (mid <= 128))))
2019-07-31 04:47:23 +08:00
begin
//sync the Zero, and set curbit roperly
2020-01-12 07:19:12 +08:00
did_sync <= 1'b1;
zero <= ~prv;// 1-prv
2020-01-12 07:19:12 +08:00
curbit <= 1;
2019-07-31 04:47:23 +08:00
end
else
2020-01-12 07:19:12 +08:00
curbit <= (mid > 128) ? (~zero) : zero;
2019-07-31 04:47:23 +08:00
2020-01-12 07:19:12 +08:00
prv <= (mid > 128) ? 1 : 0;
2019-07-31 04:47:23 +08:00
2020-01-12 07:19:12 +08:00
if (adc_d > curmaxthres)
mid <= 8'd129;
else if (adc_d < curminthres)
mid <= 8'd127;
2019-07-31 04:47:23 +08:00
else
begin
if (after_hysteresis)
begin
2020-01-12 07:19:12 +08:00
mid <= 8'd129;
end
else
begin
2020-01-12 07:19:12 +08:00
mid <= 8'd127;
end
end
2019-07-31 04:47:23 +08:00
end
2019-07-31 04:47:23 +08:00
else
begin
2017-10-21 02:27:44 +08:00
if (fccount==bitmlen)
begin
2020-01-12 07:19:12 +08:00
// fccount <= 0;
prv <= (mid > 128) ? 1 : 0;
mid <= 128;
end
else
begin
// minimum-maximum calc
2020-01-12 07:19:12 +08:00
if(adc_d > curmaxthres)
mid <= mid + 1;
else if (adc_d < curminthres)
mid <= mid - 1;
2019-07-31 04:47:23 +08:00
else
begin
if (after_hysteresis)
begin
2020-01-12 07:19:12 +08:00
mid <= mid + 1;
end
else
begin
2020-01-12 07:19:12 +08:00
mid <= mid - 1;
end
2019-07-31 04:47:23 +08:00
end
end
2019-07-31 04:47:23 +08:00
end
end
else
begin
2019-07-31 04:47:23 +08:00
end
2020-01-12 07:19:12 +08:00
// sending <= 0;
2017-10-21 02:27:44 +08:00
end
//put modulation here to maintain the correct clock. Seems that some readers are sensitive to that
reg pwr_hi;
reg pwr_oe1;
reg pwr_oe2;
reg pwr_oe3;
reg pwr_oe4;
2020-01-12 07:19:12 +08:00
wire mod = ((fccount >= bithalf) ^ dlay) & (~disabl);
2017-10-21 02:27:44 +08:00
always @(ck_1356megb or ssp_dout or power or disabl or mod)
2020-01-12 07:19:12 +08:00
begin
if (power)
begin
2017-10-21 02:27:44 +08:00
pwr_hi <= ck_1356megb;
pwr_oe1 <= 1'b0;//mod;
pwr_oe2 <= 1'b0;//mod;
pwr_oe3 <= 1'b0;//mod;
pwr_oe4 <= mod;//1'b0;
2020-01-12 07:19:12 +08:00
end
else
begin
pwr_hi <= 1'b0;
2017-10-21 02:27:44 +08:00
pwr_oe1 <= 1'b0;
pwr_oe2 <= 1'b0;
pwr_oe3 <= 1'b0;
pwr_oe4 <= mod;
2020-01-12 07:19:12 +08:00
end
end
endmodule