mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 10:37:23 -07:00
Add fpga-xc3s100e and icopyx support
This commit is contained in:
parent
d56d8f0f65
commit
e79fb92074
106 changed files with 4213 additions and 85 deletions
|
@ -1,55 +0,0 @@
|
|||
#
|
||||
# FPGA Makefile
|
||||
#
|
||||
RMDIR = rm -rf
|
||||
# rmdir only if dir is empty, tolerate failure
|
||||
RMDIR_SOFT = -rmdir
|
||||
#
|
||||
all: fpga_lf.bit fpga_hf.bit fpga_felica.bit
|
||||
clean:
|
||||
$(Q)$(RM) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp xst_felica.srp
|
||||
$(Q)$(RM) *.map *.ngc *.xrpt *.pcf *.rbt *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst
|
||||
$(Q)$(RMDIR) *_auto_* xst
|
||||
|
||||
#fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_reader.v hi_iso14443a.v hi_sniffer.v hi_flite.v hi_get_trace.v
|
||||
fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_reader.v hi_iso14443a.v hi_sniffer.v hi_get_trace.v
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] XST $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr
|
||||
|
||||
fpga_felica.ngc: fpga_felica.v fpga.ucf xst_felica.scr util.v hi_simulate.v hi_reader.v hi_sniffer.v hi_flite.v hi_get_trace.v
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] XST $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_felica.scr
|
||||
|
||||
fpga_lf.ngc: fpga_lf.v fpga.ucf xst_lf.scr util.v clk_divider.v lo_edge_detect.v lo_read.v lo_passthru.v lp20khz_1MSa_iir_filter.v min_max_tracker.v lf_edge_detect.v
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] XST $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_lf.scr
|
||||
|
||||
%.ngd: %.ngc
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] NGD $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)ngdbuild -aul -p xc2s30-5-vq100 -nt timestamp -uc fpga.ucf $< $@
|
||||
|
||||
%.ncd: %.ngd
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] MAP $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)map -p xc2s30-5-vq100 $<
|
||||
|
||||
%-placed.ncd: %.ncd
|
||||
$(Q)$(RM) $@
|
||||
$(info [-] PAR $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)par $< $@
|
||||
|
||||
%.bit: %-placed.ncd
|
||||
$(Q)$(RM) $@ $*.drc $*.rbt
|
||||
$(info [=] BITGEN $@)
|
||||
$(Q)$(XILINX_TOOLS_PREFIX)bitgen $< $@
|
||||
|
||||
.PHONY: all clean help
|
||||
help:
|
||||
@echo Possible targets:
|
||||
@echo + all - Make fpga.bit, the FPGA bitstream
|
||||
@echo + clean - Clean intermediate files, does not clean fpga.bit
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
module clk_divider(input clk, input [7:0] divisor, output [7:0] div_cnt, output div_clk);
|
||||
|
||||
reg [7:0] div_cnt_ = 0;
|
||||
reg div_clk_;
|
||||
assign div_cnt = div_cnt_;
|
||||
assign div_clk = div_clk_;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if(div_cnt == divisor) begin
|
||||
div_cnt_ <= 8'd0;
|
||||
div_clk_ = !div_clk_;
|
||||
end else
|
||||
div_cnt_ <= div_cnt_ + 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# See the schematic for the pin assignment.
|
||||
|
||||
NET "adc_d<0>" LOC = "P62" ;
|
||||
NET "adc_d<1>" LOC = "P60" ;
|
||||
NET "adc_d<2>" LOC = "P58" ;
|
||||
NET "adc_d<3>" LOC = "P57" ;
|
||||
NET "adc_d<4>" LOC = "P56" ;
|
||||
NET "adc_d<5>" LOC = "P55" ;
|
||||
NET "adc_d<6>" LOC = "P54" ;
|
||||
NET "adc_d<7>" LOC = "P53" ;
|
||||
#NET "cross_hi" LOC = "P88" ;
|
||||
#NET "miso" LOC = "P40" ;
|
||||
#PACE: Start of Constraints generated by PACE
|
||||
|
||||
#PACE: Start of PACE I/O Pin Assignments
|
||||
NET "adc_clk" LOC = "P46" ;
|
||||
NET "adc_noe" LOC = "P47" ;
|
||||
NET "ck_1356meg" LOC = "P91" ;
|
||||
NET "ck_1356megb" LOC = "P93" ;
|
||||
NET "cross_lo" LOC = "P87" ;
|
||||
NET "dbg" LOC = "P22" ;
|
||||
NET "mosi" LOC = "P43" ;
|
||||
NET "ncs" LOC = "P44" ;
|
||||
NET "pck0" LOC = "P36" ;
|
||||
NET "pwr_hi" LOC = "P80" ;
|
||||
NET "pwr_lo" LOC = "P81" ;
|
||||
NET "pwr_oe1" LOC = "P82" ;
|
||||
NET "pwr_oe2" LOC = "P83" ;
|
||||
NET "pwr_oe3" LOC = "P84" ;
|
||||
NET "pwr_oe4" LOC = "P86" ;
|
||||
NET "spck" LOC = "P39" ;
|
||||
NET "ssp_clk" LOC = "P71" ;
|
||||
NET "ssp_din" LOC = "P32" ;
|
||||
NET "ssp_dout" LOC = "P34" ;
|
||||
NET "ssp_frame" LOC = "P31" ;
|
||||
|
||||
#PACE: Start of PACE Area Constraints
|
||||
|
||||
#PACE: Start of PACE Prohibit Constraints
|
||||
|
||||
#PACE: End of Constraints generated by PACE
|
||||
|
||||
# definition of Clock nets:
|
||||
NET "ck_1356meg" TNM_NET = "clk_net_1356" ;
|
||||
NET "ck_1356megb" TNM_NET = "clk_net_1356b" ;
|
||||
NET "pck0" TNM_NET = "clk_net_pck0" ;
|
||||
NET "spck" TNM_NET = "clk_net_spck" ;
|
||||
|
||||
# Timing specs of clock nets:
|
||||
TIMEGRP "clk_net_1356_all" = "clk_net_1356" "clk_net_1356b" ;
|
||||
TIMESPEC "TS_1356MHz" = PERIOD "clk_net_1356_all" 74 ns HIGH 37 ns ;
|
||||
TIMESPEC "TS_24MHz" = PERIOD "clk_net_pck0" 42 ns HIGH 21 ns ;
|
||||
TIMESPEC "TS_4MHz" = PERIOD "clk_net_spck" 250 ns HIGH 125 ns ;
|
||||
|
Binary file not shown.
|
@ -1,226 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// The FPGA is responsible for interfacing between the A/D, the coil drivers,
|
||||
// and the ARM. In the low-frequency modes it passes the data straight
|
||||
// through, so that the ARM gets raw A/D samples over the SSP. In the high-
|
||||
// frequency modes, the FPGA might perform some demodulation first, to
|
||||
// reduce the amount of data that we must send to the ARM.
|
||||
//
|
||||
// I am not really an FPGA/ASIC designer, so I am sure that a lot of this
|
||||
// could be improved.
|
||||
//
|
||||
// Jonathan Westhues, March 2006
|
||||
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
|
||||
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||
// Piwi, Feb 2019
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h
|
||||
// Note: the definitions here are without shifts
|
||||
|
||||
// Commands:
|
||||
`define FPGA_CMD_SET_CONFREG 1
|
||||
`define FPGA_CMD_TRACE_ENABLE 2
|
||||
|
||||
// Major modes:
|
||||
`define FPGA_MAJOR_MODE_HF_READER 0
|
||||
`define FPGA_MAJOR_MODE_HF_SIMULATOR 1
|
||||
`define FPGA_MAJOR_MODE_HF_ISO14443A 2
|
||||
`define FPGA_MAJOR_MODE_HF_SNIFF 3
|
||||
`define FPGA_MAJOR_MODE_HF_ISO18092 4
|
||||
`define FPGA_MAJOR_MODE_HF_GET_TRACE 5
|
||||
`define FPGA_MAJOR_MODE_OFF 7
|
||||
|
||||
// Options for the generic HF reader
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_IQ 0
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE 1
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_PHASE 2
|
||||
`define FPGA_HF_READER_MODE_SEND_FULL_MOD 3
|
||||
`define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD 4
|
||||
`define FPGA_HF_READER_MODE_SNIFF_IQ 5
|
||||
`define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE 6
|
||||
`define FPGA_HF_READER_MODE_SNIFF_PHASE 7
|
||||
`define FPGA_HF_READER_MODE_SEND_JAM 8
|
||||
|
||||
`define FPGA_HF_READER_SUBCARRIER_848_KHZ 0
|
||||
`define FPGA_HF_READER_SUBCARRIER_424_KHZ 1
|
||||
`define FPGA_HF_READER_SUBCARRIER_212_KHZ 2
|
||||
|
||||
// Options for the HF simulated tag, how to modulate
|
||||
`define FPGA_HF_SIMULATOR_NO_MODULATION 0
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_BPSK 1
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_212K 2
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_424K 4
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 5
|
||||
|
||||
// Options for ISO14443A
|
||||
`define FPGA_HF_ISO14443A_SNIFFER 0
|
||||
`define FPGA_HF_ISO14443A_TAGSIM_LISTEN 1
|
||||
`define FPGA_HF_ISO14443A_TAGSIM_MOD 2
|
||||
`define FPGA_HF_ISO14443A_READER_LISTEN 3
|
||||
`define FPGA_HF_ISO14443A_READER_MOD 4
|
||||
|
||||
//options for ISO18092 / Felica
|
||||
`define FPGA_HF_ISO18092_FLAG_NOMOD 1 // 0001 disable modulation module
|
||||
`define FPGA_HF_ISO18092_FLAG_424K 2 // 0010 should enable 414k mode (untested). No autodetect
|
||||
`define FPGA_HF_ISO18092_FLAG_READER 4 // 0100 enables antenna power, to act as a reader instead of tag
|
||||
|
||||
`include "hi_reader.v"
|
||||
`include "hi_simulate.v"
|
||||
//`include "hi_iso14443a.v"
|
||||
`include "hi_sniffer.v"
|
||||
`include "util.v"
|
||||
`include "hi_flite.v"
|
||||
`include "hi_get_trace.v"
|
||||
|
||||
module fpga_felica(
|
||||
input spck, output miso, input mosi, input ncs,
|
||||
input pck0, input ck_1356meg, input ck_1356megb,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
input [7:0] adc_d, output adc_clk, output adc_noe,
|
||||
output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk,
|
||||
input cross_hi, input cross_lo,
|
||||
output dbg
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The SPI receiver. This sets up the configuration word, which the rest of
|
||||
// the logic looks at to determine how to connect the A/D and the coil
|
||||
// drivers (i.e., which section gets it). Also assign some symbolic names
|
||||
// to the configuration bits, for use below.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Attempt to write up how its hooked up. Iceman 2020.
|
||||
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand()
|
||||
Send 16 bit command / data pair to FPGA
|
||||
The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
|
||||
where
|
||||
C is 4bit command
|
||||
D is 12bit data
|
||||
|
||||
shift_reg receive this 16bit frame
|
||||
|
||||
|
||||
-----+--------- frame layout --------------------
|
||||
bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
-----+-------------------------------------------
|
||||
cmd | x x x x
|
||||
major| x x x
|
||||
opt | x x x
|
||||
divi | x x x x x x x x
|
||||
thres| x x x x x x x x
|
||||
-----+-------------------------------------------
|
||||
*/
|
||||
|
||||
reg [15:0] shift_reg;
|
||||
reg [8:0] conf_word;
|
||||
reg trace_enable;
|
||||
|
||||
// We switch modes between transmitting to the 13.56 MHz tag and receiving
|
||||
// from it, which means that we must make sure that we can do so without
|
||||
// glitching, or else we will glitch the transmitted carrier.
|
||||
always @(posedge ncs)
|
||||
begin
|
||||
case(shift_reg[15:12])
|
||||
`FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[8:0];
|
||||
`FPGA_CMD_TRACE_ENABLE: trace_enable <= shift_reg[0];
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge spck)
|
||||
begin
|
||||
if(~ncs)
|
||||
begin
|
||||
shift_reg[15:1] <= shift_reg[14:0];
|
||||
shift_reg[0] <= mosi;
|
||||
end
|
||||
end
|
||||
|
||||
// select module (outputs) based on major mode
|
||||
wire [2:0] major_mode = conf_word[8:6];
|
||||
|
||||
// configuring the HF reader
|
||||
wire [1:0] subcarrier_frequency = conf_word[5:4];
|
||||
wire [3:0] minor_mode = conf_word[3:0];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// And then we instantiate the modules corresponding to each of the FPGA's
|
||||
// major modes, and use muxes to connect the outputs of the active mode to
|
||||
// the output pins.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 000 - HF reader
|
||||
hi_reader hr(
|
||||
ck_1356megb,
|
||||
hr_pwr_lo, hr_pwr_hi, hr_pwr_oe1, hr_pwr_oe2, hr_pwr_oe3, hr_pwr_oe4,
|
||||
adc_d, hr_adc_clk,
|
||||
hr_ssp_frame, hr_ssp_din, ssp_dout, hr_ssp_clk,
|
||||
hr_dbg,
|
||||
subcarrier_frequency, minor_mode
|
||||
);
|
||||
|
||||
// 001 - HF simulated tag
|
||||
hi_simulate hs(
|
||||
ck_1356meg,
|
||||
hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,
|
||||
adc_d, hs_adc_clk,
|
||||
hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,
|
||||
hs_dbg,
|
||||
minor_mode
|
||||
);
|
||||
|
||||
// 011 - HF sniff
|
||||
hi_sniffer he(
|
||||
ck_1356megb,
|
||||
he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4,
|
||||
adc_d, he_adc_clk,
|
||||
he_ssp_frame, he_ssp_din, he_ssp_clk
|
||||
);
|
||||
|
||||
// 100 - HF ISO18092 FeliCa
|
||||
hi_flite hfl(
|
||||
ck_1356megb,
|
||||
hfl_pwr_lo, hfl_pwr_hi, hfl_pwr_oe1, hfl_pwr_oe2, hfl_pwr_oe3, hfl_pwr_oe4,
|
||||
adc_d, hfl_adc_clk,
|
||||
hfl_ssp_frame, hfl_ssp_din, ssp_dout, hfl_ssp_clk,
|
||||
hfl_dbg,
|
||||
minor_mode
|
||||
);
|
||||
|
||||
// 101 - HF get trace
|
||||
hi_get_trace gt(
|
||||
ck_1356megb,
|
||||
adc_d, trace_enable, major_mode,
|
||||
gt_ssp_frame, gt_ssp_din, gt_ssp_clk
|
||||
);
|
||||
|
||||
// Major modes:
|
||||
// 000 -- HF reader; subcarrier frequency and modulation depth selectable
|
||||
// 001 -- HF simulated tag
|
||||
// 010 -- HF ISO14443-A - removed for space...
|
||||
// 011 -- HF sniff
|
||||
// 100 -- HF ISO18092 FeliCa
|
||||
// 101 -- HF get trace
|
||||
// 110 -- unused
|
||||
// 111 -- FPGA_MAJOR_MODE_OFF
|
||||
|
||||
// 000 001 010 011 100 101 110 111
|
||||
mux8 mux_ssp_clk (major_mode, ssp_clk, hr_ssp_clk, hs_ssp_clk, 1'b0, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_din (major_mode, ssp_din, hr_ssp_din, hs_ssp_din, 1'b0, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_frame (major_mode, ssp_frame, hr_ssp_frame, hs_ssp_frame, 1'b0, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, hr_pwr_oe1, hs_pwr_oe1, 1'b0, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, hr_pwr_oe2, hs_pwr_oe2, 1'b0, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, hr_pwr_oe3, hs_pwr_oe3, 1'b0, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, hr_pwr_oe4, hs_pwr_oe4, 1'b0, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_lo (major_mode, pwr_lo, hr_pwr_lo, hs_pwr_lo, 1'b0, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_hi (major_mode, pwr_hi, hr_pwr_hi, hs_pwr_hi, 1'b0, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_adc_clk (major_mode, adc_clk, hr_adc_clk, hs_adc_clk, 1'b0, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_dbg (major_mode, dbg, hr_dbg, hs_dbg, 1'b0, he_dbg, hfl_dbg, 1'b0, 1'b0, 1'b0);
|
||||
|
||||
// In all modes, let the ADC's outputs be enabled.
|
||||
assign adc_noe = 1'b0;
|
||||
|
||||
endmodule
|
BIN
fpga/fpga_hf.bit
BIN
fpga/fpga_hf.bit
Binary file not shown.
241
fpga/fpga_hf.v
241
fpga/fpga_hf.v
|
@ -1,241 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// The FPGA is responsible for interfacing between the A/D, the coil drivers,
|
||||
// and the ARM. In the low-frequency modes it passes the data straight
|
||||
// through, so that the ARM gets raw A/D samples over the SSP. In the high-
|
||||
// frequency modes, the FPGA might perform some demodulation first, to
|
||||
// reduce the amount of data that we must send to the ARM.
|
||||
//
|
||||
// I am not really an FPGA/ASIC designer, so I am sure that a lot of this
|
||||
// could be improved.
|
||||
//
|
||||
// Jonathan Westhues, March 2006
|
||||
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
|
||||
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||
// Piwi, Feb 2019
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h
|
||||
// Note: the definitions here are without shifts
|
||||
|
||||
// Commands:
|
||||
`define FPGA_CMD_SET_CONFREG 1
|
||||
`define FPGA_CMD_TRACE_ENABLE 2
|
||||
|
||||
// Major modes:
|
||||
`define FPGA_MAJOR_MODE_HF_READER 0
|
||||
`define FPGA_MAJOR_MODE_HF_SIMULATOR 1
|
||||
`define FPGA_MAJOR_MODE_HF_ISO14443A 2
|
||||
`define FPGA_MAJOR_MODE_HF_SNIFF 3
|
||||
`define FPGA_MAJOR_MODE_HF_ISO18092 4
|
||||
`define FPGA_MAJOR_MODE_HF_GET_TRACE 5
|
||||
`define FPGA_MAJOR_MODE_OFF 7
|
||||
|
||||
// Options for the generic HF reader
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_IQ 0
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE 1
|
||||
`define FPGA_HF_READER_MODE_RECEIVE_PHASE 2
|
||||
`define FPGA_HF_READER_MODE_SEND_FULL_MOD 3
|
||||
`define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD 4
|
||||
`define FPGA_HF_READER_MODE_SNIFF_IQ 5
|
||||
`define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE 6
|
||||
`define FPGA_HF_READER_MODE_SNIFF_PHASE 7
|
||||
`define FPGA_HF_READER_MODE_SEND_JAM 8
|
||||
|
||||
`define FPGA_HF_READER_SUBCARRIER_848_KHZ 0
|
||||
`define FPGA_HF_READER_SUBCARRIER_424_KHZ 1
|
||||
`define FPGA_HF_READER_SUBCARRIER_212_KHZ 2
|
||||
|
||||
// Options for the HF simulated tag, how to modulate
|
||||
`define FPGA_HF_SIMULATOR_NO_MODULATION 0
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_BPSK 1
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_212K 2
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_424K 4
|
||||
`define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 5
|
||||
|
||||
// Options for ISO14443A
|
||||
`define FPGA_HF_ISO14443A_SNIFFER 0
|
||||
`define FPGA_HF_ISO14443A_TAGSIM_LISTEN 1
|
||||
`define FPGA_HF_ISO14443A_TAGSIM_MOD 2
|
||||
`define FPGA_HF_ISO14443A_READER_LISTEN 3
|
||||
`define FPGA_HF_ISO14443A_READER_MOD 4
|
||||
|
||||
//options for ISO18092 / Felica
|
||||
`define FPGA_HF_ISO18092_FLAG_NOMOD 1 // 0001 disable modulation module
|
||||
`define FPGA_HF_ISO18092_FLAG_424K 2 // 0010 should enable 414k mode (untested). No autodetect
|
||||
`define FPGA_HF_ISO18092_FLAG_READER 4 // 0100 enables antenna power, to act as a reader instead of tag
|
||||
|
||||
`include "hi_reader.v"
|
||||
`include "hi_simulate.v"
|
||||
`include "hi_iso14443a.v"
|
||||
`include "hi_sniffer.v"
|
||||
`include "util.v"
|
||||
// `include "hi_flite.v"
|
||||
`include "hi_get_trace.v"
|
||||
|
||||
module fpga_hf(
|
||||
input spck, output miso, input mosi, input ncs,
|
||||
input pck0, input ck_1356meg, input ck_1356megb,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
input [7:0] adc_d, output adc_clk, output adc_noe,
|
||||
output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk,
|
||||
input cross_hi, input cross_lo,
|
||||
output dbg
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The SPI receiver. This sets up the configuration word, which the rest of
|
||||
// the logic looks at to determine how to connect the A/D and the coil
|
||||
// drivers (i.e., which section gets it). Also assign some symbolic names
|
||||
// to the configuration bits, for use below.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Attempt to write up how its hooked up.
|
||||
/ Iceman, 2020
|
||||
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand()
|
||||
Send 16 bit command / data pair to FPGA
|
||||
The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
|
||||
where
|
||||
C is 4bit command
|
||||
D is 12bit data
|
||||
|
||||
shift_reg receive this 16bit frame
|
||||
|
||||
|
||||
-----+--------- frame layout --------------------
|
||||
bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
-----+-------------------------------------------
|
||||
cmd | x x x x
|
||||
major| x x x
|
||||
opt | x x x x
|
||||
sub | x x
|
||||
divi | x x x x x x x x
|
||||
thres| x x x x x x x x
|
||||
-----+-------------------------------------------
|
||||
*/
|
||||
|
||||
reg [15:0] shift_reg;
|
||||
reg [8:0] conf_word;
|
||||
reg trace_enable;
|
||||
|
||||
// We switch modes between transmitting to the 13.56 MHz tag and receiving
|
||||
// from it, which means that we must make sure that we can do so without
|
||||
// glitching, or else we will glitch the transmitted carrier.
|
||||
always @(posedge ncs)
|
||||
begin
|
||||
case(shift_reg[15:12])
|
||||
`FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[8:0];
|
||||
`FPGA_CMD_TRACE_ENABLE: trace_enable <= shift_reg[0];
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge spck)
|
||||
begin
|
||||
if(~ncs)
|
||||
begin
|
||||
shift_reg[15:1] <= shift_reg[14:0];
|
||||
shift_reg[0] <= mosi;
|
||||
end
|
||||
end
|
||||
|
||||
// select module (outputs) based on major mode
|
||||
wire [2:0] major_mode = conf_word[8:6];
|
||||
|
||||
// configuring the HF reader
|
||||
wire [1:0] subcarrier_frequency = conf_word[5:4];
|
||||
wire [3:0] minor_mode = conf_word[3:0];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// And then we instantiate the modules corresponding to each of the FPGA's
|
||||
// major modes, and use muxes to connect the outputs of the active mode to
|
||||
// the output pins.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 000 - HF reader
|
||||
hi_reader hr(
|
||||
ck_1356megb,
|
||||
hr_pwr_lo, hr_pwr_hi, hr_pwr_oe1, hr_pwr_oe2, hr_pwr_oe3, hr_pwr_oe4,
|
||||
adc_d, hr_adc_clk,
|
||||
hr_ssp_frame, hr_ssp_din, ssp_dout, hr_ssp_clk,
|
||||
hr_dbg,
|
||||
subcarrier_frequency, minor_mode
|
||||
);
|
||||
|
||||
// 001 - HF simulated tag
|
||||
hi_simulate hs(
|
||||
ck_1356meg,
|
||||
hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,
|
||||
adc_d, hs_adc_clk,
|
||||
hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,
|
||||
hs_dbg,
|
||||
minor_mode
|
||||
);
|
||||
|
||||
// 010 - HF ISO14443-A
|
||||
hi_iso14443a hisn(
|
||||
ck_1356meg,
|
||||
hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4,
|
||||
adc_d, hisn_adc_clk,
|
||||
hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,
|
||||
hisn_dbg,
|
||||
minor_mode
|
||||
);
|
||||
|
||||
// 011 - HF sniff
|
||||
hi_sniffer he(
|
||||
ck_1356megb,
|
||||
he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4,
|
||||
adc_d, he_adc_clk,
|
||||
he_ssp_frame, he_ssp_din, he_ssp_clk
|
||||
);
|
||||
|
||||
// 100 - HF ISO18092 FeliCa
|
||||
/*
|
||||
hi_flite hfl(
|
||||
ck_1356megb,
|
||||
hfl_pwr_lo, hfl_pwr_hi, hfl_pwr_oe1, hfl_pwr_oe2, hfl_pwr_oe3, hfl_pwr_oe4,
|
||||
adc_d, hfl_adc_clk,
|
||||
hfl_ssp_frame, hfl_ssp_din, ssp_dout, hfl_ssp_clk,
|
||||
hfl_dbg,
|
||||
minor_mode
|
||||
);
|
||||
*/
|
||||
|
||||
// 101 - HF get trace
|
||||
hi_get_trace gt(
|
||||
ck_1356megb,
|
||||
adc_d, trace_enable, major_mode,
|
||||
gt_ssp_frame, gt_ssp_din, gt_ssp_clk
|
||||
);
|
||||
|
||||
// Major modes:
|
||||
// 000 -- HF reader; subcarrier frequency and modulation depth selectable
|
||||
// 001 -- HF simulated tag
|
||||
// 010 -- HF ISO14443-A
|
||||
// 011 -- HF sniff
|
||||
// 100 -- HF ISO18092 FeliCa
|
||||
// 101 -- HF get trace
|
||||
// 110 -- unused
|
||||
// 111 -- FPGA_MAJOR_MODE_OFF
|
||||
|
||||
// 000 001 010 011 100 101 110 111
|
||||
|
||||
mux8 mux_ssp_clk (major_mode, ssp_clk, hr_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_din (major_mode, ssp_din, hr_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_frame (major_mode, ssp_frame, hr_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, hr_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, hr_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, hr_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, hr_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_lo (major_mode, pwr_lo, hr_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_hi (major_mode, pwr_hi, hr_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_adc_clk (major_mode, adc_clk, hr_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_dbg (major_mode, dbg, hr_dbg, hs_dbg, hisn_dbg, he_dbg, hfl_dbg, 1'b0, 1'b0, 1'b0);
|
||||
|
||||
// In all modes, let the ADC's outputs be enabled.
|
||||
assign adc_noe = 1'b0;
|
||||
|
||||
endmodule
|
BIN
fpga/fpga_lf.bit
BIN
fpga/fpga_lf.bit
Binary file not shown.
233
fpga/fpga_lf.v
233
fpga/fpga_lf.v
|
@ -1,233 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Jonathan Westhues, March 2006
|
||||
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||
// Piwi, Feb 2019
|
||||
// Anon, 2019
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h
|
||||
// Note: the definitions here are without shifts
|
||||
|
||||
// Commands:
|
||||
`define FPGA_CMD_SET_CONFREG 1
|
||||
`define FPGA_CMD_SET_DIVISOR 2
|
||||
`define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD 3
|
||||
|
||||
// Major modes:
|
||||
`define FPGA_MAJOR_MODE_LF_READER 0
|
||||
`define FPGA_MAJOR_MODE_LF_EDGE_DETECT 1
|
||||
`define FPGA_MAJOR_MODE_LF_PASSTHRU 2
|
||||
`define FPGA_MAJOR_MODE_LF_ADC 3
|
||||
|
||||
// Options for LF_READER
|
||||
`define FPGA_LF_ADC_READER_FIELD 1
|
||||
|
||||
// Options for LF_EDGE_DETECT
|
||||
`define FPGA_LF_EDGE_DETECT_READER_FIELD 1
|
||||
`define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 2
|
||||
|
||||
`include "lo_read.v"
|
||||
`include "lo_passthru.v"
|
||||
`include "lo_edge_detect.v"
|
||||
`include "lo_adc.v"
|
||||
`include "util.v"
|
||||
`include "clk_divider.v"
|
||||
|
||||
module fpga_lf(
|
||||
input spck, output miso, input mosi, input ncs,
|
||||
input pck0, input ck_1356meg, input ck_1356megb,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
input [7:0] adc_d, output adc_clk, output adc_noe,
|
||||
output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk,
|
||||
input cross_hi, input cross_lo,
|
||||
output dbg
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The SPI receiver. This sets up the configuration word, which the rest of
|
||||
// the logic looks at to determine how to connect the A/D and the coil
|
||||
// drivers (i.e., which section gets it). Also assign some symbolic names
|
||||
// to the configuration bits, for use below.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Attempt to write up how its hooked up. Iceman 2020.
|
||||
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand()
|
||||
Send 16 bit command / data pair to FPGA
|
||||
The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
|
||||
where
|
||||
C is 4bit command
|
||||
D is 12bit data
|
||||
|
||||
shift_reg receive this 16bit frame
|
||||
|
||||
LF command
|
||||
----------
|
||||
shift_reg[15:12] == 4bit command
|
||||
LF has three commands (FPGA_CMD_SET_CONFREG, FPGA_CMD_SET_DIVISOR, FPGA_CMD_SET_EDGE_DETECT_THRESHOLD)
|
||||
Current commands uses only 2bits. We have room for up to 4bits of commands total (7).
|
||||
|
||||
LF data
|
||||
-------
|
||||
shift_reg[11:0] == 12bit data
|
||||
lf data is divided into MAJOR MODES and configuration values.
|
||||
|
||||
The major modes uses 3bits (0,1,2,3,7 | 000, 001, 010, 011, 111)
|
||||
000 FPGA_MAJOR_MODE_LF_READER = Act as LF reader (modulate)
|
||||
001 FPGA_MAJOR_MODE_LF_EDGE_DETECT = Simulate LF
|
||||
010 FPGA_MAJOR_MODE_LF_PASSTHRU = Passthrough mode, CROSS_LO line connected to SSP_DIN. SSP_DOUT logic level controls if we modulate / listening
|
||||
011 FPGA_MAJOR_MODE_LF_ADC = refactor hitag2, clear ADC sampling
|
||||
111 FPGA_MAJOR_MODE_OFF = turn off sampling.
|
||||
|
||||
Each one of this major modes can have options. Currently these two major modes uses options.
|
||||
- FPGA_MAJOR_MODE_LF_READER
|
||||
- FPGA_MAJOR_MODE_LF_EDGE_DETECT
|
||||
|
||||
FPGA_MAJOR_MODE_LF_READER
|
||||
-------------------------------------
|
||||
lf_field = 1bit (FPGA_LF_ADC_READER_FIELD)
|
||||
|
||||
You can send FPGA_CMD_SET_DIVISOR to set with FREQUENCY the fpga should sample at
|
||||
divisor = 8bits shift_reg[7:0]
|
||||
|
||||
FPGA_MAJOR_MODE_LF_EDGE_DETECT
|
||||
------------------------------------------
|
||||
lf_ed_toggle_mode = 1bits
|
||||
lf_ed_threshold = 8bits threshold defaults to 127
|
||||
|
||||
You can send FPGA_CMD_SET_EDGE_DETECT_THRESHOLD to set a custom threshold
|
||||
lf_ed_threshold = 8bits threshold value.
|
||||
|
||||
conf_word 12bits
|
||||
conf_word[8:6] = 3bit major mode.
|
||||
conf_word[0] = 1bit lf_field
|
||||
conf_word[1] = 1bit lf_ed_toggle_mode
|
||||
conf_word[7:0] = 8bit divisor
|
||||
conf_word[7:0] = 8bit threshold
|
||||
|
||||
-----+--------- frame layout --------------------
|
||||
bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
-----+-------------------------------------------
|
||||
cmd | x x x x
|
||||
major| x x x
|
||||
opt | x x
|
||||
divi | x x x x x x x x
|
||||
thres| x x x x x x x x
|
||||
-----+-------------------------------------------
|
||||
*/
|
||||
|
||||
reg [15:0] shift_reg;
|
||||
reg [7:0] divisor;
|
||||
reg [7:0] lf_ed_threshold;
|
||||
reg [11:0] conf_word;
|
||||
|
||||
wire [2:0] major_mode = conf_word[8:6];
|
||||
wire lf_field = conf_word[0];
|
||||
wire lf_ed_toggle_mode = conf_word[1];
|
||||
|
||||
// Handles cmd / data frame from ARM
|
||||
always @(posedge ncs)
|
||||
begin
|
||||
// 4 bit command
|
||||
case (shift_reg[15:12])
|
||||
`FPGA_CMD_SET_CONFREG:
|
||||
begin
|
||||
// 12 bit data
|
||||
conf_word <= shift_reg[11:0];
|
||||
if (shift_reg[8:6] == `FPGA_MAJOR_MODE_LF_EDGE_DETECT)
|
||||
begin
|
||||
lf_ed_threshold <= 127; // default threshold
|
||||
end
|
||||
end
|
||||
|
||||
`FPGA_CMD_SET_DIVISOR:
|
||||
divisor <= shift_reg[7:0]; // 8bits
|
||||
|
||||
`FPGA_CMD_SET_EDGE_DETECT_THRESHOLD:
|
||||
lf_ed_threshold <= shift_reg[7:0]; // 8 bits
|
||||
endcase
|
||||
end
|
||||
|
||||
// Receive 16bits of data from ARM here.
|
||||
always @(posedge spck)
|
||||
begin
|
||||
if (~ncs)
|
||||
begin
|
||||
shift_reg[15:1] <= shift_reg[14:0];
|
||||
shift_reg[0] <= mosi;
|
||||
end
|
||||
end
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// And then we instantiate the modules corresponding to each of the FPGA's
|
||||
// major modes, and use muxes to connect the outputs of the active mode to
|
||||
// the output pins.
|
||||
//-----------------------------------------------------------------------------
|
||||
wire [7:0] pck_cnt;
|
||||
wire pck_divclk;
|
||||
clk_divider div_clk(pck0, divisor, pck_cnt, pck_divclk);
|
||||
|
||||
lo_read lr(
|
||||
pck0, pck_cnt, pck_divclk,
|
||||
lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,
|
||||
adc_d, lr_adc_clk,
|
||||
lr_ssp_frame, lr_ssp_din, lr_ssp_clk,
|
||||
lr_dbg, lf_field
|
||||
);
|
||||
|
||||
lo_passthru lp(
|
||||
pck_divclk,
|
||||
lp_pwr_lo, lp_pwr_hi, lp_pwr_oe1, lp_pwr_oe2, lp_pwr_oe3, lp_pwr_oe4,
|
||||
lp_adc_clk,
|
||||
lp_ssp_din, ssp_dout,
|
||||
cross_lo,
|
||||
lp_dbg
|
||||
);
|
||||
|
||||
lo_edge_detect le(
|
||||
pck0, pck_divclk,
|
||||
le_pwr_lo, le_pwr_hi, le_pwr_oe1, le_pwr_oe2, le_pwr_oe3, le_pwr_oe4,
|
||||
adc_d, le_adc_clk,
|
||||
le_ssp_frame, ssp_dout, le_ssp_clk,
|
||||
cross_lo,
|
||||
le_dbg,
|
||||
lf_field,
|
||||
lf_ed_toggle_mode, lf_ed_threshold
|
||||
);
|
||||
|
||||
lo_adc la(
|
||||
pck0,
|
||||
la_pwr_lo, la_pwr_hi, la_pwr_oe1, la_pwr_oe2, la_pwr_oe3, la_pwr_oe4,
|
||||
adc_d, la_adc_clk,
|
||||
la_ssp_frame, la_ssp_din, ssp_dout, la_ssp_clk,
|
||||
la_dbg, divisor,
|
||||
lf_field
|
||||
);
|
||||
|
||||
// Major modes:
|
||||
// 000 -- LF reader (generic)
|
||||
// 001 -- LF edge detect (generic)
|
||||
// 010 -- LF passthrough
|
||||
// 011 -- LF ADC (read/write)
|
||||
// 100 -- unused
|
||||
// 101 -- unused
|
||||
// 110 -- unused
|
||||
// 111 -- FPGA_MAJOR_MODE_OFF
|
||||
// 000 001 010 011 100 101 110 111
|
||||
mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, la_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, lp_ssp_din, la_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, le_ssp_frame, 1'b0, la_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, le_pwr_oe1, lp_pwr_oe1, la_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, le_pwr_oe2, lp_pwr_oe2, la_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, le_pwr_oe3, lp_pwr_oe3, la_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, le_pwr_oe4, lp_pwr_oe4, la_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, le_pwr_lo, lp_pwr_lo, la_pwr_lo, 1'b0, 1'b0, 1'b1, 1'b0);
|
||||
mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, le_pwr_hi, lp_pwr_hi, la_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, le_adc_clk, lp_adc_clk, la_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
mux8 mux_dbg (major_mode, dbg, lr_dbg, le_dbg, lp_dbg, la_dbg, 1'b0, 1'b0, 1'b0, 1'b0);
|
||||
|
||||
// In all modes, let the ADC's outputs be enabled.
|
||||
assign adc_noe = 1'b0;
|
||||
|
||||
endmodule
|
68
fpga/go.bat
68
fpga/go.bat
|
@ -1,68 +0,0 @@
|
|||
@echo off
|
||||
|
||||
rmdir/s/q xst
|
||||
|
||||
del fpga_lf.ngc
|
||||
xst -ifn xst_lf.scr
|
||||
if errorlevel 0 goto ok1
|
||||
goto done
|
||||
:ok1
|
||||
|
||||
del fpga_lf.ngd
|
||||
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_lf.ngc fpga_lf.ngd
|
||||
if errorlevel 0 goto ok2
|
||||
goto done
|
||||
:ok2
|
||||
|
||||
del fpga_lf.ncd
|
||||
map -p xc2s30-6vq100 fpga_lf.ngd
|
||||
if errorlevel 0 goto ok3
|
||||
goto done
|
||||
:ok3
|
||||
|
||||
del fpga_lf-placed.ncd
|
||||
par fpga_lf.ncd fpga_lf-placed.ncd
|
||||
if errorlevel 0 goto ok4
|
||||
goto done
|
||||
:ok4
|
||||
|
||||
del fpga_lf.bit fpga_lf.drc fpga_lf.rbt
|
||||
bitgen -b fpga_lf-placed.ncd fpga_lf.bit
|
||||
if errorlevel 0 goto ok5
|
||||
goto done
|
||||
:ok5
|
||||
|
||||
del fpga_hf.ngc
|
||||
xst -ifn xst_hf.scr
|
||||
if errorlevel 0 goto ok6
|
||||
goto done
|
||||
:ok6
|
||||
|
||||
del fpga_hf.ngd
|
||||
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_hf.ngc fpga_hf.ngd
|
||||
if errorlevel 0 goto ok7
|
||||
goto done
|
||||
:ok7
|
||||
|
||||
del fpga_hf.ncd
|
||||
map -p xc2s30-6vq100 fpga_hf.ngd
|
||||
if errorlevel 0 goto ok8
|
||||
goto done
|
||||
:ok8
|
||||
|
||||
del fpga_hf-placed.ncd
|
||||
par fpga_hf.ncd fpga_hf-placed.ncd
|
||||
if errorlevel 0 goto ok9
|
||||
goto done
|
||||
:ok9
|
||||
|
||||
del fpga_hf.bit fpga_hf.drc fpga_hf.rbt
|
||||
bitgen -b fpga_hf-placed.ncd fpga_hf.bit
|
||||
if errorlevel 0 goto ok10
|
||||
goto done
|
||||
:ok10
|
||||
|
||||
echo okay
|
||||
perl ..\tools\rbt2c.pl fpga_lf.rbt > ..\armsrc\fpgaimg.c
|
||||
|
||||
:done
|
369
fpga/hi_flite.v
369
fpga/hi_flite.v
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
This code demodulates and modulates signal as described in ISO/IEC 18092.
|
||||
That includes packets used for Felica, NFC Tag 3, etc. (which do overlap)
|
||||
simple envelope following algorithm is used (modification of fail0verflow LF one)
|
||||
is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave)
|
||||
|
||||
Speeds supported: only 212 kbps (fc/64) for now. Todo: 414 kbps
|
||||
though for reader, the selection has to come from ARM. modulation waits for market sprocket -doesn't really mean anything
|
||||
|
||||
mod_type: bits 210:
|
||||
bit 2 : reader drive/power on/off
|
||||
bit 1 : speed bit, 0 : 212, 1 :424
|
||||
bit 0 : listen or modulate
|
||||
*/
|
||||
|
||||
module hi_flite(
|
||||
ck_1356meg,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk,
|
||||
dbg,
|
||||
mod_type
|
||||
);
|
||||
input ck_1356meg;
|
||||
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;
|
||||
output dbg;
|
||||
input [3:0] mod_type;
|
||||
|
||||
assign dbg = 0;
|
||||
|
||||
wire power = mod_type[2];
|
||||
wire speed = mod_type[1];
|
||||
wire disabl = mod_type[0];
|
||||
|
||||
// Most off, oe4 for modulation;
|
||||
// Trying reader emulation (would presumably just require switching power on, but I am not sure)
|
||||
assign pwr_lo = 1'b0;
|
||||
assign pwr_oe2 = 1'b0;
|
||||
|
||||
// 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
|
||||
`define imin 70 // (13'd256)
|
||||
`define imax 180 // (-13'd256)
|
||||
`define ithrmin 91 // -13'd8
|
||||
`define ithrmax 160 // 13'd8
|
||||
|
||||
`define min_bitdelay_212 8
|
||||
//minimum values and corresponding thresholds
|
||||
reg [8:0] curmin=`imin;
|
||||
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;
|
||||
|
||||
`define bithalf_212 32 // half-bit length for 212 kbit
|
||||
`define bitmlen_212 63 // bit transition edge
|
||||
|
||||
`define bithalf_424 16 // half-bit length for 212 kbit
|
||||
`define bitmlen_424 31 // bit transition edge
|
||||
|
||||
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;
|
||||
reg curbit = 1'b0;
|
||||
|
||||
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
|
||||
|
||||
reg [7:0] tsinceedge = 8'd0;// ticks from last edge, desync if the valye is too large
|
||||
|
||||
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
|
||||
reg [8:0] ssp_cnt = 9'd0;
|
||||
|
||||
always @(posedge adc_clk)
|
||||
ssp_cnt <= (ssp_cnt + 1);
|
||||
|
||||
//maybe change it so that ARM sends preamble as well.
|
||||
//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
|
||||
if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed && (ssp_cnt[4:0] == 5'b00000)))
|
||||
begin
|
||||
ssp_clk <= 1'b1;
|
||||
ssp_din <= curbit;
|
||||
end
|
||||
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
|
||||
// took me a day to figure THAT out.
|
||||
if(( (~speed) && (ssp_cnt[8:0] == 9'd31)) || (speed && ssp_cnt[7:0] == 8'd15))
|
||||
begin
|
||||
ssp_frame <= 1'b1;
|
||||
end
|
||||
if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111)) || (speed &&ssp_cnt[7:0] == 8'b101111) )
|
||||
begin
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
//send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise)
|
||||
reg ssp_din;
|
||||
|
||||
//previous signal value, mostly to detect SYNC
|
||||
reg prv = 1'b1;
|
||||
|
||||
// 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.
|
||||
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
|
||||
// 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?
|
||||
|
||||
|
||||
//we need some way to flush bit_counts triggers on mod_type changes don't compile
|
||||
reg dlay;
|
||||
always @(negedge adc_clk) // every data ping?
|
||||
begin
|
||||
//envelope follow code...
|
||||
////////////
|
||||
if (fccount == bitmlen)
|
||||
begin
|
||||
if ((~try_sync) && (adc_d < curminthres) && disabl )
|
||||
begin
|
||||
fccount <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
fccount <= 0;
|
||||
end
|
||||
dlay <= ssp_dout;
|
||||
if (bit_counts > 768) // should be over ts0 now, without ARM interference... stop counting...
|
||||
begin
|
||||
bit_counts <= 0;
|
||||
end
|
||||
else
|
||||
if (power)
|
||||
bit_counts <= 0;
|
||||
else
|
||||
bit_counts <= bit_counts + 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if((~try_sync) && (adc_d < curminthres) && disabl)
|
||||
begin
|
||||
fccount <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
fccount <= fccount + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// rising edge
|
||||
if (adc_d > curmaxthres)
|
||||
begin
|
||||
case (state)
|
||||
0: begin
|
||||
curmax <= adc_d > `imax? adc_d : `imax;
|
||||
state <= 2;
|
||||
end
|
||||
1: begin
|
||||
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
|
||||
if (adc_d > curmax)
|
||||
curmax <= adc_d;
|
||||
end
|
||||
default:
|
||||
begin
|
||||
end
|
||||
endcase
|
||||
after_hysteresis <= 1'b1;
|
||||
if(try_sync)
|
||||
tsinceedge <= 0;
|
||||
end
|
||||
else if (adc_d<curminthres) //falling edge
|
||||
begin
|
||||
case (state)
|
||||
0: begin
|
||||
curmin <= adc_d<`imin? adc_d :`imin;
|
||||
state <= 1;
|
||||
end
|
||||
1: begin
|
||||
if (adc_d<curmin)
|
||||
curmin <= adc_d;
|
||||
end
|
||||
2: begin
|
||||
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;
|
||||
end
|
||||
default:
|
||||
begin
|
||||
end
|
||||
endcase
|
||||
after_hysteresis <= 0;
|
||||
if (~try_sync ) //begin modulation, lower edge...
|
||||
begin
|
||||
try_sync <= 1;
|
||||
fccount <= 1;
|
||||
did_sync <= 0;
|
||||
curbit <= 0;
|
||||
mid <= 8'd127;
|
||||
tsinceedge <= 0;
|
||||
prv <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
tsinceedge <= 0;
|
||||
end
|
||||
end
|
||||
else //stable state, low or high
|
||||
begin
|
||||
curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
|
||||
curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
|
||||
state <= 0;
|
||||
|
||||
if (try_sync )
|
||||
begin
|
||||
if (tsinceedge >= (128))
|
||||
begin
|
||||
//we might need to start counting... assuming ARM wants to reply to the frame.
|
||||
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
|
||||
tsinceedge <= (tsinceedge + 1);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if (try_sync && tsinceedge < 128)
|
||||
begin
|
||||
//detect bits in their middle ssp sampling is in sync, so it would sample all bits in order
|
||||
if (fccount == bithalf)
|
||||
begin
|
||||
if ((~did_sync) && ((prv == 1 && (mid > 128))||(prv == 0 && (mid <= 128))))
|
||||
begin
|
||||
//sync the Zero, and set curbit roperly
|
||||
did_sync <= 1'b1;
|
||||
zero <= ~prv;// 1-prv
|
||||
curbit <= 1;
|
||||
end
|
||||
else
|
||||
curbit <= (mid > 128) ? (~zero) : zero;
|
||||
|
||||
prv <= (mid > 128) ? 1 : 0;
|
||||
|
||||
if (adc_d > curmaxthres)
|
||||
mid <= 8'd129;
|
||||
else if (adc_d < curminthres)
|
||||
mid <= 8'd127;
|
||||
else
|
||||
begin
|
||||
if (after_hysteresis)
|
||||
begin
|
||||
mid <= 8'd129;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mid <= 8'd127;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (fccount==bitmlen)
|
||||
begin
|
||||
// fccount <= 0;
|
||||
prv <= (mid > 128) ? 1 : 0;
|
||||
mid <= 128;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// minimum-maximum calc
|
||||
if(adc_d > curmaxthres)
|
||||
mid <= mid + 1;
|
||||
else if (adc_d < curminthres)
|
||||
mid <= mid - 1;
|
||||
else
|
||||
begin
|
||||
if (after_hysteresis)
|
||||
begin
|
||||
mid <= mid + 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mid <= mid - 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
end
|
||||
// sending <= 0;
|
||||
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_oe3;
|
||||
reg pwr_oe4;
|
||||
|
||||
wire mod = ((fccount >= bithalf) ^ dlay) & (~disabl);
|
||||
|
||||
always @(ck_1356meg or ssp_dout or power or disabl or mod)
|
||||
begin
|
||||
if (power)
|
||||
begin
|
||||
pwr_hi <= ck_1356meg;
|
||||
pwr_oe1 <= 1'b0;//mod;
|
||||
pwr_oe3 <= 1'b0;//mod;
|
||||
pwr_oe4 <= mod;//1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
pwr_hi <= 1'b0;
|
||||
pwr_oe1 <= 1'b0;
|
||||
pwr_oe3 <= 1'b0;
|
||||
pwr_oe4 <= mod;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
endmodule
|
|
@ -1,162 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// piwi, Feb 2019
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module hi_get_trace(
|
||||
ck_1356megb,
|
||||
adc_d, trace_enable, major_mode,
|
||||
ssp_frame, ssp_din, ssp_clk
|
||||
);
|
||||
input ck_1356megb;
|
||||
input [7:0] adc_d;
|
||||
input trace_enable;
|
||||
input [2:0] major_mode;
|
||||
output ssp_frame, ssp_din, ssp_clk;
|
||||
|
||||
// clock divider
|
||||
reg [6:0] clock_cnt;
|
||||
always @(negedge ck_1356megb)
|
||||
begin
|
||||
clock_cnt <= clock_cnt + 1;
|
||||
end
|
||||
|
||||
// sample at 13,56MHz / 8. The highest signal frequency (subcarrier) is 848,5kHz, i.e. in this case we oversample by a factor of 2
|
||||
reg [2:0] sample_clock;
|
||||
always @(negedge ck_1356megb)
|
||||
begin
|
||||
if (sample_clock == 3'd7)
|
||||
sample_clock <= 3'd0;
|
||||
else
|
||||
sample_clock <= sample_clock + 1;
|
||||
end
|
||||
|
||||
|
||||
reg [11:0] addr;
|
||||
reg [11:0] start_addr;
|
||||
reg [2:0] previous_major_mode;
|
||||
reg write_enable1;
|
||||
reg write_enable2;
|
||||
always @(negedge ck_1356megb)
|
||||
begin
|
||||
previous_major_mode <= major_mode;
|
||||
if (major_mode == `FPGA_MAJOR_MODE_HF_GET_TRACE)
|
||||
begin
|
||||
write_enable1 <= 1'b0;
|
||||
write_enable2 <= 1'b0;
|
||||
if (previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched into GET_TRACE mode
|
||||
addr <= start_addr;
|
||||
if (clock_cnt == 7'd0)
|
||||
begin
|
||||
if (addr == 12'd3071)
|
||||
addr <= 12'd0;
|
||||
else
|
||||
addr <= addr + 1;
|
||||
end
|
||||
end
|
||||
else if (major_mode != `FPGA_MAJOR_MODE_OFF)
|
||||
begin
|
||||
if (trace_enable)
|
||||
begin
|
||||
if (addr[11] == 1'b0)
|
||||
begin
|
||||
write_enable1 <= 1'b1;
|
||||
write_enable2 <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
write_enable1 <= 1'b0;
|
||||
write_enable2 <= 1'b1;
|
||||
end
|
||||
if (sample_clock == 3'b000)
|
||||
begin
|
||||
if (addr == 12'd3071)
|
||||
begin
|
||||
addr <= 12'd0;
|
||||
write_enable1 <= 1'b1;
|
||||
write_enable2 <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
addr <= addr + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
write_enable1 <= 1'b0;
|
||||
write_enable2 <= 1'b0;
|
||||
start_addr <= addr;
|
||||
end
|
||||
end
|
||||
else // major_mode == `FPGA_MAJOR_MODE_OFF
|
||||
begin
|
||||
write_enable1 <= 1'b0;
|
||||
write_enable2 <= 1'b0;
|
||||
if (previous_major_mode != `FPGA_MAJOR_MODE_OFF && previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched off
|
||||
begin
|
||||
start_addr <= addr;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// (2+1)k RAM
|
||||
reg [7:0] D_out1, D_out2;
|
||||
reg [7:0] ram1 [2047:0]; // 2048 u8
|
||||
reg [7:0] ram2 [1023:0]; // 1024 u8
|
||||
|
||||
always @(negedge ck_1356megb)
|
||||
begin
|
||||
if (write_enable1)
|
||||
begin
|
||||
ram1[addr[10:0]] <= adc_d;
|
||||
D_out1 <= adc_d;
|
||||
end
|
||||
else
|
||||
D_out1 <= ram1[addr[10:0]];
|
||||
if (write_enable2)
|
||||
begin
|
||||
ram2[addr[9:0]] <= adc_d;
|
||||
D_out2 <= adc_d;
|
||||
end
|
||||
else
|
||||
D_out2 <= ram2[addr[9:0]];
|
||||
end
|
||||
|
||||
|
||||
// SSC communication to ARM
|
||||
reg ssp_clk;
|
||||
reg ssp_frame;
|
||||
reg [7:0] shift_out;
|
||||
|
||||
always @(negedge ck_1356megb)
|
||||
begin
|
||||
if (clock_cnt[3:0] == 4'd0) // update shift register every 16 clock cycles
|
||||
begin
|
||||
if (clock_cnt[6:4] == 3'd0) // either load new value
|
||||
begin
|
||||
if (addr[11] == 1'b0)
|
||||
shift_out <= D_out1;
|
||||
else
|
||||
shift_out <= D_out2;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// or shift left
|
||||
shift_out[7:1] <= shift_out[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
ssp_clk <= ~clock_cnt[3]; // ssp_clk frequency = 13,56MHz / 16 = 847,5 kHz
|
||||
|
||||
if (clock_cnt[6:4] == 3'b000) // set ssp_frame for 0...31
|
||||
ssp_frame <= 1'b1;
|
||||
else
|
||||
ssp_frame <= 1'b0;
|
||||
|
||||
end
|
||||
|
||||
assign ssp_din = shift_out[7];
|
||||
|
||||
endmodule
|
|
@ -1,569 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// ISO14443-A support for the Proxmark III
|
||||
// Gerhard de Koning Gans, April 2008
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module hi_iso14443a(
|
||||
ck_1356meg,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk,
|
||||
dbg,
|
||||
mod_type
|
||||
);
|
||||
input ck_1356meg;
|
||||
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;
|
||||
output dbg;
|
||||
input [3:0] mod_type;
|
||||
|
||||
|
||||
wire adc_clk = ck_1356meg;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reader -> PM3:
|
||||
// detecting and shaping the reader's signal. Reader will modulate the carrier by 100% (signal is either on or off). Use a
|
||||
// hysteresis (Schmitt Trigger) to avoid false triggers during slowly increasing or decreasing carrier amplitudes
|
||||
reg after_hysteresis;
|
||||
reg [11:0] has_been_low_for;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(adc_d >= 16) after_hysteresis <= 1'b1; // U >= 1,14V -> after_hysteresis = 1
|
||||
else if(adc_d < 8) after_hysteresis <= 1'b0; // U < 1,04V -> after_hysteresis = 0
|
||||
// Note: was >= 3,53V and <= 1,19V. The new trigger values allow more reliable detection of the first bit
|
||||
// (it might not reach 3,53V due to the high time constant of the high pass filter in the analogue RF part).
|
||||
// In addition, the new values are more in line with ISO14443-2: "The PICC shall detect the ”End of Pause” after the field exceeds
|
||||
// 5% of H_INITIAL and before it exceeds 60% of H_INITIAL." Depending on the signal strength, 60% might well be less than 3,53V.
|
||||
|
||||
|
||||
// detecting a loss of reader's field (adc_d < 192 for 4096 clock cycles). If this is the case,
|
||||
// set the detected reader signal (after_hysteresis) to '1' (unmodulated)
|
||||
if(adc_d >= 192)
|
||||
begin
|
||||
has_been_low_for <= 12'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(has_been_low_for == 12'd4095)
|
||||
begin
|
||||
has_been_low_for <= 12'd0;
|
||||
after_hysteresis <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
has_been_low_for <= has_been_low_for + 1;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reader -> PM3
|
||||
// detect when a reader is active (modulating). We assume that the reader is active, if we see the carrier off for at least 8
|
||||
// carrier cycles. We assume that the reader is inactive, if the carrier stayed high for at least 256 carrier cycles.
|
||||
reg deep_modulation;
|
||||
reg [2:0] deep_counter;
|
||||
reg [8:0] saw_deep_modulation;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(~(| adc_d[7:0])) // if adc_d == 0 (U <= 0,94V)
|
||||
begin
|
||||
if(deep_counter == 3'd7) // adc_d == 0 for 8 adc_clk ticks -> deep_modulation (by reader)
|
||||
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) // adc_d != 0 for 256 adc_clk ticks -> deep_modulation is over, probably waiting for tag's response
|
||||
deep_modulation <= 1'b0;
|
||||
else
|
||||
saw_deep_modulation <= saw_deep_modulation + 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag -> PM3
|
||||
// filter the input for a tag's signal. The filter box needs the 4 previous input values and is a gaussian derivative filter
|
||||
// for noise reduction and edge detection.
|
||||
// store 4 previous samples:
|
||||
reg [7:0] input_prev_4, input_prev_3, input_prev_2, input_prev_1;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
input_prev_4 <= input_prev_3;
|
||||
input_prev_3 <= input_prev_2;
|
||||
input_prev_2 <= input_prev_1;
|
||||
input_prev_1 <= adc_d;
|
||||
end
|
||||
|
||||
// adc_d_filtered = 2*input_prev4 + 1*input_prev3 + 0*input_prev2 - 1*input_prev1 - 2*input
|
||||
// = (2*input_prev4 + input_prev3) - (2*input + input_prev1)
|
||||
wire [8:0] input_prev_4_times_2 = input_prev_4 << 1;
|
||||
wire [8:0] adc_d_times_2 = adc_d << 1;
|
||||
|
||||
wire [9:0] tmp1 = input_prev_4_times_2 + input_prev_3;
|
||||
wire [9:0] tmp2 = adc_d_times_2 + input_prev_1;
|
||||
|
||||
// convert intermediate signals to signed and calculate the filter output
|
||||
wire signed [10:0] adc_d_filtered = {1'b0, tmp1} - {1'b0, tmp2};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// internal FPGA timing. Maximum required period is 128 carrier clock cycles for a full 8 Bit transfer to ARM. (i.e. we need a
|
||||
// 7 bit counter). Adjust its frequency to external reader's clock when simulating a tag or sniffing.
|
||||
reg pre_after_hysteresis;
|
||||
reg [3:0] reader_falling_edge_time;
|
||||
reg [6:0] negedge_cnt;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
// detect a reader signal's falling edge and remember its timing:
|
||||
pre_after_hysteresis <= after_hysteresis;
|
||||
if (pre_after_hysteresis && ~after_hysteresis)
|
||||
begin
|
||||
reader_falling_edge_time[3:0] <= negedge_cnt[3:0];
|
||||
end
|
||||
|
||||
// adjust internal timer counter if necessary:
|
||||
if (negedge_cnt[3:0] == 4'd13 && (mod_type == `FPGA_HF_ISO14443A_SNIFFER || mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN) && deep_modulation)
|
||||
begin
|
||||
if (reader_falling_edge_time == 4'd1) // reader signal changes right after sampling. Better sample earlier next time.
|
||||
begin
|
||||
negedge_cnt <= negedge_cnt + 2; // time warp
|
||||
end
|
||||
else if (reader_falling_edge_time == 4'd0) // reader signal changes right before sampling. Better sample later next time.
|
||||
begin
|
||||
negedge_cnt <= negedge_cnt; // freeze time
|
||||
end
|
||||
else
|
||||
begin
|
||||
negedge_cnt <= negedge_cnt + 1; // Continue as usual
|
||||
end
|
||||
reader_falling_edge_time[3:0] <= 4'd8; // adjust only once per detected edge
|
||||
end
|
||||
else if (negedge_cnt == 7'd127) // normal operation: count from 0 to 127
|
||||
begin
|
||||
negedge_cnt <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
negedge_cnt <= negedge_cnt + 1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag -> PM3:
|
||||
// determine best possible time for starting/resetting the modulation detector.
|
||||
reg [3:0] mod_detect_reset_time;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN)
|
||||
// (our) reader signal changes at negedge_cnt[3:0]=9, tag response expected to start n*16+4 ticks later, further delayed by
|
||||
// 3 ticks ADC conversion. The maximum filter output (edge detected) will be detected after subcarrier zero crossing (+7 ticks).
|
||||
// To allow some timing variances, we want to have the maximum filter outputs well within the detection window, i.e.
|
||||
// at mod_detect_reset_time+4 and mod_detect_reset_time+12 (-4 ticks).
|
||||
// 9 + 4 + 3 + 7 - 4 = 19. 19 mod 16 = 3
|
||||
begin
|
||||
mod_detect_reset_time <= 4'd4;
|
||||
end
|
||||
else
|
||||
if (mod_type == `FPGA_HF_ISO14443A_SNIFFER)
|
||||
begin
|
||||
// detect a rising edge of reader's signal and sync modulation detector to the tag's answer:
|
||||
if (~pre_after_hysteresis && after_hysteresis && deep_modulation)
|
||||
// reader signal rising edge detected at negedge_cnt[3:0]. This signal had been delayed
|
||||
// 9 ticks by the RF part + 3 ticks by the A/D converter + 1 tick to assign to after_hysteresis.
|
||||
// Then the same as above.
|
||||
// - 9 - 3 - 1 + 4 + 3 + 7 - 4 = -3
|
||||
begin
|
||||
mod_detect_reset_time <= negedge_cnt[3:0] - 4'd3;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag -> PM3:
|
||||
// modulation detector. Looks for the steepest falling and rising edges within a 16 clock period. If there is both a significant
|
||||
// falling and rising edge (in any order), a modulation is detected.
|
||||
reg signed [10:0] rx_mod_falling_edge_max;
|
||||
reg signed [10:0] rx_mod_rising_edge_max;
|
||||
reg curbit;
|
||||
|
||||
`define EDGE_DETECT_THRESHOLD 5
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(negedge_cnt[3:0] == mod_detect_reset_time)
|
||||
begin
|
||||
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
|
||||
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLD) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLD))
|
||||
curbit <= 1'b1; // modulation
|
||||
else
|
||||
curbit <= 1'b0; // no modulation
|
||||
// reset modulation detector
|
||||
rx_mod_rising_edge_max <= 0;
|
||||
rx_mod_falling_edge_max <= 0;
|
||||
end
|
||||
else // look for steepest edges (slopes)
|
||||
begin
|
||||
if (adc_d_filtered > 0)
|
||||
begin
|
||||
if (adc_d_filtered > rx_mod_falling_edge_max)
|
||||
rx_mod_falling_edge_max <= adc_d_filtered;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (adc_d_filtered < rx_mod_rising_edge_max)
|
||||
rx_mod_rising_edge_max <= adc_d_filtered;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag+Reader -> PM3
|
||||
// sample 4 bits reader data and 4 bits tag data for sniffing
|
||||
reg [3:0] reader_data;
|
||||
reg [3:0] tag_data;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(negedge_cnt[3:0] == 4'd0)
|
||||
begin
|
||||
reader_data[3:0] <= {reader_data[2:0], after_hysteresis};
|
||||
tag_data[3:0] <= {tag_data[2:0], curbit};
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PM3 -> Reader:
|
||||
// a delay line to ensure that we send the (emulated) tag's answer at the correct time according to ISO14443-3
|
||||
reg [31:0] mod_sig_buf;
|
||||
reg [4:0] mod_sig_ptr;
|
||||
reg mod_sig;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(negedge_cnt[3:0] == 4'd0) // sample data at rising edge of ssp_clk - ssp_dout changes at the falling edge.
|
||||
begin
|
||||
mod_sig_buf[31:2] <= mod_sig_buf[30:1]; // shift
|
||||
if (~ssp_dout && ~mod_sig_buf[1])
|
||||
mod_sig_buf[1] <= 1'b0; // delete the correction bit (a single 1 preceded and succeeded by 0)
|
||||
else
|
||||
mod_sig_buf[1] <= mod_sig_buf[0];
|
||||
mod_sig_buf[0] <= ssp_dout; // add new data to the delay line
|
||||
|
||||
mod_sig = mod_sig_buf[mod_sig_ptr]; // the delayed signal.
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PM3 -> Reader, internal timing:
|
||||
// a timer for the 1172 cycles fdt (Frame Delay Time). Start the timer with a rising edge of the reader's signal.
|
||||
// set fdt_elapsed when we no longer need to delay data. Set fdt_indicator when we can start sending data.
|
||||
// Note: the FPGA only takes care for the 1172 delay. To achieve an additional 1236-1172=64 ticks delay, the ARM must send
|
||||
// a correction bit (before the start bit). The correction bit will be coded as 00010000, i.e. it adds 4 bits to the
|
||||
// transmission stream, causing the required additional delay.
|
||||
reg [10:0] fdt_counter;
|
||||
reg fdt_indicator, fdt_elapsed;
|
||||
reg [3:0] mod_sig_flip;
|
||||
reg [3:0] sub_carrier_cnt;
|
||||
|
||||
// we want to achieve a delay of 1172. The RF part already has delayed the reader signals's rising edge
|
||||
// by 9 ticks, the ADC took 3 ticks and there is always a delay of 32 ticks by the mod_sig_buf. Therefore need to
|
||||
// count to 1172 - 9 - 3 - 32 = 1128
|
||||
`define FDT_COUNT 11'd1128
|
||||
|
||||
// The ARM must not send too early, otherwise the mod_sig_buf will overflow, therefore signal that we are ready
|
||||
// with fdt_indicator. The mod_sig_buf can buffer 29 excess data bits, i.e. a maximum delay of 29 * 16 = 464 adc_clk ticks.
|
||||
// fdt_indicator is assigned to sendbit after at least 1 tick, the transfer to ARM needs minimum 8 ticks. Response from
|
||||
// ARM could appear at ssp_dout 8 ticks later.
|
||||
// 1128 - 464 - 1 - 8 - 8 = 647
|
||||
`define FDT_INDICATOR_COUNT 11'd647
|
||||
// Note: worst case, assignment to sendbit takes 15 ticks more, and transfer to ARM needs 7*16 = 112 ticks more.
|
||||
// When the ARM's response then appears, the fdt_count is already 647 + 15 + 112 = 774, which still allows the ARM a possible
|
||||
// response window of 1128 - 774 = 354 ticks.
|
||||
|
||||
// reset on a pause in listen mode. I.e. the counter starts when the pause is over:
|
||||
assign fdt_reset = ~after_hysteresis && mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (fdt_reset)
|
||||
begin
|
||||
fdt_counter <= 11'd0;
|
||||
fdt_elapsed <= 1'b0;
|
||||
fdt_indicator <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(fdt_counter == `FDT_COUNT)
|
||||
begin
|
||||
if(~fdt_elapsed) // just reached fdt.
|
||||
begin
|
||||
mod_sig_flip <= negedge_cnt[3:0]; // start modulation at this time
|
||||
sub_carrier_cnt <= 4'd0; // subcarrier phase in sync with start of modulation
|
||||
fdt_elapsed <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
sub_carrier_cnt <= sub_carrier_cnt + 1;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
fdt_counter <= fdt_counter + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if(fdt_counter == `FDT_INDICATOR_COUNT) fdt_indicator <= 1'b1;
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PM3 -> Reader or Tag
|
||||
// assign a modulation signal to the antenna. This signal is either a delayed signal (to achieve fdt when sending to a reader)
|
||||
// or undelayed when sending to a tag
|
||||
reg mod_sig_coil;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD) // need to take care of proper fdt timing
|
||||
begin
|
||||
if(fdt_counter == `FDT_COUNT)
|
||||
begin
|
||||
if(fdt_elapsed)
|
||||
begin
|
||||
if(negedge_cnt[3:0] == mod_sig_flip) mod_sig_coil <= mod_sig;
|
||||
end
|
||||
else
|
||||
begin
|
||||
mod_sig_coil <= mod_sig; // just reached fdt. Immediately assign signal to coil
|
||||
end
|
||||
end
|
||||
end
|
||||
else // other modes: don't delay
|
||||
begin
|
||||
mod_sig_coil <= ssp_dout;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PM3 -> Reader
|
||||
// determine the required delay in the mod_sig_buf (set mod_sig_ptr).
|
||||
reg temp_buffer_reset;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(fdt_reset)
|
||||
begin
|
||||
mod_sig_ptr <= 5'd0;
|
||||
temp_buffer_reset = 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(fdt_counter == `FDT_COUNT && ~fdt_elapsed) // if we just reached fdt
|
||||
if(~(| mod_sig_ptr[4:0]))
|
||||
mod_sig_ptr <= 5'd8; // ... but didn't buffer a 1 yet, delay next 1 by n*128 ticks.
|
||||
else
|
||||
temp_buffer_reset = 1'b1; // else no need for further delays.
|
||||
|
||||
if(negedge_cnt[3:0] == 4'd0) // at rising edge of ssp_clk - ssp_dout changes at the falling edge.
|
||||
begin
|
||||
if((ssp_dout || (| mod_sig_ptr[4:0])) && ~fdt_elapsed) // buffer a 1 (and all subsequent data) until fdt is reached.
|
||||
if (mod_sig_ptr == 5'd31)
|
||||
mod_sig_ptr <= 5'd0; // buffer overflow - data loss.
|
||||
else
|
||||
mod_sig_ptr <= mod_sig_ptr + 1; // increase buffer (= increase delay by 16 adc_clk ticks). mod_sig_ptr always points ahead of first 1.
|
||||
else if(fdt_elapsed && ~temp_buffer_reset)
|
||||
begin
|
||||
// wait for the next 1 after fdt_elapsed before fixing the delay and starting modulation. This ensures that the response can only happen
|
||||
// at intervals of 8 * 16 = 128 adc_clk ticks (as defined in ISO14443-3)
|
||||
if(ssp_dout)
|
||||
temp_buffer_reset = 1'b1;
|
||||
if(mod_sig_ptr == 5'd1)
|
||||
mod_sig_ptr <= 5'd8; // still nothing received, need to go for the next interval
|
||||
else
|
||||
mod_sig_ptr <= mod_sig_ptr - 1; // decrease buffer.
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FPGA -> ARM communication:
|
||||
// buffer 8 bits data to be sent to ARM. Shift them out bit by bit.
|
||||
reg [7:0] to_arm;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (negedge_cnt[5:0] == 6'd63) // fill the buffer
|
||||
begin
|
||||
if (mod_type == `FPGA_HF_ISO14443A_SNIFFER)
|
||||
begin
|
||||
if(deep_modulation) // a reader is sending (or there's no field at all)
|
||||
begin
|
||||
to_arm <= {reader_data[3:0], 4'b0000}; // don't send tag data
|
||||
end
|
||||
else
|
||||
begin
|
||||
to_arm <= {reader_data[3:0], tag_data[3:0]};
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
to_arm[7:0] <= {mod_sig_ptr[4:0], mod_sig_flip[3:1]}; // feedback timing information
|
||||
end
|
||||
end
|
||||
|
||||
if(negedge_cnt[2:0] == 3'b000 && mod_type == `FPGA_HF_ISO14443A_SNIFFER) // shift at double speed
|
||||
begin
|
||||
// Don't shift if we just loaded new data, obviously.
|
||||
if(negedge_cnt[5:0] != 6'd0)
|
||||
begin
|
||||
to_arm[7:1] <= to_arm[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
if(negedge_cnt[3:0] == 4'b0000 && mod_type != `FPGA_HF_ISO14443A_SNIFFER)
|
||||
begin
|
||||
// Don't shift if we just loaded new data, obviously.
|
||||
if(negedge_cnt[6:0] != 7'd0)
|
||||
begin
|
||||
to_arm[7:1] <= to_arm[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FPGA <-> ARM communication:
|
||||
// generate a ssp clock and ssp frame signal for the synchronous transfer from/to the ARM
|
||||
reg ssp_clk;
|
||||
reg ssp_frame;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(mod_type == `FPGA_HF_ISO14443A_SNIFFER)
|
||||
// FPGA_HF_ISO14443A_SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)):
|
||||
begin
|
||||
if(negedge_cnt[2:0] == 3'd0)
|
||||
ssp_clk <= 1'b1;
|
||||
if(negedge_cnt[2:0] == 3'd4)
|
||||
ssp_clk <= 1'b0;
|
||||
|
||||
if(negedge_cnt[5:0] == 6'd0) // ssp_frame rising edge indicates start of frame
|
||||
ssp_frame <= 1'b1;
|
||||
if(negedge_cnt[5:0] == 6'd8)
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
else
|
||||
// all other modes (ssp_clk = adc_clk / 16, ssp_frame clock = adc_clk / 128):
|
||||
begin
|
||||
if(negedge_cnt[3:0] == 4'd0)
|
||||
ssp_clk <= 1'b1;
|
||||
if(negedge_cnt[3:0] == 4'd8)
|
||||
ssp_clk <= 1'b0;
|
||||
|
||||
if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame, sampled on falling edge of ssp_clk
|
||||
ssp_frame <= 1'b1;
|
||||
if(negedge_cnt[6:0] == 7'd23)
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FPGA -> ARM communication:
|
||||
// select the data to be sent to ARM
|
||||
reg bit_to_arm;
|
||||
reg sendbit;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if(negedge_cnt[3:0] == 4'd0)
|
||||
begin
|
||||
// What do we communicate to the ARM
|
||||
if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN)
|
||||
sendbit = after_hysteresis;
|
||||
else if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD)
|
||||
/* if(fdt_counter > 11'd772) sendbit = mod_sig_coil; // huh?
|
||||
else */
|
||||
sendbit = fdt_indicator;
|
||||
else if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN)
|
||||
sendbit = curbit;
|
||||
else
|
||||
sendbit = 1'b0;
|
||||
end
|
||||
|
||||
|
||||
if(mod_type == `FPGA_HF_ISO14443A_SNIFFER)
|
||||
// send sampled reader and tag data:
|
||||
bit_to_arm = to_arm[7];
|
||||
else if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD && fdt_elapsed && temp_buffer_reset)
|
||||
// send timing information:
|
||||
bit_to_arm = to_arm[7];
|
||||
else
|
||||
// send data or fdt_indicator
|
||||
bit_to_arm = sendbit;
|
||||
end
|
||||
|
||||
assign ssp_din = bit_to_arm;
|
||||
|
||||
// Subcarrier (adc_clk/16, for FPGA_HF_ISO14443A_TAGSIM_MOD only).
|
||||
wire sub_carrier;
|
||||
assign sub_carrier = ~sub_carrier_cnt[3];
|
||||
|
||||
// in FPGA_HF_ISO14443A_READER_MOD: drop carrier for mod_sig_coil == 1 (pause);
|
||||
// in FPGA_HF_ISO14443A_READER_LISTEN: carrier always on; in other modes: carrier always off
|
||||
assign pwr_hi = (ck_1356meg & (((mod_type == `FPGA_HF_ISO14443A_READER_MOD) & ~mod_sig_coil) || (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN)));
|
||||
|
||||
|
||||
// Enable HF antenna drivers:
|
||||
assign pwr_oe1 = 1'b0;
|
||||
assign pwr_oe3 = 1'b0;
|
||||
|
||||
// FPGA_HF_ISO14443A_TAGSIM_MOD: short circuit antenna with different resistances (modulated by sub_carrier modulated by mod_sig_coil)
|
||||
// for pwr_oe4 = 1 (tristate): antenna load = 10k || 33 = 32,9 Ohms
|
||||
// for pwr_oe4 = 0 (active): antenna load = 10k || 33 || 33 = 16,5 Ohms
|
||||
assign pwr_oe4 = mod_sig_coil & sub_carrier & (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD);
|
||||
|
||||
// This is all LF, so doesn't matter.
|
||||
assign pwr_oe2 = 1'b0;
|
||||
assign pwr_lo = 1'b0;
|
||||
|
||||
assign dbg = negedge_cnt[3];
|
||||
|
||||
endmodule
|
335
fpga/hi_reader.v
335
fpga/hi_reader.v
|
@ -1,335 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Jonathan Westhues, April 2006
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module hi_reader(
|
||||
ck_1356meg,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk,
|
||||
dbg,
|
||||
subcarrier_frequency, minor_mode
|
||||
);
|
||||
input ck_1356meg;
|
||||
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;
|
||||
output dbg;
|
||||
input [1:0] subcarrier_frequency;
|
||||
input [3:0] minor_mode;
|
||||
|
||||
assign adc_clk = ck_1356meg; // sample frequency is 13,56 MHz
|
||||
|
||||
// When we're a reader, we just need to do the BPSK demod; but when we're an
|
||||
// eavesdropper, we also need to pick out the commands sent by the reader,
|
||||
// using AM. Do this the same way that we do it for the simulated tag.
|
||||
reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev;
|
||||
reg [11:0] has_been_low_for;
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (& adc_d[7:0]) after_hysteresis <= 1'b1;
|
||||
else if (~(| adc_d[7:0])) after_hysteresis <= 1'b0;
|
||||
|
||||
if (after_hysteresis)
|
||||
begin
|
||||
has_been_low_for <= 12'd0;
|
||||
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
|
||||
|
||||
|
||||
// Let us report a correlation every 64 samples. I.e.
|
||||
// one Q/I pair after 4 subcarrier cycles for the 848kHz subcarrier,
|
||||
// one Q/I pair after 2 subcarrier cycles for the 424kHz subcarriers,
|
||||
// one Q/I pair for each subcarrier cyle for the 212kHz subcarrier.
|
||||
// We need a 6-bit counter for the timing.
|
||||
reg [5:0] corr_i_cnt;
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
corr_i_cnt <= corr_i_cnt + 1;
|
||||
end
|
||||
|
||||
|
||||
// A couple of registers in which to accumulate the correlations. From the 64 samples
|
||||
// we would add at most 32 times the difference between unmodulated and modulated signal. It should
|
||||
// be safe to assume that a tag will not be able to modulate the carrier signal by more than 25%.
|
||||
// 32 * 255 * 0,25 = 2040, which can be held in 11 bits. Add 1 bit for sign.
|
||||
// Temporary we might need more bits. For the 212kHz subcarrier we could possible add 32 times the
|
||||
// maximum signal value before a first subtraction would occur. 32 * 255 = 8160 can be held in 13 bits.
|
||||
// Add one bit for sign -> need 14 bit registers but final result will fit into 12 bits.
|
||||
reg signed [13:0] corr_i_accum;
|
||||
reg signed [13:0] corr_q_accum;
|
||||
// we will report maximum 8 significant bits
|
||||
reg signed [7:0] corr_i_out;
|
||||
reg signed [7:0] corr_q_out;
|
||||
|
||||
|
||||
// the amplitude of the subcarrier is sqrt(ci^2 + cq^2).
|
||||
// approximate by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|)
|
||||
reg [13:0] corr_amplitude, abs_ci, abs_cq, max_ci_cq;
|
||||
reg [12:0] min_ci_cq_2; // min_ci_cq / 2
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
if (corr_i_accum[13] == 1'b0)
|
||||
abs_ci <= corr_i_accum;
|
||||
else
|
||||
abs_ci <= -corr_i_accum;
|
||||
|
||||
if (corr_q_accum[13] == 1'b0)
|
||||
abs_cq <= corr_q_accum;
|
||||
else
|
||||
abs_cq <= -corr_q_accum;
|
||||
|
||||
if (abs_ci > abs_cq)
|
||||
begin
|
||||
max_ci_cq <= abs_ci;
|
||||
min_ci_cq_2 <= abs_cq / 2;
|
||||
end
|
||||
else
|
||||
begin
|
||||
max_ci_cq <= abs_cq;
|
||||
min_ci_cq_2 <= abs_ci / 2;
|
||||
end
|
||||
|
||||
corr_amplitude <= max_ci_cq + min_ci_cq_2;
|
||||
|
||||
end
|
||||
|
||||
|
||||
// The subcarrier reference signals
|
||||
reg subcarrier_I;
|
||||
reg subcarrier_Q;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_848_KHZ)
|
||||
begin
|
||||
subcarrier_I = ~corr_i_cnt[3];
|
||||
subcarrier_Q = ~(corr_i_cnt[3] ^ corr_i_cnt[2]);
|
||||
end
|
||||
else if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_212_KHZ)
|
||||
begin
|
||||
subcarrier_I = ~corr_i_cnt[5];
|
||||
subcarrier_Q = ~(corr_i_cnt[5] ^ corr_i_cnt[4]);
|
||||
end
|
||||
else
|
||||
begin // 424 kHz
|
||||
subcarrier_I = ~corr_i_cnt[4];
|
||||
subcarrier_Q = ~(corr_i_cnt[4] ^ corr_i_cnt[3]);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// ADC data appears on the rising edge, so sample it on the falling edge
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
// These are the correlators: we correlate against in-phase and quadrature
|
||||
// versions of our reference signal, and keep the (signed) results or the
|
||||
// resulting amplitude to send out later over the SSP.
|
||||
if (corr_i_cnt == 6'd0)
|
||||
begin
|
||||
if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE)
|
||||
begin
|
||||
// send amplitude plus 2 bits reader signal
|
||||
corr_i_out <= corr_amplitude[13:6];
|
||||
corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev};
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ)
|
||||
begin
|
||||
|
||||
// Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal
|
||||
if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111)
|
||||
corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev};
|
||||
else // truncate to maximum value
|
||||
if (corr_i_accum[13] == 1'b0)
|
||||
corr_i_out <= {7'b0111111, after_hysteresis_prev_prev};
|
||||
else
|
||||
corr_i_out <= {7'b1000000, after_hysteresis_prev_prev};
|
||||
|
||||
// Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal
|
||||
if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111)
|
||||
corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev};
|
||||
else // truncate to maximum value
|
||||
if (corr_q_accum[13] == 1'b0)
|
||||
corr_q_out <= {7'b0111111, after_hysteresis_prev};
|
||||
else
|
||||
corr_q_out <= {7'b1000000, after_hysteresis_prev};
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE)
|
||||
begin
|
||||
// send amplitude
|
||||
corr_i_out <= {2'b00, corr_amplitude[13:8]};
|
||||
corr_q_out <= corr_amplitude[7:0];
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_IQ)
|
||||
begin
|
||||
|
||||
// Send 8 bits of in phase tag signal
|
||||
if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111)
|
||||
corr_i_out <= corr_i_accum[11:4];
|
||||
else // truncate to maximum value
|
||||
if (corr_i_accum[13] == 1'b0)
|
||||
corr_i_out <= 8'b01111111;
|
||||
else
|
||||
corr_i_out <= 8'b10000000;
|
||||
|
||||
// Send 8 bits of quadrature phase tag signal
|
||||
if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111)
|
||||
corr_q_out <= corr_q_accum[11:4];
|
||||
else // truncate to maximum value
|
||||
if (corr_q_accum[13] == 1'b0)
|
||||
corr_q_out <= 8'b01111111;
|
||||
else
|
||||
corr_q_out <= 8'b10000000;
|
||||
end
|
||||
|
||||
// for each Q/I pair report two reader signal samples when sniffing. Store the 1st.
|
||||
after_hysteresis_prev_prev <= after_hysteresis;
|
||||
|
||||
// Initialize next correlation.
|
||||
// Both I and Q reference signals are high when corr_i_nct == 0. Therefore need to accumulate.
|
||||
corr_i_accum <= $signed({1'b0, adc_d});
|
||||
corr_q_accum <= $signed({1'b0, adc_d});
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (subcarrier_I)
|
||||
corr_i_accum <= corr_i_accum + $signed({1'b0, adc_d});
|
||||
else
|
||||
corr_i_accum <= corr_i_accum - $signed({1'b0, adc_d});
|
||||
|
||||
if (subcarrier_Q)
|
||||
corr_q_accum <= corr_q_accum + $signed({1'b0, adc_d});
|
||||
else
|
||||
corr_q_accum <= corr_q_accum - $signed({1'b0, adc_d});
|
||||
end
|
||||
|
||||
// for each Q/I pair report two reader signal samples when sniffing. Store the 2nd.
|
||||
if (corr_i_cnt == 6'd32)
|
||||
after_hysteresis_prev <= after_hysteresis;
|
||||
|
||||
// Then the result from last time is serialized and send out to the ARM.
|
||||
// We get one report each cycle, and each report is 16 bits, so the
|
||||
// ssp_clk should be the adc_clk divided by 64/16 = 4.
|
||||
// ssp_clk frequency = 13,56MHz / 4 = 3.39MHz
|
||||
|
||||
if (corr_i_cnt[1:0] == 2'b00)
|
||||
begin
|
||||
// Don't shift if we just loaded new data, obviously.
|
||||
if (corr_i_cnt != 6'd0)
|
||||
begin
|
||||
corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]};
|
||||
corr_q_out[7:1] <= corr_q_out[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
// ssp clock and frame signal for communication to and from ARM
|
||||
// _____ _____ _____ _
|
||||
// ssp_clk | |_____| |_____| |_____|
|
||||
// _____
|
||||
// ssp_frame ___| |____________________________
|
||||
// ___________ ___________ ___________ _
|
||||
// ssp_d_in X___________X___________X___________X_
|
||||
//
|
||||
// corr_i_cnt 0 1 2 3 4 5 6 7 8 9 10 11 12 ...
|
||||
//
|
||||
|
||||
reg ssp_clk;
|
||||
reg ssp_frame;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (corr_i_cnt[1:0] == 2'b00)
|
||||
ssp_clk <= 1'b1;
|
||||
|
||||
if (corr_i_cnt[1:0] == 2'b10)
|
||||
ssp_clk <= 1'b0;
|
||||
|
||||
// set ssp_frame signal for corr_i_cnt = 1..3
|
||||
// (send one frame with 16 Bits)
|
||||
if (corr_i_cnt == 6'd1)
|
||||
ssp_frame <= 1'b1;
|
||||
|
||||
if (corr_i_cnt == 6'd3)
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
assign ssp_din = corr_i_out[7];
|
||||
|
||||
|
||||
// a jamming signal
|
||||
reg jam_signal;
|
||||
reg [3:0] jam_counter;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (corr_i_cnt == 6'd0)
|
||||
begin
|
||||
jam_counter <= jam_counter + 1;
|
||||
jam_signal <= jam_counter[1] ^ jam_counter[3];
|
||||
end
|
||||
end
|
||||
|
||||
// Antenna drivers
|
||||
reg pwr_hi, pwr_oe4;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
if (minor_mode == `FPGA_HF_READER_MODE_SEND_SHALLOW_MOD)
|
||||
begin
|
||||
pwr_hi = ck_1356meg;
|
||||
pwr_oe4 = ssp_dout;
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_SEND_FULL_MOD)
|
||||
begin
|
||||
pwr_hi = ck_1356meg & ~ssp_dout;
|
||||
pwr_oe4 = 1'b0;
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_SEND_JAM)
|
||||
begin
|
||||
pwr_hi = ck_1356meg & jam_signal;
|
||||
pwr_oe4 = 1'b0;
|
||||
end
|
||||
else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ
|
||||
|| minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE
|
||||
|| minor_mode == `FPGA_HF_READER_MODE_SNIFF_PHASE)
|
||||
begin // all off
|
||||
pwr_hi = 1'b0;
|
||||
pwr_oe4 = 1'b0;
|
||||
end
|
||||
else // receiving from tag
|
||||
begin
|
||||
pwr_hi = ck_1356meg;
|
||||
pwr_oe4 = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// always on
|
||||
assign pwr_oe1 = 1'b0;
|
||||
assign pwr_oe3 = 1'b0;
|
||||
|
||||
// Unused.
|
||||
assign pwr_lo = 1'b0;
|
||||
assign pwr_oe2 = 1'b0;
|
||||
|
||||
// Debug Output
|
||||
assign dbg = corr_i_cnt[3];
|
||||
|
||||
endmodule
|
|
@ -1,148 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Pretend to be an ISO 14443 tag. We will do this by alternately short-
|
||||
// circuiting and open-circuiting the antenna coil, with the tri-state
|
||||
// pins.
|
||||
//
|
||||
// We communicate over the SSP, as a bitstream (i.e., might as well be
|
||||
// unframed, though we still generate the word sync signal). The output
|
||||
// (ARM -> FPGA) tells us whether to modulate or not. The input (FPGA
|
||||
// -> ARM) is us using the A/D as a fancy comparator; this is with
|
||||
// (software-added) hysteresis, to undo the high-pass filter.
|
||||
//
|
||||
// At this point only Type A is implemented. This means that we are using a
|
||||
// bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make
|
||||
// things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s)
|
||||
//
|
||||
// Jonathan Westhues, October 2006
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module hi_simulate(
|
||||
ck_1356meg,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk,
|
||||
dbg,
|
||||
mod_type
|
||||
);
|
||||
input ck_1356meg;
|
||||
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;
|
||||
output dbg;
|
||||
input [3:0] mod_type;
|
||||
|
||||
// Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can
|
||||
// always be low.
|
||||
assign pwr_hi = 1'b0; // HF antenna connected to GND
|
||||
assign pwr_lo = 1'b0; // LF antenna connected to GND
|
||||
|
||||
// This one is all LF, so doesn't matter
|
||||
assign pwr_oe2 = 1'b0;
|
||||
|
||||
assign adc_clk = ck_1356meg;
|
||||
assign dbg = ssp_frame;
|
||||
|
||||
// The comparator with hysteresis on the output from the peak detector.
|
||||
reg after_hysteresis;
|
||||
reg [11:0] has_been_low_for;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (& adc_d[7:5]) after_hysteresis <= 1'b1; // if (adc_d >= 224)
|
||||
else if (~(| adc_d[7:5])) after_hysteresis <= 1'b0; // if (adc_d <= 31)
|
||||
|
||||
if (adc_d >= 224)
|
||||
begin
|
||||
has_been_low_for <= 12'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (has_been_low_for == 12'd4095)
|
||||
begin
|
||||
has_been_low_for <= 12'd0;
|
||||
after_hysteresis <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
has_been_low_for <= has_been_low_for + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Divide 13.56 MHz to produce various frequencies for SSP_CLK
|
||||
// and modulation.
|
||||
reg [8:0] ssp_clk_divider;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
ssp_clk_divider <= (ssp_clk_divider + 1);
|
||||
|
||||
reg ssp_clk;
|
||||
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT)
|
||||
// Get bit every at 53KHz (every 8th carrier bit of 424kHz)
|
||||
ssp_clk <= ~ssp_clk_divider[7];
|
||||
else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K)
|
||||
// Get next bit at 212kHz
|
||||
ssp_clk <= ~ssp_clk_divider[5];
|
||||
else
|
||||
// Get next bit at 424kHz
|
||||
ssp_clk <= ~ssp_clk_divider[4];
|
||||
end
|
||||
|
||||
|
||||
// Produce the byte framing signal; the phase of this signal
|
||||
// is arbitrary, because it's just a bit stream in this module.
|
||||
reg ssp_frame;
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K)
|
||||
begin
|
||||
if (ssp_clk_divider[8:5] == 4'd1)
|
||||
ssp_frame <= 1'b1;
|
||||
if (ssp_clk_divider[8:5] == 4'd5)
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (ssp_clk_divider[7:4] == 4'd1)
|
||||
ssp_frame <= 1'b1;
|
||||
if (ssp_clk_divider[7:4] == 4'd5)
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Synchronize up the after-hysteresis signal, to produce DIN.
|
||||
reg ssp_din;
|
||||
always @(posedge ssp_clk)
|
||||
ssp_din = after_hysteresis;
|
||||
|
||||
// Modulating carrier frequency is fc/64 (212kHz) to fc/16 (848kHz). Reuse ssp_clk divider for that.
|
||||
reg modulating_carrier;
|
||||
always @(*)
|
||||
if(mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION)
|
||||
modulating_carrier <= 1'b0; // no modulation
|
||||
else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_BPSK)
|
||||
modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK
|
||||
else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K)
|
||||
modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off
|
||||
else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K || mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT)
|
||||
modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off
|
||||
else
|
||||
modulating_carrier <= 1'b0; // yet unused
|
||||
|
||||
|
||||
|
||||
// Load modulation. Toggle only one of these, since we are already producing much deeper
|
||||
// modulation than a real tag would.
|
||||
assign pwr_oe1 = 1'b0; // 33 Ohms Load
|
||||
assign pwr_oe4 = modulating_carrier; // 33 Ohms Load
|
||||
// This one is always on, so that we can watch the carrier.
|
||||
assign pwr_oe3 = 1'b0; // 10k Load
|
||||
|
||||
endmodule
|
|
@ -1,50 +0,0 @@
|
|||
module hi_sniffer(
|
||||
ck_1356meg,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_clk
|
||||
);
|
||||
input ck_1356meg;
|
||||
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
|
||||
input [7:0] adc_d;
|
||||
output adc_clk;
|
||||
output ssp_frame, ssp_din, ssp_clk;
|
||||
|
||||
// We are only snooping, all off.
|
||||
assign pwr_hi = 1'b0;
|
||||
assign pwr_lo = 1'b0;
|
||||
assign pwr_oe1 = 1'b0;
|
||||
assign pwr_oe2 = 1'b0;
|
||||
assign pwr_oe3 = 1'b0;
|
||||
assign pwr_oe4 = 1'b0;
|
||||
|
||||
reg ssp_frame;
|
||||
reg [7:0] adc_d_out = 8'd0;
|
||||
reg [2:0] ssp_cnt = 3'd0;
|
||||
|
||||
assign adc_clk = ck_1356meg;
|
||||
assign ssp_clk = ~ck_1356meg;
|
||||
|
||||
always @(posedge ssp_clk)
|
||||
begin
|
||||
if(ssp_cnt[2:0] == 3'd7)
|
||||
ssp_cnt[2:0] <= 3'd0;
|
||||
else
|
||||
ssp_cnt <= ssp_cnt + 1;
|
||||
|
||||
if(ssp_cnt[2:0] == 3'b000) // set frame length
|
||||
begin
|
||||
adc_d_out[7:0] <= adc_d;
|
||||
ssp_frame <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
adc_d_out[7:0] <= {1'b0, adc_d_out[7:1]};
|
||||
ssp_frame <= 1'b0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
assign ssp_din = adc_d_out[0];
|
||||
|
||||
endmodule
|
|
@ -1,77 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// input clk is 24MHz
|
||||
`include "min_max_tracker.v"
|
||||
|
||||
module lf_edge_detect(input clk, input [7:0] adc_d, input [7:0] lf_ed_threshold,
|
||||
output [7:0] max, output [7:0] min,
|
||||
output [7:0] high_threshold, output [7:0] highz_threshold,
|
||||
output [7:0] lowz_threshold, output [7:0] low_threshold,
|
||||
output edge_state, output edge_toggle);
|
||||
|
||||
min_max_tracker tracker(clk, adc_d, lf_ed_threshold, min, max);
|
||||
|
||||
// auto-tune
|
||||
assign high_threshold = (max + min) / 2 + (max - min) / 4;
|
||||
assign highz_threshold = (max + min) / 2 + (max - min) / 8;
|
||||
assign lowz_threshold = (max + min) / 2 - (max - min) / 8;
|
||||
assign low_threshold = (max + min) / 2 - (max - min) / 4;
|
||||
|
||||
// heuristic to see if it makes sense to try to detect an edge
|
||||
wire enabled =
|
||||
(high_threshold > highz_threshold)
|
||||
& (highz_threshold > lowz_threshold)
|
||||
& (lowz_threshold > low_threshold)
|
||||
& ((high_threshold - highz_threshold) > 8)
|
||||
& ((highz_threshold - lowz_threshold) > 16)
|
||||
& ((lowz_threshold - low_threshold) > 8);
|
||||
|
||||
// Toggle the output with hysteresis
|
||||
// Set to high if the ADC value is above the threshold
|
||||
// Set to low if the ADC value is below the threshold
|
||||
reg is_high = 0;
|
||||
reg is_low = 0;
|
||||
reg is_zero = 0;
|
||||
reg trigger_enabled = 1;
|
||||
reg output_edge = 0;
|
||||
reg output_state;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
is_high <= (adc_d >= high_threshold);
|
||||
is_low <= (adc_d <= low_threshold);
|
||||
is_zero <= ((adc_d > lowz_threshold) & (adc_d < highz_threshold));
|
||||
end
|
||||
|
||||
// all edges detection
|
||||
always @(posedge clk)
|
||||
if (enabled) begin
|
||||
// To enable detecting two consecutive peaks at the same level
|
||||
// (low or high) we check whether or not we went back near 0 in-between.
|
||||
// This extra check is necessary to prevent from noise artifacts
|
||||
// around the threshold values.
|
||||
if (trigger_enabled & (is_high | is_low)) begin
|
||||
output_edge <= ~output_edge;
|
||||
trigger_enabled <= 0;
|
||||
end else
|
||||
trigger_enabled <= trigger_enabled | is_zero;
|
||||
end
|
||||
|
||||
// edge states
|
||||
always @(posedge clk)
|
||||
if (enabled) begin
|
||||
if (is_high)
|
||||
output_state <= 1'd1;
|
||||
else if (is_low)
|
||||
output_state <= 1'd0;
|
||||
end
|
||||
|
||||
assign edge_state = output_state;
|
||||
assign edge_toggle = output_edge;
|
||||
|
||||
endmodule
|
|
@ -1,91 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// The way that we connect things in low-frequency simulation mode. In this
|
||||
// case just pass everything through to the ARM, which can bit-bang this
|
||||
// (because it is so slow).
|
||||
//
|
||||
// Jonathan Westhues, April 2006
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module lo_adc(
|
||||
pck0,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk,
|
||||
dbg, divisor,
|
||||
lf_field
|
||||
);
|
||||
input pck0;
|
||||
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;
|
||||
output dbg;
|
||||
input [7:0] divisor;
|
||||
input lf_field;
|
||||
|
||||
reg [7:0] to_arm_shiftreg;
|
||||
reg [7:0] pck_divider;
|
||||
reg clk_state;
|
||||
|
||||
// Antenna logic, depending on "lf_field" (in arm defined as FPGA_LF_READER_FIELD)
|
||||
wire tag_modulation = ssp_dout & !lf_field;
|
||||
wire reader_modulation = !ssp_dout & lf_field & clk_state;
|
||||
|
||||
// always on (High Frequency outputs, unused)
|
||||
assign pwr_oe1 = 1'b0;
|
||||
assign pwr_hi = 1'b0;
|
||||
|
||||
// low frequency outputs
|
||||
assign pwr_lo = reader_modulation;
|
||||
assign pwr_oe2 = 1'b0; // 33 Ohms
|
||||
assign pwr_oe3 = tag_modulation; // base antenna load = 33 Ohms
|
||||
assign pwr_oe4 = 1'b0; // 10k Ohms
|
||||
|
||||
// Debug Output ADC clock
|
||||
assign dbg = adc_clk;
|
||||
|
||||
// ADC clock out of phase with antenna driver
|
||||
assign adc_clk = ~clk_state;
|
||||
|
||||
// serialized SSP data is gated by clk_state to suppress unwanted signal
|
||||
assign ssp_din = to_arm_shiftreg[7] && !clk_state;
|
||||
|
||||
// SSP clock always runs at 24MHz
|
||||
assign ssp_clk = pck0;
|
||||
|
||||
// SSP frame is gated by clk_state and goes high when pck_divider=8..15
|
||||
assign ssp_frame = (pck_divider[7:3] == 5'd1) && !clk_state;
|
||||
|
||||
// divide 24mhz down to 3mhz
|
||||
always @(posedge pck0)
|
||||
begin
|
||||
if (pck_divider == divisor[7:0])
|
||||
begin
|
||||
pck_divider <= 8'd0;
|
||||
clk_state = !clk_state;
|
||||
end
|
||||
else
|
||||
begin
|
||||
pck_divider <= pck_divider + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// this task also runs at pck0 frequency (24Mhz) and is used to serialize
|
||||
// the ADC output which is then clocked into the ARM SSP.
|
||||
always @(posedge pck0)
|
||||
begin
|
||||
if ((pck_divider == 8'd7) && !clk_state)
|
||||
to_arm_shiftreg <= adc_d;
|
||||
else begin
|
||||
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
|
||||
// simulation showed a glitch occuring due to the LSB of the shifter
|
||||
// not being set as we shift bits out
|
||||
// this ensures the ssp_din remains low after a transfer and suppresses
|
||||
// the glitch that would occur when the last data shifted out ended in
|
||||
// a 1 bit and the next data shifted out started with a 0 bit
|
||||
to_arm_shiftreg[0] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -1,68 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// There are two modes:
|
||||
// - lf_ed_toggle_mode == 0: the output is set low (resp. high) when a low
|
||||
// (resp. high) edge/peak is detected, with hysteresis
|
||||
// - lf_ed_toggle_mode == 1: the output is toggling whenever an edge/peak
|
||||
// is detected.
|
||||
// That way you can detect two consecutive edges/peaks at the same level (L/H)
|
||||
//
|
||||
// Output:
|
||||
// - ssp_frame (wired to TIOA1 on the arm) for the edge detection/state
|
||||
// - ssp_clk: cross_lo
|
||||
`include "lp20khz_1MSa_iir_filter.v"
|
||||
`include "lf_edge_detect.v"
|
||||
|
||||
module lo_edge_detect(
|
||||
input pck0, input pck_divclk,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
input [7:0] adc_d, output adc_clk,
|
||||
output ssp_frame, input ssp_dout, output ssp_clk,
|
||||
input cross_lo,
|
||||
output dbg,
|
||||
input lf_field,
|
||||
input lf_ed_toggle_mode, input [7:0] lf_ed_threshold
|
||||
);
|
||||
|
||||
wire tag_modulation = ssp_dout & !lf_field;
|
||||
wire reader_modulation = !ssp_dout & lf_field & pck_divclk;
|
||||
|
||||
// No logic, straight through.
|
||||
assign pwr_oe1 = 1'b0; // not used in LF mode
|
||||
assign pwr_oe3 = 1'b0; // base antenna load = 33 Ohms
|
||||
// when modulating, add another 33 Ohms and 10k Ohms in parallel:
|
||||
assign pwr_oe2 = tag_modulation;
|
||||
assign pwr_oe4 = tag_modulation;
|
||||
|
||||
assign ssp_clk = cross_lo;
|
||||
assign pwr_lo = reader_modulation;
|
||||
assign pwr_hi = 1'b0;
|
||||
|
||||
// filter the ADC values
|
||||
wire data_rdy;
|
||||
wire [7:0] adc_filtered;
|
||||
assign adc_clk = pck0;
|
||||
lp20khz_1MSa_iir_filter adc_filter(pck0, adc_d, data_rdy, adc_filtered);
|
||||
|
||||
// detect edges
|
||||
wire [7:0] high_threshold, highz_threshold, lowz_threshold, low_threshold;
|
||||
wire [7:0] max, min;
|
||||
wire edge_state, edge_toggle;
|
||||
lf_edge_detect lf_ed(pck0, adc_filtered, lf_ed_threshold,
|
||||
max, min,
|
||||
high_threshold, highz_threshold, lowz_threshold, low_threshold,
|
||||
edge_state, edge_toggle);
|
||||
|
||||
assign dbg = lf_ed_toggle_mode ? edge_toggle : edge_state;
|
||||
|
||||
assign ssp_frame = lf_ed_toggle_mode ? edge_toggle : edge_state;
|
||||
|
||||
endmodule
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// For reading TI tags, we need to place the FPGA in pass through mode
|
||||
// and pass everything through to the ARM
|
||||
//-----------------------------------------------------------------------------
|
||||
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||
|
||||
module lo_passthru(
|
||||
input pck_divclk,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
output adc_clk,
|
||||
output ssp_din, input ssp_dout,
|
||||
input cross_lo,
|
||||
output dbg
|
||||
);
|
||||
|
||||
// the antenna is modulated when ssp_dout = 1, when 0 the
|
||||
// antenna drivers stop modulating and go into listen mode
|
||||
assign pwr_oe3 = 1'b0;
|
||||
assign pwr_oe1 = ssp_dout;
|
||||
assign pwr_oe2 = ssp_dout;
|
||||
assign pwr_oe4 = ssp_dout;
|
||||
assign pwr_lo = pck_divclk && ssp_dout;
|
||||
assign pwr_hi = 1'b0;
|
||||
assign adc_clk = 1'b0;
|
||||
assign ssp_din = cross_lo;
|
||||
assign dbg = cross_lo;
|
||||
|
||||
endmodule
|
|
@ -1,74 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// The way that we connect things in low-frequency read mode. In this case
|
||||
// we are generating the unmodulated low frequency carrier.
|
||||
// The A/D samples at that same rate and the result is serialized.
|
||||
//
|
||||
// Jonathan Westhues, April 2006
|
||||
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module lo_read(
|
||||
input pck0, input [7:0] pck_cnt, input pck_divclk,
|
||||
output pwr_lo, output pwr_hi,
|
||||
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||
input [7:0] adc_d, output adc_clk,
|
||||
output ssp_frame, output ssp_din, output ssp_clk,
|
||||
output dbg,
|
||||
input lf_field
|
||||
);
|
||||
|
||||
reg [7:0] to_arm_shiftreg;
|
||||
|
||||
// this task also runs at pck0 frequency (24MHz) and is used to serialize
|
||||
// the ADC output which is then clocked into the ARM SSP.
|
||||
|
||||
// because pck_divclk always transitions when pck_cnt = 0 we use the
|
||||
// pck_div counter to sync our other signals off it
|
||||
// we read the ADC value when pck_cnt=7 and shift it out on counts 8..15
|
||||
always @(posedge pck0)
|
||||
begin
|
||||
if((pck_cnt == 8'd7) && !pck_divclk)
|
||||
to_arm_shiftreg <= adc_d;
|
||||
else begin
|
||||
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
|
||||
// simulation showed a glitch occuring due to the LSB of the shifter
|
||||
// not being set as we shift bits out
|
||||
// this ensures the ssp_din remains low after a transfer and suppresses
|
||||
// the glitch that would occur when the last data shifted out ended in
|
||||
// a 1 bit and the next data shifted out started with a 0 bit
|
||||
to_arm_shiftreg[0] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// ADC samples on falling edge of adc_clk, data available on the rising edge
|
||||
|
||||
// example of ssp transfer of binary value 1100101
|
||||
// start of transfer is indicated by the rise of the ssp_frame signal
|
||||
// ssp_din changes on the rising edge of the ssp_clk clock and is clocked into
|
||||
// the ARM by the falling edge of ssp_clk
|
||||
// _______________________________
|
||||
// ssp_frame__| |__
|
||||
// _______ ___ ___
|
||||
// ssp_din __| |_______| |___| |______
|
||||
// _ _ _ _ _ _ _ _ _ _
|
||||
// ssp_clk |_| |_| |_| |_| |_| |_| |_| |_| |_| |_
|
||||
|
||||
// serialized SSP data is gated by ant_lo to suppress unwanted signal
|
||||
assign ssp_din = to_arm_shiftreg[7] && !pck_divclk;
|
||||
// SSP clock always runs at 24MHz
|
||||
assign ssp_clk = pck0;
|
||||
// SSP frame is gated by ant_lo and goes high when pck_divider=8..15
|
||||
assign ssp_frame = (pck_cnt[7:3] == 5'd1) && !pck_divclk;
|
||||
// unused signals tied low
|
||||
assign pwr_hi = 1'b0;
|
||||
assign pwr_oe1 = 1'b0;
|
||||
assign pwr_oe2 = 1'b0;
|
||||
assign pwr_oe3 = 1'b0;
|
||||
assign pwr_oe4 = 1'b0;
|
||||
// this is the antenna driver signal
|
||||
assign pwr_lo = lf_field & pck_divclk;
|
||||
// ADC clock out of phase with antenna driver
|
||||
assign adc_clk = ~pck_divclk;
|
||||
// ADC clock also routed to debug pin
|
||||
assign dbg = adc_clk;
|
||||
endmodule
|
|
@ -1,83 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// The way that we connect things in low-frequency simulation mode. In this
|
||||
// case just pass everything through to the ARM, which can bit-bang this
|
||||
// (because it is so slow).
|
||||
//
|
||||
// Jonathan Westhues, April 2006
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module lo_simulate(
|
||||
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,
|
||||
divisor
|
||||
);
|
||||
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 [7:0] divisor;
|
||||
|
||||
// No logic, straight through.
|
||||
assign pwr_oe3 = 1'b0;
|
||||
assign pwr_oe1 = ssp_dout;
|
||||
assign pwr_oe2 = ssp_dout;
|
||||
assign pwr_oe4 = ssp_dout;
|
||||
assign ssp_clk = cross_lo;
|
||||
assign pwr_lo = 1'b0;
|
||||
assign pwr_hi = 1'b0;
|
||||
assign dbg = ssp_frame;
|
||||
|
||||
// Divide the clock to be used for the ADC
|
||||
reg [7:0] pck_divider;
|
||||
reg clk_state;
|
||||
|
||||
always @(posedge pck0)
|
||||
begin
|
||||
if(pck_divider == divisor[7:0])
|
||||
begin
|
||||
pck_divider <= 8'd0;
|
||||
clk_state = !clk_state;
|
||||
end
|
||||
else
|
||||
begin
|
||||
pck_divider <= pck_divider + 1;
|
||||
end
|
||||
end
|
||||
|
||||
assign adc_clk = ~clk_state;
|
||||
|
||||
// Toggle the output with hysteresis
|
||||
// Set to high if the ADC value is above 200
|
||||
// Set to low if the ADC value is below 64
|
||||
reg is_high;
|
||||
reg is_low;
|
||||
reg output_state;
|
||||
|
||||
always @(posedge pck0)
|
||||
begin
|
||||
if((pck_divider == 8'd7) && !clk_state) begin
|
||||
is_high = (adc_d >= 8'd191);
|
||||
is_low = (adc_d <= 8'd64);
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge is_high or posedge is_low)
|
||||
begin
|
||||
if(is_high)
|
||||
output_state <= 1'd1;
|
||||
else if(is_low)
|
||||
output_state <= 1'd0;
|
||||
end
|
||||
|
||||
assign ssp_frame = output_state;
|
||||
|
||||
endmodule
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Butterworth low pass IIR filter
|
||||
// input: 8bit ADC signal, 1MS/s
|
||||
// output: 8bit value, Fc=20khz
|
||||
//
|
||||
// coef: (using http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
|
||||
// Recurrence relation:
|
||||
// y[n] = ( 1 * x[n- 2])
|
||||
// + ( 2 * x[n- 1])
|
||||
// + ( 1 * x[n- 0])
|
||||
|
||||
// + ( -0.8371816513 * y[n- 2])
|
||||
// + ( 1.8226949252 * y[n- 1])
|
||||
//
|
||||
// therefore:
|
||||
// a = [1,2,1]
|
||||
// b = [-0.8371816513, 1.8226949252]
|
||||
// b is approximated to b = [-0xd6/0x100, 0x1d3 / 0x100] (for optimization)
|
||||
// gain = 2.761139367e2
|
||||
//
|
||||
// See details about its design see
|
||||
// https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html
|
||||
module lp20khz_1MSa_iir_filter(input clk, input [7:0] adc_d, output rdy, output [7:0] out);
|
||||
|
||||
// clk is 24MHz, the IIR filter is designed for 1MS/s
|
||||
// hence we need to divide it by 24
|
||||
// using a shift register takes less area than a counter
|
||||
reg [23:0] cnt = 1;
|
||||
assign rdy = cnt[0];
|
||||
always @(posedge clk)
|
||||
cnt <= {cnt[22:0], cnt[23]};
|
||||
|
||||
reg [7:0] x0 = 0;
|
||||
reg [7:0] x1 = 0;
|
||||
reg [16:0] y0 = 0;
|
||||
reg [16:0] y1 = 0;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (rdy)
|
||||
begin
|
||||
x0 <= x1;
|
||||
x1 <= adc_d;
|
||||
y0 <= y1;
|
||||
y1 <=
|
||||
// center the signal:
|
||||
// input range is [0; 255]
|
||||
// We want "128" to be at the center of the 17bit register
|
||||
// (128+z)*gain = 17bit center
|
||||
// z = (1<<16)/gain - 128 = 109
|
||||
// We could use 9bit x registers for that, but that would be
|
||||
// a waste, let's just add the constant during the computation
|
||||
// (x0+109) + 2*(x1+109) + (x2+109) = x0 + 2*x1 + x2 + 436
|
||||
x0 + {x1, 1'b0} + adc_d + 436
|
||||
// we want "- y0 * 0xd6 / 0x100" using only shift and add
|
||||
// 0xd6 == 0b11010110
|
||||
// so *0xd6/0x100 is equivalent to
|
||||
// ((x << 1) + (x << 2) + (x << 4) + (x << 6) + (x << 7)) >> 8
|
||||
// which is also equivalent to
|
||||
// (x >> 7) + (x >> 6) + (x >> 4) + (x >> 2) + (x >> 1)
|
||||
- ((y0 >> 7) + (y0 >> 6) + (y0 >> 4) + (y0 >> 2) + (y0 >> 1)) // - y0 * 0xd6 / 0x100
|
||||
// we want "+ y1 * 0x1d3 / 0x100"
|
||||
// 0x1d3 == 0b111010011
|
||||
// so this is equivalent to
|
||||
// ((x << 0) + (x << 1) + (x << 4) + (x << 6) + (x << 7) + (x << 8)) >> 8
|
||||
// which is also equivalent to
|
||||
// (x >> 8) + (x >> 7) + (x >> 4) + (x >> 2) + (x >> 1) + (x >> 0)
|
||||
+ ((y1 >> 8) + (y1 >> 7) + (y1 >> 4) + (y1 >> 2) + (y1 >> 1) + y1);
|
||||
end
|
||||
end
|
||||
|
||||
// output: reduce to 8bit
|
||||
assign out = y1[16:9];
|
||||
|
||||
endmodule
|
|
@ -1,65 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// track min and max peak values (envelope follower)
|
||||
//
|
||||
// NB: the min value (resp. max value) is updated only when the next high peak
|
||||
// (resp. low peak) is reached/detected, since you can't know it isn't a
|
||||
// local minima (resp. maxima) until then.
|
||||
// This also means the peaks are detected with an unpredictable delay.
|
||||
// This algorithm therefore can't be used directly for realtime peak detections,
|
||||
// but it can be used as a simple envelope follower.
|
||||
module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold,
|
||||
output [7:0] min, output [7:0] max);
|
||||
|
||||
reg [7:0] min_val = 255;
|
||||
reg [7:0] max_val = 0;
|
||||
reg [7:0] cur_min_val = 255;
|
||||
reg [7:0] cur_max_val = 0;
|
||||
reg [1:0] state = 0;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
case (state)
|
||||
0: // initialize
|
||||
begin
|
||||
if (cur_max_val >= ({1'b0, adc_d} + threshold))
|
||||
state <= 2;
|
||||
else if (adc_d >= ({1'b0, cur_min_val} + threshold))
|
||||
state <= 1;
|
||||
if (cur_max_val <= adc_d)
|
||||
cur_max_val <= adc_d;
|
||||
else if (adc_d <= cur_min_val)
|
||||
cur_min_val <= adc_d;
|
||||
end
|
||||
1: // high phase
|
||||
begin
|
||||
if (cur_max_val <= adc_d)
|
||||
cur_max_val <= adc_d;
|
||||
else if (({1'b0, adc_d} + threshold) <= cur_max_val) begin
|
||||
state <= 2;
|
||||
cur_min_val <= adc_d;
|
||||
max_val <= cur_max_val;
|
||||
end
|
||||
end
|
||||
2: // low phase
|
||||
begin
|
||||
if (adc_d <= cur_min_val)
|
||||
cur_min_val <= adc_d;
|
||||
else if (adc_d >= ({1'b0, cur_min_val} + threshold)) begin
|
||||
state <= 1;
|
||||
cur_max_val <= adc_d;
|
||||
min_val <= cur_min_val;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign min = min_val;
|
||||
assign max = max_val;
|
||||
|
||||
endmodule
|
27
fpga/sim.tcl
27
fpga/sim.tcl
|
@ -1,27 +0,0 @@
|
|||
#------------------------------------------------------------------------------
|
||||
# Run the simulation testbench in ModelSim: recompile both Verilog source
|
||||
# files, then start the simulation, add a lot of signals to the waveform
|
||||
# viewer, and run. I should (TODO) fix the absolute paths at some point.
|
||||
#
|
||||
# Jonathan Westhues, Mar 2006
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga.v
|
||||
vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga_tb.v
|
||||
|
||||
vsim work.fpga_tb
|
||||
|
||||
add wave sim:/fpga_tb/adc_clk
|
||||
add wave sim:/fpga_tb/adc_d
|
||||
add wave sim:/fpga_tb/pwr_lo
|
||||
add wave sim:/fpga_tb/ssp_clk
|
||||
add wave sim:/fpga_tb/ssp_frame
|
||||
add wave sim:/fpga_tb/ssp_din
|
||||
add wave sim:/fpga_tb/ssp_dout
|
||||
|
||||
add wave sim:/fpga_tb/dut/clk_lo
|
||||
add wave sim:/fpga_tb/dut/pck_divider
|
||||
add wave sim:/fpga_tb/dut/carrier_divider_lo
|
||||
add wave sim:/fpga_tb/dut/conf_word
|
||||
|
||||
run 30000
|
|
@ -1,50 +0,0 @@
|
|||
`include "fpga.v"
|
||||
|
||||
module testbed_fpga;
|
||||
reg spck, mosi, ncs;
|
||||
wire miso;
|
||||
reg pck0i, ck_1356meg, ck_1356megb;
|
||||
wire pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
|
||||
reg [7:0] adc_d;
|
||||
wire adc_clk, adc_noe;
|
||||
reg ssp_dout;
|
||||
wire ssp_frame, ssp_din, ssp_clk;
|
||||
|
||||
fpga dut(
|
||||
spck, miso, mosi, ncs,
|
||||
pck0i, ck_1356meg, ck_1356megb,
|
||||
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
|
||||
adc_d, adc_clk, adc_noe,
|
||||
ssp_frame, ssp_din, ssp_dout, ssp_clk
|
||||
);
|
||||
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
|
||||
// init inputs
|
||||
#5 ncs=1;
|
||||
#5 spck = 1;
|
||||
#5 mosi = 1;
|
||||
|
||||
#50 ncs=0;
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
#5 mosi = $random;
|
||||
#5 spck = 0;
|
||||
#5 spck = 1;
|
||||
end
|
||||
#5 ncs=1;
|
||||
|
||||
#50 ncs=0;
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
#5 mosi = $random;
|
||||
#5 spck = 0;
|
||||
#5 spck = 1;
|
||||
end
|
||||
#5 ncs=1;
|
||||
|
||||
#50 mosi=1;
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule // main
|
|
@ -1,109 +0,0 @@
|
|||
`include "hi_read_tx.v"
|
||||
|
||||
/*
|
||||
pck0 - input main 24MHz clock (PLL / 4)
|
||||
[7:0] adc_d - input data from A/D converter
|
||||
shallow_modulation - modulation type
|
||||
|
||||
pwr_lo - output to coil drivers (ssp_clk / 8)
|
||||
adc_clk - output A/D clock signal
|
||||
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
|
||||
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
|
||||
ssp_clk - output SSP clock signal
|
||||
|
||||
ck_1356meg - input unused
|
||||
ck_1356megb - input unused
|
||||
ssp_dout - input unused
|
||||
cross_hi - input unused
|
||||
cross_lo - input unused
|
||||
|
||||
pwr_hi - output unused, tied low
|
||||
pwr_oe1 - output unused, undefined
|
||||
pwr_oe2 - output unused, undefined
|
||||
pwr_oe3 - output unused, undefined
|
||||
pwr_oe4 - output unused, undefined
|
||||
dbg - output alias for adc_clk
|
||||
*/
|
||||
|
||||
module testbed_hi_read_tx;
|
||||
reg pck0;
|
||||
reg [7:0] adc_d;
|
||||
reg shallow_modulation;
|
||||
|
||||
wire pwr_lo;
|
||||
wire adc_clk;
|
||||
reg ck_1356meg;
|
||||
reg ck_1356megb;
|
||||
wire ssp_frame;
|
||||
wire ssp_din;
|
||||
wire ssp_clk;
|
||||
reg ssp_dout;
|
||||
wire pwr_hi;
|
||||
wire pwr_oe1;
|
||||
wire pwr_oe2;
|
||||
wire pwr_oe3;
|
||||
wire pwr_oe4;
|
||||
wire cross_lo;
|
||||
wire cross_hi;
|
||||
wire dbg;
|
||||
|
||||
hi_read_tx #(5,200) dut(
|
||||
.pck0(pck0),
|
||||
.ck_1356meg(ck_1356meg),
|
||||
.ck_1356megb(ck_1356megb),
|
||||
.pwr_lo(pwr_lo),
|
||||
.pwr_hi(pwr_hi),
|
||||
.pwr_oe1(pwr_oe1),
|
||||
.pwr_oe2(pwr_oe2),
|
||||
.pwr_oe3(pwr_oe3),
|
||||
.pwr_oe4(pwr_oe4),
|
||||
.adc_d(adc_d),
|
||||
.adc_clk(adc_clk),
|
||||
.ssp_frame(ssp_frame),
|
||||
.ssp_din(ssp_din),
|
||||
.ssp_dout(ssp_dout),
|
||||
.ssp_clk(ssp_clk),
|
||||
.cross_hi(cross_hi),
|
||||
.cross_lo(cross_lo),
|
||||
.dbg(dbg),
|
||||
.shallow_modulation(shallow_modulation)
|
||||
);
|
||||
|
||||
integer idx, i;
|
||||
|
||||
// main clock
|
||||
always #5 begin
|
||||
ck_1356megb = !ck_1356megb;
|
||||
ck_1356meg = ck_1356megb;
|
||||
end
|
||||
|
||||
//crank DUT
|
||||
task crank_dut;
|
||||
begin
|
||||
@(posedge ssp_clk) ;
|
||||
ssp_dout = $random;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
|
||||
// init inputs
|
||||
ck_1356megb = 0;
|
||||
adc_d = 0;
|
||||
ssp_dout=0;
|
||||
|
||||
// shallow modulation off
|
||||
shallow_modulation=0;
|
||||
for (i = 0 ; i < 16 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
|
||||
// shallow modulation on
|
||||
shallow_modulation=1;
|
||||
for (i = 0 ; i < 16 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule // main
|
|
@ -1,116 +0,0 @@
|
|||
`include "hi_simulate.v"
|
||||
|
||||
/*
|
||||
pck0 - input main 24MHz clock (PLL / 4)
|
||||
[7:0] adc_d - input data from A/D converter
|
||||
mod_type - modulation type
|
||||
|
||||
pwr_lo - output to coil drivers (ssp_clk / 8)
|
||||
adc_clk - output A/D clock signal
|
||||
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
|
||||
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
|
||||
ssp_clk - output SSP clock signal
|
||||
|
||||
ck_1356meg - input unused
|
||||
ck_1356megb - input unused
|
||||
ssp_dout - input unused
|
||||
cross_hi - input unused
|
||||
cross_lo - input unused
|
||||
|
||||
pwr_hi - output unused, tied low
|
||||
pwr_oe1 - output unused, undefined
|
||||
pwr_oe2 - output unused, undefined
|
||||
pwr_oe3 - output unused, undefined
|
||||
pwr_oe4 - output unused, undefined
|
||||
dbg - output alias for adc_clk
|
||||
*/
|
||||
|
||||
module testbed_hi_simulate;
|
||||
reg pck0;
|
||||
reg [7:0] adc_d;
|
||||
reg mod_type;
|
||||
|
||||
wire pwr_lo;
|
||||
wire adc_clk;
|
||||
reg ck_1356meg;
|
||||
reg ck_1356megb;
|
||||
wire ssp_frame;
|
||||
wire ssp_din;
|
||||
wire ssp_clk;
|
||||
reg ssp_dout;
|
||||
wire pwr_hi;
|
||||
wire pwr_oe1;
|
||||
wire pwr_oe2;
|
||||
wire pwr_oe3;
|
||||
wire pwr_oe4;
|
||||
wire cross_lo;
|
||||
wire cross_hi;
|
||||
wire dbg;
|
||||
|
||||
hi_simulate #(5,200) dut(
|
||||
.pck0(pck0),
|
||||
.ck_1356meg(ck_1356meg),
|
||||
.ck_1356megb(ck_1356megb),
|
||||
.pwr_lo(pwr_lo),
|
||||
.pwr_hi(pwr_hi),
|
||||
.pwr_oe1(pwr_oe1),
|
||||
.pwr_oe2(pwr_oe2),
|
||||
.pwr_oe3(pwr_oe3),
|
||||
.pwr_oe4(pwr_oe4),
|
||||
.adc_d(adc_d),
|
||||
.adc_clk(adc_clk),
|
||||
.ssp_frame(ssp_frame),
|
||||
.ssp_din(ssp_din),
|
||||
.ssp_dout(ssp_dout),
|
||||
.ssp_clk(ssp_clk),
|
||||
.cross_hi(cross_hi),
|
||||
.cross_lo(cross_lo),
|
||||
.dbg(dbg),
|
||||
.mod_type(mod_type)
|
||||
);
|
||||
|
||||
integer idx, i;
|
||||
|
||||
// main clock
|
||||
always #5 begin
|
||||
ck_1356megb = !ck_1356megb;
|
||||
ck_1356meg = ck_1356megb;
|
||||
end
|
||||
|
||||
always begin
|
||||
@(negedge adc_clk) ;
|
||||
adc_d = $random;
|
||||
end
|
||||
|
||||
//crank DUT
|
||||
task crank_dut;
|
||||
begin
|
||||
@(negedge ssp_clk) ;
|
||||
ssp_dout = $random;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
|
||||
// init inputs
|
||||
ck_1356megb = 0;
|
||||
// random values
|
||||
adc_d = 0;
|
||||
ssp_dout=1;
|
||||
|
||||
// shallow modulation off
|
||||
mod_type=0;
|
||||
for (i = 0 ; i < 16 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
|
||||
// shallow modulation on
|
||||
mod_type=1;
|
||||
for (i = 0 ; i < 16 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule // main
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
`include "lo_read.v"
|
||||
/*
|
||||
pck0 - input main 24MHz clock (PLL / 4)
|
||||
[7:0] adc_d - input data from A/D converter
|
||||
lo_is_125khz - input freq selector (1=125kHz, 0=136kHz)
|
||||
|
||||
pwr_lo - output to coil drivers (ssp_clk / 8)
|
||||
adc_clk - output A/D clock signal
|
||||
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
|
||||
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
|
||||
ssp_clk - output SSP clock signal 1MHz/1.09MHz (pck0 / 2*(11+lo_is_125khz) )
|
||||
|
||||
ck_1356meg - input unused
|
||||
ck_1356megb - input unused
|
||||
ssp_dout - input unused
|
||||
cross_hi - input unused
|
||||
cross_lo - input unused
|
||||
|
||||
pwr_hi - output unused, tied low
|
||||
pwr_oe1 - output unused, undefined
|
||||
pwr_oe2 - output unused, undefined
|
||||
pwr_oe3 - output unused, undefined
|
||||
pwr_oe4 - output unused, undefined
|
||||
dbg - output alias for adc_clk
|
||||
*/
|
||||
|
||||
module testbed_lo_read;
|
||||
reg pck0;
|
||||
reg [7:0] adc_d;
|
||||
reg lo_is_125khz;
|
||||
reg [15:0] divisor;
|
||||
|
||||
wire pwr_lo;
|
||||
wire adc_clk;
|
||||
wire ck_1356meg;
|
||||
wire ck_1356megb;
|
||||
wire ssp_frame;
|
||||
wire ssp_din;
|
||||
wire ssp_clk;
|
||||
reg ssp_dout;
|
||||
wire pwr_hi;
|
||||
wire pwr_oe1;
|
||||
wire pwr_oe2;
|
||||
wire pwr_oe3;
|
||||
wire pwr_oe4;
|
||||
wire cross_lo;
|
||||
wire cross_hi;
|
||||
wire dbg;
|
||||
|
||||
lo_read #(5,10) dut(
|
||||
.pck0(pck0),
|
||||
.ck_1356meg(ck_1356meg),
|
||||
.ck_1356megb(ck_1356megb),
|
||||
.pwr_lo(pwr_lo),
|
||||
.pwr_hi(pwr_hi),
|
||||
.pwr_oe1(pwr_oe1),
|
||||
.pwr_oe2(pwr_oe2),
|
||||
.pwr_oe3(pwr_oe3),
|
||||
.pwr_oe4(pwr_oe4),
|
||||
.adc_d(adc_d),
|
||||
.adc_clk(adc_clk),
|
||||
.ssp_frame(ssp_frame),
|
||||
.ssp_din(ssp_din),
|
||||
.ssp_dout(ssp_dout),
|
||||
.ssp_clk(ssp_clk),
|
||||
.cross_hi(cross_hi),
|
||||
.cross_lo(cross_lo),
|
||||
.dbg(dbg),
|
||||
.lo_is_125khz(lo_is_125khz),
|
||||
.divisor(divisor)
|
||||
);
|
||||
|
||||
integer idx, i, adc_val=8;
|
||||
|
||||
// main clock
|
||||
always #5 pck0 = !pck0;
|
||||
|
||||
task crank_dut;
|
||||
begin
|
||||
@(posedge adc_clk) ;
|
||||
adc_d = adc_val;
|
||||
adc_val = (adc_val *2) + 53;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
|
||||
// init inputs
|
||||
pck0 = 0;
|
||||
adc_d = 0;
|
||||
ssp_dout = 0;
|
||||
lo_is_125khz = 1;
|
||||
divisor = 255; //min 16, 95=125kHz, max 255
|
||||
|
||||
// simulate 4 A/D cycles at 125kHz
|
||||
for (i = 0 ; i < 8 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
endmodule // main
|
|
@ -1,101 +0,0 @@
|
|||
`include "lo_simulate.v"
|
||||
|
||||
/*
|
||||
pck0 - input main 24MHz clock (PLL / 4)
|
||||
[7:0] adc_d - input data from A/D converter
|
||||
|
||||
|
||||
pwr_lo - output to coil drivers (ssp_clk / 8)
|
||||
adc_clk - output A/D clock signal
|
||||
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
|
||||
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
|
||||
ssp_clk - output SSP clock signal
|
||||
|
||||
ck_1356meg - input unused
|
||||
ck_1356megb - input unused
|
||||
ssp_dout - input unused
|
||||
cross_hi - input unused
|
||||
cross_lo - input unused
|
||||
|
||||
pwr_hi - output unused, tied low
|
||||
pwr_oe1 - output unused, undefined
|
||||
pwr_oe2 - output unused, undefined
|
||||
pwr_oe3 - output unused, undefined
|
||||
pwr_oe4 - output unused, undefined
|
||||
dbg - output alias for adc_clk
|
||||
*/
|
||||
|
||||
module testbed_lo_simulate;
|
||||
reg pck0;
|
||||
reg [7:0] adc_d;
|
||||
|
||||
|
||||
wire pwr_lo;
|
||||
wire adc_clk;
|
||||
wire ck_1356meg;
|
||||
wire ck_1356megb;
|
||||
wire ssp_frame;
|
||||
wire ssp_din;
|
||||
wire ssp_clk;
|
||||
reg ssp_dout;
|
||||
wire pwr_hi;
|
||||
wire pwr_oe1;
|
||||
wire pwr_oe2;
|
||||
wire pwr_oe3;
|
||||
wire pwr_oe4;
|
||||
reg cross_lo;
|
||||
wire cross_hi;
|
||||
wire dbg;
|
||||
|
||||
lo_simulate #(5,200) dut(
|
||||
.pck0(pck0),
|
||||
.ck_1356meg(ck_1356meg),
|
||||
.ck_1356megb(ck_1356megb),
|
||||
.pwr_lo(pwr_lo),
|
||||
.pwr_hi(pwr_hi),
|
||||
.pwr_oe1(pwr_oe1),
|
||||
.pwr_oe2(pwr_oe2),
|
||||
.pwr_oe3(pwr_oe3),
|
||||
.pwr_oe4(pwr_oe4),
|
||||
.adc_d(adc_d),
|
||||
.adc_clk(adc_clk),
|
||||
.ssp_frame(ssp_frame),
|
||||
.ssp_din(ssp_din),
|
||||
.ssp_dout(ssp_dout),
|
||||
.ssp_clk(ssp_clk),
|
||||
.cross_hi(cross_hi),
|
||||
.cross_lo(cross_lo),
|
||||
.dbg(dbg)
|
||||
);
|
||||
|
||||
|
||||
integer i, counter=0;
|
||||
|
||||
// main clock
|
||||
always #5 pck0 = !pck0;
|
||||
|
||||
//cross_lo is not really synced to pck0 but it's roughly pck0/192 (24MHz/192=125kHz)
|
||||
task crank_dut;
|
||||
begin
|
||||
@(posedge pck0) ;
|
||||
counter = counter + 1;
|
||||
if (counter == 192) begin
|
||||
counter = 0;
|
||||
ssp_dout = $random;
|
||||
cross_lo = 1;
|
||||
end else begin
|
||||
cross_lo = 0;
|
||||
end
|
||||
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
pck0 = 0;
|
||||
for (i = 0 ; i < 4096 ; i = i + 1) begin
|
||||
crank_dut;
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule // main
|
|
@ -1,87 +0,0 @@
|
|||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
#
|
||||
# This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
# at your option, any later version. See the LICENSE.txt file for the text of
|
||||
# the license.
|
||||
#-----------------------------------------------------------------------------
|
||||
MKDIR = mkdir -p
|
||||
TEST_OUTDIR = tb_tmp
|
||||
|
||||
TB_SOURCES = \
|
||||
tb_lp20khz_1MSa_iir_filter.v \
|
||||
tb_min_max_tracker.v \
|
||||
tb_lf_edge_detect.v
|
||||
|
||||
TBS = $(TB_SOURCES:.v=.vvp)
|
||||
|
||||
TB_DATA = \
|
||||
pcf7931_write1byte_1MSA_data \
|
||||
pcf7931_read_1MSA_data
|
||||
|
||||
all: $(TBS) tests
|
||||
|
||||
%.vvp: %.v
|
||||
iverilog -I .. -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf *.vvp $(TEST_OUTDIR)
|
||||
|
||||
tests: tb_lp20khz_1MSa_iir_filter tb_min_max_tracker tb_lf_edge_detect
|
||||
|
||||
tb_lp20khz_1MSa_iir_filter: tb_lp20khz_1MSa_iir_filter.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in); \
|
||||
$(call check_golden,$$d,filtered); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
tb_min_max_tracker: tb_min_max_tracker.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in filtered.gold); \
|
||||
$(call check_golden,$$d,min); \
|
||||
$(call check_golden,$$d,max); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
tb_lf_edge_detect: tb_lf_edge_detect.vvp | test_dir
|
||||
@printf "Testing $@\n"
|
||||
@for d in $(TB_DATA); do \
|
||||
$(call run_test,$@.vvp,$$d,in filtered.gold); \
|
||||
$(call check_golden,$$d,min); \
|
||||
$(call check_golden,$$d,max); \
|
||||
$(call check_golden,$$d,state); \
|
||||
$(call check_golden,$$d,toggle); \
|
||||
$(call check_golden,$$d,high); \
|
||||
$(call check_golden,$$d,highz); \
|
||||
$(call check_golden,$$d,lowz); \
|
||||
$(call check_golden,$$d,low); \
|
||||
done; \
|
||||
rm -f $(TEST_OUTDIR)/data.*
|
||||
|
||||
test_dir:
|
||||
@if [ ! -d $(TEST_OUTDIR) ] ; then $(MKDIR) $(TEST_OUTDIR) ; fi
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# $(1) = basename
|
||||
# $(2) = extension to check
|
||||
check_golden = \
|
||||
printf " Checking $(1).$(2)... "; \
|
||||
mv $(TEST_OUTDIR)/data.$(2) $(TEST_OUTDIR)/$(1).$(2); \
|
||||
if cmp -s tb_data/$(1).$(2).gold $(TEST_OUTDIR)/$(1).$(2); then \
|
||||
printf "OK\n"; \
|
||||
else \
|
||||
printf "ERROR\n"; \
|
||||
fi
|
||||
|
||||
# $(1) = vvp file
|
||||
# $(2) = data basename
|
||||
# $(3) = data extensions to copy
|
||||
run_test = \
|
||||
env echo " With $(2)... "; \
|
||||
cp tb_data/$(2).time $(TEST_OUTDIR); \
|
||||
for e in $(3); do cp tb_data/$(2).$$e $(TEST_OUTDIR)/data.$$e; done; \
|
||||
./$(1)
|
|
@ -1,54 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
#-----------------------------------------------------------------------------
|
||||
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
#
|
||||
# This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
# at your option, any later version. See the LICENSE.txt file for the text of
|
||||
# the license.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
try:
|
||||
import numpy
|
||||
except ModuleNotFoundError:
|
||||
print("Please install numpy module first.")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
except ModuleNotFoundError:
|
||||
print("Please install matplotlib module first.")
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: %s <basename>" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
BASENAME = sys.argv[1]
|
||||
|
||||
nx = numpy.fromfile(BASENAME + ".time")
|
||||
|
||||
def plot_time(dat1):
|
||||
plt.plot(nx, dat1)
|
||||
|
||||
sig = bytearray(open(BASENAME + ".filtered", 'rb').read())
|
||||
min_vals = bytearray(open(BASENAME + ".min", 'rb').read())
|
||||
max_vals = bytearray(open(BASENAME + ".max", 'rb').read())
|
||||
states = bytearray(open(BASENAME + ".state", 'rb').read())
|
||||
toggles = bytearray(open(BASENAME+ ".toggle", 'rb').read())
|
||||
high = bytearray(open(BASENAME + ".high", 'rb').read())
|
||||
highz = bytearray(open(BASENAME + ".highz", 'rb').read())
|
||||
lowz = bytearray(open(BASENAME + ".lowz", 'rb').read())
|
||||
low = bytearray(open(BASENAME + ".low", 'rb').read())
|
||||
|
||||
plot_time(sig)
|
||||
plot_time(min_vals)
|
||||
plot_time(max_vals)
|
||||
plot_time(states)
|
||||
plot_time(toggles)
|
||||
plot_time(high)
|
||||
plot_time(highz)
|
||||
plot_time(lowz)
|
||||
plot_time(low)
|
||||
|
||||
plt.show()
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,111 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for lf_edge_detect
|
||||
`include "lf_edge_detect.v"
|
||||
|
||||
`define FIN "tb_tmp/data.filtered.gold"
|
||||
`define FOUT_MIN "tb_tmp/data.min"
|
||||
`define FOUT_MAX "tb_tmp/data.max"
|
||||
`define FOUT_STATE "tb_tmp/data.state"
|
||||
`define FOUT_TOGGLE "tb_tmp/data.toggle"
|
||||
`define FOUT_HIGH "tb_tmp/data.high"
|
||||
`define FOUT_HIGHZ "tb_tmp/data.highz"
|
||||
`define FOUT_LOWZ "tb_tmp/data.lowz"
|
||||
`define FOUT_LOW "tb_tmp/data.low"
|
||||
|
||||
module lf_edge_detect_tb;
|
||||
|
||||
integer fin, fout_state, fout_toggle;
|
||||
integer fout_high, fout_highz, fout_lowz, fout_low, fout_min, fout_max;
|
||||
integer r;
|
||||
|
||||
reg clk = 0;
|
||||
reg [7:0] adc_d;
|
||||
wire adc_clk;
|
||||
wire data_rdy;
|
||||
wire edge_state;
|
||||
wire edge_toggle;
|
||||
|
||||
wire [7:0] high_threshold;
|
||||
wire [7:0] highz_threshold;
|
||||
wire [7:0] lowz_threshold;
|
||||
wire [7:0] low_threshold;
|
||||
wire [7:0] max;
|
||||
wire [7:0] min;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout_min = $fopen(`FOUT_MIN, "w+");
|
||||
fout_max = $fopen(`FOUT_MAX, "w+");
|
||||
fout_state = $fopen(`FOUT_STATE, "w+");
|
||||
fout_toggle = $fopen(`FOUT_TOGGLE, "w+");
|
||||
fout_high = $fopen(`FOUT_HIGH, "w+");
|
||||
fout_highz = $fopen(`FOUT_HIGHZ, "w+");
|
||||
fout_lowz = $fopen(`FOUT_LOWZ, "w+");
|
||||
fout_low = $fopen(`FOUT_LOW, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
// input
|
||||
initial
|
||||
begin
|
||||
while (!$feof(fin)) begin
|
||||
@(negedge clk) adc_d <= $fgetc(fin);
|
||||
end
|
||||
|
||||
if ($feof(fin))
|
||||
begin
|
||||
# 3 $fclose(fin);
|
||||
$fclose(fout_state);
|
||||
$fclose(fout_toggle);
|
||||
$fclose(fout_high);
|
||||
$fclose(fout_highz);
|
||||
$fclose(fout_lowz);
|
||||
$fclose(fout_low);
|
||||
$fclose(fout_min);
|
||||
$fclose(fout_max);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
// $monitor("%d\t S: %b, E: %b", $time, edge_state, edge_toggle);
|
||||
end
|
||||
|
||||
// output
|
||||
always @(negedge clk)
|
||||
if ($time > 2) begin
|
||||
r = $fputc(min, fout_min);
|
||||
r = $fputc(max, fout_max);
|
||||
r = $fputc(edge_state, fout_state);
|
||||
r = $fputc(edge_toggle, fout_toggle);
|
||||
r = $fputc(high_threshold, fout_high);
|
||||
r = $fputc(highz_threshold, fout_highz);
|
||||
r = $fputc(lowz_threshold, fout_lowz);
|
||||
r = $fputc(low_threshold, fout_low);
|
||||
end
|
||||
|
||||
// module to test
|
||||
lf_edge_detect detect(clk, adc_d, 8'd127,
|
||||
max, min,
|
||||
high_threshold, highz_threshold,
|
||||
lowz_threshold, low_threshold,
|
||||
edge_state, edge_toggle);
|
||||
|
||||
endmodule
|
|
@ -1,55 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for lp20khz_1MSa_iir_filter
|
||||
`include "lp20khz_1MSa_iir_filter.v"
|
||||
|
||||
`define FIN "tb_tmp/data.in"
|
||||
`define FOUT "tb_tmp/data.filtered"
|
||||
|
||||
module lp20khz_1MSa_iir_filter_tb;
|
||||
|
||||
integer fin, fout, r;
|
||||
|
||||
reg clk;
|
||||
reg [7:0] adc_d;
|
||||
wire data_rdy;
|
||||
wire [7:0] adc_filtered;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout = $fopen(`FOUT, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
always @(posedge clk)
|
||||
if (data_rdy) begin
|
||||
if ($time > 1)
|
||||
r = $fputc(adc_filtered, fout);
|
||||
if (!$feof(fin))
|
||||
adc_d <= $fgetc(fin);
|
||||
else begin
|
||||
$fclose(fin);
|
||||
$fclose(fout);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
// module to test
|
||||
lp20khz_1MSa_iir_filter filter(clk, adc_d, data_rdy, adc_filtered);
|
||||
|
||||
endmodule
|
|
@ -1,74 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// testbench for min_max_tracker
|
||||
`include "min_max_tracker.v"
|
||||
|
||||
`define FIN "tb_tmp/data.filtered.gold"
|
||||
`define FOUT_MIN "tb_tmp/data.min"
|
||||
`define FOUT_MAX "tb_tmp/data.max"
|
||||
|
||||
module min_max_tracker_tb;
|
||||
|
||||
integer fin;
|
||||
integer fout_min, fout_max;
|
||||
integer r;
|
||||
|
||||
reg clk;
|
||||
reg [7:0] adc_d;
|
||||
wire [7:0] min;
|
||||
wire [7:0] max;
|
||||
|
||||
initial
|
||||
begin
|
||||
clk = 0;
|
||||
fin = $fopen(`FIN, "r");
|
||||
if (!fin) begin
|
||||
$display("ERROR: can't open the data file");
|
||||
$finish;
|
||||
end
|
||||
fout_min = $fopen(`FOUT_MIN, "w+");
|
||||
fout_max = $fopen(`FOUT_MAX, "w+");
|
||||
if (!$feof(fin))
|
||||
adc_d = $fgetc(fin); // read the first value
|
||||
end
|
||||
|
||||
always
|
||||
# 1 clk = !clk;
|
||||
|
||||
// input
|
||||
initial
|
||||
begin
|
||||
while (!$feof(fin)) begin
|
||||
@(negedge clk) adc_d <= $fgetc(fin);
|
||||
end
|
||||
|
||||
if ($feof(fin))
|
||||
begin
|
||||
# 3 $fclose(fin);
|
||||
$fclose(fout_min);
|
||||
$fclose(fout_max);
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
// $monitor("%d\t min: %x, max: %x", $time, min, max);
|
||||
end
|
||||
|
||||
// output
|
||||
always @(negedge clk)
|
||||
if ($time > 2) begin
|
||||
r = $fputc(min, fout_min);
|
||||
r = $fputc(max, fout_max);
|
||||
end
|
||||
|
||||
// module to test
|
||||
min_max_tracker tracker(clk, adc_d, 8'd127, min, max);
|
||||
|
||||
endmodule
|
27
fpga/util.v
27
fpga/util.v
|
@ -1,27 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// General-purpose miscellany.
|
||||
//
|
||||
// Jonathan Westhues, April 2006.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
module mux8(sel, y, x0, x1, x2, x3, x4, x5, x6, x7);
|
||||
input [2:0] sel;
|
||||
input x0, x1, x2, x3, x4, x5, x6, x7;
|
||||
output y;
|
||||
reg y;
|
||||
|
||||
always @(x0 or x1 or x2 or x3 or x4 or x5 or x6 or x7 or sel)
|
||||
begin
|
||||
case (sel)
|
||||
3'b000: y = x0;
|
||||
3'b001: y = x1;
|
||||
3'b010: y = x2;
|
||||
3'b011: y = x3;
|
||||
3'b100: y = x4;
|
||||
3'b101: y = x5;
|
||||
3'b110: y = x6;
|
||||
3'b111: y = x7;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -1 +0,0 @@
|
|||
run -ifn fpga_felica.v -ifmt Verilog -ofn fpga_felica.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_felica -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact
|
|
@ -1 +0,0 @@
|
|||
run -ifn fpga_hf.v -ifmt Verilog -ofn fpga_hf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_hf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact
|
|
@ -1 +0,0 @@
|
|||
run -ifn fpga_lf.v -ifmt Verilog -ofn fpga_lf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_lf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact
|
Loading…
Add table
Add a link
Reference in a new issue