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 =