`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
`default_nettype none
|
`default_nettype none
|
|
|
module Iso7816_3_t0_analyzer(
|
module Iso7816_3_t0_analyzer(
|
input wire nReset,
|
input wire nReset,
|
input wire clk,
|
input wire clk,
|
input wire [DIVIDER_WIDTH-1:0] clkPerCycle,
|
input wire [DIVIDER_WIDTH-1:0] clkPerCycle,
|
input wire isoReset,
|
input wire isoReset,
|
input wire isoClk,
|
input wire isoClk,
|
input wire isoVdd,
|
input wire isoVdd,
|
input wire isoSio,
|
input wire isoSio,
|
output reg [3:0] fiCode,
|
output reg [3:0] fiCode,
|
output reg [3:0] diCode,
|
output reg [3:0] diCode,
|
output wire [12:0] fi,
|
output wire [12:0] fi,
|
output wire [7:0] di,
|
output wire [7:0] di,
|
output wire [12:0] cyclesPerEtu,
|
output wire [12:0] cyclesPerEtu,
|
output wire [7:0] fMax,
|
output wire [7:0] fMax,
|
output wire isActivated,
|
output wire isActivated,
|
output wire tsReceived,
|
output wire tsReceived,
|
output wire tsError,
|
output wire tsError,
|
output wire useIndirectConvention,
|
output wire useIndirectConvention,
|
output wire atrIsEarly,//high if TS received before 400 cycles after reset release
|
output wire atrIsEarly,//high if TS received before 400 cycles after reset release
|
output wire atrIsLate,//high if TS is still not received after 40000 cycles after reset release
|
output wire atrIsLate,//high if TS is still not received after 40000 cycles after reset release
|
output reg [3:0] atrK,//number of historical bytes
|
output reg [3:0] atrK,//number of historical bytes
|
output reg atrHasTck,
|
output reg atrHasTck,
|
output reg atrCompleted,
|
output reg atrCompleted,
|
output reg useT0,
|
output reg useT0,
|
output reg useT1,
|
output reg useT1,
|
output reg useT15,
|
output reg useT15,
|
output reg waitCardTx,
|
output reg waitCardTx,
|
output reg waitTermTx,
|
output reg waitTermTx,
|
output reg cardTx,
|
output reg cardTx,
|
output reg termTx,
|
output reg termTx,
|
output wire guardTime,
|
output wire guardTime,
|
output wire overrunError,
|
output wire overrunError,
|
output wire frameError,
|
output wire frameError,
|
output reg [7:0] lastByte,
|
output reg [7:0] lastByte,
|
output reg [31:0] bytesCnt
|
output reg [31:0] bytesCnt
|
);
|
);
|
parameter DIVIDER_WIDTH = 1;
|
parameter DIVIDER_WIDTH = 1;
|
|
|
reg [8:0] tsCnt;//counter to start ATR 400 cycles after reset release
|
reg [8:0] tsCnt;//counter to start ATR 400 cycles after reset release
|
|
|
reg [7:0] buffer[256+5:0];
|
reg [7:0] buffer[256+5:0];
|
localparam CLA_I= 8*4;
|
localparam CLA_I= 8*4;
|
localparam INS_I= 8*3;
|
localparam INS_I= 8*3;
|
localparam P1_I = 8*2;
|
localparam P1_I = 8*2;
|
localparam P2_I = 8*1;
|
localparam P2_I = 8*1;
|
localparam P3_I = 0;
|
localparam P3_I = 0;
|
reg [CLA_I+7:0] tpduHeader;
|
reg [CLA_I+7:0] tpduHeader;
|
|
|
//wire COM_clk=isoClk;
|
//wire COM_clk=isoClk;
|
//integer COM_errorCnt;
|
//integer COM_errorCnt;
|
//wire txPending=1'b0;
|
//wire txPending=1'b0;
|
//wire txRun=1'b0;
|
//wire txRun=1'b0;
|
|
|
wire rxRun, rxStartBit, overrunErrorFlag, frameErrorFlag, bufferFull;
|
wire rxRun, rxStartBit, overrunErrorFlag, frameErrorFlag, bufferFull;
|
assign overrunErrorFlag = overrunError;
|
assign overrunErrorFlag = overrunError;
|
assign frameErrorFlag = frameError;
|
assign frameErrorFlag = frameError;
|
|
|
wire [7:0] rxData;
|
wire [7:0] rxData;
|
reg ackFlags;
|
reg ackFlags;
|
|
|
wire msbFirst = useIndirectConvention;
|
wire msbFirst = useIndirectConvention;
|
wire sioHighValue = ~useIndirectConvention;
|
wire sioHighValue = ~useIndirectConvention;
|
wire oddParity = 1'b0;
|
wire oddParity = 1'b0;
|
|
|
wire [7:0] dataOut = sioHighValue ? rxData : ~rxData;
|
wire [7:0] dataOut = sioHighValue ? rxData : ~rxData;
|
|
|
|
|
//`include "ComRxDriverTasks.v"
|
//`include "ComRxDriverTasks.v"
|
|
|
wire endOfRx;
|
wire endOfRx;
|
|
|
wire stopBit2 = useT0;//1 if com use 2 stop bits --> 12 ETU / byte
|
wire stopBit2 = useT0;//1 if com use 2 stop bits --> 12 ETU / byte
|
|
|
RxCoreSelfContained #(
|
RxCoreSelfContained #(
|
.DIVIDER_WIDTH(DIVIDER_WIDTH),
|
.DIVIDER_WIDTH(DIVIDER_WIDTH),
|
.CLOCK_PER_BIT_WIDTH(4'd13),
|
.CLOCK_PER_BIT_WIDTH(4'd13),
|
.PRECISE_STOP_BIT(1'b1))
|
.PRECISE_STOP_BIT(1'b1))
|
rxCore (
|
rxCore (
|
.dataOut(rxData),
|
.dataOut(rxData),
|
.overrunErrorFlag(overrunError),
|
.overrunErrorFlag(overrunError),
|
.dataOutReadyFlag(bufferFull),
|
.dataOutReadyFlag(bufferFull),
|
.frameErrorFlag(frameError),
|
.frameErrorFlag(frameError),
|
.endOfRx(endOfRx),
|
.endOfRx(endOfRx),
|
.run(rxRun),
|
.run(rxRun),
|
.startBit(rxStartBit),
|
.startBit(rxStartBit),
|
.stopBit(guardTime),
|
.stopBit(guardTime),
|
.clkPerCycle(clkPerCycle),
|
.clkPerCycle(clkPerCycle),
|
.clocksPerBit(cyclesPerEtu-1),
|
.clocksPerBit(cyclesPerEtu-1),
|
.stopBit2(stopBit2),
|
.stopBit2(stopBit2),
|
.oddParity(oddParity),
|
.oddParity(oddParity),
|
.msbFirst(msbFirst),
|
.msbFirst(msbFirst),
|
.ackFlags(ackFlags),
|
.ackFlags(ackFlags),
|
.serialIn(isoSio),
|
.serialIn(isoSio),
|
.comClk(isoClk),
|
.comClk(isoClk),
|
.clk(clk),
|
.clk(clk),
|
.nReset(nReset)
|
.nReset(nReset)
|
);
|
);
|
|
|
TsAnalyzer tsAnalyzer(
|
TsAnalyzer tsAnalyzer(
|
.nReset(nReset),
|
.nReset(nReset),
|
.isoReset(isoReset),
|
.isoReset(isoReset),
|
.isoClk(isoClk),
|
.isoClk(isoClk),
|
.isoVdd(isoVdd),
|
.isoVdd(isoVdd),
|
.isoSio(isoSio),
|
.isoSio(isoSio),
|
.endOfRx(endOfRx),
|
.endOfRx(endOfRx),
|
.rxData(rxData),
|
.rxData(rxData),
|
.isActivated(isActivated),
|
.isActivated(isActivated),
|
.tsReceived(tsReceived),
|
.tsReceived(tsReceived),
|
.tsError(tsError),
|
.tsError(tsError),
|
.atrIsEarly(atrIsEarly),
|
.atrIsEarly(atrIsEarly),
|
.atrIsLate(atrIsLate),
|
.atrIsLate(atrIsLate),
|
.useIndirectConvention(useIndirectConvention)
|
.useIndirectConvention(useIndirectConvention)
|
);
|
);
|
|
|
FiDiAnalyzer fiDiAnalyzer(
|
FiDiAnalyzer fiDiAnalyzer(
|
.fiCode(fiCode),
|
.fiCode(fiCode),
|
.diCode(diCode),
|
.diCode(diCode),
|
.fi(fi),
|
.fi(fi),
|
.di(di),
|
.di(di),
|
.cyclesPerEtu(cyclesPerEtu),
|
.cyclesPerEtu(cyclesPerEtu),
|
.fMax(fMax)
|
.fMax(fMax)
|
);
|
);
|
|
|
wire run = rxStartBit | rxRun;
|
wire run = rxStartBit | rxRun;
|
localparam ATR_T0 = 0;
|
localparam ATR_T0 = 0;
|
localparam ATR_TDI = 1;
|
localparam ATR_TDI = 1;
|
localparam ATR_HISTORICAL = 2;
|
localparam ATR_HISTORICAL = 2;
|
localparam ATR_TCK = 3;
|
localparam ATR_TCK = 3;
|
localparam T0_HEADER = 0;
|
localparam T0_HEADER = 0;
|
localparam T0_PB = 0;
|
localparam T0_HEADER_TPDU = 1;
|
localparam T0_DATA = 0;
|
localparam T0_PB = 2;
|
|
localparam T0_DATA = 3;
|
|
localparam T0_NACK_DATA = 4;
|
|
localparam T0_SW1 = 5;
|
|
localparam T0_SW2 = 6;
|
|
localparam T0_HEADER_PPS = 100;
|
|
|
integer fsmState;
|
integer fsmState;
|
|
|
reg [11:0] tdiStruct;
|
reg [11:0] tdiStruct;
|
wire [3:0] tdiCnt;//i+1
|
wire [3:0] tdiCnt;//i+1
|
wire [7:0] tdiData;//value of TDi
|
wire [7:0] tdiData;//value of TDi
|
assign {tdiCnt,tdiData}=tdiStruct;
|
assign {tdiCnt,tdiData}=tdiStruct;
|
|
|
wire [1:0] nIfBytes;
|
wire [1:0] nIfBytes;
|
HammingWeight hammingWeight(.dataIn(tdiData[7:4]), .hammingWeight(nIfBytes));
|
HammingWeight hammingWeight(.dataIn(tdiData[7:4]), .hammingWeight(nIfBytes));
|
reg [7:0] tempBytesCnt;
|
reg [7:0] tempBytesCnt;
|
always @(posedge isoClk, negedge nReset) begin
|
always @(posedge isoClk, negedge nReset) begin
|
if(~nReset) begin
|
if(~nReset) begin
|
lastByte<=8'b0;
|
lastByte<=8'b0;
|
ackFlags<=1'b0;
|
ackFlags<=1'b0;
|
bytesCnt<=32'b0;
|
bytesCnt<=32'b0;
|
end else if(ackFlags) begin
|
end else if(ackFlags) begin
|
ackFlags<=1'b0;
|
ackFlags<=1'b0;
|
end else if(frameErrorFlag|bufferFull) begin
|
end else if(frameErrorFlag|bufferFull) begin
|
lastByte<=dataOut;
|
lastByte<=dataOut;
|
ackFlags<=1'b1;
|
ackFlags<=1'b1;
|
bytesCnt<=bytesCnt+1'b1;
|
bytesCnt<=bytesCnt+1'b1;
|
end
|
end
|
end
|
end
|
always @(posedge isoClk, negedge nReset) begin
|
always @(posedge isoClk, negedge nReset) begin
|
if(~nReset) begin
|
if(~nReset) begin
|
fiCode<=4'b0001;
|
fiCode<=4'b0001;
|
diCode<=4'b0001;
|
diCode<=4'b0001;
|
useT0<=1'b1;
|
useT0<=1'b1;
|
useT1<=1'b0;
|
useT1<=1'b0;
|
useT15<=1'b0;
|
useT15<=1'b0;
|
waitCardTx<=1'b0;
|
{waitCardTx,waitTermTx}<=2'b00;
|
waitTermTx<=1'b0;
|
|
fsmState<=ATR_TDI;
|
fsmState<=ATR_TDI;
|
atrHasTck<=1'b0;
|
atrHasTck<=1'b0;
|
tempBytesCnt<=8'h0;
|
tempBytesCnt<=8'h0;
|
tdiStruct<=12'h0;
|
tdiStruct<=12'h0;
|
atrCompleted<=1'b0;
|
atrCompleted<=1'b0;
|
|
atrK<=4'b0;
|
end else if(isActivated) begin
|
end else if(isActivated) begin
|
if(~tsReceived) begin
|
if(~tsReceived) begin
|
waitCardTx<=1'b1;
|
{waitCardTx,waitTermTx}<=2'b10;
|
end else if(~atrCompleted) begin
|
end else if(~atrCompleted) begin
|
//ATR analysis
|
//ATR analysis
|
case(fsmState)
|
case(fsmState)
|
ATR_TDI: begin
|
ATR_TDI: begin
|
if(endOfRx) begin
|
if(endOfRx) begin
|
if(tempBytesCnt==nIfBytes) begin //TDi bytes
|
if(tempBytesCnt==nIfBytes) begin //TDi bytes
|
tempBytesCnt <= 2'h0;
|
tempBytesCnt <= 2'h0;
|
tdiStruct <= {tdiCnt+1,dataOut};
|
tdiStruct <= {tdiCnt+1,dataOut};
|
if(4'h0==tdiCnt) begin//this is T0
|
if(4'h0==tdiCnt) begin//this is T0
|
atrK <= dataOut[3:0];
|
atrK <= dataOut[3:0];
|
fsmState <= (4'b0!=dataOut[7:4]) ? ATR_TDI :
|
fsmState <= (4'b0!=dataOut[7:4]) ? ATR_TDI :
|
(4'b0!=dataOut[3:0]) ? ATR_HISTORICAL : T0_HEADER;
|
(4'b0!=dataOut[3:0]) ? ATR_HISTORICAL : T0_HEADER;
|
end else begin//TDi, i from 1 to 15
|
end else begin//TDi, i from 1 to 15
|
fsmState <= (4'b0!=dataOut[7:4]) ? ATR_TDI :
|
fsmState <= (4'b0!=dataOut[7:4]) ? ATR_TDI :
|
(4'b0!=atrK) ? ATR_HISTORICAL : T0_HEADER;
|
(4'b0!=atrK) ? ATR_HISTORICAL : T0_HEADER;
|
end
|
end
|
|
if(12'h0=={dataOut,atrK}) begin
|
|
atrCompleted <= 1'b1;
|
|
{waitCardTx,waitTermTx}<=2'b01;
|
|
end
|
end else begin //TA, TB or TC bytes
|
end else begin //TA, TB or TC bytes
|
//TODO: get relevant info
|
//TODO: get relevant info
|
tempBytesCnt <= tempBytesCnt+1;
|
tempBytesCnt <= tempBytesCnt+1;
|
end
|
end
|
end
|
end
|
end
|
end
|
ATR_HISTORICAL: begin
|
ATR_HISTORICAL: begin
|
if(endOfRx) begin
|
if(endOfRx) begin
|
if(tempBytesCnt==atrK) begin
|
if(tempBytesCnt==atrK) begin
|
|
tempBytesCnt <= 8'h0;
|
|
if(atrHasTck) begin
|
|
fsmState <= ATR_TCK;
|
|
end else begin
|
atrCompleted <= ~atrHasTck;
|
atrCompleted <= ~atrHasTck;
|
fsmState <= atrHasTck ? ATR_TCK : T0_HEADER;
|
{waitCardTx,waitTermTx}<=2'b10;
|
|
fsmState <= T0_HEADER;
|
|
end
|
end else begin
|
end else begin
|
tempBytesCnt <= tempBytesCnt+1;
|
tempBytesCnt <= tempBytesCnt+1;
|
end
|
end
|
end
|
end
|
end
|
end
|
ATR_TCK: begin
|
ATR_TCK: begin
|
if(endOfRx) begin
|
if(endOfRx) begin
|
//TODO:check
|
//TODO:check
|
atrCompleted <= 1'b1;
|
atrCompleted <= 1'b1;
|
|
{waitCardTx,waitTermTx}<=2'b10;
|
fsmState <= T0_HEADER;
|
fsmState <= T0_HEADER;
|
end
|
end
|
end
|
end
|
endcase
|
endcase
|
end else if(useT0) begin
|
end else if(useT0) begin
|
//T=0 cmd/response monitoring state machine
|
//T=0 cmd/response monitoring state machine
|
|
case(fsmState)
|
|
T0_HEADER: begin
|
|
if(endOfRx) begin
|
|
tpduHeader[CLA_I+:8]<=dataOut;
|
|
tempBytesCnt <= 1;
|
|
if(8'hFF==dataOut)
|
|
fsmState <= T0_HEADER_PPS;//TODO
|
|
else
|
|
fsmState <= T0_HEADER_TPDU;
|
|
end
|
|
end
|
|
T0_HEADER_TPDU: begin
|
|
if(endOfRx) begin
|
|
tpduHeader[(CLA_I-(tempBytesCnt*8))+:8]<=dataOut;
|
|
if(4==tempBytesCnt) begin
|
|
tempBytesCnt <= 8'h0;
|
|
fsmState <= T0_PB;
|
|
{waitCardTx,waitTermTx}<=2'b10;
|
|
end else begin
|
|
tempBytesCnt <= tempBytesCnt+1;
|
|
end
|
|
end
|
|
end
|
|
T0_PB: begin
|
|
if(endOfRx) begin
|
|
case(dataOut[7:4])
|
|
4'h6: begin
|
|
fsmState <= (4'h0==dataOut[3:0]) ? T0_PB : T0_SW2;
|
|
end
|
|
4'h9: begin
|
|
fsmState <= T0_SW2;
|
|
end
|
|
default: begin
|
|
case(dataOut)
|
|
tpduHeader[INS_I+:8]: begin//ACK
|
|
fsmState <= T0_DATA;
|
|
{waitCardTx,waitTermTx}<=2'b11;
|
|
end
|
|
~tpduHeader[INS_I+:8]: begin//NACK
|
|
fsmState <= T0_NACK_DATA;
|
|
{waitCardTx,waitTermTx}<=2'b11;
|
|
end
|
|
default: begin //invalid
|
|
//TODO
|
|
end
|
|
endcase
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
T0_NACK_DATA: begin
|
|
if(endOfRx) begin
|
|
fsmState <= T0_PB;
|
|
{waitCardTx,waitTermTx}<=2'b10;
|
|
tempBytesCnt <= tempBytesCnt+1;
|
|
end
|
|
end
|
|
T0_SW1: begin
|
|
if(endOfRx) begin
|
|
//TODO:check != 60 but equal to 6x or 9x
|
|
fsmState <= T0_SW2;
|
|
{waitCardTx,waitTermTx}<=2'b10;
|
|
end
|
|
end
|
|
T0_SW2: begin
|
|
if(endOfRx) begin
|
|
fsmState <= T0_HEADER;
|
|
{waitCardTx,waitTermTx}<=2'b01;
|
|
end
|
|
end
|
|
T0_DATA: begin
|
|
if(endOfRx) begin
|
|
if(tempBytesCnt==(tpduHeader[P3_I+:8]-1)) begin
|
|
tempBytesCnt <= 0;
|
|
fsmState <= T0_SW1;
|
|
{waitCardTx,waitTermTx}<=2'b10;
|
|
end else begin
|
|
tempBytesCnt <= tempBytesCnt+1;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
reg [1:0] txDir;
|
reg [1:0] txDir;
|
always @(*) begin: errorSigDirectionBlock
|
always @(*) begin: errorSigDirectionBlock
|
if(guardTime & ~isoSio)
|
if(guardTime & ~isoSio)
|
{cardTx, termTx}={txDir[0],txDir[1]};
|
{cardTx, termTx}={txDir[0],txDir[1]};
|
else
|
else
|
{cardTx, termTx}={txDir[1],txDir[0]};
|
{cardTx, termTx}={txDir[1],txDir[0]};
|
end
|
end
|
always @(posedge isoClk, negedge nReset) begin: comDirectionBlock
|
always @(posedge isoClk, negedge nReset) begin: comDirectionBlock
|
if(~nReset | ~run) begin
|
if(~nReset | ~run) begin
|
txDir<=2'b00;
|
txDir<=2'b00;
|
end else begin
|
end else begin
|
if(~guardTime) begin //{waitCardTx, waitTermTx} is updated during stop bits so we hold current value here
|
if(~guardTime) begin //{waitCardTx, waitTermTx} is updated during stop bits so we hold current value here
|
case({waitCardTx, waitTermTx})
|
case({waitCardTx, waitTermTx})
|
2'b00: txDir<=2'b00;
|
2'b00: txDir<=2'b00;//no one should/is sending
|
2'b01: txDir<=2'b01;
|
2'b01: txDir<=2'b01;//terminal should/is sending
|
2'b10: txDir<=2'b10;
|
2'b10: txDir<=2'b10;//card should/is sending
|
2'b11: txDir<=2'b00;
|
2'b11: txDir<=2'b11;//either card OR terminal should/is sending (we just don't know)
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
|
|