mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Add fpga-xc3s100e and icopyx support
This commit is contained in:
parent
d56d8f0f65
commit
e79fb92074
106 changed files with 4213 additions and 85 deletions
5
Makefile
5
Makefile
|
@ -123,7 +123,7 @@ nonce2key/%: FORCE
|
||||||
mf_nonce_brute/%: FORCE
|
mf_nonce_brute/%: FORCE
|
||||||
$(info [*] MAKE $@)
|
$(info [*] MAKE $@)
|
||||||
$(Q)$(MAKE) --no-print-directory -C tools/mf_nonce_brute $(patsubst mf_nonce_brute/%,%,$@) DESTDIR=$(MYDESTDIR)
|
$(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 $@)
|
$(info [*] MAKE $@)
|
||||||
$(Q)$(MAKE) --no-print-directory -C tools/fpga_compress $(patsubst fpga_compress/%,%,$@) DESTDIR=$(MYDESTDIR)
|
$(Q)$(MAKE) --no-print-directory -C tools/fpga_compress $(patsubst fpga_compress/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||||
bootrom/%: FORCE cleanifplatformchanged
|
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 bootrom clean
|
||||||
$(Q)$(MAKE) --no-print-directory -C armsrc clean
|
$(Q)$(MAKE) --no-print-directory -C armsrc clean
|
||||||
$(Q)$(MAKE) --no-print-directory -C recovery 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=$(PLATFORM) > .Makefile.options.cache
|
||||||
$(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache
|
$(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache
|
||||||
$(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache
|
$(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache
|
||||||
|
@ -252,7 +253,7 @@ style:
|
||||||
# Make sure astyle is installed
|
# Make sure astyle is installed
|
||||||
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
@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
|
# 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 perl -pi -e 's/[ \t]+$$//' {} \; \
|
||||||
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \
|
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \
|
||||||
-exec sh -c "echo >> {}" \;
|
-exec sh -c "echo >> {}" \;
|
||||||
|
|
|
@ -212,11 +212,7 @@ static void MeasureAntennaTuning(void) {
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
|
||||||
SpinDelay(50);
|
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;
|
payload.v_hf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
|
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
|
// Measure HF in milliVolt
|
||||||
static uint16_t MeasureAntennaTuningHfData(void) {
|
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;
|
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 (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.
|
// 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;
|
hf_av = hf_max = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av);
|
Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av);
|
||||||
hf_baseline = hf_av;
|
hf_baseline = hf_av;
|
||||||
}
|
}
|
||||||
|
@ -666,11 +654,7 @@ void ListenReaderField(uint8_t limit) {
|
||||||
LED_B_OFF();
|
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;
|
hf_av_new = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
// see if there's a significant change
|
// see if there's a significant change
|
||||||
if (ABS(hf_av - hf_av_new) > REPORT_CHANGE) {
|
if (ABS(hf_av - hf_av_new) > REPORT_CHANGE) {
|
||||||
Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new);
|
Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new);
|
||||||
|
|
|
@ -18,11 +18,14 @@ extern bool g_hf_field_active;
|
||||||
void hf_field_off(void);
|
void hf_field_off(void);
|
||||||
int tearoff_hook(void);
|
int tearoff_hook(void);
|
||||||
|
|
||||||
|
#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
|
// 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
|
#define MAX_ADC_HF_VOLTAGE 36300
|
||||||
|
#endif
|
||||||
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
|
// 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
|
#define MAX_ADC_LF_VOLTAGE 140800
|
||||||
|
|
||||||
extern int ToSendMax;
|
extern int ToSendMax;
|
||||||
|
|
|
@ -445,8 +445,11 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
||||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
||||||
|
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
#if defined XC3
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||||
|
#else
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA);
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA);
|
||||||
|
#endif
|
||||||
// allocate command receive buffer
|
// allocate command receive buffer
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
BigBuf_Clear_ext(false);
|
BigBuf_Clear_ext(false);
|
||||||
|
|
|
@ -269,10 +269,11 @@ static void DownloadFPGA_byte(uint8_t w) {
|
||||||
// Download the fpga image starting at current stream position with length FpgaImageLen bytes
|
// 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) {
|
static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t compressed_fpga_stream, uint8_t *output_buffer) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
#if !defined XC3
|
||||||
AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
|
AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
|
||||||
AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
|
AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
|
||||||
HIGH(GPIO_FPGA_ON); // ensure everything is powered on
|
HIGH(GPIO_FPGA_ON); // ensure everything is powered on
|
||||||
|
#endif
|
||||||
|
|
||||||
SpinDelay(50);
|
SpinDelay(50);
|
||||||
|
|
||||||
|
@ -285,7 +286,13 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t
|
||||||
// PIO controls the following pins
|
// PIO controls the following pins
|
||||||
AT91C_BASE_PIOA->PIO_PER =
|
AT91C_BASE_PIOA->PIO_PER =
|
||||||
GPIO_FPGA_NINIT |
|
GPIO_FPGA_NINIT |
|
||||||
|
#if defined XC3
|
||||||
|
//3S100E M2 & M3 PIO ENA
|
||||||
|
GPIO_SPCK |
|
||||||
|
GPIO_MOSI |
|
||||||
|
#endif
|
||||||
GPIO_FPGA_DONE;
|
GPIO_FPGA_DONE;
|
||||||
|
|
||||||
// Enable pull-ups
|
// Enable pull-ups
|
||||||
AT91C_BASE_PIOA->PIO_PPUER =
|
AT91C_BASE_PIOA->PIO_PPUER =
|
||||||
GPIO_FPGA_NINIT |
|
GPIO_FPGA_NINIT |
|
||||||
|
@ -299,8 +306,19 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t
|
||||||
AT91C_BASE_PIOA->PIO_OER =
|
AT91C_BASE_PIOA->PIO_OER =
|
||||||
GPIO_FPGA_NPROGRAM |
|
GPIO_FPGA_NPROGRAM |
|
||||||
GPIO_FPGA_CCLK |
|
GPIO_FPGA_CCLK |
|
||||||
|
#if defined XC3
|
||||||
|
//3S100E M2 & M3 OUTPUT ENA
|
||||||
|
GPIO_SPCK |
|
||||||
|
GPIO_MOSI |
|
||||||
|
#endif
|
||||||
GPIO_FPGA_DIN;
|
GPIO_FPGA_DIN;
|
||||||
|
|
||||||
|
#if defined XC3
|
||||||
|
//3S100E M2 & M3 OUTPUT HIGH
|
||||||
|
HIGH(GPIO_SPCK);
|
||||||
|
HIGH(GPIO_MOSI);
|
||||||
|
#endif
|
||||||
|
|
||||||
// enter FPGA configuration mode
|
// enter FPGA configuration mode
|
||||||
LOW(GPIO_FPGA_NPROGRAM);
|
LOW(GPIO_FPGA_NPROGRAM);
|
||||||
SpinDelay(50);
|
SpinDelay(50);
|
||||||
|
@ -319,6 +337,13 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp_t
|
||||||
return;
|
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++) {
|
for (i = 0; i < FpgaImageLen; i++) {
|
||||||
int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||||
if (b < 0) {
|
if (b < 0) {
|
||||||
|
@ -396,6 +421,43 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
||||||
return result;
|
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
|
// Check which FPGA image is currently loaded (if any). If necessary
|
||||||
// decompress and load the correct (HF or LF) image to the FPGA
|
// decompress and load the correct (HF or LF) image to the FPGA
|
||||||
|
@ -408,6 +470,14 @@ void FpgaDownloadAndGo(int bitstream_version) {
|
||||||
return;
|
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 waiting time extension request as this will take a while
|
||||||
send_wtx(1500);
|
send_wtx(1500);
|
||||||
|
|
||||||
|
@ -431,6 +501,12 @@ void FpgaDownloadAndGo(int bitstream_version) {
|
||||||
downloaded_bitstream = 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
|
// turn off antenna
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
|
||||||
|
|
|
@ -1972,11 +1972,7 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
||||||
ADC_MODE_STARTUP_TIME(1) |
|
ADC_MODE_STARTUP_TIME(1) |
|
||||||
ADC_MODE_SAMPLE_HOLD_TIME(15);
|
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);
|
AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF);
|
||||||
#endif
|
|
||||||
|
|
||||||
// start ADC
|
// start ADC
|
||||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||||
|
@ -2003,35 +1999,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
||||||
++check;
|
++check;
|
||||||
|
|
||||||
// test if the field exists
|
// 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)) {
|
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) {
|
||||||
|
|
||||||
analogCnt++;
|
analogCnt++;
|
||||||
|
@ -2059,7 +2026,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
||||||
analogAVG = 0;
|
analogAVG = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// receive and test the miller decoding
|
// receive and test the miller decoding
|
||||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||||
|
|
|
@ -772,11 +772,7 @@ void SimulateIso14443bTag(uint8_t *pupi) {
|
||||||
// find reader field
|
// find reader field
|
||||||
if (cardSTATE == SIM_NOFIELD) {
|
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;
|
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
if (vHf > MF_MINFIELDV) {
|
if (vHf > MF_MINFIELDV) {
|
||||||
cardSTATE = SIM_IDLE;
|
cardSTATE = SIM_IDLE;
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
@ -976,11 +972,7 @@ void Simulate_iso14443b_srx_tag(uint8_t *uid) {
|
||||||
// find reader field
|
// find reader field
|
||||||
if (cardSTATE == SIM_NOFIELD) {
|
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;
|
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
if (vHf > MF_MINFIELDV) {
|
if (vHf > MF_MINFIELDV) {
|
||||||
cardSTATE = SIM_IDLE;
|
cardSTATE = SIM_IDLE;
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
|
@ -1727,11 +1727,7 @@ void SimTagIso15693(uint8_t *uid) {
|
||||||
// find reader field
|
// find reader field
|
||||||
if (chip_state == NO_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;
|
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
if (vHf > MF_MINFIELDV) {
|
if (vHf > MF_MINFIELDV) {
|
||||||
chip_state = IDLE;
|
chip_state = IDLE;
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
|
@ -543,11 +543,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
||||||
// find reader field
|
// find reader field
|
||||||
if (cardSTATE == MFEMUL_NOFIELD) {
|
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;
|
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||||
#endif
|
|
||||||
|
|
||||||
if (vHf > MF_MINFIELDV) {
|
if (vHf > MF_MINFIELDV) {
|
||||||
cardSTATE_TO_IDLE();
|
cardSTATE_TO_IDLE();
|
||||||
|
|
|
@ -51,11 +51,7 @@ void ReadThinFilm(void) {
|
||||||
static uint16_t FpgaSendQueueDelay;
|
static uint16_t FpgaSendQueueDelay;
|
||||||
|
|
||||||
static uint16_t ReadReaderField(void) {
|
static uint16_t ReadReaderField(void) {
|
||||||
#if defined RDV4
|
|
||||||
return AvgAdc(ADC_CHAN_HF_RDV40);
|
|
||||||
#else
|
|
||||||
return AvgAdc(ADC_CHAN_HF);
|
return AvgAdc(ADC_CHAN_HF);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) {
|
static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ OBJDIR = obj
|
||||||
INCLUDE = -I../include -I../common_arm -I../common_fpga -I../common -I.
|
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
|
# 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
|
INCLUDES = ../include/proxmark3_arm.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/pm3_cmd.h
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ Known definitions:
|
||||||
+--------------------------------------------+
|
+--------------------------------------------+
|
||||||
| PM3GENERIC | Proxmark3 generic target |
|
| PM3GENERIC | Proxmark3 generic target |
|
||||||
+--------------------------------------------+
|
+--------------------------------------------+
|
||||||
|
| PM3ICOPYX | iCopy-X with XC3S100E |
|
||||||
|
+--------------------------------------------+
|
||||||
|
|
||||||
+============================================+
|
+============================================+
|
||||||
| PLATFORM_EXTRAS | DESCRIPTION |
|
| PLATFORM_EXTRAS | DESCRIPTION |
|
||||||
|
@ -71,15 +73,23 @@ $(HELP_DEFINITIONS)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
PLTNAME = Unknown Platform
|
PLTNAME = Unknown Platform
|
||||||
|
PLATFORM_FPGA = fpga-undefined
|
||||||
|
|
||||||
ifeq ($(PLATFORM),PM3RDV4)
|
ifeq ($(PLATFORM),PM3RDV4)
|
||||||
PLATFORM_DEFS = -DWITH_SMARTCARD -DWITH_FLASH -DRDV4
|
PLATFORM_DEFS = -DWITH_SMARTCARD -DWITH_FLASH -DRDV4
|
||||||
PLTNAME = Proxmark3 RDV4
|
PLTNAME = Proxmark3 RDV4
|
||||||
|
PLATFORM_FPGA = xc2s30
|
||||||
else ifeq ($(PLATFORM),PM3OTHER)
|
else ifeq ($(PLATFORM),PM3OTHER)
|
||||||
$(warning PLATFORM=PM3OTHER is deprecated, please use PLATFORM=PM3GENERIC)
|
$(warning PLATFORM=PM3OTHER is deprecated, please use PLATFORM=PM3GENERIC)
|
||||||
PLTNAME = Proxmark3 generic target
|
PLTNAME = Proxmark3 generic target
|
||||||
|
PLATFORM_FPGA = xc2s30
|
||||||
else ifeq ($(PLATFORM),PM3GENERIC)
|
else ifeq ($(PLATFORM),PM3GENERIC)
|
||||||
PLTNAME = Proxmark3 generic target
|
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
|
else
|
||||||
$(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS))
|
$(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS))
|
||||||
|
@ -204,6 +214,7 @@ export PLATFORM_EXTRAS
|
||||||
export PLATFORM_EXTRAS_INFO
|
export PLATFORM_EXTRAS_INFO
|
||||||
export PLATFORM_SIZE
|
export PLATFORM_SIZE
|
||||||
export PLTNAME
|
export PLTNAME
|
||||||
|
export PLATFORM_FPGA
|
||||||
export PLATFORM_DEFS
|
export PLATFORM_DEFS
|
||||||
export PLATFORM_DEFS_INFO
|
export PLATFORM_DEFS_INFO
|
||||||
export PLATFORM_DEFS_INFO_STANDALONE
|
export PLATFORM_DEFS_INFO_STANDALONE
|
||||||
|
@ -212,6 +223,7 @@ export PLATFORM_CHANGED
|
||||||
$(info ===================================================================)
|
$(info ===================================================================)
|
||||||
$(info Platform name: $(PLTNAME))
|
$(info Platform name: $(PLTNAME))
|
||||||
$(info PLATFORM: $(PLATFORM))
|
$(info PLATFORM: $(PLATFORM))
|
||||||
|
$(info PLATFORM_FPGA: $(PLATFORM_FPGA))
|
||||||
$(info PLATFORM_SIZE: $(PLATFORM_SIZE))
|
$(info PLATFORM_SIZE: $(PLATFORM_SIZE))
|
||||||
$(info Platform extras: $(PLATFORM_EXTRAS_INFO))
|
$(info Platform extras: $(PLATFORM_EXTRAS_INFO))
|
||||||
$(info Included options: $(PLATFORM_DEFS_INFO))
|
$(info Included options: $(PLATFORM_DEFS_INFO))
|
||||||
|
|
|
@ -12,7 +12,11 @@
|
||||||
|
|
||||||
#define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(bitparse_fixed_header)
|
#define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(bitparse_fixed_header)
|
||||||
#define FPGA_INTERLEAVE_SIZE 288
|
#define FPGA_INTERLEAVE_SIZE 288
|
||||||
|
#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
|
#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_RING_BUFFER_BYTES (1024 * 39)
|
||||||
#define FPGA_TRACE_SIZE 3072
|
#define FPGA_TRACE_SIZE 3072
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ At the moment both are maintained because they don't perfectly overlap yet.
|
||||||
|
|
||||||
| Feature | Makefile | Remarks |
|
| Feature | Makefile | Remarks |
|
||||||
|-----|---|---|
|
|-----|---|---|
|
||||||
| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC` |
|
| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX` |
|
||||||
| Platform size | `PLATFORM_SIZE=` | values: `256`, `512` |
|
| Platform size | `PLATFORM_SIZE=` | values: `256`, `512` |
|
||||||
| Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` |
|
| 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 |
|
| Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list |
|
||||||
|
|
|
@ -45,6 +45,7 @@ Here are the supported values you can assign to `PLATFORM` in `Makefile.platform
|
||||||
|-----------------|--------------------------|
|
|-----------------|--------------------------|
|
||||||
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
| PM3RDV4 (def) | Proxmark3 RDV4 |
|
||||||
| PM3GENERIC | Proxmark3 generic target |
|
| PM3GENERIC | Proxmark3 generic target |
|
||||||
|
| PM3ICOPYX | iCopy-X with XC3S100E |
|
||||||
|
|
||||||
By default `PLATFORM=PM3RDV4`.
|
By default `PLATFORM=PM3RDV4`.
|
||||||
|
|
||||||
|
|
68
fpga-xc3s100e/.gitignore
vendored
Normal file
68
fpga-xc3s100e/.gitignore
vendored
Normal file
|
@ -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/
|
674
fpga-xc3s100e/LICENSE
Normal file
674
fpga-xc3s100e/LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
25
fpga-xc3s100e/clk_divider.v
Normal file
25
fpga-xc3s100e/clk_divider.v
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
module clk_divider(input clk, input [7:0] divisor, output [7:0] div_cnt, output div_clk);
|
||||||
|
|
||||||
|
reg [7:0] div_cnt_ = 0;
|
||||||
|
reg div_clk_;
|
||||||
|
assign div_cnt = div_cnt_;
|
||||||
|
assign div_clk = div_clk_;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
if(div_cnt == divisor) begin
|
||||||
|
div_cnt_ <= 8'd0;
|
||||||
|
div_clk_ = !div_clk_;
|
||||||
|
end else
|
||||||
|
div_cnt_ <= div_cnt_ + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
9
fpga-xc3s100e/compile.sh
Executable file
9
fpga-xc3s100e/compile.sh
Executable file
|
@ -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 .
|
||||||
|
)
|
49
fpga-xc3s100e/define.v
Normal file
49
fpga-xc3s100e/define.v
Normal file
|
@ -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
|
56
fpga-xc3s100e/fpga.ucf
Normal file
56
fpga-xc3s100e/fpga.ucf
Normal file
|
@ -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
|
81
fpga-xc3s100e/fpga_allinone.v
Normal file
81
fpga-xc3s100e/fpga_allinone.v
Normal file
|
@ -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
|
193
fpga-xc3s100e/fpga_hfmod.v
Normal file
193
fpga-xc3s100e/fpga_hfmod.v
Normal file
|
@ -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 <izsh at fail0verflow.com>, 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
|
236
fpga-xc3s100e/fpga_lfmod.v
Normal file
236
fpga-xc3s100e/fpga_lfmod.v
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Jonathan Westhues, March 2006
|
||||||
|
// iZsh <izsh at fail0verflow.com>, June 2014
|
||||||
|
// Piwi, Feb 2019
|
||||||
|
// Anon, 2019
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h
|
||||||
|
// Note: the definitions here are without shifts
|
||||||
|
|
||||||
|
// Commands:
|
||||||
|
`define FPGA_CMD_SET_CONFREG 1
|
||||||
|
`define FPGA_CMD_SET_DIVISOR 2
|
||||||
|
`define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD 3
|
||||||
|
|
||||||
|
// Major modes:
|
||||||
|
`define FPGA_MAJOR_MODE_LF_READER 0
|
||||||
|
`define FPGA_MAJOR_MODE_LF_EDGE_DETECT 1
|
||||||
|
`define FPGA_MAJOR_MODE_LF_PASSTHRU 2
|
||||||
|
`define FPGA_MAJOR_MODE_LF_ADC 3
|
||||||
|
|
||||||
|
// Options for LF_READER
|
||||||
|
`define FPGA_LF_ADC_READER_FIELD 1
|
||||||
|
|
||||||
|
// Options for LF_EDGE_DETECT
|
||||||
|
`define FPGA_LF_EDGE_DETECT_READER_FIELD 1
|
||||||
|
`define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 2
|
||||||
|
|
||||||
|
//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
|
368
fpga-xc3s100e/hi_flite.v
Normal file
368
fpga-xc3s100e/hi_flite.v
Normal file
|
@ -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<curminthres) //falling edge
|
||||||
|
begin
|
||||||
|
case (state)
|
||||||
|
0: begin
|
||||||
|
curmin <= adc_d<`imin? adc_d :`imin;
|
||||||
|
state <= 1;
|
||||||
|
end
|
||||||
|
1: begin
|
||||||
|
if (adc_d<curmin)
|
||||||
|
curmin <= adc_d;
|
||||||
|
end
|
||||||
|
2: begin
|
||||||
|
curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
|
||||||
|
curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
|
||||||
|
curmin <= adc_d < `imin ? adc_d : `imin;
|
||||||
|
state <= 1;
|
||||||
|
end
|
||||||
|
default:
|
||||||
|
begin
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
after_hysteresis <= 0;
|
||||||
|
if (~try_sync ) //begin modulation, lower edge...
|
||||||
|
begin
|
||||||
|
try_sync <= 1;
|
||||||
|
fccount <= 1;
|
||||||
|
did_sync <= 0;
|
||||||
|
curbit <= 0;
|
||||||
|
mid <= 8'd127;
|
||||||
|
tsinceedge <= 0;
|
||||||
|
prv <= 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
tsinceedge <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else //stable state, low or high
|
||||||
|
begin
|
||||||
|
curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4));
|
||||||
|
curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4));
|
||||||
|
state <= 0;
|
||||||
|
|
||||||
|
if (try_sync )
|
||||||
|
begin
|
||||||
|
if (tsinceedge >= (128))
|
||||||
|
begin
|
||||||
|
//we might need to start counting... assuming ARM wants to reply to the frame.
|
||||||
|
bit_counts <= 1;// i think? 128 is about 2 bits passed... but 1 also works
|
||||||
|
try_sync <= 0;
|
||||||
|
did_sync <= 0;//desync
|
||||||
|
curmin <= `imin; //reset envelope
|
||||||
|
curmax <= `imax;
|
||||||
|
curminthres <= `ithrmin;
|
||||||
|
curmaxthres <= `ithrmax;
|
||||||
|
prv <= 1;
|
||||||
|
tsinceedge <= 0;
|
||||||
|
after_hysteresis <= 1'b1;
|
||||||
|
curbit <= 0;
|
||||||
|
mid <= 8'd128;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tsinceedge <= (tsinceedge + 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (try_sync && tsinceedge < 128)
|
||||||
|
begin
|
||||||
|
//detect bits in their middle ssp sampling is in sync, so it would sample all bits in order
|
||||||
|
if (fccount == bithalf)
|
||||||
|
begin
|
||||||
|
if ((~did_sync) && ((prv == 1 && (mid > 128))||(prv == 0 && (mid <= 128))))
|
||||||
|
begin
|
||||||
|
//sync the Zero, and set curbit roperly
|
||||||
|
did_sync <= 1'b1;
|
||||||
|
zero <= ~prv;// 1-prv
|
||||||
|
curbit <= 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
curbit <= (mid > 128) ? (~zero) : zero;
|
||||||
|
|
||||||
|
prv <= (mid > 128) ? 1 : 0;
|
||||||
|
|
||||||
|
if (adc_d > curmaxthres)
|
||||||
|
mid <= 8'd129;
|
||||||
|
else if (adc_d < curminthres)
|
||||||
|
mid <= 8'd127;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (after_hysteresis)
|
||||||
|
begin
|
||||||
|
mid <= 8'd129;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
mid <= 8'd127;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (fccount==bitmlen)
|
||||||
|
begin
|
||||||
|
// fccount <= 0;
|
||||||
|
prv <= (mid > 128) ? 1 : 0;
|
||||||
|
mid <= 128;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// minimum-maximum calc
|
||||||
|
if(adc_d > curmaxthres)
|
||||||
|
mid <= mid + 1;
|
||||||
|
else if (adc_d < curminthres)
|
||||||
|
mid <= mid - 1;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (after_hysteresis)
|
||||||
|
begin
|
||||||
|
mid <= mid + 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
mid <= mid - 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
end
|
||||||
|
// sending <= 0;
|
||||||
|
end
|
||||||
|
//put modulation here to maintain the correct clock. Seems that some readers are sensitive to that
|
||||||
|
reg pwr_hi;
|
||||||
|
reg pwr_oe1;
|
||||||
|
reg pwr_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
|
164
fpga-xc3s100e/hi_get_trace.v
Normal file
164
fpga-xc3s100e/hi_get_trace.v
Normal file
|
@ -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
|
584
fpga-xc3s100e/hi_iso14443a.v
Normal file
584
fpga-xc3s100e/hi_iso14443a.v
Normal file
|
@ -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 â€<C3A2>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
|
335
fpga-xc3s100e/hi_reader.v
Normal file
335
fpga-xc3s100e/hi_reader.v
Normal file
|
@ -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
|
152
fpga-xc3s100e/hi_simulate.v
Normal file
152
fpga-xc3s100e/hi_simulate.v
Normal file
|
@ -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
|
50
fpga-xc3s100e/hi_sniffer.v
Normal file
50
fpga-xc3s100e/hi_sniffer.v
Normal file
|
@ -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
|
0
fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise
Normal file
0
fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.ise
Normal file
479
fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl
Normal file
479
fpga-xc3s100e/iseproj/fpga_hf/fpga_hf.tcl
Normal file
|
@ -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 <options>"
|
||||||
|
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/<language>/<simulator>"
|
||||||
|
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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
77
fpga-xc3s100e/lf_edge_detect.v
Normal file
77
fpga-xc3s100e/lf_edge_detect.v
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// input clk is 24MHz
|
||||||
|
`include "min_max_tracker.v"
|
||||||
|
|
||||||
|
module lf_edge_detect(input clk, input [7:0] adc_d, input [7:0] lf_ed_threshold,
|
||||||
|
output [7:0] max, output [7:0] min,
|
||||||
|
output [7:0] high_threshold, output [7:0] highz_threshold,
|
||||||
|
output [7:0] lowz_threshold, output [7:0] low_threshold,
|
||||||
|
output edge_state, output edge_toggle);
|
||||||
|
|
||||||
|
min_max_tracker tracker(clk, adc_d, lf_ed_threshold, min, max);
|
||||||
|
|
||||||
|
// auto-tune
|
||||||
|
assign high_threshold = (max + min) / 2 + (max - min) / 4;
|
||||||
|
assign highz_threshold = (max + min) / 2 + (max - min) / 8;
|
||||||
|
assign lowz_threshold = (max + min) / 2 - (max - min) / 8;
|
||||||
|
assign low_threshold = (max + min) / 2 - (max - min) / 4;
|
||||||
|
|
||||||
|
// heuristic to see if it makes sense to try to detect an edge
|
||||||
|
wire enabled =
|
||||||
|
(high_threshold > highz_threshold)
|
||||||
|
& (highz_threshold > lowz_threshold)
|
||||||
|
& (lowz_threshold > low_threshold)
|
||||||
|
& ((high_threshold - highz_threshold) > 8)
|
||||||
|
& ((highz_threshold - lowz_threshold) > 16)
|
||||||
|
& ((lowz_threshold - low_threshold) > 8);
|
||||||
|
|
||||||
|
// Toggle the output with hysteresis
|
||||||
|
// Set to high if the ADC value is above the threshold
|
||||||
|
// Set to low if the ADC value is below the threshold
|
||||||
|
reg is_high = 0;
|
||||||
|
reg is_low = 0;
|
||||||
|
reg is_zero = 0;
|
||||||
|
reg trigger_enabled = 1;
|
||||||
|
reg output_edge = 0;
|
||||||
|
reg output_state;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
is_high <= (adc_d >= high_threshold);
|
||||||
|
is_low <= (adc_d <= low_threshold);
|
||||||
|
is_zero <= ((adc_d > lowz_threshold) & (adc_d < highz_threshold));
|
||||||
|
end
|
||||||
|
|
||||||
|
// all edges detection
|
||||||
|
always @(posedge clk)
|
||||||
|
if (enabled) begin
|
||||||
|
// To enable detecting two consecutive peaks at the same level
|
||||||
|
// (low or high) we check whether or not we went back near 0 in-between.
|
||||||
|
// This extra check is necessary to prevent from noise artifacts
|
||||||
|
// around the threshold values.
|
||||||
|
if (trigger_enabled & (is_high | is_low)) begin
|
||||||
|
output_edge <= ~output_edge;
|
||||||
|
trigger_enabled <= 0;
|
||||||
|
end else
|
||||||
|
trigger_enabled <= trigger_enabled | is_zero;
|
||||||
|
end
|
||||||
|
|
||||||
|
// edge states
|
||||||
|
always @(posedge clk)
|
||||||
|
if (enabled) begin
|
||||||
|
if (is_high)
|
||||||
|
output_state <= 1'd1;
|
||||||
|
else if (is_low)
|
||||||
|
output_state <= 1'd0;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign edge_state = output_state;
|
||||||
|
assign edge_toggle = output_edge;
|
||||||
|
|
||||||
|
endmodule
|
91
fpga-xc3s100e/lo_adc.v
Normal file
91
fpga-xc3s100e/lo_adc.v
Normal file
|
@ -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
|
70
fpga-xc3s100e/lo_edge_detect.v
Normal file
70
fpga-xc3s100e/lo_edge_detect.v
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// There are two modes:
|
||||||
|
// - lf_ed_toggle_mode == 0: the output is set low (resp. high) when a low
|
||||||
|
// (resp. high) edge/peak is detected, with hysteresis
|
||||||
|
// - lf_ed_toggle_mode == 1: the output is toggling whenever an edge/peak
|
||||||
|
// is detected.
|
||||||
|
// That way you can detect two consecutive edges/peaks at the same level (L/H)
|
||||||
|
//
|
||||||
|
// Output:
|
||||||
|
// - ssp_frame (wired to TIOA1 on the arm) for the edge detection/state
|
||||||
|
// - ssp_clk: cross_lo
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
29
fpga-xc3s100e/lo_passthru.v
Normal file
29
fpga-xc3s100e/lo_passthru.v
Normal file
|
@ -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 <izsh at fail0verflow.com>, June 2014
|
||||||
|
|
||||||
|
module lo_passthru(
|
||||||
|
input pck_divclk,
|
||||||
|
output pwr_lo, output pwr_hi,
|
||||||
|
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||||
|
output adc_clk,
|
||||||
|
output ssp_din, input ssp_dout,
|
||||||
|
input cross_lo,
|
||||||
|
output dbg
|
||||||
|
);
|
||||||
|
|
||||||
|
// the antenna is modulated when ssp_dout = 1, when 0 the
|
||||||
|
// antenna drivers stop modulating and go into listen mode
|
||||||
|
assign pwr_oe3 = 1'b0;
|
||||||
|
assign pwr_oe1 = ssp_dout;
|
||||||
|
assign pwr_oe2 = ssp_dout;
|
||||||
|
assign pwr_oe4 = ssp_dout;
|
||||||
|
assign pwr_lo = pck_divclk && ssp_dout;
|
||||||
|
assign pwr_hi = 1'b0;
|
||||||
|
assign adc_clk = 1'b0;
|
||||||
|
assign ssp_din = cross_lo;
|
||||||
|
assign dbg = cross_lo;
|
||||||
|
|
||||||
|
endmodule
|
74
fpga-xc3s100e/lo_read.v
Normal file
74
fpga-xc3s100e/lo_read.v
Normal file
|
@ -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 <izsh at fail0verflow.com>, June 2014
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module lo_read(
|
||||||
|
input pck0, input [7:0] pck_cnt, input pck_divclk,
|
||||||
|
output pwr_lo, output pwr_hi,
|
||||||
|
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
|
||||||
|
input [7:0] adc_d, output adc_clk,
|
||||||
|
output ssp_frame, output ssp_din, output ssp_clk,
|
||||||
|
output dbg,
|
||||||
|
input lf_field
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [7:0] to_arm_shiftreg;
|
||||||
|
|
||||||
|
// this task also runs at pck0 frequency (24MHz) and is used to serialize
|
||||||
|
// the ADC output which is then clocked into the ARM SSP.
|
||||||
|
|
||||||
|
// because pck_divclk always transitions when pck_cnt = 0 we use the
|
||||||
|
// pck_div counter to sync our other signals off it
|
||||||
|
// we read the ADC value when pck_cnt=7 and shift it out on counts 8..15
|
||||||
|
always @(posedge pck0)
|
||||||
|
begin
|
||||||
|
if((pck_cnt == 8'd7) && !pck_divclk)
|
||||||
|
to_arm_shiftreg <= adc_d;
|
||||||
|
else begin
|
||||||
|
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
|
||||||
|
// simulation showed a glitch occuring due to the LSB of the shifter
|
||||||
|
// not being set as we shift bits out
|
||||||
|
// this ensures the ssp_din remains low after a transfer and suppresses
|
||||||
|
// the glitch that would occur when the last data shifted out ended in
|
||||||
|
// a 1 bit and the next data shifted out started with a 0 bit
|
||||||
|
to_arm_shiftreg[0] <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// ADC samples on falling edge of adc_clk, data available on the rising edge
|
||||||
|
|
||||||
|
// example of ssp transfer of binary value 1100101
|
||||||
|
// start of transfer is indicated by the rise of the ssp_frame signal
|
||||||
|
// ssp_din changes on the rising edge of the ssp_clk clock and is clocked into
|
||||||
|
// the ARM by the falling edge of ssp_clk
|
||||||
|
// _______________________________
|
||||||
|
// ssp_frame__| |__
|
||||||
|
// _______ ___ ___
|
||||||
|
// ssp_din __| |_______| |___| |______
|
||||||
|
// _ _ _ _ _ _ _ _ _ _
|
||||||
|
// ssp_clk |_| |_| |_| |_| |_| |_| |_| |_| |_| |_
|
||||||
|
|
||||||
|
// serialized SSP data is gated by ant_lo to suppress unwanted signal
|
||||||
|
assign ssp_din = to_arm_shiftreg[7] && !pck_divclk;
|
||||||
|
// SSP clock always runs at 24MHz
|
||||||
|
assign ssp_clk = pck0;
|
||||||
|
// SSP frame is gated by ant_lo and goes high when pck_divider=8..15
|
||||||
|
assign ssp_frame = (pck_cnt[7:3] == 5'd1) && !pck_divclk;
|
||||||
|
// unused signals tied low
|
||||||
|
assign pwr_hi = 1'b0;
|
||||||
|
assign pwr_oe1 = 1'b0;
|
||||||
|
assign pwr_oe2 = 1'b0;
|
||||||
|
assign pwr_oe3 = 1'b0;
|
||||||
|
assign pwr_oe4 = 1'b0;
|
||||||
|
// this is the antenna driver signal
|
||||||
|
assign pwr_lo = lf_field & pck_divclk;
|
||||||
|
// ADC clock out of phase with antenna driver
|
||||||
|
assign adc_clk = ~pck_divclk;
|
||||||
|
// ADC clock also routed to debug pin
|
||||||
|
assign dbg = adc_clk;
|
||||||
|
endmodule
|
81
fpga-xc3s100e/lp20khz_1MSa_iir_filter.v
Normal file
81
fpga-xc3s100e/lp20khz_1MSa_iir_filter.v
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Butterworth low pass IIR filter
|
||||||
|
// input: 8bit ADC signal, 1MS/s
|
||||||
|
// output: 8bit value, Fc=20khz
|
||||||
|
//
|
||||||
|
// coef: (using http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
|
||||||
|
// Recurrence relation:
|
||||||
|
// y[n] = ( 1 * x[n- 2])
|
||||||
|
// + ( 2 * x[n- 1])
|
||||||
|
// + ( 1 * x[n- 0])
|
||||||
|
|
||||||
|
// + ( -0.8371816513 * y[n- 2])
|
||||||
|
// + ( 1.8226949252 * y[n- 1])
|
||||||
|
//
|
||||||
|
// therefore:
|
||||||
|
// a = [1,2,1]
|
||||||
|
// b = [-0.8371816513, 1.8226949252]
|
||||||
|
// b is approximated to b = [-0xd6/0x100, 0x1d3 / 0x100] (for optimization)
|
||||||
|
// gain = 2.761139367e2
|
||||||
|
//
|
||||||
|
// See details about its design see
|
||||||
|
// https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html
|
||||||
|
module lp20khz_1MSa_iir_filter(input clk, input [7:0] adc_d, output rdy, output [7:0] out);
|
||||||
|
|
||||||
|
// clk is 24MHz, the IIR filter is designed for 1MS/s
|
||||||
|
// hence we need to divide it by 24
|
||||||
|
// using a shift register takes less area than a counter
|
||||||
|
reg [23:0] cnt = 1;
|
||||||
|
assign rdy = cnt[0];
|
||||||
|
always @(posedge clk)
|
||||||
|
cnt <= {cnt[22:0], cnt[23]};
|
||||||
|
|
||||||
|
reg [7:0] x0 = 0;
|
||||||
|
reg [7:0] x1 = 0;
|
||||||
|
reg [16:0] y0 = 0;
|
||||||
|
reg [16:0] y1 = 0;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
if (rdy)
|
||||||
|
begin
|
||||||
|
x0 <= x1;
|
||||||
|
x1 <= adc_d;
|
||||||
|
y0 <= y1;
|
||||||
|
y1 <=
|
||||||
|
// center the signal:
|
||||||
|
// input range is [0; 255]
|
||||||
|
// We want "128" to be at the center of the 17bit register
|
||||||
|
// (128+z)*gain = 17bit center
|
||||||
|
// z = (1<<16)/gain - 128 = 109
|
||||||
|
// We could use 9bit x registers for that, but that would be
|
||||||
|
// a waste, let's just add the constant during the computation
|
||||||
|
// (x0+109) + 2*(x1+109) + (x2+109) = x0 + 2*x1 + x2 + 436
|
||||||
|
x0 + {x1, 1'b0} + adc_d + 436
|
||||||
|
// we want "- y0 * 0xd6 / 0x100" using only shift and add
|
||||||
|
// 0xd6 == 0b11010110
|
||||||
|
// so *0xd6/0x100 is equivalent to
|
||||||
|
// ((x << 1) + (x << 2) + (x << 4) + (x << 6) + (x << 7)) >> 8
|
||||||
|
// which is also equivalent to
|
||||||
|
// (x >> 7) + (x >> 6) + (x >> 4) + (x >> 2) + (x >> 1)
|
||||||
|
- ((y0 >> 7) + (y0 >> 6) + (y0 >> 4) + (y0 >> 2) + (y0 >> 1)) // - y0 * 0xd6 / 0x100
|
||||||
|
// we want "+ y1 * 0x1d3 / 0x100"
|
||||||
|
// 0x1d3 == 0b111010011
|
||||||
|
// so this is equivalent to
|
||||||
|
// ((x << 0) + (x << 1) + (x << 4) + (x << 6) + (x << 7) + (x << 8)) >> 8
|
||||||
|
// which is also equivalent to
|
||||||
|
// (x >> 8) + (x >> 7) + (x >> 4) + (x >> 2) + (x >> 1) + (x >> 0)
|
||||||
|
+ ((y1 >> 8) + (y1 >> 7) + (y1 >> 4) + (y1 >> 2) + (y1 >> 1) + y1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// output: reduce to 8bit
|
||||||
|
assign out = y1[16:9];
|
||||||
|
|
||||||
|
endmodule
|
65
fpga-xc3s100e/min_max_tracker.v
Normal file
65
fpga-xc3s100e/min_max_tracker.v
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// track min and max peak values (envelope follower)
|
||||||
|
//
|
||||||
|
// NB: the min value (resp. max value) is updated only when the next high peak
|
||||||
|
// (resp. low peak) is reached/detected, since you can't know it isn't a
|
||||||
|
// local minima (resp. maxima) until then.
|
||||||
|
// This also means the peaks are detected with an unpredictable delay.
|
||||||
|
// This algorithm therefore can't be used directly for realtime peak detections,
|
||||||
|
// but it can be used as a simple envelope follower.
|
||||||
|
module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold,
|
||||||
|
output [7:0] min, output [7:0] max);
|
||||||
|
|
||||||
|
reg [7:0] min_val = 255;
|
||||||
|
reg [7:0] max_val = 0;
|
||||||
|
reg [7:0] cur_min_val = 255;
|
||||||
|
reg [7:0] cur_max_val = 0;
|
||||||
|
reg [1:0] state = 0;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
begin
|
||||||
|
case (state)
|
||||||
|
0: // initialize
|
||||||
|
begin
|
||||||
|
if (cur_max_val >= ({1'b0, adc_d} + threshold))
|
||||||
|
state <= 2;
|
||||||
|
else if (adc_d >= ({1'b0, cur_min_val} + threshold))
|
||||||
|
state <= 1;
|
||||||
|
if (cur_max_val <= adc_d)
|
||||||
|
cur_max_val <= adc_d;
|
||||||
|
else if (adc_d <= cur_min_val)
|
||||||
|
cur_min_val <= adc_d;
|
||||||
|
end
|
||||||
|
1: // high phase
|
||||||
|
begin
|
||||||
|
if (cur_max_val <= adc_d)
|
||||||
|
cur_max_val <= adc_d;
|
||||||
|
else if (({1'b0, adc_d} + threshold) <= cur_max_val) begin
|
||||||
|
state <= 2;
|
||||||
|
cur_min_val <= adc_d;
|
||||||
|
max_val <= cur_max_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
2: // low phase
|
||||||
|
begin
|
||||||
|
if (adc_d <= cur_min_val)
|
||||||
|
cur_min_val <= adc_d;
|
||||||
|
else if (adc_d >= ({1'b0, cur_min_val} + threshold)) begin
|
||||||
|
state <= 1;
|
||||||
|
cur_max_val <= adc_d;
|
||||||
|
min_val <= cur_min_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign min = min_val;
|
||||||
|
assign max = max_val;
|
||||||
|
|
||||||
|
endmodule
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue