From e79fb9207460138a8eb1a341711b5682bed14bcd Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 21 Aug 2021 23:43:06 +0200 Subject: [PATCH] Add fpga-xc3s100e and icopyx support --- Makefile | 5 +- armsrc/appmain.c | 16 - armsrc/appmain.h | 11 +- armsrc/felica.c | 5 +- armsrc/fpgaloader.c | 78 +- armsrc/iso14443a.c | 34 - armsrc/iso14443b.c | 8 - armsrc/iso15693.c | 4 - armsrc/mifaresim.c | 4 - armsrc/thinfilm.c | 4 - common_arm/Makefile.common | 2 +- common_arm/Makefile.hal | 12 + common_fpga/fpga.h | 6 +- doc/md/Development/Makefile-vs-CMake.md | 2 +- .../4_Advanced-compilation-parameters.md | 1 + {fpga => fpga-xc2s30}/Makefile | 0 {fpga => fpga-xc2s30}/clk_divider.v | 0 {fpga => fpga-xc2s30}/fpga.ucf | 0 {fpga => fpga-xc2s30}/fpga_felica.bit | Bin {fpga => fpga-xc2s30}/fpga_felica.v | 0 {fpga => fpga-xc2s30}/fpga_hf.bit | Bin {fpga => fpga-xc2s30}/fpga_hf.v | 0 {fpga => fpga-xc2s30}/fpga_lf.bit | Bin {fpga => fpga-xc2s30}/fpga_lf.v | 0 {fpga => fpga-xc2s30}/go.bat | 0 {fpga => fpga-xc2s30}/hi_flite.v | 0 {fpga => fpga-xc2s30}/hi_get_trace.v | 0 {fpga => fpga-xc2s30}/hi_iso14443a.v | 0 {fpga => fpga-xc2s30}/hi_reader.v | 0 {fpga => fpga-xc2s30}/hi_simulate.v | 0 {fpga => fpga-xc2s30}/hi_sniffer.v | 0 {fpga => fpga-xc2s30}/lf_edge_detect.v | 0 {fpga => fpga-xc2s30}/lo_adc.v | 0 {fpga => fpga-xc2s30}/lo_edge_detect.v | 0 {fpga => fpga-xc2s30}/lo_passthru.v | 0 {fpga => fpga-xc2s30}/lo_read.v | 0 {fpga => fpga-xc2s30}/lo_simulate.v | 0 .../lp20khz_1MSa_iir_filter.v | 0 {fpga => fpga-xc2s30}/min_max_tracker.v | 0 {fpga => fpga-xc2s30}/sim.tcl | 0 {fpga => fpga-xc2s30}/testbed_fpga.v | 0 {fpga => fpga-xc2s30}/testbed_hi_read_tx.v | 0 {fpga => fpga-xc2s30}/testbed_hi_simulate.v | 0 {fpga => fpga-xc2s30}/testbed_lo_read.v | 0 {fpga => fpga-xc2s30}/testbed_lo_simulate.v | 0 {fpga => fpga-xc2s30}/tests/Makefile | 0 .../tests/plot_edgedetect.py | 0 .../pcf7931_read_1MSA_data.filtered.gold | 0 .../tb_data/pcf7931_read_1MSA_data.high.gold | 0 .../tb_data/pcf7931_read_1MSA_data.highz.gold | 0 .../tests/tb_data/pcf7931_read_1MSA_data.in | 0 .../tb_data/pcf7931_read_1MSA_data.low.gold | 0 .../tb_data/pcf7931_read_1MSA_data.lowz.gold | 0 .../tb_data/pcf7931_read_1MSA_data.max.gold | Bin .../tb_data/pcf7931_read_1MSA_data.min.gold | 0 .../tb_data/pcf7931_read_1MSA_data.state.gold | Bin .../tests/tb_data/pcf7931_read_1MSA_data.time | Bin .../pcf7931_read_1MSA_data.toggle.gold | Bin ...pcf7931_write1byte_1MSA_data.filtered.gold | 0 .../pcf7931_write1byte_1MSA_data.high.gold | 0 .../pcf7931_write1byte_1MSA_data.highz.gold | 0 .../tb_data/pcf7931_write1byte_1MSA_data.in | 0 .../pcf7931_write1byte_1MSA_data.low.gold | 0 .../pcf7931_write1byte_1MSA_data.lowz.gold | 0 .../pcf7931_write1byte_1MSA_data.max.gold | Bin .../pcf7931_write1byte_1MSA_data.min.gold | 0 .../pcf7931_write1byte_1MSA_data.state.gold | Bin .../tb_data/pcf7931_write1byte_1MSA_data.time | Bin .../pcf7931_write1byte_1MSA_data.toggle.gold | Bin .../tests/tb_lf_edge_detect.v | 0 .../tests/tb_lp20khz_1MSa_iir_filter.v | 0 .../tests/tb_min_max_tracker.v | 0 {fpga => fpga-xc2s30}/util.v | 0 {fpga => fpga-xc2s30}/xst_felica.scr | 0 {fpga => fpga-xc2s30}/xst_hf.scr | 0 {fpga => fpga-xc2s30}/xst_lf.scr | 0 fpga-xc3s100e/.gitignore | 68 ++ fpga-xc3s100e/LICENSE | 674 ++++++++++++++++++ fpga-xc3s100e/clk_divider.v | 25 + fpga-xc3s100e/compile.sh | 9 + fpga-xc3s100e/define.v | 49 ++ fpga-xc3s100e/fpga.ucf | 56 ++ fpga-xc3s100e/fpga_allinone.v | 81 +++ fpga-xc3s100e/fpga_hfmod.v | 193 +++++ fpga-xc3s100e/fpga_lfmod.v | 236 ++++++ fpga-xc3s100e/hi_flite.v | 368 ++++++++++ fpga-xc3s100e/hi_get_trace.v | 164 +++++ fpga-xc3s100e/hi_iso14443a.v | 584 +++++++++++++++ fpga-xc3s100e/hi_reader.v | 335 +++++++++ fpga-xc3s100e/hi_simulate.v | 152 ++++ fpga-xc3s100e/hi_sniffer.v | 50 ++ fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise | 0 fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl | 479 +++++++++++++ fpga-xc3s100e/lf_edge_detect.v | 77 ++ fpga-xc3s100e/lo_adc.v | 91 +++ fpga-xc3s100e/lo_edge_detect.v | 70 ++ fpga-xc3s100e/lo_passthru.v | 29 + fpga-xc3s100e/lo_read.v | 74 ++ fpga-xc3s100e/lp20khz_1MSa_iir_filter.v | 81 +++ fpga-xc3s100e/min_max_tracker.v | 65 ++ fpga-xc3s100e/mux2_onein.v | 21 + fpga-xc3s100e/mux2_oneout.v | 21 + fpga-xc3s100e/util.v | 27 + include/config_gpio.h | 6 +- include/proxmark3_arm.h | 7 +- tools/fpga_compress/Makefile | 14 +- 106 files changed, 4213 insertions(+), 85 deletions(-) rename {fpga => fpga-xc2s30}/Makefile (100%) rename {fpga => fpga-xc2s30}/clk_divider.v (100%) rename {fpga => fpga-xc2s30}/fpga.ucf (100%) rename {fpga => fpga-xc2s30}/fpga_felica.bit (100%) rename {fpga => fpga-xc2s30}/fpga_felica.v (100%) rename {fpga => fpga-xc2s30}/fpga_hf.bit (100%) rename {fpga => fpga-xc2s30}/fpga_hf.v (100%) rename {fpga => fpga-xc2s30}/fpga_lf.bit (100%) rename {fpga => fpga-xc2s30}/fpga_lf.v (100%) rename {fpga => fpga-xc2s30}/go.bat (100%) rename {fpga => fpga-xc2s30}/hi_flite.v (100%) rename {fpga => fpga-xc2s30}/hi_get_trace.v (100%) rename {fpga => fpga-xc2s30}/hi_iso14443a.v (100%) rename {fpga => fpga-xc2s30}/hi_reader.v (100%) rename {fpga => fpga-xc2s30}/hi_simulate.v (100%) rename {fpga => fpga-xc2s30}/hi_sniffer.v (100%) rename {fpga => fpga-xc2s30}/lf_edge_detect.v (100%) rename {fpga => fpga-xc2s30}/lo_adc.v (100%) rename {fpga => fpga-xc2s30}/lo_edge_detect.v (100%) rename {fpga => fpga-xc2s30}/lo_passthru.v (100%) rename {fpga => fpga-xc2s30}/lo_read.v (100%) rename {fpga => fpga-xc2s30}/lo_simulate.v (100%) rename {fpga => fpga-xc2s30}/lp20khz_1MSa_iir_filter.v (100%) rename {fpga => fpga-xc2s30}/min_max_tracker.v (100%) rename {fpga => fpga-xc2s30}/sim.tcl (100%) rename {fpga => fpga-xc2s30}/testbed_fpga.v (100%) rename {fpga => fpga-xc2s30}/testbed_hi_read_tx.v (100%) rename {fpga => fpga-xc2s30}/testbed_hi_simulate.v (100%) rename {fpga => fpga-xc2s30}/testbed_lo_read.v (100%) rename {fpga => fpga-xc2s30}/testbed_lo_simulate.v (100%) rename {fpga => fpga-xc2s30}/tests/Makefile (100%) rename {fpga => fpga-xc2s30}/tests/plot_edgedetect.py (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.high.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.highz.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.in (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.low.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.max.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.min.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.state.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.time (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.filtered.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.high.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.highz.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.in (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.lowz.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.time (100%) rename {fpga => fpga-xc2s30}/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold (100%) rename {fpga => fpga-xc2s30}/tests/tb_lf_edge_detect.v (100%) rename {fpga => fpga-xc2s30}/tests/tb_lp20khz_1MSa_iir_filter.v (100%) rename {fpga => fpga-xc2s30}/tests/tb_min_max_tracker.v (100%) rename {fpga => fpga-xc2s30}/util.v (100%) rename {fpga => fpga-xc2s30}/xst_felica.scr (100%) rename {fpga => fpga-xc2s30}/xst_hf.scr (100%) rename {fpga => fpga-xc2s30}/xst_lf.scr (100%) create mode 100644 fpga-xc3s100e/.gitignore create mode 100644 fpga-xc3s100e/LICENSE create mode 100644 fpga-xc3s100e/clk_divider.v create mode 100755 fpga-xc3s100e/compile.sh create mode 100644 fpga-xc3s100e/define.v create mode 100644 fpga-xc3s100e/fpga.ucf create mode 100644 fpga-xc3s100e/fpga_allinone.v create mode 100644 fpga-xc3s100e/fpga_hfmod.v create mode 100644 fpga-xc3s100e/fpga_lfmod.v create mode 100644 fpga-xc3s100e/hi_flite.v create mode 100644 fpga-xc3s100e/hi_get_trace.v create mode 100644 fpga-xc3s100e/hi_iso14443a.v create mode 100644 fpga-xc3s100e/hi_reader.v create mode 100644 fpga-xc3s100e/hi_simulate.v create mode 100644 fpga-xc3s100e/hi_sniffer.v create mode 100644 fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise create mode 100644 fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl create mode 100644 fpga-xc3s100e/lf_edge_detect.v create mode 100644 fpga-xc3s100e/lo_adc.v create mode 100644 fpga-xc3s100e/lo_edge_detect.v create mode 100644 fpga-xc3s100e/lo_passthru.v create mode 100644 fpga-xc3s100e/lo_read.v create mode 100644 fpga-xc3s100e/lp20khz_1MSa_iir_filter.v create mode 100644 fpga-xc3s100e/min_max_tracker.v create mode 100644 fpga-xc3s100e/mux2_onein.v create mode 100644 fpga-xc3s100e/mux2_oneout.v create mode 100644 fpga-xc3s100e/util.v diff --git a/Makefile b/Makefile index 4ba68b3ae..d8fd3092d 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ nonce2key/%: FORCE mf_nonce_brute/%: FORCE $(info [*] MAKE $@) $(Q)$(MAKE) --no-print-directory -C tools/mf_nonce_brute $(patsubst mf_nonce_brute/%,%,$@) DESTDIR=$(MYDESTDIR) -fpga_compress/%: FORCE +fpga_compress/%: FORCE cleanifplatformchanged $(info [*] MAKE $@) $(Q)$(MAKE) --no-print-directory -C tools/fpga_compress $(patsubst fpga_compress/%,%,$@) DESTDIR=$(MYDESTDIR) bootrom/%: FORCE cleanifplatformchanged @@ -222,6 +222,7 @@ ifeq ($(PLATFORM_CHANGED),true) $(Q)$(MAKE) --no-print-directory -C bootrom clean $(Q)$(MAKE) --no-print-directory -C armsrc clean $(Q)$(MAKE) --no-print-directory -C recovery clean + $(Q)$(MAKE) --no-print-directory -C tools/fpga_compress clean $(Q)echo CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache $(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache $(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache @@ -252,7 +253,7 @@ style: # Make sure astyle is installed @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v, pm3 - find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" -or -name "pm3" \) \) \ + find . \( -not -path "./cov-int/*" -and -not -path "./fpga*/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" -or -name "pm3" \) \) \ -exec perl -pi -e 's/[ \t]+$$//' {} \; \ -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ -exec sh -c "echo >> {}" \; diff --git a/armsrc/appmain.c b/armsrc/appmain.c index f30b194a8..3c60d6002 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -212,11 +212,7 @@ static void MeasureAntennaTuning(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); SpinDelay(50); -#if defined RDV4 - payload.v_hf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else payload.v_hf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_MEASURE_ANTENNA_TUNING, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); @@ -226,11 +222,7 @@ static void MeasureAntennaTuning(void) { // Measure HF in milliVolt static uint16_t MeasureAntennaTuningHfData(void) { -#if defined RDV4 - return (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else return (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif } @@ -610,12 +602,8 @@ void ListenReaderField(uint8_t limit) { if (limit == HF_ONLY) { -#if defined RDV4 // iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader. - hf_av = hf_max = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else hf_av = hf_max = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av); hf_baseline = hf_av; } @@ -666,11 +654,7 @@ void ListenReaderField(uint8_t limit) { LED_B_OFF(); } -#if defined RDV4 - hf_av_new = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else hf_av_new = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif // see if there's a significant change if (ABS(hf_av - hf_av_new) > REPORT_CHANGE) { Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new); diff --git a/armsrc/appmain.h b/armsrc/appmain.h index 1a12f2858..9d1d422c5 100644 --- a/armsrc/appmain.h +++ b/armsrc/appmain.h @@ -18,11 +18,14 @@ extern bool g_hf_field_active; void hf_field_off(void); int tearoff_hook(void); -// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV -#define MAX_ADC_HF_VOLTAGE 36300 +#if defined RDV4 || defined ICOPYX + // ADC Vref = 3300mV, and an (10000k+240k):240k voltage divider on the LF input can measure voltages up to 140800 mV + #define MAX_ADC_HF_VOLTAGE 140800 +#else + // ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV + #define MAX_ADC_HF_VOLTAGE 36300 +#endif // ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV -#define MAX_ADC_HF_VOLTAGE_RDV40 140800 -// ADC Vref = 3300mV, and an (10000k+240k):240k voltage divider on the LF input can measure voltages up to 140800 mV #define MAX_ADC_LF_VOLTAGE 140800 extern int ToSendMax; diff --git a/armsrc/felica.c b/armsrc/felica.c index 223345a58..9eacea99d 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -445,8 +445,11 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { if (g_dbglevel >= DBG_DEBUG) Dbprintf("Start iso18092_setup"); LEDsoff(); +#if defined XC3 + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); +#else FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA); - +#endif // allocate command receive buffer BigBuf_free(); BigBuf_Clear_ext(false); diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index f6d0c2ed0..2f999403c 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -269,10 +269,11 @@ static void DownloadFPGA_byte(uint8_t w) { // Download the fpga image starting at current stream position with length FpgaImageLen bytes static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t compressed_fpga_stream, uint8_t *output_buffer) { int i = 0; - +#if !defined XC3 AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON; AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON; HIGH(GPIO_FPGA_ON); // ensure everything is powered on +#endif SpinDelay(50); @@ -285,7 +286,13 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t // PIO controls the following pins AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_NINIT | +#if defined XC3 + //3S100E M2 & M3 PIO ENA + GPIO_SPCK | + GPIO_MOSI | +#endif GPIO_FPGA_DONE; + // Enable pull-ups AT91C_BASE_PIOA->PIO_PPUER = GPIO_FPGA_NINIT | @@ -299,8 +306,19 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_NPROGRAM | GPIO_FPGA_CCLK | +#if defined XC3 + //3S100E M2 & M3 OUTPUT ENA + GPIO_SPCK | + GPIO_MOSI | +#endif GPIO_FPGA_DIN; +#if defined XC3 + //3S100E M2 & M3 OUTPUT HIGH + HIGH(GPIO_SPCK); + HIGH(GPIO_MOSI); +#endif + // enter FPGA configuration mode LOW(GPIO_FPGA_NPROGRAM); SpinDelay(50); @@ -319,6 +337,13 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t return; } +#if defined XC3 + //3S100E M2 & M3 RETURN TO NORMAL + LOW(GPIO_SPCK); + LOW(GPIO_MOSI); + AT91C_BASE_PIOA->PIO_PDR = GPIO_SPCK | GPIO_MOSI; +#endif + for (i = 0; i < FpgaImageLen; i++) { int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); if (b < 0) { @@ -396,6 +421,43 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3 return result; } +//---------------------------------------------------------------------------- +// Change FPGA image status, if image loaded. +// bitstream_version is your new fpga image version +// return true if can change. +// return false if image is unloaded. +//---------------------------------------------------------------------------- +#if defined XC3 +static bool FpgaConfCurrentMode(int bitstream_version) { + // fpga "XC3S100E" image merge + // If fpga image is no init + // We need load hf_lf_allinone.bit + if (downloaded_bitstream != 0) { + // test start + // PIO controls the following pins + AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_SWITCH; + // These pins are outputs + AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_SWITCH; + + // try to turn off antenna + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + if (bitstream_version == FPGA_BITSTREAM_LF) { + LOW(GPIO_FPGA_SWITCH); + } + else { + HIGH(GPIO_FPGA_SWITCH); + } + // update downloaded_bitstream + downloaded_bitstream = bitstream_version; + // turn off antenna + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return true; + } + return false; +} +#endif + //---------------------------------------------------------------------------- // Check which FPGA image is currently loaded (if any). If necessary // decompress and load the correct (HF or LF) image to the FPGA @@ -408,6 +470,14 @@ void FpgaDownloadAndGo(int bitstream_version) { return; } +#if defined XC3 + // If we can change image version + // direct return. + if (FpgaConfCurrentMode(bitstream_version)) { + return; + } +#endif + // Send waiting time extension request as this will take a while send_wtx(1500); @@ -431,6 +501,12 @@ void FpgaDownloadAndGo(int bitstream_version) { downloaded_bitstream = bitstream_version; } +#if defined XC3 + // first download fpga image to hf + // we need to change fpga status to hf + FpgaConfCurrentMode(bitstream_version); +#endif + // turn off antenna FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 564a2001a..bed78e8b9 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1972,11 +1972,7 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { ADC_MODE_STARTUP_TIME(1) | ADC_MODE_SAMPLE_HOLD_TIME(15); -#if defined RDV4 - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_RDV40); -#else AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF); -#endif // start ADC AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; @@ -2003,35 +1999,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { ++check; // test if the field exists -#if defined RDV4 - if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_RDV40)) { - - analogCnt++; - - analogAVG += (AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40] & 0x3FF); - - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - - if (analogCnt >= 32) { - - if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { - - if (timer == 0) { - timer = GetTickCount(); - } else { - // 50ms no field --> card to idle state - if (GetTickCountDelta(timer) > 50) { - return 2; - } - } - } else { - timer = 0; - } - analogCnt = 0; - analogAVG = 0; - } - } -#else if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { analogCnt++; @@ -2059,7 +2026,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { analogAVG = 0; } } -#endif // receive and test the miller decoding if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index d246c10e7..9fe5e51d0 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -772,11 +772,7 @@ void SimulateIso14443bTag(uint8_t *pupi) { // find reader field if (cardSTATE == SIM_NOFIELD) { -#if defined RDV4 - vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif if (vHf > MF_MINFIELDV) { cardSTATE = SIM_IDLE; LED_A_ON(); @@ -976,11 +972,7 @@ void Simulate_iso14443b_srx_tag(uint8_t *uid) { // find reader field if (cardSTATE == SIM_NOFIELD) { -#if defined RDV4 - vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif if (vHf > MF_MINFIELDV) { cardSTATE = SIM_IDLE; LED_A_ON(); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 649fd82f5..06e48bf84 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1727,11 +1727,7 @@ void SimTagIso15693(uint8_t *uid) { // find reader field if (chip_state == NO_FIELD) { -#if defined RDV4 - vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; -#else vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; -#endif if (vHf > MF_MINFIELDV) { chip_state = IDLE; LED_A_ON(); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index a096f8e46..585c44158 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -543,11 +543,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // find reader field if (cardSTATE == MFEMUL_NOFIELD) { - #if defined RDV4 - vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * SumAdc(ADC_CHAN_HF_RDV40, 32)) >> 15; - #else vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; - #endif if (vHf > MF_MINFIELDV) { cardSTATE_TO_IDLE(); diff --git a/armsrc/thinfilm.c b/armsrc/thinfilm.c index dc99bf4c7..506dbbe85 100644 --- a/armsrc/thinfilm.c +++ b/armsrc/thinfilm.c @@ -51,11 +51,7 @@ void ReadThinFilm(void) { static uint16_t FpgaSendQueueDelay; static uint16_t ReadReaderField(void) { -#if defined RDV4 - return AvgAdc(ADC_CHAN_HF_RDV40); -#else return AvgAdc(ADC_CHAN_HF); -#endif } static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) { diff --git a/common_arm/Makefile.common b/common_arm/Makefile.common index e6d1636e9..f5fad1401 100644 --- a/common_arm/Makefile.common +++ b/common_arm/Makefile.common @@ -35,7 +35,7 @@ OBJDIR = obj INCLUDE = -I../include -I../common_arm -I../common_fpga -I../common -I. # Also search prerequisites in the common directory (for usb.c), the fpga directory (for fpga.bit), and the lz4 directory -VPATH = . ../common_arm ../common ../common/crapto1 ../common/mbedtls ../common/lz4 ../fpga ../armsrc/Standalone +VPATH = . ../common_arm ../common ../common/crapto1 ../common/mbedtls ../common/lz4 ../fpga-$(PLATFORM_FPGA) ../armsrc/Standalone INCLUDES = ../include/proxmark3_arm.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/pm3_cmd.h diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index cda6ac1b9..b611afb60 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -21,6 +21,8 @@ Known definitions: +--------------------------------------------+ | PM3GENERIC | Proxmark3 generic target | +--------------------------------------------+ +| PM3ICOPYX | iCopy-X with XC3S100E | ++--------------------------------------------+ +============================================+ | PLATFORM_EXTRAS | DESCRIPTION | @@ -71,15 +73,23 @@ $(HELP_DEFINITIONS) endef PLTNAME = Unknown Platform +PLATFORM_FPGA = fpga-undefined ifeq ($(PLATFORM),PM3RDV4) PLATFORM_DEFS = -DWITH_SMARTCARD -DWITH_FLASH -DRDV4 PLTNAME = Proxmark3 RDV4 + PLATFORM_FPGA = xc2s30 else ifeq ($(PLATFORM),PM3OTHER) $(warning PLATFORM=PM3OTHER is deprecated, please use PLATFORM=PM3GENERIC) PLTNAME = Proxmark3 generic target + PLATFORM_FPGA = xc2s30 else ifeq ($(PLATFORM),PM3GENERIC) PLTNAME = Proxmark3 generic target + PLATFORM_FPGA = xc2s30 +else ifeq ($(PLATFORM),PM3ICOPYX) + PLATFORM_DEFS = -DWITH_FLASH -DICOPYX -DXC3 + PLTNAME = iCopy-X with XC3S100E + PLATFORM_FPGA = xc3s100e else $(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS)) @@ -204,6 +214,7 @@ export PLATFORM_EXTRAS export PLATFORM_EXTRAS_INFO export PLATFORM_SIZE export PLTNAME +export PLATFORM_FPGA export PLATFORM_DEFS export PLATFORM_DEFS_INFO export PLATFORM_DEFS_INFO_STANDALONE @@ -212,6 +223,7 @@ export PLATFORM_CHANGED $(info ===================================================================) $(info Platform name: $(PLTNAME)) $(info PLATFORM: $(PLATFORM)) +$(info PLATFORM_FPGA: $(PLATFORM_FPGA)) $(info PLATFORM_SIZE: $(PLATFORM_SIZE)) $(info Platform extras: $(PLATFORM_EXTRAS_INFO)) $(info Included options: $(PLATFORM_DEFS_INFO)) diff --git a/common_fpga/fpga.h b/common_fpga/fpga.h index c8390ff7e..9874c3c5c 100644 --- a/common_fpga/fpga.h +++ b/common_fpga/fpga.h @@ -12,7 +12,11 @@ #define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(bitparse_fixed_header) #define FPGA_INTERLEAVE_SIZE 288 -#define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#if defined XC3 + #define FPGA_CONFIG_SIZE 72864L // our current fpga_[lh]f.bit files are 72742 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#else + #define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#endif #define FPGA_RING_BUFFER_BYTES (1024 * 39) #define FPGA_TRACE_SIZE 3072 diff --git a/doc/md/Development/Makefile-vs-CMake.md b/doc/md/Development/Makefile-vs-CMake.md index a6a9c497a..df696e5ec 100644 --- a/doc/md/Development/Makefile-vs-CMake.md +++ b/doc/md/Development/Makefile-vs-CMake.md @@ -91,7 +91,7 @@ At the moment both are maintained because they don't perfectly overlap yet. | Feature | Makefile | Remarks | |-----|---|---| -| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC` | +| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX` | | Platform size | `PLATFORM_SIZE=` | values: `256`, `512` | | Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` | | Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list | diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index ee2d10d4b..018ac490e 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -45,6 +45,7 @@ Here are the supported values you can assign to `PLATFORM` in `Makefile.platform |-----------------|--------------------------| | PM3RDV4 (def) | Proxmark3 RDV4 | | PM3GENERIC | Proxmark3 generic target | +| PM3ICOPYX | iCopy-X with XC3S100E | By default `PLATFORM=PM3RDV4`. diff --git a/fpga/Makefile b/fpga-xc2s30/Makefile similarity index 100% rename from fpga/Makefile rename to fpga-xc2s30/Makefile diff --git a/fpga/clk_divider.v b/fpga-xc2s30/clk_divider.v similarity index 100% rename from fpga/clk_divider.v rename to fpga-xc2s30/clk_divider.v diff --git a/fpga/fpga.ucf b/fpga-xc2s30/fpga.ucf similarity index 100% rename from fpga/fpga.ucf rename to fpga-xc2s30/fpga.ucf diff --git a/fpga/fpga_felica.bit b/fpga-xc2s30/fpga_felica.bit similarity index 100% rename from fpga/fpga_felica.bit rename to fpga-xc2s30/fpga_felica.bit diff --git a/fpga/fpga_felica.v b/fpga-xc2s30/fpga_felica.v similarity index 100% rename from fpga/fpga_felica.v rename to fpga-xc2s30/fpga_felica.v diff --git a/fpga/fpga_hf.bit b/fpga-xc2s30/fpga_hf.bit similarity index 100% rename from fpga/fpga_hf.bit rename to fpga-xc2s30/fpga_hf.bit diff --git a/fpga/fpga_hf.v b/fpga-xc2s30/fpga_hf.v similarity index 100% rename from fpga/fpga_hf.v rename to fpga-xc2s30/fpga_hf.v diff --git a/fpga/fpga_lf.bit b/fpga-xc2s30/fpga_lf.bit similarity index 100% rename from fpga/fpga_lf.bit rename to fpga-xc2s30/fpga_lf.bit diff --git a/fpga/fpga_lf.v b/fpga-xc2s30/fpga_lf.v similarity index 100% rename from fpga/fpga_lf.v rename to fpga-xc2s30/fpga_lf.v diff --git a/fpga/go.bat b/fpga-xc2s30/go.bat similarity index 100% rename from fpga/go.bat rename to fpga-xc2s30/go.bat diff --git a/fpga/hi_flite.v b/fpga-xc2s30/hi_flite.v similarity index 100% rename from fpga/hi_flite.v rename to fpga-xc2s30/hi_flite.v diff --git a/fpga/hi_get_trace.v b/fpga-xc2s30/hi_get_trace.v similarity index 100% rename from fpga/hi_get_trace.v rename to fpga-xc2s30/hi_get_trace.v diff --git a/fpga/hi_iso14443a.v b/fpga-xc2s30/hi_iso14443a.v similarity index 100% rename from fpga/hi_iso14443a.v rename to fpga-xc2s30/hi_iso14443a.v diff --git a/fpga/hi_reader.v b/fpga-xc2s30/hi_reader.v similarity index 100% rename from fpga/hi_reader.v rename to fpga-xc2s30/hi_reader.v diff --git a/fpga/hi_simulate.v b/fpga-xc2s30/hi_simulate.v similarity index 100% rename from fpga/hi_simulate.v rename to fpga-xc2s30/hi_simulate.v diff --git a/fpga/hi_sniffer.v b/fpga-xc2s30/hi_sniffer.v similarity index 100% rename from fpga/hi_sniffer.v rename to fpga-xc2s30/hi_sniffer.v diff --git a/fpga/lf_edge_detect.v b/fpga-xc2s30/lf_edge_detect.v similarity index 100% rename from fpga/lf_edge_detect.v rename to fpga-xc2s30/lf_edge_detect.v diff --git a/fpga/lo_adc.v b/fpga-xc2s30/lo_adc.v similarity index 100% rename from fpga/lo_adc.v rename to fpga-xc2s30/lo_adc.v diff --git a/fpga/lo_edge_detect.v b/fpga-xc2s30/lo_edge_detect.v similarity index 100% rename from fpga/lo_edge_detect.v rename to fpga-xc2s30/lo_edge_detect.v diff --git a/fpga/lo_passthru.v b/fpga-xc2s30/lo_passthru.v similarity index 100% rename from fpga/lo_passthru.v rename to fpga-xc2s30/lo_passthru.v diff --git a/fpga/lo_read.v b/fpga-xc2s30/lo_read.v similarity index 100% rename from fpga/lo_read.v rename to fpga-xc2s30/lo_read.v diff --git a/fpga/lo_simulate.v b/fpga-xc2s30/lo_simulate.v similarity index 100% rename from fpga/lo_simulate.v rename to fpga-xc2s30/lo_simulate.v diff --git a/fpga/lp20khz_1MSa_iir_filter.v b/fpga-xc2s30/lp20khz_1MSa_iir_filter.v similarity index 100% rename from fpga/lp20khz_1MSa_iir_filter.v rename to fpga-xc2s30/lp20khz_1MSa_iir_filter.v diff --git a/fpga/min_max_tracker.v b/fpga-xc2s30/min_max_tracker.v similarity index 100% rename from fpga/min_max_tracker.v rename to fpga-xc2s30/min_max_tracker.v diff --git a/fpga/sim.tcl b/fpga-xc2s30/sim.tcl similarity index 100% rename from fpga/sim.tcl rename to fpga-xc2s30/sim.tcl diff --git a/fpga/testbed_fpga.v b/fpga-xc2s30/testbed_fpga.v similarity index 100% rename from fpga/testbed_fpga.v rename to fpga-xc2s30/testbed_fpga.v diff --git a/fpga/testbed_hi_read_tx.v b/fpga-xc2s30/testbed_hi_read_tx.v similarity index 100% rename from fpga/testbed_hi_read_tx.v rename to fpga-xc2s30/testbed_hi_read_tx.v diff --git a/fpga/testbed_hi_simulate.v b/fpga-xc2s30/testbed_hi_simulate.v similarity index 100% rename from fpga/testbed_hi_simulate.v rename to fpga-xc2s30/testbed_hi_simulate.v diff --git a/fpga/testbed_lo_read.v b/fpga-xc2s30/testbed_lo_read.v similarity index 100% rename from fpga/testbed_lo_read.v rename to fpga-xc2s30/testbed_lo_read.v diff --git a/fpga/testbed_lo_simulate.v b/fpga-xc2s30/testbed_lo_simulate.v similarity index 100% rename from fpga/testbed_lo_simulate.v rename to fpga-xc2s30/testbed_lo_simulate.v diff --git a/fpga/tests/Makefile b/fpga-xc2s30/tests/Makefile similarity index 100% rename from fpga/tests/Makefile rename to fpga-xc2s30/tests/Makefile diff --git a/fpga/tests/plot_edgedetect.py b/fpga-xc2s30/tests/plot_edgedetect.py similarity index 100% rename from fpga/tests/plot_edgedetect.py rename to fpga-xc2s30/tests/plot_edgedetect.py diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.filtered.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.high.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.high.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.high.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.high.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.highz.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.highz.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.highz.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.highz.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.in b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.in similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.in rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.in diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.low.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.low.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.low.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.low.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.lowz.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.max.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.max.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.max.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.max.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.min.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.min.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.min.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.min.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.state.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.state.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.state.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.state.gold diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.time b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.time similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.time rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.time diff --git a/fpga/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold b/fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_read_1MSA_data.toggle.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.filtered.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.filtered.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.filtered.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.filtered.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.high.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.high.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.high.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.high.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.highz.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.highz.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.highz.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.highz.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.in b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.in similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.in rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.in diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.low.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.lowz.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.lowz.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.lowz.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.lowz.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.max.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.min.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.state.gold diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.time b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.time similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.time rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.time diff --git a/fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold b/fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold similarity index 100% rename from fpga/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold rename to fpga-xc2s30/tests/tb_data/pcf7931_write1byte_1MSA_data.toggle.gold diff --git a/fpga/tests/tb_lf_edge_detect.v b/fpga-xc2s30/tests/tb_lf_edge_detect.v similarity index 100% rename from fpga/tests/tb_lf_edge_detect.v rename to fpga-xc2s30/tests/tb_lf_edge_detect.v diff --git a/fpga/tests/tb_lp20khz_1MSa_iir_filter.v b/fpga-xc2s30/tests/tb_lp20khz_1MSa_iir_filter.v similarity index 100% rename from fpga/tests/tb_lp20khz_1MSa_iir_filter.v rename to fpga-xc2s30/tests/tb_lp20khz_1MSa_iir_filter.v diff --git a/fpga/tests/tb_min_max_tracker.v b/fpga-xc2s30/tests/tb_min_max_tracker.v similarity index 100% rename from fpga/tests/tb_min_max_tracker.v rename to fpga-xc2s30/tests/tb_min_max_tracker.v diff --git a/fpga/util.v b/fpga-xc2s30/util.v similarity index 100% rename from fpga/util.v rename to fpga-xc2s30/util.v diff --git a/fpga/xst_felica.scr b/fpga-xc2s30/xst_felica.scr similarity index 100% rename from fpga/xst_felica.scr rename to fpga-xc2s30/xst_felica.scr diff --git a/fpga/xst_hf.scr b/fpga-xc2s30/xst_hf.scr similarity index 100% rename from fpga/xst_hf.scr rename to fpga-xc2s30/xst_hf.scr diff --git a/fpga/xst_lf.scr b/fpga-xc2s30/xst_lf.scr similarity index 100% rename from fpga/xst_lf.scr rename to fpga-xc2s30/xst_lf.scr diff --git a/fpga-xc3s100e/.gitignore b/fpga-xc3s100e/.gitignore new file mode 100644 index 000000000..b21d41545 --- /dev/null +++ b/fpga-xc3s100e/.gitignore @@ -0,0 +1,68 @@ +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# iMPACT generated files +_impactbatch.log +impact.xsl +impact_impact.xwbt +ise_impact.cmd +webtalk_impact.xml + +# Core Generator generated files +xaw2verilog.log + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ +fpga_hf_xdb/tmp/ diff --git a/fpga-xc3s100e/LICENSE b/fpga-xc3s100e/LICENSE new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/fpga-xc3s100e/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/fpga-xc3s100e/clk_divider.v b/fpga-xc3s100e/clk_divider.v new file mode 100644 index 000000000..9a57879b0 --- /dev/null +++ b/fpga-xc3s100e/clk_divider.v @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 iZsh +// +// 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 + diff --git a/fpga-xc3s100e/compile.sh b/fpga-xc3s100e/compile.sh new file mode 100755 index 000000000..741ed0bb8 --- /dev/null +++ b/fpga-xc3s100e/compile.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +( + cd iseproj/fpga_hf + xtclsh fpga_hf.tcl run_process + mv fpga_hf.bit ../.. + git checkout fpga_hf.ise + git clean -dfx . +) diff --git a/fpga-xc3s100e/define.v b/fpga-xc3s100e/define.v new file mode 100644 index 000000000..248cab22a --- /dev/null +++ b/fpga-xc3s100e/define.v @@ -0,0 +1,49 @@ +// 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 \ No newline at end of file diff --git a/fpga-xc3s100e/fpga.ucf b/fpga-xc3s100e/fpga.ucf new file mode 100644 index 000000000..4cb06a9d6 --- /dev/null +++ b/fpga-xc3s100e/fpga.ucf @@ -0,0 +1,56 @@ +# See the schematic for the pin assignment. + +#NET "cross_hi" LOC = "P88" ; +#NET "miso" LOC = "P40" ; + +# 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 ; +NET "FPGA_SWITCH" CLOCK_DEDICATED_ROUTE = FALSE ; +#PACE: Start of Constraints generated by PACE + +#PACE: Start of PACE I/O Pin Assignments +NET "adc_clk" LOC = "P65" ; +NET "adc_d<0>" LOC = "P79" ; +NET "adc_d<1>" LOC = "P78" ; +NET "adc_d<2>" LOC = "P71" ; +NET "adc_d<3>" LOC = "P70" ; +NET "adc_d<4>" LOC = "P69" ; +NET "adc_d<5>" LOC = "P68" ; +NET "adc_d<6>" LOC = "P67" ; +NET "adc_d<7>" LOC = "P66" ; +NET "adc_noe" LOC = "P62" ; +NET "ck_1356meg" LOC = "p88" ; +NET "ck_1356megb" LOC = "p89" ; +NET "cross_lo" LOC = "P90" ; +NET "dbg" LOC = "P22" ; +NET "FPGA_SWITCH" LOC = "P38" ; +NET "mosi" LOC = "P43" ; +NET "ncs" LOC = "P40" ; +NET "pck0" LOC = "P36" ; +NET "pwr_hi" LOC = "P85" ; +NET "pwr_lo" LOC = "P83" ; +NET "PWR_LO_EN" LOC = "P94" ; +NET "pwr_oe1" LOC = "P84" ; +NET "pwr_oe2" LOC = "P91" ; +NET "pwr_oe3" LOC = "P92" ; +NET "pwr_oe4" LOC = "P86" ; +NET "spck" LOC = "P39" ; +NET "ssp_clk" LOC = "P33" ; +NET "ssp_din" LOC = "P32" ; +NET "ssp_dout" LOC = "P34" ; +NET "ssp_frame" LOC = "P27" ; + +#PACE: Start of PACE Area Constraints + +#PACE: Start of PACE Prohibit Constraints + +#PACE: End of Constraints generated by PACE diff --git a/fpga-xc3s100e/fpga_allinone.v b/fpga-xc3s100e/fpga_allinone.v new file mode 100644 index 000000000..dbd9eca8b --- /dev/null +++ b/fpga-xc3s100e/fpga_allinone.v @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 16:09:14 05/13/2020 +// Design Name: +// Module Name: fpga_all_in_one +// Project Name: +// Target Devices: +// Tool versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// +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, + output PWR_LO_EN, + input FPGA_SWITCH + ); + + +fpga_hfmod hfmod( + hfspck, hfmiso, hfmosi, hfncs, + hfpck0, hfck_1356meg, hfck_1356megb, + hfpwr_lo, hfpwr_hi, + hfpwr_oe1, hfpwr_oe2, hfpwr_oe3, hfpwr_oe4, + adc_d, hfadc_clk, hfadc_noe, + hfssp_frame, hfssp_din, hfssp_dout, hfssp_clk, + hfcross_hi, hfcross_lo, + hfdbg +); + +fpga_lfmod lfmod( + lfspck, lfmiso, lfmosi, lfncs, + lfpck0, lfck_1356meg, lfck_1356megb, + lfpwr_lo, lfpwr_hi, + lfpwr_oe1, lfpwr_oe2, lfpwr_oe3, lfpwr_oe4, + adc_d, lfadc_clk, lfadc_noe, + lfssp_frame, lfssp_din, lfssp_dout, lfssp_clk, + lfcross_hi, lfcross_lo, + lfdbg, + lfPWR_LO_EN +); + +mux2_oneout mux_spck_all (FPGA_SWITCH, spck, hfspck, lfspck); +mux2_one mux_miso_all (FPGA_SWITCH, miso, hfmiso, lfmiso); +mux2_oneout mux_mosi_all (FPGA_SWITCH, mosi, hfmosi, lfmosi); +mux2_oneout mux_ncs_all (FPGA_SWITCH, ncs, hfncs, lfncs); +mux2_oneout mux_pck0_all (FPGA_SWITCH, pck0, hfpck0, lfpck0); +mux2_oneout mux_ck_1356meg_all (FPGA_SWITCH, ck_1356meg, hfck_1356meg, lfck_1356meg); +mux2_oneout mux_ck_1356megb_all (FPGA_SWITCH, ck_1356megb, hfck_1356megb, lfck_1356megb); +mux2_one mux_pwr_lo_all (FPGA_SWITCH, pwr_lo, hfpwr_lo, lfpwr_lo); +mux2_one mux_pwr_hi_all (FPGA_SWITCH, pwr_hi, hfpwr_hi, lfpwr_hi); +mux2_one mux_pwr_oe1_all (FPGA_SWITCH, pwr_oe1, hfpwr_oe1, lfpwr_oe1); +mux2_one mux_pwr_oe2_all (FPGA_SWITCH, pwr_oe2, hfpwr_oe2, lfpwr_oe2); +mux2_one mux_pwr_oe3_all (FPGA_SWITCH, pwr_oe3, hfpwr_oe3, lfpwr_oe3); +mux2_one mux_pwr_oe4_all (FPGA_SWITCH, pwr_oe4, hfpwr_oe4, lfpwr_oe4); +mux2_one mux_adc_clk_all (FPGA_SWITCH, adc_clk, hfadc_clk, lfadc_clk); +mux2_one mux_adc_noe_all (FPGA_SWITCH, adc_noe, adc_noe, lfadc_noe); +mux2_one mux_ssp_frame_all (FPGA_SWITCH, ssp_frame, hfssp_frame, lfssp_frame); +mux2_one mux_ssp_din_all (FPGA_SWITCH, ssp_din, hfssp_din, lfssp_din); +mux2_oneout mux_ssp_dout_all (FPGA_SWITCH, ssp_dout, hfssp_dout, lfssp_dout); +mux2_one mux_ssp_clk_all (FPGA_SWITCH, ssp_clk, hfssp_clk, lfssp_clk); +mux2_oneout mux_cross_hi_all (FPGA_SWITCH, cross_hi, hfcross_hi, lfcross_hi); +mux2_oneout mux_cross_lo_all (FPGA_SWITCH, cross_lo, hfcross_lo, lfcross_lo); +mux2_one mux_dbg_all (FPGA_SWITCH, dbg, hfdbg, lfdbg); +mux2_one mux_PWR_LO_EN_all (FPGA_SWITCH, PWR_LO_EN, 1'b0, lfPWR_LO_EN); + +endmodule diff --git a/fpga-xc3s100e/fpga_hfmod.v b/fpga-xc3s100e/fpga_hfmod.v new file mode 100644 index 000000000..82780446c --- /dev/null +++ b/fpga-xc3s100e/fpga_hfmod.v @@ -0,0 +1,193 @@ +//----------------------------------------------------------------------------- +// 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 , June 2014 +// Piwi, Feb 2019 +//----------------------------------------------------------------------------- + +//For ISE 10.1 PROJ,IDE cannot apply definition to all files +`include "define.v" + + +//For ISE 10.1 PROJ,IDE auto include +//`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_hfmod( + 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 +); + +// 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 diff --git a/fpga-xc3s100e/fpga_lfmod.v b/fpga-xc3s100e/fpga_lfmod.v new file mode 100644 index 000000000..02827386b --- /dev/null +++ b/fpga-xc3s100e/fpga_lfmod.v @@ -0,0 +1,236 @@ +//----------------------------------------------------------------------------- +// Jonathan Westhues, March 2006 +// iZsh , 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 + +//For ISE 10.1 PROJ,IDE auto include +//`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_lfmod( + 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, + output PWR_LO_EN +); + +//----------------------------------------------------------------------------- +// 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[7:5] = 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); +mux8 mux_ant (major_mode, PWR_LO_EN, 1'b1, 1'b1, 1'b1, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0); + +// In all modes, let the ADC's outputs be enabled. +assign adc_noe = 1'b0; + +endmodule diff --git a/fpga-xc3s100e/hi_flite.v b/fpga-xc3s100e/hi_flite.v new file mode 100644 index 000000000..6cb87825e --- /dev/null +++ b/fpga-xc3s100e/hi_flite.v @@ -0,0 +1,368 @@ +/* + 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; + +// 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> 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_oe2; +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_oe2 <= 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_oe2 <= 1'b0; + pwr_oe3 <= 1'b0; + pwr_oe4 <= mod; + end +end + +endmodule diff --git a/fpga-xc3s100e/hi_get_trace.v b/fpga-xc3s100e/hi_get_trace.v new file mode 100644 index 000000000..ebe8cfb99 --- /dev/null +++ b/fpga-xc3s100e/hi_get_trace.v @@ -0,0 +1,164 @@ +//----------------------------------------------------------------------------- +// +// piwi, Feb 2019 +//----------------------------------------------------------------------------- +//For ISE 10.1 PROJ,IDE cannot apply definition to all files +`include "define.v" + +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 diff --git a/fpga-xc3s100e/hi_iso14443a.v b/fpga-xc3s100e/hi_iso14443a.v new file mode 100644 index 000000000..1c84cd9c4 --- /dev/null +++ b/fpga-xc3s100e/hi_iso14443a.v @@ -0,0 +1,584 @@ +//----------------------------------------------------------------------------- +// 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 3 +`define EDGE_DETECT_THRESHOLDHIGH 20 + +always @(negedge adc_clk) +begin + if(negedge_cnt[3:0] == mod_detect_reset_time) + begin + if (mod_type == `FPGA_HF_ISO14443A_SNIFFER) + begin + // detect modulation signal: if modulating, there must have been a falling AND a rising edge + if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLDHIGH) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLDHIGH)) + curbit <= 1'b1; // modulation + else + curbit <= 1'b0; // no modulation + end + else + 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 + end + // 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 diff --git a/fpga-xc3s100e/hi_reader.v b/fpga-xc3s100e/hi_reader.v new file mode 100644 index 000000000..b90f9a99c --- /dev/null +++ b/fpga-xc3s100e/hi_reader.v @@ -0,0 +1,335 @@ +//----------------------------------------------------------------------------- +// +// 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 diff --git a/fpga-xc3s100e/hi_simulate.v b/fpga-xc3s100e/hi_simulate.v new file mode 100644 index 000000000..7fe943aee --- /dev/null +++ b/fpga-xc3s100e/hi_simulate.v @@ -0,0 +1,152 @@ +//----------------------------------------------------------------------------- +// 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 +//----------------------------------------------------------------------------- + +//For ISE 10.1 PROJ,IDE cannot apply definition to all files +`include "define.v" + + +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 diff --git a/fpga-xc3s100e/hi_sniffer.v b/fpga-xc3s100e/hi_sniffer.v new file mode 100644 index 000000000..c2dc844a7 --- /dev/null +++ b/fpga-xc3s100e/hi_sniffer.v @@ -0,0 +1,50 @@ +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 diff --git a/fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise b/fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise new file mode 100644 index 000000000..e69de29bb diff --git a/fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl b/fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl new file mode 100644 index 000000000..114f0df18 --- /dev/null +++ b/fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl @@ -0,0 +1,479 @@ +# +# Project automation script for fpga_hf +# +# Created for ISE version 10.1 +# +# This file contains several Tcl procedures (procs) that you can use to automate +# your project by running from xtclsh or the Project Navigator Tcl console. +# If you load this file (using the Tcl command: source fpga_hf.tcl, then you can +# run any of the procs included here. +# You may also edit any of these procs to customize them. See comments in each +# proc for more instructions. +# +# This file contains the following procedures: +# +# Top Level procs (meant to be called directly by the user): +# run_process: you can use this top-level procedure to run any processes +# that you choose to by adding and removing comments, or by +# adding new entries. +# rebuild_project: you can alternatively use this top-level procedure +# to recreate your entire project, and the run selected processes. +# +# Lower Level (helper) procs (called under in various cases by the top level procs): +# show_help: print some basic information describing how this script works +# add_source_files: adds the listed source files to your project. +# set_project_props: sets the project properties that were in effect when this +# script was generated. +# create_libraries: creates and adds file to VHDL libraries that were defined when +# this script was generated. +# create_partitions: adds any partitions that were defined when this script was generated. +# set_process_props: set the process properties as they were set for your project +# when this script was generated. +# + +set myProject "fpga_hf.ise" +set myScript "fpga_hf.tcl" + +# +# Main (top-level) routines +# + +# +# run_process +# This procedure is used to run processes on an existing project. You may comment or +# uncomment lines to control which processes are run. This routine is set up to run +# the Implement Design and Generate Programming File processes by default. This proc +# also sets process properties as specified in the "set_process_props" proc. Only +# those properties which have values different from their current settings in the project +# file will be modified in the project. +# +proc run_process {} { + + global myScript + global myProject + + ## put out a 'heartbeat' - so we know something's happening. + puts "\n$myScript: running ($myProject)...\n" + + if { ! [ open_project ] } { + return false + } + + set_process_props + # + # Remove the comment characters (#'s) to enable the following commands + # process run "Synthesize" + # process run "Translate" + # process run "Map" + # process run "Place & Route" + # + puts "Running 'Implement Design'" + if { ! [ process run "Implement Design" ] } { + puts "$myScript: Implementation run failed, check run output for details." + project close + return + } + puts "Running 'Generate Programming File'" + if { ! [ process run "Generate Programming File" ] } { + puts "$myScript: Generate Programming File run failed, check run output for details." + project close + return + } + + puts "Run completed." + project close + +} + +# +# rebuild_project +# +# This procedure renames the project file (if it exists) and recreates the project. +# It then sets project properties and adds project sources as specified by the +# set_project_props and add_source_files support procs. It recreates VHDL libraries +# and partitions as they existed at the time this script was generated. +# +# It then calls run_process to set process properties and run selected processes. +# +proc rebuild_project {} { + + global myScript + global myProject + + ## put out a 'heartbeat' - so we know something's happening. + puts "\n$myScript: rebuilding ($myProject)...\n" + + if { [ file exists $myProject ] } { + puts "$myScript: Removing existing project file." + file delete $myProject + } + + puts "$myScript: Rebuilding project $myProject" + project new $myProject + set_project_props + add_source_files + create_libraries + create_partitions + puts "$myScript: project rebuild completed." + + run_process + +} + +# +# Support Routines +# + +# +# show_help: print information to help users understand the options available when +# running this script. +# +proc show_help {} { + + global myScript + + puts "" + puts "usage: xtclsh $myScript " + puts " or you can run xtclsh and then enter 'source $myScript'." + puts "" + puts "options:" + puts " run_process - set properties and run processes." + puts " rebuild_project - rebuild the project from scratch and run processes." + puts " set_project_props - set project properties (device, speed, etc.)" + puts " add_source_files - add source files" + puts " create_libraries - create vhdl libraries" + puts " create_partitions - create partitions" + puts " set_process_props - set process property values" + puts " show_help - print this message" + puts "" +} + +proc open_project {} { + + global myScript + global myProject + + if { ! [ file exists $myProject ] } { + ## project file isn't there, rebuild it. + puts "Project $myProject not found. Use ${myProject}_rebuild to recreate it." + return false + } + + project open $myProject + + return true + +} +# +# set_project_props +# +# This procedure sets the project properties as they were set in the project +# at the time this script was generated. +# +proc set_project_props {} { + + global myScript + + if { ! [ open_project ] } { + return false + } + + puts "$myScript: Setting project properties..." + + project set family "Spartan3E" + project set device "xc3s100e" + project set package "vq100" + project set speed "-4" + project set top_level_module_type "HDL" + project set synthesis_tool "XST (VHDL/Verilog)" + project set simulator "ISE Simulator (VHDL/Verilog)" + project set "Preferred Language" "Verilog" + project set "Enable Message Filtering" "false" + project set "Display Incremental Messages" "false" + +} + + +# +# add_source_files +# +# This procedure add the source files that were known to the project at the +# time this script was generated. +# +proc add_source_files {} { + + global myScript + + if { ! [ open_project ] } { + return false + } + + puts "$myScript: Adding sources to project..." + + xfile add "../../clk_divider.v" + xfile add "../../define.v" + xfile add "../../fpga.ucf" + xfile add "../../fpga_allinone.v" + xfile add "../../fpga_hfmod.v" + xfile add "../../fpga_lfmod.v" + xfile add "../../hi_flite.v" + xfile add "../../hi_get_trace.v" + xfile add "../../hi_iso14443a.v" + xfile add "../../hi_reader.v" + xfile add "../../hi_simulate.v" + xfile add "../../hi_sniffer.v" + xfile add "../../lf_edge_detect.v" + xfile add "../../lo_adc.v" + xfile add "../../lo_edge_detect.v" + xfile add "../../lo_passthru.v" + xfile add "../../lo_read.v" + xfile add "../../lp20khz_1MSa_iir_filter.v" + xfile add "../../mux2_onein.v" + xfile add "../../mux2_oneout.v" + xfile add "../../util.v" + + # Set the Top Module as well... + project set top "fpga_hf" + + puts "$myScript: project sources reloaded." + +} ; # end add_source_files + +# +# create_libraries +# +# This procedure defines VHDL libraries and associates files with those libraries. +# It is expected to be used when recreating the project. Any libraries defined +# when this script was generated are recreated by this procedure. +# +proc create_libraries {} { + + global myScript + + if { ! [ open_project ] } { + return false + } + + puts "$myScript: Creating libraries..." + + + # must close the project or library definitions aren't saved. + project close + +} ; # end create_libraries + +# +# create_partitions +# +# This procedure creates partitions on instances in your project. +# It is expected to be used when recreating the project. Any partitions +# defined when this script was generated are recreated by this procedure. +# +proc create_partitions {} { + + global myScript + + if { ! [ open_project ] } { + return false + } + + puts "$myScript: Creating Partitions..." + + + # must close the project or partition definitions aren't saved. + project close + +} ; # end create_partitions + +# +# set_process_props +# +# This procedure sets properties as requested during script generation (either +# all of the properties, or only those modified from their defaults). +# +proc set_process_props {} { + + global myScript + + if { ! [ open_project ] } { + return false + } + + puts "$myScript: setting process properties..." + + project set "Compiled Library Directory" "\$XILINX//" + project set "Use SmartGuide" "false" + project set "SmartGuide Filename" "fpga_hf_guide.ncd" + project set "Multiplier Style" "Auto" -process "Synthesize - XST" + project set "Configuration Rate" "Default (1)" -process "Generate Programming File" + project set "Map to Input Functions" "4" -process "Map" + project set "Number of Clock Buffers" "24" -process "Synthesize - XST" + project set "Max Fanout" "500" -process "Synthesize - XST" + project set "Case Implementation Style" "None" -process "Synthesize - XST" + project set "Decoder Extraction" "true" -process "Synthesize - XST" + project set "Priority Encoder Extraction" "Yes" -process "Synthesize - XST" + project set "Mux Extraction" "Yes" -process "Synthesize - XST" + project set "RAM Extraction" "true" -process "Synthesize - XST" + project set "ROM Extraction" "true" -process "Synthesize - XST" + project set "FSM Encoding Algorithm" "Auto" -process "Synthesize - XST" + project set "Logical Shifter Extraction" "true" -process "Synthesize - XST" + project set "Optimization Goal" "Speed" -process "Synthesize - XST" + project set "Optimization Effort" "Normal" -process "Synthesize - XST" + project set "Resource Sharing" "true" -process "Synthesize - XST" + project set "Shift Register Extraction" "true" -process "Synthesize - XST" + project set "XOR Collapsing" "true" -process "Synthesize - XST" + project set "Other Bitgen Command Line Options" "" -process "Generate Programming File" + project set "Show All Models" "false" -process "Generate IBIS Model" + project set "Target UCF File Name" "" -process "Back-annotate Pin Locations" + project set "Ignore User Timing Constraints" "false" -process "Map" + project set "Use RLOC Constraints" "true" -process "Map" + project set "Other Map Command Line Options" "" -process "Map" + project set "Use LOC Constraints" "true" -process "Translate" + project set "Other Ngdbuild Command Line Options" "" -process "Translate" + project set "Ignore User Timing Constraints" "false" -process "Place & Route" + project set "Other Place & Route Command Line Options" "" -process "Place & Route" + project set "UserID Code (8 Digit Hexadecimal)" "0xFFFFFFFF" -process "Generate Programming File" + project set "Reset DCM if SHUTDOWN & AGHIGH performed" "false" -process "Generate Programming File" + project set "Configuration Pin Done" "Pull Up" -process "Generate Programming File" + project set "Create ASCII Configuration File" "false" -process "Generate Programming File" + project set "Create Binary Configuration File" "false" -process "Generate Programming File" + project set "Create Bit File" "true" -process "Generate Programming File" + project set "Enable BitStream Compression" "false" -process "Generate Programming File" + project set "Run Design Rules Checker (DRC)" "true" -process "Generate Programming File" + project set "Enable Cyclic Redundancy Checking (CRC)" "true" -process "Generate Programming File" + project set "Create IEEE 1532 Configuration File" "false" -process "Generate Programming File" + project set "Configuration Pin Program" "Pull Up" -process "Generate Programming File" + project set "JTAG Pin TCK" "Pull Up" -process "Generate Programming File" + project set "JTAG Pin TDI" "Pull Up" -process "Generate Programming File" + project set "JTAG Pin TDO" "Pull Up" -process "Generate Programming File" + project set "JTAG Pin TMS" "Pull Up" -process "Generate Programming File" + project set "Unused IOB Pins" "Pull Down" -process "Generate Programming File" + project set "Security" "Enable Readback and Reconfiguration" -process "Generate Programming File" + project set "FPGA Start-Up Clock" "CCLK" -process "Generate Programming File" + project set "Done (Output Events)" "Default (4)" -process "Generate Programming File" + project set "Drive Done Pin High" "false" -process "Generate Programming File" + project set "Enable Outputs (Output Events)" "Default (5)" -process "Generate Programming File" + project set "Release DLL (Output Events)" "Default (NoWait)" -process "Generate Programming File" + project set "Release Write Enable (Output Events)" "Default (6)" -process "Generate Programming File" + project set "Enable Internal Done Pipe" "false" -process "Generate Programming File" + project set "Allow Logic Optimization Across Hierarchy" "false" -process "Map" + project set "Optimization Strategy (Cover Mode)" "Area" -process "Map" + project set "Disable Register Ordering" "false" -process "Map" + project set "Pack I/O Registers/Latches into IOBs" "Off" -process "Map" + project set "Replicate Logic to Allow Logic Level Reduction" "true" -process "Map" + project set "Generate Detailed MAP Report" "false" -process "Map" + project set "Map Slice Logic into Unused Block RAMs" "false" -process "Map" + project set "Perform Timing-Driven Packing and Placement" "false" -process "Map" + project set "Trim Unconnected Signals" "true" -process "Map" + project set "Create I/O Pads from Ports" "false" -process "Translate" + project set "Macro Search Path" "" -process "Translate" + project set "Netlist Translation Type" "Timestamp" -process "Translate" + project set "User Rules File for Netlister Launcher" "" -process "Translate" + project set "Allow Unexpanded Blocks" "false" -process "Translate" + project set "Allow Unmatched LOC Constraints" "false" -process "Translate" + project set "Starting Placer Cost Table (1-100)" "1" -process "Place & Route" + project set "Placer Effort Level (Overrides Overall Level)" "None" -process "Place & Route" + project set "Router Effort Level (Overrides Overall Level)" "None" -process "Place & Route" + project set "Place And Route Mode" "Normal Place and Route" -process "Place & Route" + project set "Use Bonded I/Os" "false" -process "Place & Route" + project set "Add I/O Buffers" "true" -process "Synthesize - XST" + project set "Global Optimization Goal" "AllClockNets" -process "Synthesize - XST" + project set "Keep Hierarchy" "No" -process "Synthesize - XST" + project set "Register Balancing" "No" -process "Synthesize - XST" + project set "Register Duplication" "true" -process "Synthesize - XST" + project set "Asynchronous To Synchronous" "false" -process "Synthesize - XST" + project set "Automatic BRAM Packing" "false" -process "Synthesize - XST" + project set "BRAM Utilization Ratio" "100" -process "Synthesize - XST" + project set "Bus Delimiter" "<>" -process "Synthesize - XST" + project set "Case" "Maintain" -process "Synthesize - XST" + project set "Cores Search Directories" "" -process "Synthesize - XST" + project set "Cross Clock Analysis" "false" -process "Synthesize - XST" + project set "Equivalent Register Removal" "true" -process "Synthesize - XST" + project set "FSM Style" "LUT" -process "Synthesize - XST" + project set "Generate RTL Schematic" "Yes" -process "Synthesize - XST" + project set "Generics, Parameters" "" -process "Synthesize - XST" + project set "Hierarchy Separator" "/" -process "Synthesize - XST" + project set "HDL INI File" "" -process "Synthesize - XST" + project set "Library Search Order" "" -process "Synthesize - XST" + project set "Netlist Hierarchy" "As Optimized" -process "Synthesize - XST" + project set "Optimize Instantiated Primitives" "false" -process "Synthesize - XST" + project set "Pack I/O Registers into IOBs" "Auto" -process "Synthesize - XST" + project set "Read Cores" "true" -process "Synthesize - XST" + project set "Slice Packing" "true" -process "Synthesize - XST" + project set "Slice Utilization Ratio" "100" -process "Synthesize - XST" + project set "Use Clock Enable" "Yes" -process "Synthesize - XST" + project set "Use Synchronous Reset" "Yes" -process "Synthesize - XST" + project set "Use Synchronous Set" "Yes" -process "Synthesize - XST" + project set "Use Synthesis Constraints File" "true" -process "Synthesize - XST" + project set "Custom Compile File List" "" -process "Synthesize - XST" + project set "Verilog Include Directories" "" -process "Synthesize - XST" + project set "Verilog 2001" "true" -process "Synthesize - XST" + project set "Verilog Macros" "" -process "Synthesize - XST" + project set "Work Directory" "./xst" -process "Synthesize - XST" + project set "Write Timing Constraints" "false" -process "Synthesize - XST" + project set "Other XST Command Line Options" "" -process "Synthesize - XST" + project set "Map Effort Level" "Medium" -process "Map" + project set "Combinatorial Logic Optimization" "false" -process "Map" + project set "Starting Placer Cost Table (1-100)" "1" -process "Map" + project set "Power Reduction" "false" -process "Map" + project set "Register Duplication" "false" -process "Map" + project set "Synthesis Constraints File" "" -process "Synthesize - XST" + project set "Mux Style" "Auto" -process "Synthesize - XST" + project set "RAM Style" "Auto" -process "Synthesize - XST" + project set "Timing Mode" "Non Timing Driven" -process "Map" + project set "Generate Asynchronous Delay Report" "false" -process "Place & Route" + project set "Generate Clock Region Report" "false" -process "Place & Route" + project set "Generate Post-Place & Route Simulation Model" "false" -process "Place & Route" + project set "Generate Post-Place & Route Static Timing Report" "true" -process "Place & Route" + project set "Nodelist File (Unix Only)" "" -process "Place & Route" + project set "Number of PAR Iterations (0-100)" "3" -process "Place & Route" + project set "Save Results in Directory (.dir will be appended)" "" -process "Place & Route" + project set "Number of Results to Save (0-100)" "" -process "Place & Route" + project set "Power Reduction" "false" -process "Place & Route" + project set "Timing Mode" "Performance Evaluation" -process "Place & Route" + project set "Enable Debugging of Serial Mode BitStream" "false" -process "Generate Programming File" + project set "CLB Pack Factor Percentage" "100" -process "Map" + project set "Place & Route Effort Level (Overall)" "Standard" -process "Place & Route" + project set "Move First Flip-Flop Stage" "true" -process "Synthesize - XST" + project set "Move Last Flip-Flop Stage" "true" -process "Synthesize - XST" + project set "ROM Style" "Auto" -process "Synthesize - XST" + project set "Safe Implementation" "No" -process "Synthesize - XST" + project set "Extra Effort" "None" -process "Map" + project set "Power Activity File" "" -process "Map" + project set "Power Activity File" "" -process "Place & Route" + project set "Extra Effort (Highest PAR level only)" "None" -process "Place & Route" + + puts "$myScript: project property values set." + +} ; # end set_process_props + +proc main {} { + + if { [llength $::argv] == 0 } { + show_help + return true + } + + foreach option $::argv { + switch $option { + "show_help" { show_help } + "run_process" { run_process } + "rebuild_project" { rebuild_project } + "set_project_props" { set_project_props } + "add_source_files" { add_source_files } + "create_libraries" { create_libraries } + "create_partitions" { create_partitions } + "set_process_props" { set_process_props } + default { puts "unrecognized option: $option"; show_help } + } + } +} + +if { $tcl_interactive } { + show_help +} else { + if {[catch {main} result]} { + puts "$myScript failed: $result." + } +} + diff --git a/fpga-xc3s100e/lf_edge_detect.v b/fpga-xc3s100e/lf_edge_detect.v new file mode 100644 index 000000000..d086f95fc --- /dev/null +++ b/fpga-xc3s100e/lf_edge_detect.v @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 iZsh +// +// 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 diff --git a/fpga-xc3s100e/lo_adc.v b/fpga-xc3s100e/lo_adc.v new file mode 100644 index 000000000..aba849fcc --- /dev/null +++ b/fpga-xc3s100e/lo_adc.v @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// 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 diff --git a/fpga-xc3s100e/lo_edge_detect.v b/fpga-xc3s100e/lo_edge_detect.v new file mode 100644 index 000000000..d91bf3845 --- /dev/null +++ b/fpga-xc3s100e/lo_edge_detect.v @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 iZsh +// +// 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 + +//For ISE 10.1 PROJ,IDE auto include +//`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 + diff --git a/fpga-xc3s100e/lo_passthru.v b/fpga-xc3s100e/lo_passthru.v new file mode 100644 index 000000000..f0f2847a0 --- /dev/null +++ b/fpga-xc3s100e/lo_passthru.v @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// For reading TI tags, we need to place the FPGA in pass through mode +// and pass everything through to the ARM +//----------------------------------------------------------------------------- +// iZsh , 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 diff --git a/fpga-xc3s100e/lo_read.v b/fpga-xc3s100e/lo_read.v new file mode 100644 index 000000000..8f778309b --- /dev/null +++ b/fpga-xc3s100e/lo_read.v @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// 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 , 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 diff --git a/fpga-xc3s100e/lp20khz_1MSa_iir_filter.v b/fpga-xc3s100e/lp20khz_1MSa_iir_filter.v new file mode 100644 index 000000000..2dbfd6945 --- /dev/null +++ b/fpga-xc3s100e/lp20khz_1MSa_iir_filter.v @@ -0,0 +1,81 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 iZsh +// +// 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 diff --git a/fpga-xc3s100e/min_max_tracker.v b/fpga-xc3s100e/min_max_tracker.v new file mode 100644 index 000000000..5e8bbedf1 --- /dev/null +++ b/fpga-xc3s100e/min_max_tracker.v @@ -0,0 +1,65 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2014 iZsh +// +// 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 diff --git a/fpga-xc3s100e/mux2_onein.v b/fpga-xc3s100e/mux2_onein.v new file mode 100644 index 000000000..86f17a553 --- /dev/null +++ b/fpga-xc3s100e/mux2_onein.v @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Two way MUX. +// +// kombi, 2020.05 +//----------------------------------------------------------------------------- + +module mux2_one(sel, y, x0, x1); + input [1:0] sel; + input x0, x1; + output y; + reg y; + +always @(x0 or x1 or sel) +begin + case (sel) + 1'b0: y = x1; + 1'b1: y = x0; + endcase +end + +endmodule diff --git a/fpga-xc3s100e/mux2_oneout.v b/fpga-xc3s100e/mux2_oneout.v new file mode 100644 index 000000000..3cbc0fd6b --- /dev/null +++ b/fpga-xc3s100e/mux2_oneout.v @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Two way MUX. +// +// kombi, 2020.05 +//----------------------------------------------------------------------------- + +module mux2_oneout(sel, y, x0, x1); + input [1:0] sel; + output x0, x1; + input y; + reg x0, x1; + +always @(x0 or x1 or sel) +begin + case (sel) + 1'b0: x1 = y; + 1'b1: x0 = y; + endcase +end + +endmodule diff --git a/fpga-xc3s100e/util.v b/fpga-xc3s100e/util.v new file mode 100644 index 000000000..0842ac64f --- /dev/null +++ b/fpga-xc3s100e/util.v @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// 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 diff --git a/include/config_gpio.h b/include/config_gpio.h index 89e63de5d..68f995078 100644 --- a/include/config_gpio.h +++ b/include/config_gpio.h @@ -43,7 +43,11 @@ #define GPIO_BUTTON AT91C_PIO_PA23 #define GPIO_USB_PU AT91C_PIO_PA24 #define GPIO_RELAY AT91C_PIO_PA25 -#define GPIO_FPGA_ON AT91C_PIO_PA26 +#if defined XC3 + #define GPIO_FPGA_SWITCH AT91C_PIO_PA26 +#else + #define GPIO_FPGA_ON AT91C_PIO_PA26 +#endif #define GPIO_FPGA_DONE AT91C_PIO_PA27 #define GPIO_FPGA_NPROGRAM AT91C_PIO_PA28 #define GPIO_FPGA_CCLK AT91C_PIO_PA29 diff --git a/include/proxmark3_arm.h b/include/proxmark3_arm.h index 67632c8b2..82faff36c 100644 --- a/include/proxmark3_arm.h +++ b/include/proxmark3_arm.h @@ -28,8 +28,11 @@ #define PWM_CHANNEL(x) (1 << (x)) #define ADC_CHAN_LF 4 -#define ADC_CHAN_HF 5 -#define ADC_CHAN_HF_RDV40 7 +#if defined RDV4 || defined ICOPYX + #define ADC_CHAN_HF 7 +#else + #define ADC_CHAN_HF 5 +#endif #define ADC_MODE_PRESCALE(x) ((x) << 8) #define ADC_MODE_STARTUP_TIME(x) ((x) << 16) #define ADC_MODE_SAMPLE_HOLD_TIME(x) ((x) << 24) diff --git a/tools/fpga_compress/Makefile b/tools/fpga_compress/Makefile index fb2f9d23d..324860995 100644 --- a/tools/fpga_compress/Makefile +++ b/tools/fpga_compress/Makefile @@ -1,7 +1,19 @@ +ifeq ($(PLTNAME),) + -include ../../Makefile.platform + -include ../../.Makefile.options.cache + ifneq ($(PLATFORM), $(CACHED_PLATFORM)) + $(error platform definitions have been changed, please "make clean" at the root of the project) + endif +endif + MYSRCPATHS = MYINCLUDES = -I../../common_fpga MYCFLAGS = -std=c99 -D_ISOC99_SOURCE -MYDEFS = +ifeq ($(PLATFORM),PM3ICOPYX) + MYDEFS = -DXC3 +else + MYDEFS = +endif MYSRCS = MYLIBS =