From 7cc204bff881ce1d1833d8e93469f6bbba80c70e Mon Sep 17 00:00:00 2001 From: iZsh <izsh@fail0verflow.com> Date: Fri, 20 Jun 2014 01:02:59 +0200 Subject: [PATCH] THIS REQUIRES A BOOTROM UPDATE!! To save FPGA area, split the LF and HF bitstreams and load them on-demand. --- .gitignore | 6 +- armsrc/Makefile | 9 +- armsrc/appmain.c | 9 +- armsrc/apps.h | 28 ++- armsrc/fpgaloader.c | 45 +++- armsrc/hitag2.c | 3 + armsrc/iclass.c | 6 + armsrc/iso14443.c | 4 + armsrc/iso14443a.c | 1 + armsrc/iso15693.c | 5 + armsrc/ldscript | 3 +- armsrc/legicrf.c | 2 + armsrc/lfops.c | 12 + armsrc/mifarecmd.c | 506 ++++++++++++++++++++--------------------- client/Makefile | 6 +- common/ldscript.common | 4 +- fpga/Makefile | 40 ++-- fpga/clk_divider.v | 25 ++ fpga/fpga.bit | Bin 42172 -> 0 bytes fpga/fpga.v | 220 ------------------ fpga/fpga_hf.bit | Bin 0 -> 42175 bytes fpga/fpga_hf.v | 150 ++++++++++++ fpga/fpga_lf.bit | Bin 0 -> 42175 bytes fpga/fpga_lf.v | 125 ++++++++++ fpga/go.bat | 52 ++++- fpga/lo_edge_detect.v | 53 +---- fpga/lo_passthru.v | 44 +--- fpga/lo_read.v | 67 ++---- fpga/xst.scr | 1 - fpga/xst_hf.scr | 1 + fpga/xst_lf.scr | 1 + include/proxmark3.h | 4 + 32 files changed, 771 insertions(+), 661 deletions(-) create mode 100644 fpga/clk_divider.v delete mode 100644 fpga/fpga.bit delete mode 100644 fpga/fpga.v create mode 100644 fpga/fpga_hf.bit create mode 100644 fpga/fpga_hf.v create mode 100644 fpga/fpga_lf.bit create mode 100644 fpga/fpga_lf.v delete mode 100644 fpga/xst.scr create mode 100644 fpga/xst_hf.scr create mode 100644 fpga/xst_lf.scr diff --git a/.gitignore b/.gitignore index 3f6347a0..3b258b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,11 +19,13 @@ lua luac fpga/* -!fpga/fpga.bit +!fpga/fpga_lf.bit +!fpga/fpga_hf.bit !fpga/*.v !fpga/Makefile !fpga/fpga.ucf -!fpga/xst.scr +!fpga/xst_lf.scr +!fpga/xst_hf.scr !fpga/go.bat !fpga/sim.tcl diff --git a/armsrc/Makefile b/armsrc/Makefile index 2e5350bb..e10c1001 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -52,10 +52,13 @@ OBJS = $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19 all: $(OBJS) -$(OBJDIR)/fpga.o: fpga.bit - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_bit_start=_binary_fpga_bit_start --redefine-sym _binary____fpga_fpga_bit_end=_binary_fpga_bit_end --prefix-sections=fpga_bit $^ $@ +$(OBJDIR)/fpga_lf.o: fpga_lf.bit + $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_lf_bit_start=_binary_fpga_lf_bit_start --redefine-sym _binary____fpga_fpga_lf_bit_end=_binary_fpga_lf_bit_end --prefix-sections=fpga_lf_bit $^ $@ -$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga.o $(THUMBOBJ) $(ARMOBJ) +$(OBJDIR)/fpga_hf.o: fpga_hf.bit + $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_hf_bit_start=_binary_fpga_hf_bit_start --redefine-sym _binary____fpga_fpga_hf_bit_end=_binary_fpga_hf_bit_end --prefix-sections=fpga_hf_bit $^ $@ + +$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_lf.o $(OBJDIR)/fpga_hf.o $(THUMBOBJ) $(ARMOBJ) $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) $(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b6c32200..b7bc87e7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -214,6 +214,7 @@ void MeasureAntennaTuning(void) * ( hopefully around 95 if it is tuned to 125kHz!) */ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); for (i=255; i>19; i--) { WDT_HIT(); @@ -236,6 +237,7 @@ void MeasureAntennaTuning(void) LED_A_ON(); // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(20); // Vref = 3300mV, and an 10:1 voltage divider on the input @@ -264,6 +266,7 @@ void MeasureAntennaTuningHf(void) for (;;) { // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(20); // Vref = 3300mV, and an 10:1 voltage divider on the input @@ -286,6 +289,7 @@ void SimulateTagHfListen(void) // We're using this mode just so that I can test it out; the simulated // tag mode would work just as well and be simpler. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); // We need to listen to the high-frequency, peak-detected path. @@ -365,6 +369,7 @@ void SendVersion(void) void SamyRun() { DbpString("Stand-alone mode! No PC necessary."); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // 3 possible options? no just 2 for now #define OPTS 2 @@ -923,6 +928,7 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_SET_LF_DIVISOR: + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]); break; @@ -1017,7 +1023,8 @@ void __attribute__((noreturn)) AppMain(void) AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; // Load the FPGA image, which we have stored in our flash. - FpgaDownloadAndGo(); + // (the HF version by default) + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); StartTickCount(); diff --git a/armsrc/apps.h b/armsrc/apps.h index 92228b8d..76d1247a 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -67,7 +67,8 @@ extern uint32_t BigBuf[]; /// fpga.h void FpgaSendCommand(uint16_t cmd, uint16_t v); void FpgaWriteConfWord(uint8_t v); -void FpgaDownloadAndGo(void); +void FpgaDownloadAndGo(int bitstream_version); +int FpgaGatherBitstreamVersion(); void FpgaGatherVersion(char *dst, int len); void FpgaSetupSsc(void); void SetupSpi(int mode); @@ -77,17 +78,20 @@ bool FpgaSetupSscDma(uint8_t *buf, int len); void SetAdcMuxFor(uint32_t whichGpio); // Definitions for the FPGA commands. -#define FPGA_CMD_SET_CONFREG (1<<12) -#define FPGA_CMD_SET_DIVISOR (2<<12) +#define FPGA_CMD_SET_CONFREG (1<<12) +#define FPGA_CMD_SET_DIVISOR (2<<12) // Definitions for the FPGA configuration word. -#define FPGA_MAJOR_MODE_LF_READER (0<<5) +// LF +#define FPGA_MAJOR_MODE_LF_READER (0<<5) #define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) -#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5) -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5) -#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5) -#define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5) -#define FPGA_MAJOR_MODE_OFF (7<<5) +#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) +// HF +#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) +#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) +#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) +// BOTH +#define FPGA_MAJOR_MODE_OFF (7<<5) // Options for LF_EDGE_DETECT #define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) // Options for the HF reader, tx to tag @@ -95,14 +99,14 @@ void SetAdcMuxFor(uint32_t whichGpio); // Options for the HF reader, correlating against rx from tag #define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) #define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) -#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) +#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) #define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) #define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) #define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) // Options for ISO14443A -#define FPGA_HF_ISO14443A_SNIFFER (0<<0) +#define FPGA_HF_ISO14443A_SNIFFER (0<<0) #define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) #define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) #define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index d63310a3..2f996bc5 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -252,7 +252,7 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers static char *bitparse_headers_start; static char *bitparse_bitstream_end; -static int bitparse_initialized; +static int bitparse_initialized = 0; /* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01 * After that the format is 1 byte section type (ASCII character), 2 byte length @@ -322,12 +322,28 @@ int bitparse_find_section(char section_name, char **section_start, unsigned int // Find out which FPGA image format is stored in flash, then call DownloadFPGA // with the right parameters to download the image //----------------------------------------------------------------------------- -extern char _binary_fpga_bit_start, _binary_fpga_bit_end; -void FpgaDownloadAndGo(void) +extern char _binary_fpga_lf_bit_start, _binary_fpga_lf_bit_end; +extern char _binary_fpga_hf_bit_start, _binary_fpga_hf_bit_end; +void FpgaDownloadAndGo(int bitstream_version) { + void *bit_start; + void *bit_end; + + // check whether or not the bitstream is already loaded + if (FpgaGatherBitstreamVersion() == bitstream_version) + return; + + if (bitstream_version == FPGA_BITSTREAM_LF) { + bit_start = &_binary_fpga_lf_bit_start; + bit_end = &_binary_fpga_lf_bit_end; + } else if (bitstream_version == FPGA_BITSTREAM_HF) { + bit_start = &_binary_fpga_hf_bit_start; + bit_end = &_binary_fpga_hf_bit_end; + } else + return; /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start */ - if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) { + if(bitparse_init(bit_start, bit_end)) { /* Successfully initialized the .bit parser. Find the 'e' section and * send its contents to the FPGA. */ @@ -351,6 +367,17 @@ void FpgaDownloadAndGo(void) DownloadFPGA((char*)0x102000, 10524*4, 1); } +int FpgaGatherBitstreamVersion() +{ + char temp[256]; + FpgaGatherVersion(temp, sizeof (temp)); + if (!memcmp("LF", temp, 2)) + return FPGA_BITSTREAM_LF; + else if (!memcmp("HF", temp, 2)) + return FPGA_BITSTREAM_HF; + return FPGA_BITSTREAM_ERR; +} + void FpgaGatherVersion(char *dst, int len) { char *fpga_info; @@ -359,13 +386,15 @@ void FpgaGatherVersion(char *dst, int len) if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) { strncat(dst, "FPGA image: legacy image without version information", len-1); } else { - strncat(dst, "FPGA image built", len-1); /* USB packets only have 48 bytes data payload, so be terse */ -#if 0 if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { - strncat(dst, " from ", len-1); - strncat(dst, fpga_info, len-1); + if (!memcmp("fpga_lf", fpga_info, 7)) + strncat(dst, "LF ", len-1); + else if (!memcmp("fpga_hf", fpga_info, 7)) + strncat(dst, "HF ", len-1); } + strncat(dst, "FPGA image built", len-1); +#if 0 if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { strncat(dst, " for ", len-1); strncat(dst, fpga_info, len-1); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 1a0e9b56..9181a62e 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -743,6 +743,7 @@ void SnoopHitag(uint32_t type) { // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); @@ -966,6 +967,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); @@ -1124,6 +1126,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { bool bStop; bool bQuitTraceFull = false; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Reset the return status bSuccessful = false; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 8d65b523..9c5e8b2b 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -689,6 +689,8 @@ void RAMFUNC SnoopIClass(void) // into trace, along with its length and other annotations. //uint8_t *trace = (uint8_t *)BigBuf; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // reset traceLen to 0 iso14a_set_tracing(TRUE); iso14a_clear_trace(); @@ -995,6 +997,8 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain) { uint8_t simType = arg0; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Enable and clear the trace tracing = TRUE; traceLen = 0; @@ -1426,6 +1430,8 @@ void ReaderIClass(uint8_t arg0) { uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Reset trace buffer memset(trace, 0x44, RECV_CMD_OFFSET); traceLen = 0; diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c index 5e8eddd2..7a445bcb 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443.c @@ -350,6 +350,7 @@ void SimulateIso14443Tag(void) int cmdsRecvd = 0; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); memset(receivedCmd, 0x44, 400); CodeIso14443bAsTag(response1, sizeof(response1)); @@ -867,6 +868,7 @@ void ReadSTMemoryIso14443(uint32_t dwLast) { uint8_t i = 0x00; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Make sure that we start from off, since the tags are stateful; // confusing things will happen if we don't reset them between reads. LED_D_OFF(); @@ -1011,6 +1013,7 @@ void RAMFUNC SnoopIso14443(void) // response from the tag. int triggered = TRUE; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // The command (reader -> tag) that we're working on receiving. uint8_t *receivedCmd = (uint8_t *)(BigBuf) + DEMOD_TRACE_SIZE; // The response (tag -> reader) that we're working on receiving. @@ -1196,6 +1199,7 @@ done: void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[]) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); if(!powerfield) { // Make sure that we start from off, since the tags are stateful; diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 9afe0788..099e1d68 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1763,6 +1763,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u } void iso14443a_setup(uint8_t fpga_minor_mode) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Set up the synchronous serial port FpgaSetupSsc(); // connect Demodulated Signal to ADC: diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 63e72c14..ed7beb6f 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -606,6 +606,7 @@ void AcquireRawAdcSamplesIso15693(void) int8_t prev = 0; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BuildIdentifyRequest(); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -687,6 +688,7 @@ void RecordRawAdcSamplesIso15693(void) int8_t prev = 0; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Setup SSC FpgaSetupSsc(); @@ -753,6 +755,7 @@ void Iso15693InitReader() { LED_C_OFF(); LED_D_OFF(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Setup SSC // FpgaSetupSsc(); @@ -1015,6 +1018,7 @@ void ReaderIso15693(uint32_t parameter) // Blank arrays memset(BigBuf + 3660, 0, 300); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Setup SSC FpgaSetupSsc(); @@ -1165,6 +1169,7 @@ void SimTagIso15693(uint32_t parameter) // Blank arrays memset(answer1, 0, 100); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Setup SSC FpgaSetupSsc(); diff --git a/armsrc/ldscript b/armsrc/ldscript index dcb04bf0..d0be3b6a 100644 --- a/armsrc/ldscript +++ b/armsrc/ldscript @@ -21,7 +21,8 @@ ENTRY(Vector) SECTIONS { .fpgaimage : { - *(fpga_bit.data) + *(fpga_lf_bit.data) + *(fpga_hf_bit.data) } >fpgaimage :fpgaimage .start : { diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index f2eb680b..3fbdf5cb 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -310,6 +310,7 @@ static uint32_t perform_setup_phase_rwd(int iv) } static void LegicCommonInit(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); @@ -687,6 +688,7 @@ void LegicRfSimulate(int phase, int frame, int reqresp) legic_frame_drift = frame; legic_reqresp_drift = reqresp; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 76c4b44e..a0fa870b 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -17,6 +17,7 @@ void AcquireRawAdcSamples125k(int divisor) { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz else if (divisor == 0) @@ -69,6 +70,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, int at134khz; /* Make sure the tag is reset */ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(2500); @@ -158,6 +160,7 @@ void ReadTItag(void) uint32_t threshold = (sampleslo - sampleshi + 1)>>1; // TI tags charge at 134.2Khz + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz // Place FPGA in passthrough mode, in this mode the CROSS_LO line @@ -365,6 +368,7 @@ void AcquireTiType(void) // if not provided a valid crc will be computed from the data and written. void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); if(crc == 0) { crc = update_crc16(crc, (idlo)&0xff); crc = update_crc16(crc, (idlo>>8)&0xff); @@ -436,6 +440,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol) int i; uint8_t *tab = (uint8_t *)BigBuf; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; @@ -602,6 +607,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) int m=0, n=0, i=0, idx=0, found=0, lastval=0; uint32_t hi2=0, hi=0, lo=0; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); @@ -815,6 +821,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) uint32_t code=0, code2=0; //uint32_t hi2=0, hi=0, lo=0; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); @@ -1132,6 +1139,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) // Write one bit to card void T55xxWriteBit(int bit) { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); if (bit == 0) @@ -1147,6 +1155,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod { unsigned int i; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); @@ -1191,6 +1200,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) uint8_t *dest = (uint8_t *)BigBuf; int m=0, i=0; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); m = sizeof(BigBuf); // Clear destination buffer before sending the command memset(dest, 128, m); @@ -1255,6 +1265,7 @@ void T55xxReadTrace(void){ uint8_t *dest = (uint8_t *)BigBuf; int m=0, i=0; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); m = sizeof(BigBuf); // Clear destination buffer before sending the command memset(dest, 128, m); @@ -1970,6 +1981,7 @@ void SendForward(uint8_t fwd_bit_count) { LED_D_ON(); //Field on + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index c934a280..6a491b53 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -91,66 +91,66 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // iso14a_set_tracing(TRUE); - -} - -void MifareUReadBlock(uint8_t arg0,uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); + +} + +void MifareUReadBlock(uint8_t arg0,uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); - break; - }; - - if(mifare_ultra_halt(cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); - LED_B_OFF(); - - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -//----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. -// read sector (data = 4 x 16 bytes = 64 bytes) + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read sector (data = 4 x 16 bytes = 64 bytes) //----------------------------------------------------------------------------- void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { @@ -242,72 +242,72 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // iso14a_set_tracing(TRUE); - -} - -void MifareUReadCard(uint8_t arg0, uint8_t *datain) -{ - // params - uint8_t sectorNo = arg0; - - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); -// iso14a_set_tracing(false); - + +} + +void MifareUReadCard(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t sectorNo = arg0; + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); +// iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - for(int sec=0;sec<16;sec++){ - if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec); - break; - }; - } - if(mifare_ultra_halt(cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); - //cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32); - LED_B_OFF(); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// iso14a_set_tracing(TRUE); - -} - - -//----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. -// read block + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + for(int sec=0;sec<16;sec++){ + if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec); + break; + }; + } + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + //cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read block //----------------------------------------------------------------------------- void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { @@ -384,137 +384,137 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // iso14a_set_tracing(TRUE); - -} - -void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - byte_t blockdata[16]; - - memset(blockdata,'\0',16); - memcpy(blockdata, datain,16); - - // variables - byte_t isOK = 0; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); - // iso14a_set_tracing(false); - + +} + +void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + byte_t blockdata[16]; + + memset(blockdata,'\0',16); + memcpy(blockdata, datain,16); + + // variables + byte_t isOK = 0; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + // iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - break; - }; - - if(mifare_ultra_halt(cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,0,0); -// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// iso14a_set_tracing(TRUE); - -} - -void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - byte_t blockdata[4]; - - memcpy(blockdata, datain,4); - - // variables - byte_t isOK = 0; - uint8_t uid[10]; - uint32_t cuid; - - // clear trace - iso14a_clear_trace(); - // iso14a_set_tracing(false); - + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,0,0); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + byte_t blockdata[4]; + + memcpy(blockdata, datain,4); + + // variables + byte_t isOK = 0; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + // iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - break; - }; - - if(mifare_ultra_halt(cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,0,0); -// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// iso14a_set_tracing(TRUE); - -} - -// Return 1 if the nonce is invalid else return 0 -int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { - return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,0,0); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +// Return 1 if the nonce is invalid else return 0 +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { + return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; } diff --git a/client/Makefile b/client/Makefile index 6d75b4bb..e4a3580b 100644 --- a/client/Makefile +++ b/client/Makefile @@ -24,8 +24,10 @@ QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 MOC = $(QTDIR)/bin/moc LUAPLATFORM = mingw else ifeq ($(platform),Darwin) -CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers -QTLDLIBS = -framework QtGui -framework QtCore +#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers +#QTLDLIBS = -framework QtGui -framework QtCore +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui +QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore MOC = moc LUAPLATFORM = macosx else diff --git a/common/ldscript.common b/common/ldscript.common index 7cde5891..f1b63550 100644 --- a/common/ldscript.common +++ b/common/ldscript.common @@ -13,8 +13,8 @@ MEMORY { bootphase1 : ORIGIN = 0x00100000, LENGTH = 0x200 /* Phase 1 bootloader: Copies real bootloader to RAM */ bootphase2 : ORIGIN = 0x00100200, LENGTH = 0x2000 - 0x200 /* Main bootloader code, stored in Flash, executed from RAM */ - fpgaimage : ORIGIN = 0x00102000, LENGTH = 64k - 0x2000 /* Place where the FPGA image will end up */ - osimage : ORIGIN = 0x00110000, LENGTH = 256K - 64k /* Place where the main OS will end up */ + fpgaimage : ORIGIN = 0x00102000, LENGTH = 96k - 0x2000 /* Place where the FPGA image will end up */ + osimage : ORIGIN = 0x00118000, LENGTH = 256K - 96k /* Place where the main OS will end up */ ram : ORIGIN = 0x00200000, LENGTH = 64K - 0x20 /* RAM, minus small common area */ commonarea : ORIGIN = 0x00200000 + 64K - 0x20, LENGTH = 0x20 /* Communication between bootloader and main OS */ } diff --git a/fpga/Makefile b/fpga/Makefile index 12aeaaae..1aaa9f76 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -1,31 +1,33 @@ include ../common/Makefile.common -all: fpga.ngc fpga.ngd fpga.ncd fpga-placed.ncd fpga.bit +all: fpga_lf.bit fpga_hf.bit clean: - $(DELETE) fpga.bgn fpga.drc fpga.ncd fpga.ngd fpga_par.xrpt fpga-placed.pad fpga-placed.par fpga-placed.xpi fpga_usage.xml xlnx_auto_0.ise xst.srp - $(DELETE) fpga.map fpga.ngc fpga_ngdbuild.xrpt fpga.pcf fpga-placed_pad.csv fpga-placed.ptwx fpga.rbt xlnx_auto_0_xdb - $(DELETE) fpga.bld fpga.mrp fpga.ngc_xst.xrpt fpga.ngm fpga-placed.ncd fpga-placed_pad.txt fpga-placed.unroutes fpga_summary.xml netlist.lst xst + $(DELETE) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp + $(DELETE) *.map *.ngc *.xrpt *.pcf *.rbt *_auto_* *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst xst -fpga.ngc: fpga.v fpga.ucf xst.scr util.v lo_edge_detect.v lo_read.v lo_passthru.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v - $(DELETE) fpga.ngc - $(XILINX_TOOLS_PREFIX)xst -ifn xst.scr +fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v + $(DELETE) $@ + $(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr -fpga.ngd: fpga.ngc - $(DELETE) fpga.ngd - $(XILINX_TOOLS_PREFIX)ngdbuild -aul -p xc2s30-5-vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd +fpga_lf.ngc: fpga_lf.v fpga.ucf xst_lf.scr util.v clk_divider.v lo_edge_detect.v lo_read.v lo_passthru.v + $(DELETE) $@ + $(XILINX_TOOLS_PREFIX)xst -ifn xst_lf.scr -fpga.ncd: fpga.ngd - $(DELETE) fpga.ncd - $(XILINX_TOOLS_PREFIX)map -p xc2s30-5-vq100 fpga.ngd +%.ngd: %.ngc + $(DELETE) $@ + $(XILINX_TOOLS_PREFIX)ngdbuild -aul -p xc2s30-5-vq100 -nt timestamp -uc fpga.ucf $< $@ -fpga-placed.ncd: fpga.ncd - $(DELETE) fpga-placed.ncd - $(XILINX_TOOLS_PREFIX)par fpga.ncd fpga-placed.ncd +%.ncd: %.ngd + $(DELETE) $@ + $(XILINX_TOOLS_PREFIX)map -p xc2s30-5-vq100 $< -fpga.bit: fpga-placed.ncd - $(DELETE) fpga.bit fpga.drc fpga.rbt - $(XILINX_TOOLS_PREFIX)bitgen fpga-placed.ncd fpga.bit +%-placed.ncd: %.ncd + $(DELETE) $@ + $(XILINX_TOOLS_PREFIX)par $< $@ +%.bit: %-placed.ncd + $(DELETE) $@ $*.drc $*.rbt + $(XILINX_TOOLS_PREFIX)bitgen $< $@ .PHONY: all clean help help: diff --git a/fpga/clk_divider.v b/fpga/clk_divider.v new file mode 100644 index 00000000..882af5cc --- /dev/null +++ b/fpga/clk_divider.v @@ -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 + diff --git a/fpga/fpga.bit b/fpga/fpga.bit deleted file mode 100644 index e5ea4fcd33b41a65cf776e06d388ebfcad02bff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42172 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 ChxqLP diff --git a/fpga/fpga.v b/fpga/fpga.v deleted file mode 100644 index a083ae5c..00000000 --- a/fpga/fpga.v +++ /dev/null @@ -1,220 +0,0 @@ -//----------------------------------------------------------------------------- -// The FPGA is responsible for interfacing between the A/D, the coil drivers, -// and the ARM. In the low-frequency modes it passes the data straight -// through, so that the ARM gets raw A/D samples over the SSP. In the high- -// frequency modes, the FPGA might perform some demodulation first, to -// reduce the amount of data that we must send to the ARM. -// -// I am not really an FPGA/ASIC designer, so I am sure that a lot of this -// could be improved. -// -// Jonathan Westhues, March 2006 -// Added ISO14443-A support by Gerhard de Koning Gans, April 2008 -//----------------------------------------------------------------------------- - -`include "lo_read.v" -`include "lo_passthru.v" -`include "lo_edge_detect.v" -`include "hi_read_tx.v" -`include "hi_read_rx_xcorr.v" -`include "hi_simulate.v" -`include "hi_iso14443a.v" -`include "util.v" - -module fpga( - spck, miso, mosi, ncs, - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, adc_noe, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg -); - input spck, mosi, ncs; - output miso; - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk, adc_noe; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - -//assign pck0 = pck0i; -// IBUFG #(.IOSTANDARD("DEFAULT") ) pck0b( -// .O(pck0), -// .I(pck0i) -// ); -//assign spck = spcki; -// IBUFG #(.IOSTANDARD("DEFAULT") ) spckb( - // .O(spck), - // .I(spcki) -// ); - - -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- - -reg [15:0] shift_reg; -reg [7:0] divisor; -reg [7:0] conf_word; - -// 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]) - 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG - 4'b0010: divisor <= shift_reg[7:0]; // FPGA_CMD_SET_DIVISOR - endcase -end - -always @(posedge spck) -begin - if(~ncs) - begin - shift_reg[15:1] <= shift_reg[14:0]; - shift_reg[0] <= mosi; - end -end - -wire [2:0] major_mode; -assign major_mode = conf_word[7:5]; - -// For the low-frequency configuration: -wire lo_is_125khz; -assign lo_is_125khz = conf_word[3]; - -// For the high-frequency transmit configuration: modulation depth, either -// 100% (just quite driving antenna, steady LOW), or shallower (tri-state -// some fraction of the buffers) -wire hi_read_tx_shallow_modulation; -assign hi_read_tx_shallow_modulation = conf_word[0]; - -// For the high-frequency receive correlator: frequency against which to -// correlate. -wire hi_read_rx_xcorr_848; -assign hi_read_rx_xcorr_848 = conf_word[0]; -// and whether to drive the coil (reader) or just short it (snooper) -wire hi_read_rx_xcorr_snoop; -assign hi_read_rx_xcorr_snoop = conf_word[1]; - -// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4 -wire hi_read_rx_xcorr_quarter; -assign hi_read_rx_xcorr_quarter = conf_word[2]; - -// For the high-frequency simulated tag: what kind of modulation to use. -wire [2:0] hi_simulate_mod_type; -assign hi_simulate_mod_type = conf_word[2:0]; - -// For the high-frequency simulated tag: what kind of modulation to use. -wire lf_field; -assign lf_field = conf_word[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. -//----------------------------------------------------------------------------- - -lo_read lr( - pck0, ck_1356meg, ck_1356megb, - 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, ssp_dout, lr_ssp_clk, - cross_hi, cross_lo, - lr_dbg, - lo_is_125khz, divisor -); - -lo_passthru lp( - pck0, ck_1356meg, ck_1356megb, - lp_pwr_lo, lp_pwr_hi, lp_pwr_oe1, lp_pwr_oe2, lp_pwr_oe3, lp_pwr_oe4, - adc_d, lp_adc_clk, - lp_ssp_frame, lp_ssp_din, ssp_dout, lp_ssp_clk, - cross_hi, cross_lo, - lp_dbg, divisor -); - -lo_edge_detect ls( - pck0, ck_1356meg, ck_1356megb, - ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4, - adc_d, ls_adc_clk, - ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk, - cross_hi, cross_lo, - ls_dbg, divisor, - lf_field -); - -hi_read_tx ht( - pck0, ck_1356meg, ck_1356megb, - ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4, - adc_d, ht_adc_clk, - ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk, - cross_hi, cross_lo, - ht_dbg, - hi_read_tx_shallow_modulation -); - -hi_read_rx_xcorr hrxc( - pck0, ck_1356meg, ck_1356megb, - hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4, - adc_d, hrxc_adc_clk, - hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, - cross_hi, cross_lo, - hrxc_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter -); - -hi_simulate hs( - pck0, ck_1356meg, ck_1356megb, - 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, - cross_hi, cross_lo, - hs_dbg, - hi_simulate_mod_type -); - -hi_iso14443a hisn( - pck0, ck_1356meg, ck_1356megb, - 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, - cross_hi, cross_lo, - hisn_dbg, - hi_simulate_mod_type -); - -// Major modes: -// 000 -- LF reader (generic) -// 001 -- LF simulated tag (generic) -// 010 -- HF reader, transmitting to tag; modulation depth selectable -// 011 -- HF reader, receiving from tag, correlating as it goes; frequency selectable -// 100 -- HF simulated tag -// 101 -- HF ISO14443-A -// 110 -- LF passthrough -// 111 -- everything off - -mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, ls_ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, lp_ssp_clk, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, ls_ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, lp_ssp_din, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, ls_ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, lp_ssp_frame, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, ls_pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, lp_pwr_oe1, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, ls_pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, lp_pwr_oe2, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, ls_pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, lp_pwr_oe3, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, ls_pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, lp_pwr_oe4, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, ls_pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, lp_pwr_lo, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, ls_pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, lp_pwr_hi, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, ls_adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, lp_adc_clk, 1'b0); -mux8 mux_dbg (major_mode, dbg, lr_dbg, ls_dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, lp_dbg, 1'b0); - -// In all modes, let the ADC's outputs be enabled. -assign adc_noe = 1'b0; - -endmodule diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit new file mode 100644 index 0000000000000000000000000000000000000000..5389428c5539eb60eee9f27b6956ca950aa79b15 GIT binary patch literal 42175 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 literal 0 HcmV?d00001 diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v new file mode 100644 index 00000000..ff7c904a --- /dev/null +++ b/fpga/fpga_hf.v @@ -0,0 +1,150 @@ +//----------------------------------------------------------------------------- +// 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 +//----------------------------------------------------------------------------- + +`include "hi_read_tx.v" +`include "hi_read_rx_xcorr.v" +`include "hi_simulate.v" +`include "hi_iso14443a.v" +`include "util.v" + +module fpga_hf( + input spck, output miso, input mosi, input ncs, + input pck0, input ck_1356meg, input ck_1356megb, + output pwr_lo, output pwr_hi, + output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4, + input [7:0] adc_d, output adc_clk, output adc_noe, + output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk, + input cross_hi, input cross_lo, + output dbg +); + +//----------------------------------------------------------------------------- +// The SPI receiver. This sets up the configuration word, which the rest of +// the logic looks at to determine how to connect the A/D and the coil +// drivers (i.e., which section gets it). Also assign some symbolic names +// to the configuration bits, for use below. +//----------------------------------------------------------------------------- + +reg [15:0] shift_reg; +reg [7:0] conf_word; + +// 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]) + 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG + endcase +end + +always @(posedge spck) +begin + if(~ncs) + begin + shift_reg[15:1] <= shift_reg[14:0]; + shift_reg[0] <= mosi; + end +end + +wire [2:0] major_mode; +assign major_mode = conf_word[7:5]; + +// For the high-frequency transmit configuration: modulation depth, either +// 100% (just quite driving antenna, steady LOW), or shallower (tri-state +// some fraction of the buffers) +wire hi_read_tx_shallow_modulation = conf_word[0]; + +// For the high-frequency receive correlator: frequency against which to +// correlate. +wire hi_read_rx_xcorr_848 = conf_word[0]; +// and whether to drive the coil (reader) or just short it (snooper) +wire hi_read_rx_xcorr_snoop = conf_word[1]; + +// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4 +wire hi_read_rx_xcorr_quarter = conf_word[2]; + +// For the high-frequency simulated tag: what kind of modulation to use. +wire [2:0] hi_simulate_mod_type = conf_word[2: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. +//----------------------------------------------------------------------------- + +hi_read_tx ht( + pck0, ck_1356meg, ck_1356megb, + ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4, + adc_d, ht_adc_clk, + ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk, + cross_hi, cross_lo, + ht_dbg, + hi_read_tx_shallow_modulation +); + +hi_read_rx_xcorr hrxc( + pck0, ck_1356meg, ck_1356megb, + hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4, + adc_d, hrxc_adc_clk, + hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, + cross_hi, cross_lo, + hrxc_dbg, + hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter +); + +hi_simulate hs( + pck0, ck_1356meg, ck_1356megb, + 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, + cross_hi, cross_lo, + hs_dbg, + hi_simulate_mod_type +); + +hi_iso14443a hisn( + pck0, ck_1356meg, ck_1356megb, + 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, + cross_hi, cross_lo, + hisn_dbg, + hi_simulate_mod_type +); + +// Major modes: + +// 000 -- HF reader, transmitting to tag; modulation depth selectable +// 001 -- HF reader, receiving from tag, correlating as it goes; frequency selectable +// 010 -- HF simulated tag +// 011 -- HF ISO14443-A +// 111 -- everything off + +mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, 1'b0, 1'b0, 1'b0, 1'b0); + +// In all modes, let the ADC's outputs be enabled. +assign adc_noe = 1'b0; + +endmodule diff --git a/fpga/fpga_lf.bit b/fpga/fpga_lf.bit new file mode 100644 index 0000000000000000000000000000000000000000..133ea9924b546523b0128737e5082cc723406319 GIT binary patch literal 42175 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 IQt~1H2Y^weQ~&?~ literal 0 HcmV?d00001 diff --git a/fpga/fpga_lf.v b/fpga/fpga_lf.v new file mode 100644 index 00000000..8dea68d7 --- /dev/null +++ b/fpga/fpga_lf.v @@ -0,0 +1,125 @@ +//----------------------------------------------------------------------------- +// 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 +//----------------------------------------------------------------------------- + +`include "lo_read.v" +`include "lo_passthru.v" +`include "lo_edge_detect.v" +`include "util.v" +`include "clk_divider.v" + +module fpga_lf( + input spck, output miso, input mosi, input ncs, + input pck0, input ck_1356meg, input ck_1356megb, + output pwr_lo, output pwr_hi, + output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4, + input [7:0] adc_d, output adc_clk, output adc_noe, + output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk, + input cross_hi, input cross_lo, + output dbg +); + +//----------------------------------------------------------------------------- +// The SPI receiver. This sets up the configuration word, which the rest of +// the logic looks at to determine how to connect the A/D and the coil +// drivers (i.e., which section gets it). Also assign some symbolic names +// to the configuration bits, for use below. +//----------------------------------------------------------------------------- + +reg [15:0] shift_reg; +reg [7:0] divisor; +reg [7:0] conf_word; + +// 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]) + 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG + 4'b0010: divisor <= shift_reg[7:0]; // FPGA_CMD_SET_DIVISOR + endcase +end + +always @(posedge spck) +begin + if(~ncs) + begin + shift_reg[15:1] <= shift_reg[14:0]; + shift_reg[0] <= mosi; + end +end + +wire [2:0] major_mode; +assign major_mode = conf_word[7:5]; + +// For the low-frequency configuration: +wire lf_field = conf_word[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. +//----------------------------------------------------------------------------- +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 +); + +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_cnt, 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 +); + +// Major modes: +// 000 -- LF reader (generic) +// 001 -- LF edge detect (generic) +// 010 -- LF passthrough + +mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, le_ssp_frame, 1'b0, 1'b0, 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, 1'b0, 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, 1'b0, 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, 1'b0, 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, 1'b0, 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, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, le_pwr_hi, lp_pwr_hi, 1'b0, 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, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, lr_dbg, le_dbg, lp_dbg, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); + +// In all modes, let the ADC's outputs be enabled. +assign adc_noe = 1'b0; + +endmodule diff --git a/fpga/go.bat b/fpga/go.bat index 8600d3cd..d9704e08 100644 --- a/fpga/go.bat +++ b/fpga/go.bat @@ -2,37 +2,67 @@ rmdir/s/q xst -del fpga.ngc -xst -ifn xst.scr +del fpga_lf.ngc +xst -ifn xst_lf.scr if errorlevel 0 goto ok1 goto done :ok1 -del fpga.ngd -ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd +del fpga_lf.ngd +ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_lf.ngc fpga_lf.ngd if errorlevel 0 goto ok2 goto done :ok2 -del fpga.ncd -map -p xc2s30-6vq100 fpga.ngd +del fpga_lf.ncd +map -p xc2s30-6vq100 fpga_lf.ngd if errorlevel 0 goto ok3 goto done :ok3 -del fpga-placed.ncd -par fpga.ncd fpga-placed.ncd +del fpga_lf-placed.ncd +par fpga_lf.ncd fpga_lf-placed.ncd if errorlevel 0 goto ok4 goto done :ok4 -del fpga.bit fpga.drc fpga.rbt -bitgen -b fpga-placed.ncd fpga.bit +del fpga_lf.bit fpga_lf.drc fpga_lf.rbt +bitgen -b fpga_lf-placed.ncd fpga_lf.bit if errorlevel 0 goto ok5 goto done :ok5 +del fpga_hf.ngc +xst -ifn xst_hf.scr +if errorlevel 0 goto ok6 +goto done +:ok6 + +del fpga_hf.ngd +ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_hf.ngc fpga_hf.ngd +if errorlevel 0 goto ok7 +goto done +:ok7 + +del fpga_hf.ncd +map -p xc2s30-6vq100 fpga_hf.ngd +if errorlevel 0 goto ok8 +goto done +:ok8 + +del fpga_hf-placed.ncd +par fpga_hf.ncd fpga_hf-placed.ncd +if errorlevel 0 goto ok9 +goto done +:ok9 + +del fpga_hf.bit fpga_hf.drc fpga_hf.rbt +bitgen -b fpga_hf-placed.ncd fpga_hf.bit +if errorlevel 0 goto ok10 +goto done +:ok10 + echo okay -perl ..\tools\rbt2c.pl fpga.rbt > ..\armsrc\fpgaimg.c +perl ..\tools\rbt2c.pl fpga_lf.rbt > ..\armsrc\fpgaimg.c :done diff --git a/fpga/lo_edge_detect.v b/fpga/lo_edge_detect.v index 8458ee69..af600b83 100644 --- a/fpga/lo_edge_detect.v +++ b/fpga/lo_edge_detect.v @@ -7,34 +7,18 @@ //----------------------------------------------------------------------------- module lo_edge_detect( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - divisor, - lf_field + 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, input ssp_dout, output ssp_clk, + input cross_lo, + output dbg, + input lf_field ); - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input [7:0] divisor; - input lf_field; -// Divide the clock to be used for the ADC -reg [7:0] pck_divider; -reg clk_state; - -wire tag_modulation; -assign tag_modulation = ssp_dout & !lf_field; -wire reader_modulation; -assign reader_modulation = !ssp_dout & lf_field & clk_state; +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 @@ -46,20 +30,7 @@ assign pwr_lo = reader_modulation; assign pwr_hi = 1'b0; assign dbg = ssp_frame; -always @(posedge pck0) -begin - if(pck_divider == divisor[7:0]) - begin - pck_divider <= 8'd0; - clk_state = !clk_state; - end - else - begin - pck_divider <= pck_divider + 1; - end -end - -assign adc_clk = ~clk_state; +assign adc_clk = ~pck_divclk; // Toggle the output with hysteresis // Set to high if the ADC value is above 200 @@ -70,7 +41,7 @@ reg output_state; always @(posedge pck0) begin - if((pck_divider == 8'd7) && !clk_state) begin + if((pck_cnt == 8'd7) && !pck_divclk) begin is_high = (adc_d >= 8'd190); is_low = (adc_d <= 8'd70); end diff --git a/fpga/lo_passthru.v b/fpga/lo_passthru.v index 5c59d11c..933728eb 100644 --- a/fpga/lo_passthru.v +++ b/fpga/lo_passthru.v @@ -4,42 +4,14 @@ //----------------------------------------------------------------------------- module lo_passthru( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, divisor + input 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 ); - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input [7:0] divisor; - -reg [7:0] pck_divider; -reg ant_lo; - -// this task runs on the rising egde of pck0 clock (24Mhz) and creates ant_lo -// which is high for (divisor+1) pck0 cycles and low for the same duration -// ant_lo is therefore a 50% duty cycle clock signal with a frequency of -// 12Mhz/(divisor+1) which drives the antenna as well as the ADC clock adc_clk -always @(posedge pck0) -begin - if(pck_divider == divisor[7:0]) - begin - pck_divider <= 8'd0; - ant_lo = !ant_lo; - end - else - begin - pck_divider <= pck_divider + 1; - end -end // the antenna is modulated when ssp_dout = 1, when 0 the // antenna drivers stop modulating and go into listen mode @@ -47,7 +19,7 @@ assign pwr_oe3 = 1'b0; assign pwr_oe1 = ssp_dout; assign pwr_oe2 = ssp_dout; assign pwr_oe4 = ssp_dout; -assign pwr_lo = ant_lo && ssp_dout; +assign pwr_lo = pck_divclk && ssp_dout; assign pwr_hi = 1'b0; assign adc_clk = 1'b0; assign ssp_din = cross_lo; diff --git a/fpga/lo_read.v b/fpga/lo_read.v index e6f245ca..f2d79127 100644 --- a/fpga/lo_read.v +++ b/fpga/lo_read.v @@ -7,65 +7,34 @@ //----------------------------------------------------------------------------- module lo_read( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - lo_is_125khz, divisor + 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 pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input lo_is_125khz; // redundant signal, no longer used anywhere - input [7:0] divisor; reg [7:0] to_arm_shiftreg; -reg [7:0] pck_divider; -reg ant_lo; - -// this task runs on the rising egde of pck0 clock (24Mhz) and creates ant_lo -// which is high for (divisor+1) pck0 cycles and low for the same duration -// ant_lo is therefore a 50% duty cycle clock signal with a frequency of -// 12Mhz/(divisor+1) which drives the antenna as well as the ADC clock adc_clk -always @(posedge pck0) -begin - if(pck_divider == divisor[7:0]) - begin - pck_divider <= 8'd0; - ant_lo = !ant_lo; - 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. -// because ant_lo always transitions when pck_divider = 0 we use the -// pck_divider counter to sync our other signals off it -// we read the ADC value when pck_divider=7 and shift it out on counts 8..15 +// 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_divider == 8'd7) && !ant_lo) - to_arm_shiftreg <= adc_d; - else - begin - to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0]; + 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; + to_arm_shiftreg[0] <= 1'b0; end end @@ -83,11 +52,11 @@ end // ssp_clk |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ // serialized SSP data is gated by ant_lo to suppress unwanted signal -assign ssp_din = to_arm_shiftreg[7] && !ant_lo; +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_divider[7:3] == 5'd1) && !ant_lo; +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; @@ -95,9 +64,9 @@ assign pwr_oe2 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; // this is the antenna driver signal -assign pwr_lo = ant_lo; +assign pwr_lo = pck_divclk; // ADC clock out of phase with antenna driver -assign adc_clk = ~ant_lo; +assign adc_clk = ~pck_divclk; // ADC clock also routed to debug pin assign dbg = adc_clk; endmodule diff --git a/fpga/xst.scr b/fpga/xst.scr deleted file mode 100644 index 406bbeee..00000000 --- a/fpga/xst.scr +++ /dev/null @@ -1 +0,0 @@ -run -ifn fpga.v -ifmt Verilog -ofn fpga.ngc -ofmt NGC -p xc2s30-5-vq100 -opt_mode Speed -opt_level 1 -ent fpga diff --git a/fpga/xst_hf.scr b/fpga/xst_hf.scr new file mode 100644 index 00000000..dd2fdc85 --- /dev/null +++ b/fpga/xst_hf.scr @@ -0,0 +1 @@ +run -ifn fpga_hf.v -ifmt Verilog -ofn fpga_hf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_hf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact diff --git a/fpga/xst_lf.scr b/fpga/xst_lf.scr new file mode 100644 index 00000000..2d6c7e95 --- /dev/null +++ b/fpga/xst_lf.scr @@ -0,0 +1 @@ +run -ifn fpga_lf.v -ifmt Verilog -ofn fpga_lf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_lf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact diff --git a/include/proxmark3.h b/include/proxmark3.h index ce263ca1..8c9417da 100644 --- a/include/proxmark3.h +++ b/include/proxmark3.h @@ -60,6 +60,10 @@ #define SPI_FPGA_MODE 0 #define SPI_LCD_MODE 1 +#define FPGA_BITSTREAM_ERR 0 +#define FPGA_BITSTREAM_LF 1 +#define FPGA_BITSTREAM_HF 2 + #define TRUE 1 #define FALSE 0 -- 2.39.5