mirror of
https://github.com/Proxmark/proxmark3.git
synced 2024-11-11 18:17:46 +08:00
6658905f18
It is identical to the popular 20081211, with the doob addition (20090301), a linux client, and two additional commands for LF analysis. Let me know if you find issues here!
360 lines
8.1 KiB
Verilog
360 lines
8.1 KiB
Verilog
//-----------------------------------------------------------------------------
|
|
// 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
|