]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - fpga/hi_iso14443a.v
Initial commit for the firmware. Used the 20090306_ela version as baseline.
[proxmark3-svn] / fpga / hi_iso14443a.v
diff --git a/fpga/hi_iso14443a.v b/fpga/hi_iso14443a.v
new file mode 100644 (file)
index 0000000..eb03fa2
--- /dev/null
@@ -0,0 +1,360 @@
+//-----------------------------------------------------------------------------
+// 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
Impressum, Datenschutz