From dad7df4a55af37eb98a4bfb5010c5c9975437e0c Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 13 Aug 2018 15:06:43 +0200 Subject: [PATCH] ISO15693 device side improvements * increase accuracy by doubling the sample frequency (hi_read_rx_xcorr.v) * adjust armsrc/iso15693.c and client/cmdhf15.c accordingly * use more accurate approximation for sqrt(ci^2 + cq^2) * improve EOF detection (was often mistaken for Logic0, resulting in "error, uneven octet! (extra bits!)") --- armsrc/iso15693.c | 126 ++++++++++++++++++++-------------------- client/cmdhf15.c | 49 +++++++++------- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_read_rx_xcorr.v | 78 ++++++++++++++----------- 4 files changed, 135 insertions(+), 118 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 1f0b8193..ad6f5cfc 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -81,7 +81,10 @@ #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) -int DEBUG=0; +// approximate amplitude=sqrt(ci^2+cq^2) +#define AMPLITUDE(ci, cq) (MAX(ABS(ci), ABS(cq)) + (MIN(ABS(ci), ABS(cq))>>1)) + +static int DEBUG = 0; // --------------------------- @@ -303,13 +306,9 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * // NOW READ RESPONSE FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads c = 0; getNext = false; for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { int8_t b; b = (int8_t)AT91C_BASE_SSC->SSC_RHR; @@ -319,11 +318,11 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - uint8_t r = ABS(b) + ABS(prev); + uint8_t r = AMPLITUDE(b, prev); - dest[c++] = (uint8_t)r; + dest[c++] = r; - if(c >= 2000) { + if(c >= 4000) { break; } } else { @@ -341,12 +340,10 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * int i, j; int max = 0, maxPos=0; - int skip = 4; - - // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + int skip = 2; // First, correlate for SOF - for(i = 0; i < 100; i++) { + for(i = 0; i < 200; i++) { // usually, SOF is found around i = 60 int corr = 0; for(j = 0; j < arraylen(FrameSOF); j += skip) { corr += FrameSOF[j]*dest[i+(j/skip)]; @@ -356,7 +353,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * maxPos = i; } } - // Dbprintf("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); + if (DEBUG) Dbprintf("SOF at %d, correlation %d", maxPos, max/(arraylen(FrameSOF)/skip)); int k = 0; // this will be our return value @@ -370,10 +367,15 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; + int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; for(j = 0; j < arraylen(Logic0); j += skip) { corr0 += Logic0[j]*dest[i+(j/skip)]; } + corr01 = corr00 = corr0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr00 += Logic0[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; + corr01 += Logic1[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; + } for(j = 0; j < arraylen(Logic1); j += skip) { corr1 += Logic1[j]*dest[i+(j/skip)]; } @@ -381,11 +383,14 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * corrEOF += FrameEOF[j]*dest[i+(j/skip)]; } // Even things out by the length of the target waveform. + corr00 *= 2; + corr01 *= 2; corr0 *= 4; corr1 *= 4; - if(corrEOF > corr1 && corrEOF > corr0) { - // Dbprintf("EOF at %d", i); + if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) { + if (DEBUG) Dbprintf("EOF at %d, correlation %d (corr01: %d, corr00: %d, corr1: %d, corr0: %d)", + i, corrEOF, corr01, corr00, corr1, corr0); break; } else if(corr1 > corr0) { i += arraylen(Logic1)/skip; @@ -398,7 +403,7 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int * k++; mask = 0x01; } - if((i+(int)arraylen(FrameEOF)) >= 2000) { + if((i+(int)arraylen(FrameEOF)/skip) >= 4000) { DbpString("ran off end!"); break; } @@ -446,9 +451,6 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int c = 0; getNext = false; for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; @@ -457,11 +459,11 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - uint8_t r = ABS(b) + ABS(prev); + uint8_t r = AMPLITUDE(b, prev); - dest[c++] = (uint8_t)r; + dest[c++] = r; - if(c >= 20000) { + if(c >= BIGBUF_SIZE) { break; } } else { @@ -479,12 +481,10 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int int i, j; int max = 0, maxPos=0; - int skip = 4; - -// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + int skip = 2; // First, correlate for SOF - for(i = 0; i < 19000; i++) { + for(i = 0; i < 38000; i++) { int corr = 0; for(j = 0; j < arraylen(FrameSOF); j += skip) { corr += FrameSOF[j]*dest[i+(j/skip)]; @@ -494,7 +494,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int maxPos = i; } } -// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); + if (DEBUG) Dbprintf("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); int k = 0; // this will be our return value @@ -508,10 +508,15 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for(;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; + int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; for(j = 0; j < arraylen(Logic0); j += skip) { corr0 += Logic0[j]*dest[i+(j/skip)]; } + corr01 = corr00 = corr0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr00 += Logic0[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; + corr01 += Logic1[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; + } for(j = 0; j < arraylen(Logic1); j += skip) { corr1 += Logic1[j]*dest[i+(j/skip)]; } @@ -519,11 +524,14 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int corrEOF += FrameEOF[j]*dest[i+(j/skip)]; } // Even things out by the length of the target waveform. + corr00 *= 2; + corr01 *= 2; corr0 *= 4; corr1 *= 4; - if(corrEOF > corr1 && corrEOF > corr0) { - // DbpString("EOF at %d", i); + if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) { + if (DEBUG) Dbprintf("EOF at %d, correlation %d (corr01: %d, corr00: %d, corr1: %d, corr0: %d)", + i, corrEOF, corr01, corr00, corr1, corr0); break; } else if(corr1 > corr0) { i += arraylen(Logic1)/skip; @@ -536,7 +544,7 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int k++; mask = 0x01; } - if((i+(int)arraylen(FrameEOF)) >= 2000) { + if((i+(int)arraylen(FrameEOF)/skip) >= BIGBUF_SIZE) { DbpString("ran off end!"); break; } @@ -602,10 +610,6 @@ void AcquireRawAdcSamplesIso15693(void) break; } } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } WDT_HIT(); } @@ -614,9 +618,6 @@ void AcquireRawAdcSamplesIso15693(void) c = 0; getNext = false; for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { int8_t b; b = (int8_t)AT91C_BASE_SSC->SSC_RHR; @@ -626,11 +627,11 @@ void AcquireRawAdcSamplesIso15693(void) // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - uint8_t r = ABS(b) + ABS(prev); + uint8_t r = AMPLITUDE(b, prev); - dest[c++] = (uint8_t)r; + dest[c++] = r; - if(c >= 2000) { + if(c >= 4000) { break; } } else { @@ -668,9 +669,6 @@ void RecordRawAdcSamplesIso15693(void) c = 0; getNext = false; for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { int8_t b; b = (int8_t)AT91C_BASE_SSC->SSC_RHR; @@ -680,11 +678,11 @@ void RecordRawAdcSamplesIso15693(void) // every other is Q. We just want power, so abs(I) + abs(Q) is // close to what we want. if(getNext) { - uint8_t r = ABS(b) + ABS(prev); + uint8_t r = AMPLITUDE(b, prev); - dest[c++] = (uint8_t)r; + dest[c++] = r; - if(c >= 7000) { + if(c >= 14000) { break; } } else { @@ -836,7 +834,7 @@ int SendDataTag(uint8_t *send, int sendlen, int init, int speed, uint8_t **recv) if (init) Iso15693InitReader(); int answerLen=0; - uint8_t *answer = BigBuf_get_addr() + 3660; + uint8_t *answer = BigBuf_get_addr() + 4000; if (recv != NULL) memset(answer, 0, 100); if (!speed) { @@ -957,7 +955,7 @@ void ReaderIso15693(uint32_t parameter) int answerLen1 = 0; int answerLen2 = 0; - int answerLen3 = 0; + // int answerLen3 = 0; int i = 0; int samples = 0; int tsamples = 0; @@ -967,11 +965,11 @@ void ReaderIso15693(uint32_t parameter) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - uint8_t *answer1 = BigBuf_get_addr() + 3660; - uint8_t *answer2 = BigBuf_get_addr() + 3760; - uint8_t *answer3 = BigBuf_get_addr() + 3860; + uint8_t *answer1 = BigBuf_get_addr() + 4000; + uint8_t *answer2 = BigBuf_get_addr() + 4100; + // uint8_t *answer3 = BigBuf_get_addr() + 4200; // Blank arrays - memset(answer1, 0x00, 300); + memset(answer1, 0x00, 200); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup SSC @@ -1025,21 +1023,21 @@ void ReaderIso15693(uint32_t parameter) TagUID[3],TagUID[2],TagUID[1],TagUID[0]); - Dbprintf("%d octets read from SELECT request:", answerLen2); - DbdecodeIso15693Answer(answerLen2,answer2); - Dbhexdump(answerLen2,answer2,true); + // Dbprintf("%d octets read from SELECT request:", answerLen2); + // DbdecodeIso15693Answer(answerLen2,answer2); + // Dbhexdump(answerLen2,answer2,true); - Dbprintf("%d octets read from XXX request:", answerLen3); - DbdecodeIso15693Answer(answerLen3,answer3); - Dbhexdump(answerLen3,answer3,true); + // Dbprintf("%d octets read from XXX request:", answerLen3); + // DbdecodeIso15693Answer(answerLen3,answer3); + // Dbhexdump(answerLen3,answer3,true); // read all pages if (answerLen1>=12 && DEBUG) { i=0; while (i<32) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID,i); - TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); - answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); if (answerLen2>0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); DbdecodeIso15693Answer(answerLen2,answer2); @@ -1073,7 +1071,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - uint8_t *buf = BigBuf_get_addr() + 3660; + uint8_t *buf = BigBuf_get_addr() + 4000; memset(buf, 0x00, 100); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1177,7 +1175,7 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8 if (recv) { LED_B_ON(); - cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); + cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); LED_B_OFF(); if (DEBUG) { diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 08cc3b15..b6a84c1c 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -268,7 +268,7 @@ static char* TagErrorStr(uint8_t error) { case 0x02: return "The command is not recognised"; case 0x03: return "The option is not supported."; case 0x0f: return "Unknown error."; - case 0x10: return "The specified block is not available (doesn’t exist)."; + case 0x10: return "The specified block is not available (doesn't exist)."; case 0x11: return "The specified block is already -locked and thus cannot be locked again"; case 0x12: return "The specified block is locked and its content cannot be changed."; case 0x13: return "The specified block was not successfully programmed."; @@ -286,12 +286,12 @@ int CmdHF15Demod(const char *Cmd) int i, j; int max = 0, maxPos = 0; - int skip = 4; + int skip = 2; - if (GraphTraceLen < 1000) return 0; + if (GraphTraceLen < 2000) return 0; // First, correlate for SOF - for (i = 0; i < 100; i++) { + for (i = 0; i < 200; i++) { int corr = 0; for (j = 0; j < arraylen(FrameSOF); j += skip) { corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; @@ -310,23 +310,30 @@ int CmdHF15Demod(const char *Cmd) memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for (;;) { - int corr0 = 0, corr1 = 0, corrEOF = 0; - for (j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j] * GraphBuffer[i + (j / skip)]; - } - for (j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j] * GraphBuffer[i + (j / skip)]; - } - for (j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)]; - } - // Even things out by the length of the target waveform. - corr0 *= 4; - corr1 *= 4; - - if (corrEOF > corr1 && corrEOF > corr0) { - PrintAndLog("EOF at %d", i); - break; + int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j]*GraphBuffer[i+(j/skip)]; + } + corr01 = corr00 = corr0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr00 += Logic0[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)]; + corr01 += Logic1[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)]; + } + for(j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j]*GraphBuffer[i+(j/skip)]; + } + for(j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr00 *= 2; + corr01 *= 2; + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) { + PrintAndLog("EOF at %d", i); + break; } else if (corr1 > corr0) { i += arraylen(Logic1) / skip; outBuf[k] |= mask; diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 229151dfbf50cb8de730a85446ccbc18407e8474..ac99b9ee5d31a14d038018e946c5ac6ebfc77dc0 100644 GIT binary patch literal 42175 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 H#h3iQz8y}h literal 42175 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 Z%S`zFE0UDq-{Xn`{Cl{VmhxZne*^UawK@O* diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index 433d6736..26ee8426 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -27,22 +27,12 @@ assign pwr_hi = ck_1356megb & (~snoop); assign pwr_oe1 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; +// Unused. +assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; -reg [2:0] fc_div; -always @(negedge ck_1356megb) - fc_div <= fc_div + 1; +assign adc_clk = ck_1356megb; // sample frequency is 13,56 MHz -(* clock_signal = "yes" *) reg adc_clk; // sample frequency, always 16 * fc -always @(ck_1356megb, xcorr_is_848, xcorr_quarter_freq, fc_div) - if (xcorr_is_848 & ~xcorr_quarter_freq) // fc = 847.5 kHz, standard ISO14443B - adc_clk <= ck_1356megb; - else if (~xcorr_is_848 & ~xcorr_quarter_freq) // fc = 423.75 kHz - adc_clk <= fc_div[0]; - else if (xcorr_is_848 & xcorr_quarter_freq) // fc = 211.875 kHz - adc_clk <= fc_div[1]; - else // fc = 105.9375 kHz - adc_clk <= fc_div[2]; - // 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. @@ -69,9 +59,18 @@ begin end end -// Let us report a correlation every 4 subcarrier cycles, or 4*16=64 samples, -// so we need a 6-bit counter. + +// 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 + // And a couple of registers in which to accumulate the correlations. // 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%. @@ -86,12 +85,29 @@ reg ssp_clk; reg ssp_frame; -always @(negedge adc_clk) -begin - corr_i_cnt <= corr_i_cnt + 1; -end - +// The subcarrier reference signals +reg subcarrier_I; +reg subcarrier_Q; +always @(corr_i_cnt or xcorr_is_848 or xcorr_quarter_freq) +begin + if (xcorr_is_848 & ~xcorr_quarter_freq) // 848 kHz + begin + subcarrier_I = ~corr_i_cnt[3]; + subcarrier_Q = ~(corr_i_cnt[3] ^ corr_i_cnt[2]); + end + else if (xcorr_is_848 & xcorr_quarter_freq) // 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 @@ -109,30 +125,30 @@ begin end else begin - // 8 bits of tag signal + // Send 8 most significant bits of tag signal corr_i_out <= corr_i_accum[11:4]; corr_q_out <= corr_q_accum[11:4]; end - + // Initialize next correlation. + // Both I and Q reference signals are high when corr_i_nct == 0. Therefore need to accumulate. corr_i_accum <= adc_d; corr_q_accum <= adc_d; end else begin - if(corr_i_cnt[3]) - corr_i_accum <= corr_i_accum - adc_d; - else + if (subcarrier_I) corr_i_accum <= corr_i_accum + adc_d; + else + corr_i_accum <= corr_i_accum - adc_d; - if(corr_i_cnt[3] == corr_i_cnt[2]) // phase shifted by pi/2 + if (subcarrier_Q) corr_q_accum <= corr_q_accum + adc_d; else corr_q_accum <= corr_q_accum - adc_d; end - // The logic in hi_simulate.v reports 4 samples per bit. We report two - // (I, Q) pairs per bit, so we should do 2 samples per pair. + // for each Q/I pair report two reader signal samples when sniffing if(corr_i_cnt == 6'd32) after_hysteresis_prev <= after_hysteresis; @@ -167,8 +183,4 @@ assign ssp_din = corr_i_out[7]; assign dbg = corr_i_cnt[3]; -// Unused. -assign pwr_lo = 1'b0; -assign pwr_oe2 = 1'b0; - endmodule