--- /dev/null
+//-----------------------------------------------------------------------------
+// ISO14443-A support for the Proxmark III
+// Gerhard de Koning Gans, April 2008
+//-----------------------------------------------------------------------------
+
+module hi_iso14443a(
+ 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,
+ mod_type
+);
+ 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;
+ input [2:0] mod_type;
+
+reg ssp_clk;
+reg ssp_frame;
+
+reg fc_div_2;
+always @(posedge ck_1356meg)
+ fc_div_2 = ~fc_div_2;
+
+wire adc_clk;
+assign adc_clk = ck_1356meg;
+
+reg after_hysteresis, after_hysteresis_prev1, after_hysteresis_prev2, after_hysteresis_prev3;
+reg [11:0] has_been_low_for;
+reg [8:0] saw_deep_modulation;
+reg [2:0] deep_counter;
+reg deep_modulation;
+always @(negedge adc_clk)
+begin
+ if(& adc_d[7:6]) after_hysteresis <= 1'b1;
+ else if(~(| adc_d[7:4])) after_hysteresis <= 1'b0;
+
+ if(~(| adc_d[7:0]))
+ begin
+ if(deep_counter == 3'd7)
+ begin
+ deep_modulation <= 1'b1;
+ saw_deep_modulation <= 8'd0;
+ end
+ else
+ deep_counter <= deep_counter + 1;
+ end
+ else
+ begin
+ deep_counter <= 3'd0;
+ if(saw_deep_modulation == 8'd255)
+ deep_modulation <= 1'b0;
+ else
+ saw_deep_modulation <= saw_deep_modulation + 1;
+ end
+
+ if(after_hysteresis)
+ begin
+ has_been_low_for <= 7'b0;
+ end
+ else
+ begin
+ if(has_been_low_for == 12'd4095)
+ begin
+ has_been_low_for <= 12'd0;
+ after_hysteresis <= 1'b1;
+ end
+ else
+ has_been_low_for <= has_been_low_for + 1;
+ end
+end
+
+// Report every 4 subcarrier cycles
+// 64 periods of carrier frequency => 6-bit counter [negedge_cnt]
+reg [5:0] negedge_cnt;
+reg bit1, bit2, bit3;
+reg [3:0] count_ones;
+reg [3:0] count_zeros;
+wire [7:0] avg;
+reg [7:0] lavg;
+reg signed [12:0] step1;
+reg signed [12:0] step2;
+reg [7:0] stepsize;
+reg curbit;
+reg [12:0] average;
+wire signed [9:0] dif;
+
+// A register to send the results to the arm
+reg signed [7:0] to_arm;
+
+assign avg[7:0] = average[11:4];
+assign dif = lavg - avg;
+
+reg bit_to_arm;
+reg fdt_indicator, fdt_elapsed;
+reg [10:0] fdt_counter;
+reg [47:0] mod_sig_buf;
+wire mod_sig_buf_empty;
+reg [5:0] mod_sig_ptr;
+reg [3:0] mod_sig_flip;
+reg mod_sig, mod_sig_coil;
+reg temp_buffer_reset;
+reg sendbit;
+
+assign mod_sig_buf_empty = ~(|mod_sig_buf[47:0]);
+reg [2:0] ssp_frame_counter;
+
+// ADC data appears on the rising edge, so sample it on the falling edge
+always @(negedge adc_clk)
+begin
+
+ // last bit = 0 then fdt = 1172, in case of 0x26 (7-bit command, LSB first!)
+ // last bit = 1 then fdt = 1236, in case of 0x52 (7-bit command, LSB first!)
+ if(fdt_counter == 11'd740) fdt_indicator = 1'b1;
+
+ if(fdt_counter == 11'd1148)
+ begin
+ if(fdt_elapsed)
+ begin
+ if(negedge_cnt[3:0] == mod_sig_flip[3:0]) mod_sig_coil <= mod_sig;
+ end
+ else
+ begin
+ mod_sig_flip[3:0] <= negedge_cnt[3:0];
+ mod_sig_coil <= mod_sig;
+ fdt_elapsed = 1'b1;
+ fdt_indicator = 1'b0;
+
+ if(~(| mod_sig_ptr[5:0])) mod_sig_ptr <= 6'b001001;
+ else temp_buffer_reset = 1'b1; // fix position of the buffer pointer
+ end
+ end
+ else
+ begin
+ fdt_counter <= fdt_counter + 1;
+ end
+
+ if(& negedge_cnt[3:0])
+ begin
+ // When there is a dip in the signal and not in reader mode
+ if(~after_hysteresis && mod_sig_buf_empty && ~((mod_type == 3'b100) || (mod_type == 3'b011) || (mod_type == 3'b010))) // last condition to prevent reset
+ begin
+ fdt_counter <= 11'd0;
+ fdt_elapsed = 1'b0;
+ fdt_indicator = 1'b0;
+ temp_buffer_reset = 1'b0;
+ mod_sig_ptr <= 6'b000000;
+ end
+
+ lavg <= avg;
+
+ if(stepsize<16) stepsize = 8'd16;
+
+ if(dif>0)
+ begin
+ step1 = dif*3;
+ step2 = stepsize*2; // 3:2
+ if(step1>step2)
+ begin
+ curbit = 1'b0;
+ stepsize = dif;
+ end
+ end
+ else
+ begin
+ step1 = dif*3;
+ step1 = -step1;
+ step2 = stepsize*2;
+ if(step1>step2)
+ begin
+ curbit = 1'b1;
+ stepsize = -dif;
+ end
+ end
+
+ if(curbit)
+ begin
+ count_zeros <= 4'd0;
+ if(& count_ones[3:2])
+ begin
+ curbit = 1'b0; // suppressed signal
+ stepsize = 8'd24; // just a fine number
+ end
+ else
+ begin
+ count_ones <= count_ones + 1;
+ end
+ end
+ else
+ begin
+ count_ones <= 4'd0;
+ if(& count_zeros[3:0])
+ begin
+ stepsize = 8'd24;
+ end
+ else
+ begin
+ count_zeros <= count_zeros + 1;
+ end
+ end
+
+ // What do we communicate to the ARM
+ if(mod_type == 3'b001) sendbit = after_hysteresis;
+ else if(mod_type == 3'b010)
+ begin
+ if(fdt_counter > 11'd772) sendbit = mod_sig_coil;
+ else sendbit = fdt_indicator;
+ end
+ else if(mod_type == 3'b011) sendbit = curbit;
+ else sendbit = 1'b0;
+
+ end
+
+ if(~(| negedge_cnt[3:0])) average <= adc_d;
+ else average <= average + adc_d;
+
+ if(negedge_cnt == 7'd63)
+ begin
+ if(deep_modulation)
+ begin
+ to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,1'b0,1'b0,1'b0,1'b0};
+ end
+ else
+ begin
+ to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,bit1,bit2,bit3,curbit};
+ end
+
+ negedge_cnt <= 0;
+
+ end
+ else
+ begin
+ negedge_cnt <= negedge_cnt + 1;
+ end
+
+ if(negedge_cnt == 6'd15)
+ begin
+ after_hysteresis_prev1 <= after_hysteresis;
+ bit1 <= curbit;
+ end
+ if(negedge_cnt == 6'd31)
+ begin
+ after_hysteresis_prev2 <= after_hysteresis;
+ bit2 <= curbit;
+ end
+ if(negedge_cnt == 6'd47)
+ begin
+ after_hysteresis_prev3 <= after_hysteresis;
+ bit3 <= curbit;
+ end
+
+
+ if(mod_type != 3'b000)
+ begin
+ if(negedge_cnt[3:0] == 4'b1000)
+ begin
+ // The modulation signal of the tag
+ mod_sig_buf[47:0] <= {mod_sig_buf[46:1], ssp_dout, 1'b0};
+ if((ssp_dout || (| mod_sig_ptr[5:0])) && ~fdt_elapsed)
+ if(mod_sig_ptr == 6'b101110)
+ begin
+ mod_sig_ptr <= 6'b000000;
+ end
+ else mod_sig_ptr <= mod_sig_ptr + 1;
+ else if(fdt_elapsed && ~temp_buffer_reset)
+ begin
+ if(ssp_dout) temp_buffer_reset = 1'b1;
+ if(mod_sig_ptr == 6'b000010) mod_sig_ptr <= 6'b001001;
+ else mod_sig_ptr <= mod_sig_ptr - 1;
+ end
+ else
+ begin
+ // side effect: when ptr = 1 it will cancel the first 1 of every block of ones
+ if(~mod_sig_buf[mod_sig_ptr-1] && ~mod_sig_buf[mod_sig_ptr+1]) mod_sig = 1'b0;
+ else mod_sig = mod_sig_buf[mod_sig_ptr] & fdt_elapsed; // & fdt_elapsed was for direct relay to oe4
+ end
+ end
+ end
+
+ // SSP Clock and data
+ if(mod_type == 3'b000)
+ begin
+ if(negedge_cnt[2:0] == 3'b100)
+ ssp_clk <= 1'b0;
+
+ if(negedge_cnt[2:0] == 3'b000)
+ begin
+ ssp_clk <= 1'b1;
+ // Don't shift if we just loaded new data, obviously.
+ if(negedge_cnt != 7'd0)
+ begin
+ to_arm[7:1] <= to_arm[6:0];
+ end
+ end
+
+ if(negedge_cnt[5:4] == 2'b00)
+ ssp_frame = 1'b1;
+ else
+ ssp_frame = 1'b0;
+
+ bit_to_arm = to_arm[7];
+ end
+ else
+ begin
+ if(negedge_cnt[3:0] == 4'b1000) ssp_clk <= 1'b0;
+
+ if(negedge_cnt[3:0] == 4'b0111)
+ begin
+ if(ssp_frame_counter == 3'd7) ssp_frame_counter <= 3'd0;
+ else ssp_frame_counter <= ssp_frame_counter + 1;
+ end
+
+ if(negedge_cnt[3:0] == 4'b0000)
+ begin
+ ssp_clk <= 1'b1;
+ end
+
+ ssp_frame = (ssp_frame_counter == 3'd7);
+
+ bit_to_arm = sendbit;
+ end
+
+end
+
+assign ssp_din = bit_to_arm;
+
+// Modulating carrier frequency is fc/16
+wire modulating_carrier;
+assign modulating_carrier = (mod_sig_coil & negedge_cnt[3] & (mod_type == 3'b010));
+assign pwr_hi = (ck_1356megb & (((mod_type == 3'b100) & ~mod_sig_coil) || (mod_type == 3'b011)));
+
+// This one is all LF, so doesn't matter
+//assign pwr_oe2 = modulating_carrier;
+assign pwr_oe2 = 1'b0;
+
+// Toggle only one of these, since we are already producing much deeper
+// modulation than a real tag would.
+//assign pwr_oe1 = modulating_carrier;
+assign pwr_oe1 = 1'b0;
+assign pwr_oe4 = modulating_carrier;
+//assign pwr_oe4 = 1'b0;
+
+// This one is always on, so that we can watch the carrier.
+//assign pwr_oe3 = modulating_carrier;
+assign pwr_oe3 = 1'b0;
+
+
+assign dbg = negedge_cnt[3];
+
+// Unused.
+assign pwr_lo = 1'b0;
+
+endmodule