URL
https://opencores.org/ocsvn/iso7816_3_master/iso7816_3_master/trunk
Subversion Repositories iso7816_3_master
Compare Revisions
- This comparison shows the changes necessary to convert path
/iso7816_3_master
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/test/tb_HalfDuplexUartIf.v
0,0 → 1,275
`timescale 1ns / 1ps |
|
//////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: |
// |
// Create Date: 22:45:51 10/31/2010 |
// Design Name: HalfDuplexUartIf |
// Module Name: /home/seb/dev/hardware/Uart/tb_HalfDuplexUartIf.v |
// Project Name: Uart |
// Target Device: |
// Tool versions: |
// Description: |
// |
// Verilog Test Fixture created by ISE for module: HalfDuplexUartIf |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
module tb_HalfDuplexUartIf; |
parameter CLK_PERIOD = 10;//should be %2 |
parameter DIVIDER_WIDTH = 16; |
// Inputs |
reg nReset; |
reg clk; |
reg [DIVIDER_WIDTH-1:0] clkPerCycle; |
reg [7:0] dataIn; |
reg nWeDataIn; |
reg nCsDataOut; |
reg nCsStatusOut; |
wire serialIn; |
|
// Outputs |
wire [7:0] dataOut; |
wire [7:0] statusOut; |
wire serialOut; |
wire isTx; |
|
// Inputs |
reg [7:0] dataIn2; |
reg nWeDataIn2; |
reg nCsDataOut2; |
reg nCsStatusOut2; |
wire serialIn2; |
|
// Outputs |
wire [7:0] dataOut2; |
wire [7:0] statusOut2; |
wire serialOut2; |
wire isTx2; |
|
// Bidirs |
wire serialLine = isTx ? serialOut : isTx2 ? serialOut2 : 1'bz; |
pullup(serialLine); |
|
assign serialIn = serialLine; |
assign serialIn2 = serialLine; |
|
// Instantiate the Unit Under Test (UUT) |
HalfDuplexUartIf #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
uut ( |
.nReset(nReset), |
.clk(clk), |
.clkPerCycle(clkPerCycle), |
.dataIn(dataIn), |
.nWeDataIn(nWeDataIn), |
.dataOut(dataOut), |
.nCsDataOut(nCsDataOut), |
.statusOut(statusOut), |
.nCsStatusOut(nCsStatusOut), |
.serialIn(serialIn), |
.serialOut(serialOut), |
.isTx(isTx) |
); |
|
HalfDuplexUartIf #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
uut2 ( |
.nReset(nReset), |
.clk(clk), |
.clkPerCycle(clkPerCycle), |
.dataIn(dataIn2), |
.nWeDataIn(nWeDataIn2), |
.dataOut(dataOut2), |
.nCsDataOut(nCsDataOut2), |
.statusOut(statusOut2), |
.nCsStatusOut(nCsStatusOut2), |
.serialIn(serialIn2), |
.serialOut(serialOut2), |
.isTx(isTx2) |
); |
|
integer tbErrorCnt; |
wire bufferFull = statusOut[0]; |
wire bufferFull2 = statusOut2[0]; |
wire txPending = statusOut[6]; |
wire txPending2 = statusOut2[6]; |
|
/*//this is sensitive to glitch in combo logic so we cannot use wait(txRun == 0) or @negedge(txRun)... |
wire bufferFull = statusOut[0]; |
wire rxRun = statusOut[5]; |
wire txRun = statusOut[6]; |
|
wire bufferFull2 = statusOut2[0]; |
wire rxRun2 = statusOut2[5]; |
wire txRun2 = statusOut2[6]; |
*/ |
//reg bufferFull ;//already registered |
reg rxRun ; |
reg txRun ; |
|
//reg bufferFull2 ; |
reg rxRun2 ; |
reg txRun2 ; |
always @(posedge clk) begin |
//bufferFull <= statusOut[0]; |
rxRun <= statusOut[5]; |
txRun <= statusOut[7]; |
//bufferFull2 <= statusOut2[0]; |
rxRun2 <= statusOut2[5]; |
txRun2 <= statusOut2[7]; |
end |
|
task sendByte; |
input [7:0] data; |
begin |
wait(bufferFull==1'b0); |
dataIn=data; |
nWeDataIn=0; |
@(posedge clk); |
dataIn=8'hxx; |
nWeDataIn=1; |
@(posedge clk); |
end |
endtask |
|
task sendByte2; |
input [7:0] data; |
begin |
wait(bufferFull2==1'b0); |
dataIn2=data; |
nWeDataIn2=0; |
@(posedge clk); |
dataIn2=8'hxx; |
nWeDataIn2=1; |
@(posedge clk); |
end |
endtask |
|
task receiveByte; |
input [7:0] data; |
begin |
wait(txPending==1'b0);//wait start of last tx if any |
wait(txRun==1'b0);//wait end of previous transmission if any |
wait(bufferFull==1'b1);//wait reception of a byte |
@(posedge clk); |
nCsDataOut=0; |
@(posedge clk); |
nCsDataOut=1; |
if(data!=dataOut) begin |
tbErrorCnt=tbErrorCnt+1; |
$display("ERROR %d: uart1 received %x instead of %x",tbErrorCnt, dataOut, data); |
end |
@(posedge clk); |
end |
endtask |
|
task receiveByte2; |
input [7:0] data; |
begin |
wait(txPending2==1'b0);//wait start of last tx if any |
wait(txRun2==1'b0);//wait end of previous transmission if any |
wait(bufferFull2==1'b1);//wait reception of a byte |
@(posedge clk); |
nCsDataOut2=0; |
@(posedge clk); |
nCsDataOut2=1; |
if(data!=dataOut2) begin |
tbErrorCnt=tbErrorCnt+1; |
$display("ERROR %d: uart2 received %x instead of %x (time=%d)",tbErrorCnt, dataOut2, data,$time); |
end else |
$display("INFO: uart2 received %x (time=%d)",dataOut2,$time); |
@(posedge clk); |
end |
endtask |
|
integer tbSequenceDone; |
integer tbSequenceDone2; |
initial begin |
// Initialize Inputs |
nReset = 0; |
clk = 0; |
dataIn = 0; |
clkPerCycle = 0; |
nWeDataIn = 1; |
nCsDataOut = 1; |
nCsStatusOut = 1; |
nWeDataIn2 = 1; |
nCsDataOut2 = 1; |
nCsStatusOut2 = 1; |
tbErrorCnt=0; |
tbSequenceDone=0; |
tbSequenceDone2=0; |
// Wait 100 ns for global reset to finish |
#(CLK_PERIOD*10); |
#(CLK_PERIOD/2); |
nReset = 1; |
// Add stimulus here |
@(posedge clk); |
dataIn=8'h3B; |
nWeDataIn=0; |
@(posedge clk); |
dataIn=8'h00; |
nWeDataIn=1; |
@(posedge clk); |
if(bufferFull==1'b0) begin |
tbErrorCnt=tbErrorCnt+1; |
$display("ERROR %d: bufferFull==1'b0",tbErrorCnt); |
end |
@(posedge clk); |
@(posedge clk); |
if(bufferFull==1'b1) begin |
tbErrorCnt=tbErrorCnt+1; |
$display("ERROR %d: bufferFull==1'b1",tbErrorCnt); |
end |
//sendByte(8'h3B); |
|
sendByte(8'h97); |
sendByte(8'h12); |
sendByte(8'h34); |
receiveByte(8'h55); |
sendByte(8'h56); |
sendByte(8'h78); |
tbSequenceDone=1; |
end |
|
initial begin |
receiveByte2(8'h3B); |
receiveByte2(8'h97); |
receiveByte2(8'h12); |
receiveByte2(8'h34); |
sendByte2(8'h55); |
receiveByte2(8'h56); |
receiveByte2(8'h78); |
tbSequenceDone2=1; |
end |
initial begin |
wait(tbSequenceDone & tbSequenceDone2); |
if(tbErrorCnt) |
$display("INFO: Test FAILED (%d errors)", tbErrorCnt); |
else |
$display("INFO: Test PASSED"); |
#10; |
$finish; |
end |
initial begin |
// timeout |
#10000; |
tbErrorCnt=tbErrorCnt+1; |
$display("ERROR: timeout expired"); |
#10; |
$finish; |
end |
|
always |
#(CLK_PERIOD/2) clk = ! clk; |
|
|
|
endmodule |
|
/trunk/test/tb_BasicHalfDuplexUart.v
0,0 → 1,87
`timescale 1ns / 1ps |
|
//////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: |
// |
// Create Date: 19:45:19 10/31/2010 |
// Design Name: BasicHalfDuplexUart |
// Module Name: /home/seb/dev/hardware/Uart/tb_BasicHalfDuplexUart.v |
// Project Name: Uart |
// Target Device: |
// Tool versions: |
// Description: |
// |
// Verilog Test Fixture created by ISE for module: BasicHalfDuplexUart |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
module tb_BasicHalfDuplexUart; |
|
// Inputs |
reg [7:0] txData; |
reg [12:0] clocksPerBit; |
reg stopBit2; |
reg startTx; |
reg ackFlags; |
reg clk; |
reg nReset; |
|
// Outputs |
wire [7:0] rxData; |
wire overrunErrorFlag; |
wire dataOutReadyFlag; |
wire frameErrorFlag; |
wire run; |
wire rxStartBit; |
wire txFull; |
wire isTx; |
|
// Bidirs |
wire serialLine; |
|
// Instantiate the Unit Under Test (UUT) |
BasicHalfDuplexUart uut ( |
.rxData(rxData), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.run(run), |
.rxStartBit(rxStartBit), |
.txFull(txFull), |
.isTx(isTx), |
.serialLine(serialLine), |
.txData(txData), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.startTx(startTx), |
.ackFlags(ackFlags), |
.clk(clk), |
.nReset(nReset) |
); |
|
initial begin |
// Initialize Inputs |
txData = 0; |
clocksPerBit = 0; |
stopBit2 = 0; |
startTx = 0; |
ackFlags = 0; |
clk = 0; |
reset = 0; |
|
// Wait 100 ns for global reset to finish |
#100; |
|
// Add stimulus here |
|
end |
|
endmodule |
|
/trunk/test/RxCoreTestBench.v
0,0 → 1,665
`timescale 1ns / 1ps |
|
//////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: |
// |
// Create Date: 21:02:24 09/02/2010 |
// Design Name: RxCore |
// Module Name: D:/Hardware/Uart/tb_RxCore.v |
// Project Name: Uart |
// Target Device: |
// Tool versions: |
// Description: |
// |
// Verilog Test Fixture created by ISE for module: RxCore |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
module tb_RxCoreComparator( |
output reg implMismatch, |
output [7:0] dataOut, |
output overrunErrorFlag, //new data has been received before dataOut was read |
output dataOutReadyFlag, //new data available |
output frameErrorFlag, //bad parity or bad stop bits |
output endOfRx, |
output run, //rx is definitely started, one of the three flag will be set |
output startBit, //rx is started, but we don't know yet if real rx or just a glitch |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input ackFlags, |
input serialIn, |
input clk, |
input nReset |
); |
|
parameter CLK_PERIOD = 10;//should be %2 |
//parameters to override |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
parameter IN_POLARITY = 1'b0; |
parameter PARITY_POLARITY = 1'b0; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
wire [7:0] ref_dataOut; |
wire ref_overrunErrorFlag; |
wire ref_dataOutReadyFlag; |
wire ref_frameErrorFlag; |
wire ref_endOfRx; |
wire ref_run; |
wire ref_startBit; |
|
RxCoreSpec #(.PARITY_POLARITY(PARITY_POLARITY)) ref ( |
.dataOut(ref_dataOut), |
.overrunErrorFlag(ref_overrunErrorFlag), |
.dataOutReadyFlag(ref_dataOutReadyFlag), |
.frameErrorFlag(ref_frameErrorFlag), |
.endOfRx(ref_endOfRx), |
.run(ref_run), |
.startBit(ref_startBit), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.ackFlags(ackFlags), |
.serialIn(serialIn), |
.clk(clk), |
.nReset(nReset) |
); |
|
RxCoreSelfContained #(.PARITY_POLARITY(PARITY_POLARITY)) uut ( |
.dataOut(dataOut), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.endOfRx(endOfRx), |
.run(run), |
.startBit(startBit), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.ackFlags(ackFlags), |
.serialIn(serialIn), |
.clk(clk), |
.nReset(nReset) |
); |
|
initial |
implMismatch=0; |
|
always @(posedge clk, posedge nReset) begin |
implMismatch=0; |
if(dataOut!=ref_dataOut) begin |
implMismatch=1; |
$display ("ERROR: dataOut!=ref_dataOut"); |
end |
if(overrunErrorFlag!=ref_overrunErrorFlag) begin |
implMismatch=1; |
$display ("ERROR: overrunErrorFlag!=ref_overrunErrorFlag"); |
end |
if(dataOutReadyFlag!=ref_dataOutReadyFlag) begin |
implMismatch=1; |
$display ("ERROR: dataOutReadyFlag!=ref_dataOutReadyFlag"); |
end |
if(frameErrorFlag!=ref_frameErrorFlag) begin |
implMismatch=1; |
$display ("ERROR: frameErrorFlag!=ref_frameErrorFlag"); |
end |
if(endOfRx!=ref_endOfRx) begin |
implMismatch=1; |
$display ("ERROR: endOfRx!=ref_endOfRx"); |
end |
if(run!=ref_run) begin |
implMismatch=1; |
$display ("ERROR: run!=ref_run"); |
end |
if(startBit!=ref_startBit) begin |
implMismatch=1; |
$display ("ERROR: startBit!=ref_startBit"); |
end |
end |
|
endmodule |
|
|
module tb_RxCore; |
parameter PARITY = 1; |
parameter CLK_PERIOD = 10;//should be %2 |
// Inputs |
reg [12:0] clocksPerBit; |
reg stopBit2; |
reg ackFlags; |
wire realSerialIn; |
reg clk; |
reg nReset; |
|
// Outputs |
wire [7:0] dataOut; |
wire overrunErrorFlag; |
wire dataOutReadyFlag; |
wire frameErrorFlag; |
wire run; |
wire startBit; |
|
|
reg serialIn; |
assign #1 realSerialIn = serialIn; |
|
// Instantiate the Unit Under Test (UUT) |
wire implMismatch; |
tb_RxCoreComparator #(.PARITY_POLARITY(PARITY)) uut ( |
.implMismatch(implMismatch), |
.dataOut(dataOut), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.endOfRx(endOfRx), |
.run(run), |
.startBit(startBit), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.ackFlags(ackFlags), |
.serialIn(realSerialIn), |
.clk(clk), |
.nReset(nReset) |
); |
|
|
//test bench signals |
reg tbClock; |
integer tbError; |
integer tbClockCounter; |
integer tbBitTime; |
integer tbStartBitTime,tbRunBitFallTime, tbByteTime, tbByteMinTime, tbByteClockCounter; |
integer tbLastStartBit; |
reg tbStartBitEn;//set this to 0 to turn of start bit detection (useful when testing glitch) |
|
event TrigResetDut; |
event TrigResetDutRelease; |
event TrigTerminateSim; |
|
initial |
begin |
$display ("###################################################"); |
clk = 0; |
nReset = 0; |
tbError = 0; |
tbClockCounter=0; |
end |
|
initial |
@ (TrigTerminateSim) begin |
$display ("Terminating simulation"); |
if (tbError == 0) begin |
$display ("Simulation Result : PASSED"); |
end |
else begin |
$display ("Simulation Result : FAILED, %d error(s)", tbError); |
end |
$display ("###################################################"); |
#1 $finish; |
end |
|
//parameter values for SendByte task |
localparam WRONG_PARITY=8; |
localparam ACKFLAGS=4; |
localparam EXPECT_OVERRUN=2; |
localparam EXPECT_FRAME_ERROR=1; |
|
initial |
forever begin |
@ (TrigResetDut); |
$display ("Applying nReset"); |
nReset = 0; |
#(CLK_PERIOD*10); |
nReset = 1; |
$display ("Reset release"); |
-> TrigResetDutRelease; |
end |
|
initial begin |
//tb signals |
tbBitTime=8; |
tbStartBitEn=1; |
// DUT Inputs |
clocksPerBit = tbBitTime-1; |
stopBit2=0; |
ackFlags = 0; |
clk = 0; |
nReset = 0; |
tbClock=0; |
tbError=0; |
serialIn=1; |
|
//tb signals which depends on DUT config |
//those times are in clock cycle unit |
tbByteTime=(11+stopBit2)*tbBitTime; |
tbByteMinTime=tbByteTime-(tbBitTime/4); |
tbdataOutReadyBitMinTime=9*tbBitTime+(tbBitTime/2)-1; |
tbdataOutReadyBitMaxTime=tbdataOutReadyBitMinTime+(tbBitTime/4)+1; |
|
tc01_basicTransfer(); |
tc02_earliestAckFlags(); |
tc03_ackFlagsPolling(); |
tc04_contiuousTransfer(); |
tc05_parityError(); |
tc06_basicOverrun(); |
tc07_abortedStart(); |
tc08_stopBitViolation(); |
tc09_ackFlagsPollingFrameError(); |
|
#(CLK_PERIOD*12); |
-> TrigTerminateSim; |
end |
|
reg ackFlagsDone; |
task ackFlagsTask; |
begin |
ackFlags=1; |
#(CLK_PERIOD*1); |
ackFlagsDone=1; |
ackFlags=0; |
#(CLK_PERIOD*1); |
if(dataOutReadyFlag) begin |
tbError=tbError+1; |
$display("Error %d: dataOutReadyFlag is still set",tbError); |
end |
end |
endtask |
|
task tc01_basicTransfer; |
begin |
//uut.dataOut=8'b0;//to see the point where it becomes undefined when a rx started |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h55, 0); |
#(CLK_PERIOD*tbBitTime*2); |
ackFlagsTask(); |
end |
endtask |
|
task tc02_earliestAckFlags; |
begin |
//uut.dataOut=8'b0;//to see the point where it becomes undefined when a rx started |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
fork |
SendByte(8'h55, 0); |
begin |
wait(dataOutReadyFlag===1); |
ackFlagsTask(); |
end |
join |
end |
endtask |
|
task tc03_ackFlagsPolling; |
begin |
//uut.dataOut=8'b0;//to see the point where it becomes undefined when a rx started |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
ackFlags=1;//stuck it to one to simulate intensive polling |
#(CLK_PERIOD*2); |
fork |
SendByte(8'h55, 0); |
begin |
wait(dataOutReadyFlag===1);//check that dataOutReadyFlag is set even if ackFlags is set continuously |
#1; |
ackFlagsDone=1;//set ackFlagsDone to avoid to get dummy error due to the check within SendByte |
end |
join |
ackFlags=0; |
end |
endtask |
|
task tc04_contiuousTransfer; |
integer i,tc04Done; |
begin |
tc04Done=0; |
//uut.dataOut=8'b0;//to see the point where it becomes undefined when a rx started |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
lateAckFlagsEnable=1; |
fork |
begin |
for(i=0;i<256;i=i+1) begin |
SendByte(i, 0); |
//not supported by ISE12.2 (AR# 36304) |
//replaced by LATE_ACKFLAGS |
/*fork |
SendByte(i, 0); |
begin//ackFlags at the latest time possible for continuous transfer |
#(CLK_PERIOD*((tbBitTime/2)+tbBitTime-1)); |
ackFlagsTask(); |
end |
join*/ |
end |
tc04Done=1; |
end |
begin |
wait(run===1); |
@(negedge tbIsRx); |
//Spec change, run goes low one cycles earlier so a negedge happen even during continuous transfers |
//to emulate old behavior, a signal following run can be implement using a flip flop and combine run and following signal with an or gate... |
/*if(0==tc04Done) begin |
tbError=tbError+1; |
$display("Error %d: tbIsRx went low during continuous transfer",tbError); |
end*/ |
end |
join |
lateAckFlagsEnable=0; |
end |
endtask |
|
task tc05_parityError; |
begin |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
SendByte(8'h55, WRONG_PARITY|EXPECT_FRAME_ERROR); |
#(CLK_PERIOD*10); |
ackFlagsTask(); |
#(CLK_PERIOD*10); |
SendByte(8'hAA, ACKFLAGS); |
end |
endtask |
|
task tc06_basicOverrun; |
begin |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
SendByte(8'h55, 0); |
SendByte(8'hAA, EXPECT_OVERRUN); |
end |
endtask |
|
task tc07_abortedStart; |
begin |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
tbStartBitEn=0; |
serialIn=0; |
#(CLK_PERIOD*((tbBitTime/2)-1)); |
serialIn=1; |
tbStartBitEn=1; |
#(CLK_PERIOD*(tbBitTime/2)); |
SendByte(8'h55, ACKFLAGS); |
end |
endtask |
|
task tc08_stopBitViolation; |
begin |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByteEarlyExit(8'h00, ACKFLAGS); |
SendByte(8'h55, ACKFLAGS|EXPECT_FRAME_ERROR); |
end |
endtask |
|
task tc09_ackFlagsPollingFrameError; |
begin |
//uut.dataOut=8'b0;//to see the point where it becomes undefined when a rx started |
-> TrigResetDut;@(TrigResetDutRelease); |
#(CLK_PERIOD*2); |
SendByte(8'h00, ACKFLAGS); |
ackFlags=1;//stuck it to one to simulate intensive polling |
#(CLK_PERIOD*2); |
fork |
SendByte(8'h55, WRONG_PARITY|EXPECT_FRAME_ERROR); |
begin |
wait(frameErrorFlag===1);//check that frameErrorFlag is set even if ackFlags is set continuously |
#1; |
ackFlagsDone=1;//set ackFlagsDone to avoid to get dummy error due to the check within SendByte |
end |
join |
ackFlags=0; |
end |
endtask |
|
/*always |
#1 tbClock = ! tbClock;*/ |
always |
#(CLK_PERIOD/2) clk = ! clk; |
|
always @(posedge clk) begin |
tbClockCounter = tbClockCounter + 1; |
if(implMismatch) |
tbError=tbError+1; |
end |
|
|
reg tbIsRx; |
always @(posedge clk) begin |
case({run, startBit}) |
2'bx0: tbIsRx<=1'b0; |
2'b0x: tbIsRx<=1'b0; |
2'b00: tbIsRx<=1'b0; |
2'b01: tbIsRx<=1'b1; |
2'b10: tbIsRx<=1'b1; |
2'bx1: tbIsRx<=1'b1; |
2'b1x: tbIsRx<=1'b1; |
2'b11: begin |
tbError=tbError+1; |
$display("Error %d: run & StartBit are set simultaneously during clock rising edge",tbError); |
end |
endcase |
end |
|
reg lateAckFlagsEnable; |
initial |
lateAckFlagsEnable=0; |
|
always @(posedge SendByteStart) begin:LATE_ACKFLAGS |
if(lateAckFlagsEnable) begin |
#(CLK_PERIOD*(tbBitTime-1)); |
//#(CLK_PERIOD);//to test it is really the latest cycle to ack the flags |
ackFlagsTask(); |
end |
end |
|
|
function computeParity; |
input [7:0] data; |
integer parity; |
begin |
parity = 0; |
parity = ^data; |
parity = parity ^ PARITY ^ 1; |
computeParity = parity; |
end |
endfunction |
|
integer tbStartBitTimeSampler; |
initial |
forever begin |
@ (posedge startBit); |
if(tbStartBitEn && (1===startBit)) begin //ignore posedge from 0 to x. |
tbStartBitTimeSampler = tbClockCounter; |
tbByteClockCounter=0; |
tbLastStartBit=startBit; |
fork |
begin |
#(CLK_PERIOD*tbBitTime); |
tbStartBitTime=tbStartBitTimeSampler; |
end |
for(tbByteClockCounter=0;tbByteClockCounter<tbByteTime;tbByteClockCounter=tbByteClockCounter+1) begin |
@ (posedge clk); |
if((tbLastStartBit ==0) && (startBit == 1)) begin //this is to handle early start bit (happens before end of previous byte) |
$display("Early start bit (%d)",tbClockCounter); |
if(tbClockCounter-tbStartBitTime < tbByteMinTime) begin //frame error case |
if(frameErrorFlag != 1) begin |
tbError=tbError+1; |
$display("Error %d: start bit too early but frameErrorFlag is not set",tbError); |
end |
end else begin |
if(frameErrorFlag != 0) begin |
tbError=tbError+1; |
$display("Error %d: start bit within tolerated advance but frameErrorFlag is set",tbError); |
end |
end |
tbStartBitTime = tbClockCounter; |
tbByteClockCounter=0; |
end |
tbLastStartBit=startBit; |
end |
join |
end |
end |
initial |
forever begin |
@ (negedge run); |
if(0===run) begin //ignore negedge from 1 to x. |
tbRunBitFallTime = tbClockCounter; |
if(tbRunBitFallTime-tbStartBitTime < tbByteMinTime) begin |
tbError=tbError+1; |
$display("Error %d: tbRunBitFallTime-tbStartBitTime =%d, >= %d was expected",tbError, tbRunBitFallTime-tbStartBitTime, tbByteMinTime ); |
end |
if(tbRunBitFallTime-tbStartBitTime > tbByteTime) begin |
tbError=tbError+1; |
$display("Error %d: tbRunBitFallTime-tbStartBitTime =%d, <=%d was expected",tbError, tbRunBitFallTime-tbStartBitTime, tbByteTime ); |
end |
end |
end |
initial |
forever begin |
wait(dataOutReadyFlag===1); |
ackFlagsDone=0; |
wait(dataOutReadyFlag===0); |
end |
|
reg [7:0] latchedDataOut; |
integer tbdataOutReadyBitTime; |
integer tbdataOutReadyBitMinTime,tbdataOutReadyBitMaxTime; |
initial |
forever begin |
@ (posedge dataOutReadyFlag); |
if(1===dataOutReadyFlag) begin //ignore posedge from 0 to x. |
latchedDataOut<=dataOut; |
tbdataOutReadyBitTime = tbClockCounter; |
if(tbdataOutReadyBitTime-tbStartBitTime < tbdataOutReadyBitMinTime) begin |
tbError=tbError+1; |
$display("Error %d: tbdataOutReadyBitTime-tbStartBitTime =%d, >= %d was expected",tbError, tbdataOutReadyBitTime-tbStartBitTime, tbdataOutReadyBitMinTime ); |
end |
if(tbdataOutReadyBitTime-tbStartBitTime > tbdataOutReadyBitMaxTime) begin |
tbError=tbError+1; |
$display("Error %d: tbdataOutReadyBitTime-tbStartBitTime =%d, <=%d was expected",tbError, tbdataOutReadyBitTime-tbStartBitTime, tbdataOutReadyBitMaxTime ); |
end |
end |
end |
|
reg SendByteStart; |
task SendByte; |
input [7:0] data; |
input [3:0] flags; |
begin |
SendByteEarlyExit(data,flags); |
#(CLK_PERIOD*(tbBitTime-3)); |
end |
endtask |
task SendByteEarlyExit; |
input [7:0] data; |
input [3:0] flags; |
reg wrongParity; |
reg ackFlagsWhenReady; |
reg expectOverrunError; |
reg expectFrameError; |
reg [7:0] initialData; |
begin |
{wrongParity,ackFlagsWhenReady,expectOverrunError,expectFrameError}=flags; |
initialData=data; |
serialIn=0;//start bit |
fork |
begin |
SendByteStart=1; |
#1; |
SendByteStart=0; |
end |
#(CLK_PERIOD*tbBitTime); |
join |
serialIn=data[0];//0 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[1];//1 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[2];//2 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[3];//3 |
`ifdef TEST_TB |
force uut.internalIn=1; |
`endif |
#(CLK_PERIOD*tbBitTime); |
`ifdef TEST_TB |
release uut.internalIn; |
`endif |
serialIn=data[4];//4 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[5];//5 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[6];//6 |
#(CLK_PERIOD*tbBitTime); |
serialIn=data[7];//7 |
#(CLK_PERIOD*tbBitTime); |
if(wrongParity) |
serialIn=~computeParity(data);//wrong parity |
else |
serialIn=computeParity(data);//parity |
#(CLK_PERIOD*tbBitTime); |
if(expectOverrunError & ~ackFlagsDone) begin |
if(overrunErrorFlag != 1) begin |
tbError=tbError+1; |
$display("Error %d: Overrun error expected but overrunErrorFlag is not set",tbError); |
end else if(data!=initialData) begin |
tbError=tbError+1; |
$display("Error %d: Data changed despite overrun condition",tbError); |
end |
end |
if(expectFrameError & ~ackFlagsDone) begin |
if(frameErrorFlag != 1) begin |
tbError=tbError+1; |
$display("Error %d: Frame error expected but frameErrorFlag is not set",tbError); |
end |
serialIn=1; |
#(CLK_PERIOD*tbBitTime*12);//make sure the receiver return to idle state |
end |
if(~expectOverrunError & ~expectFrameError) begin |
if(dataOut!=latchedDataOut)begin |
tbError=tbError+1; |
$display("Error %d: latchedDataOut mismatch-->dataOut changed after dataOutReadyFlag edge, dataOut=0x%x, latchedDataOut=0x%x",tbError, dataOut, latchedDataOut); |
end |
if(data!==dataOut)begin |
tbError=tbError+1; |
$display("Error %d: dataOut mismatch, dataOut=0x%x, 0x%x was expected",tbError, dataOut, data); |
end |
if(~dataOutReadyFlag & ~ackFlagsDone)begin |
tbError=tbError+1; |
$display("Error %d: dataOutReadyFlag is not set",tbError); |
end |
if(frameErrorFlag|overrunErrorFlag)begin |
tbError=tbError+1; |
$display("Error %d: frameErrorFlag|overrunErrorFlag not expected but set",tbError); |
end |
end |
serialIn=1;//stop1 |
fork |
if(ackFlagsWhenReady) begin |
#(CLK_PERIOD*1); |
ackFlagsTask(); |
end else |
#(CLK_PERIOD*3); |
join |
end |
endtask |
|
|
endmodule |
|
/trunk/test/TxCoreTestBench.v
0,0 → 1,102
`timescale 1ns / 1ps |
|
//////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 22:53:00 08/29/2010 |
// Design Name: TxCore |
// Module Name: D:/Hardware/Uart/tb_TxCore.v |
// Project Name: Uart |
// Target Device: |
// Tool versions: |
// Description: |
// |
// Verilog Test Fixture created by ISE for module: TxCore |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
module tb_TxCore; |
parameter PARITY = 1; |
parameter CLK_PERIOD = 10;//should be %2 |
// Inputs |
reg [7:0] dataIn; |
reg loadDataIn; |
reg [12:0] clocksPerBit; |
reg stopBit2; |
wire oddParity=0; //if 1, parity bit is such that data+parity have an odd number of 1 |
wire msbFirst=0; //if 1, bits will be send in the order startBit, b7, b6, b5...b0, parity |
reg clk; |
reg nReset; |
|
// Outputs |
wire serialOut; |
wire run; |
wire full; |
wire stopBits; |
|
// Instantiate the Unit Under Test (UUT) |
TxCore #(.PARITY_POLARITY(PARITY)) uut ( |
.serialOut(serialOut), |
.run(run), |
.full(full), |
.stopBits(stopBits), |
.dataIn(dataIn), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.oddParity(oddParity), |
.msbFirst(msbFirst), |
.loadDataIn(loadDataIn), |
.clk(clk), |
.nReset(nReset) |
); |
|
//test bench signals |
reg tbClock; |
reg tbBitCounter; |
|
initial begin |
tbClock=0; |
tbBitCounter=0; |
// Initialize Inputs |
dataIn = 0; |
loadDataIn = 0; |
clocksPerBit = 8; |
stopBit2=0; |
clk = 0; |
nReset = 0; |
#(CLK_PERIOD*10); |
nReset = 1; |
#(CLK_PERIOD*10); |
// Add stimulus here |
dataIn = 8'b1000_0000; |
loadDataIn = 1; |
wait(full==1); |
wait(full==0); |
//loadDataIn=0; |
dataIn = 8'b0111_1111; |
//loadDataIn = 1; |
wait(full==1); |
wait(full==0); |
loadDataIn=0; |
end |
|
initial begin |
// timeout |
#10000; |
$finish; |
end |
|
always |
#1 tbClock = ! tbClock; |
always |
#(CLK_PERIOD/2) clk = ! clk; |
|
endmodule |
|
/trunk/sources/Uart.v
0,0 → 1,138
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 08/31/2010 |
// Design Name: |
// Module Name: Uart |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: Half duplex UART with 1 byte buffer |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module BasicHalfDuplexUart( |
output [7:0] rxData, |
output overrunErrorFlag, //new data has been received before dataOut was read |
output dataOutReadyFlag, //new data available |
output frameErrorFlag, //bad parity or bad stop bits |
output txRun, //tx is started |
output endOfRx, //one cycle pulse: 1 during last cycle of last stop bit of rx |
output rxRun, //rx is definitely started, one of the three flag will be set |
output rxStartBit, //rx is started, but we don't know yet if real rx or just a glitch |
output txFull, |
output isTx, //1 only when tx is ongoing. Indicates the direction of the com line. |
|
input serialIn, //signals to merged into a inout signal according to "isTx" |
output serialOut, |
output comClk, |
|
input [DIVIDER_WIDTH-1:0] clkPerCycle, |
input [7:0] txData, |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input oddParity, //if 1, parity bit is such that data+parity have an odd number of 1 |
input msbFirst, //if 1, bits order is: startBit, b7, b6, b5...b0, parity |
input startTx, |
input ackFlags, |
input clk, |
input nReset |
); |
|
//parameters to override |
parameter DIVIDER_WIDTH = 1; |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
parameter IN_POLARITY = 1'b0; |
parameter PARITY_POLARITY = 1'b1; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
//constant definition for states |
localparam IDLE_STATE = 3'b000; |
localparam RX_STATE = 3'b001; |
localparam TX_STATE = 3'b011; |
|
wire rxSerialIn = isTx ? STOP_BIT1 : serialIn; |
//wire serialOut; |
wire loadDataIn; |
|
wire txStopBits; |
|
assign isTx = txRun & ~txStopBits; |
//let this to top level to avoid inout signal |
//assign serialLine = isTx ? serialOut : 1'bz; |
|
assign loadDataIn = startTx & ~rxStartBit & (~rxRun | endOfRx); |
|
/*//complicated approach... instead we can simply divide the clock at lower levels |
wire useEarlyComClk = |clkPerCycle ? 1'b1:1'b0; |
reg dividedClk; |
wire earlyComClk;//earlier than comClk by 1 cycle of clk (use to make 1 cycle pulse signals) |
always @(posedge clk)begin |
if(useEarlyComClk) |
dividedClk <= earlyComClk; |
end |
assign comClk=useEarlyComClk ? dividedClk : clk;//clock for communication |
wire endOfRxComClk;//pulse of 1 cycle of comClk |
assign endOfRx = useEarlyComClk ? endOfRxComClk & earlyComClk & ~comClk : endOfRxComClk;//pulse of 1 cycle of clk |
ClkDivider #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
clkDivider( |
.nReset(nReset), |
.clk(clk), |
.divider(clkPerCycle), |
.dividedClk(earlyComClk) |
); |
*/ |
|
// Instantiate the module |
RxCoreSelfContained #( |
.DIVIDER_WIDTH(DIVIDER_WIDTH), |
.PARITY_POLARITY(PARITY_POLARITY)) |
rxCore ( |
.dataOut(rxData), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.endOfRx(endOfRx), |
.run(rxRun), |
.startBit(rxStartBit), |
.clkPerCycle(clkPerCycle), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.oddParity(oddParity), |
.msbFirst(msbFirst), |
.ackFlags(ackFlags), |
.serialIn(rxSerialIn), |
.comClk(comClk), |
.clk(clk), |
.nReset(nReset) |
); |
TxCore #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
txCore ( |
.serialOut(serialOut), |
.run(txRun), |
.full(txFull), |
.stopBits(txStopBits), |
.dataIn(txData), |
.clkPerCycle(clkPerCycle), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.oddParity(oddParity), |
.msbFirst(msbFirst), |
.loadDataIn(loadDataIn), |
.comClk(comClk), |
.clk(clk), |
.nReset(nReset) |
); |
|
endmodule |
/trunk/sources/Iso7816_3_Master.v
0,0 → 1,111
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: |
// |
// Create Date: 17:16:40 01/09/2011 |
// Design Name: |
// Module Name: Iso7816_3_Master |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module Iso7816_3_Master( |
input nReset, |
input clk, |
//input [15:0] clkPerCycle,//not supported yet |
input startActivation,//Starts activation sequence |
input startDeactivation,//Starts deactivation sequence |
input [7:0] dataIn, |
input nWeDataIn, |
input [12:0] cyclePerEtu, |
output [7:0] dataOut, |
input nCsDataOut, |
output [7:0] statusOut, |
input nCsStatusOut, |
output reg isActivated,//set to high by activation sequence, set to low by deactivation sequence |
output useIndirectConvention, |
output tsError,//high if TS character is wrong |
output atrIsEarly,//high if TS received before 400 cycles after reset release |
output atrIsLate,//high if TS is still not received after 40000 cycles after reset release |
//ISO7816 signals |
inout isoSio, |
output isoClk, |
output isoReset, |
output isoVdd |
); |
|
assign isoSio = isTx ? serialOut : 1'bz; |
|
HalfDuplexUartIf uart ( |
.nReset(nReset), |
.clk(clk), |
.clkPerCycle(1'b0), |
.dataIn(dataIn), |
.nWeDataIn(nWeDataIn), |
.dataOut(dataOut), |
.nCsDataOut(nCsDataOut), |
.statusOut(statusOut), |
.nCsStatusOut(nCsStatusOut), |
.serialIn(isoSio), |
.serialOut(serialOut), |
.isTx(isTx), |
.comClk(comClk) |
); |
|
reg isoClkEn; |
assign isoClk = isoClkEn ? comClk : 1'b0; |
|
reg [16:0] resetCnt; |
assign atrIsEarly = ~waitTs & (resetCnt<(16'h100+16'd400)); |
assign atrIsLate = resetCnt>(16'h100+16'd40000); |
assign useIndirectConvention = ~waitTs & (ts==8'h3F); |
assign tsError = ~waitTs & (ts!=8'h3B) & ~useIndirectConvention; |
reg waitTs; |
always @(posedge comClk, negedge nReset) begin |
if(~nReset) begin |
isoClkEn <= 1'b0; |
resetCnt<=16'b0; |
waitTs<=1'b1; |
isoReset <= 1'b0; |
isoVdd <= 1'b0; |
isActivated <= 1'b0; |
end else if(isActivated) begin |
if(waitTs) begin |
if(statusOut[0]) begin |
waitTs<=1'b0; |
ts<=dataOut; |
end |
resetCnt<=resetCnt+1; |
end |
if(startDeactivation) begin |
isoVdd <= 1'b0; |
isoClkEn <= 1'b0; |
isoReset <= 1'b0; |
resetCnt<=16'b0; |
isActivated <= 1'b0; |
end |
end else begin |
if(startActivation) begin |
waitTs <= 1'b1; |
isoVdd <= 1'b1; |
isoClkEn <= 1'b1; |
if(16'h100 == resetCnt) begin |
isActivated <=1'b1; |
isoReset <=1'b1; |
end else |
resetCnt<=resetCnt + 1; |
end else begin |
resetCnt<=16'b0; |
end |
end |
end |
endmodule |
/trunk/sources/RxCoreSpec.v
0,0 → 1,368
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 09/04/2010 |
// Design Name: |
// Module Name: RxCore2 |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: non synthetizable model used as reference in test bench |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
/* |
module Delay(); |
|
task WaitClocks; |
input [CLOCK_PER_BIT_WIDTH-1:0] limit; |
integer bitClocksCounter; |
begin |
for(bitClocksCounter=0;bitClocksCounter<limit;bitClocksCounter=bitClocksCounter+1) begin |
@(posedge syncClk); |
end |
end |
endtask |
|
endmodule |
*/ |
|
module RxCoreSpec( |
output reg [7:0] dataOut, |
output reg overrunErrorFlag, //new data has been received before dataOut was read |
output reg dataOutReadyFlag, //new data available |
output reg frameErrorFlag, //bad parity or bad stop bits |
output reg endOfRx, |
output reg run, //rx is definitely started, one of the three flag will be set |
output reg startBit, //rx is started, but we don't know yet if real rx or just a glitch |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input ackFlags, |
input serialIn, |
input clk, |
input nReset |
); |
parameter CLK_PERIOD = 10;//should be %2 |
//parameters to override |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
parameter IN_POLARITY = 1'b0; |
parameter PARITY_POLARITY = 1'b0; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
//constant definition for states |
localparam IDLE_BIT = ~START_BIT; |
|
integer bitCounter; |
|
reg parityBit; |
reg rxStarted; |
|
wire internalIn; |
wire parityError; |
|
assign internalIn = serialIn ^ IN_POLARITY; |
assign parityError= parityBit ^ internalIn ^ PARITY_POLARITY ^ 1'b1; |
reg syncClk; |
|
/*logic to avoid race condition on flags |
if internal logic set the flag and at the same time |
the signal ackFlags is set (that normally clears the flags), the flag should be set |
*/ |
reg setOverrunErrorFlag; |
reg nResetOverrunErrorFlag; |
always @(negedge clk) begin |
setOverrunErrorFlag<=1'b0; |
end |
|
//flag set has priority over flag nReset |
always @(setOverrunErrorFlag,nResetOverrunErrorFlag) begin |
if((setOverrunErrorFlag===1'b1) || (setOverrunErrorFlag===1'bx)) begin |
overrunErrorFlag<=setOverrunErrorFlag; |
if(nResetOverrunErrorFlag) |
nResetOverrunErrorFlag=0; |
end else begin |
if(nResetOverrunErrorFlag) begin |
overrunErrorFlag<=0; |
nResetOverrunErrorFlag=0; |
end |
end |
end |
|
reg setDataOutReadyFlag; |
reg nResetDataOutReadyFlag; |
always @(negedge clk) begin |
setDataOutReadyFlag<=1'b0; |
end |
|
//flag set has priority over flag nReset |
always @(setDataOutReadyFlag,nResetDataOutReadyFlag) begin |
if((setDataOutReadyFlag===1'b1) || (setDataOutReadyFlag===1'bx)) begin |
dataOutReadyFlag<=setDataOutReadyFlag; |
if(nResetDataOutReadyFlag) |
nResetDataOutReadyFlag=0; |
end else begin |
if(nResetDataOutReadyFlag) begin |
dataOutReadyFlag<=0; |
nResetDataOutReadyFlag=0; |
end |
end |
end |
|
reg setFrameErrorFlag; |
reg nResetFrameErrorFlag; |
always @(negedge clk) begin |
setFrameErrorFlag<=1'b0; |
end |
|
//flag set has priority over flag nReset |
always @(setFrameErrorFlag,nResetFrameErrorFlag) begin |
if((setFrameErrorFlag===1'b1) || (setFrameErrorFlag===1'bx)) begin |
frameErrorFlag<=setFrameErrorFlag; |
if(nResetFrameErrorFlag) |
nResetFrameErrorFlag=0; |
end else begin |
if(nResetFrameErrorFlag) begin |
frameErrorFlag<=0; |
nResetFrameErrorFlag=0; |
end |
end |
end |
|
reg dataOutReadyFlagAckDone; |
reg frameErrorFlagAckDone; |
|
always @(posedge clk) begin:ACK_FLAGS |
if(ackFlags) begin |
if(0==rxStarted) |
nResetOverrunErrorFlag<=1;//otherwise, done in OVERRUN_BIT block |
if(dataOutReadyFlag!==1'bx) |
nResetDataOutReadyFlag<=1'b1; |
dataOutReadyFlagAckDone<=1'b1; |
if(frameErrorFlag!==1'bx) |
nResetFrameErrorFlag<=1'b1; |
frameErrorFlagAckDone<=1'b1; |
end |
end |
|
reg internalStart; |
integer clockCounter; |
always@(posedge internalStart) begin:CLOCK_COUNTER |
for(clockCounter=0;clockCounter<(11+stopBit2)*(clocksPerBit+1);clockCounter=clockCounter+1) begin |
syncClk=0; |
#(CLK_PERIOD/2); |
syncClk=1; |
#(CLK_PERIOD/2); |
end |
end |
|
reg abortStart; |
always@(posedge abortStart) begin:ABORT_START |
abortStart<=0; |
startBit<=1'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
if(internalIn) |
startBit<=0; |
end |
//Start bit spec |
always@(negedge internalIn) begin:START_BIT_BLK |
if(frameErrorFlag | overrunErrorFlag) begin |
//nothing to do, wait clear from outside |
end else begin |
internalStart<=1; |
startBit<=1'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
internalStart<=0; |
startBit<=1; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
if(internalIn==0) begin |
startBit<=1'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
startBit<=0; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
#(CLK_PERIOD*(10+stopBit2)*(clocksPerBit+1));//ignore falling edge until end of the byte |
end else begin |
abortStart<=1; |
end |
end |
end |
|
wire [31:0] stopStart=10*(clocksPerBit+1); |
wire [31:0] stopEnd=((10+stopBit2)*(clocksPerBit+1)+((clocksPerBit+1)*3)/4); |
wire isInStop=(clockCounter>=stopStart) && (clockCounter<stopEnd); |
reg runBitSet; |
//Run bit spec |
always@(negedge internalIn) begin:RUN_BIT_SET |
if(frameErrorFlag | overrunErrorFlag) begin |
//nothing to do, wait clear from outside |
end else if(~isInStop) begin |
runBitSet<=1'b0; |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
if(internalIn == 0) begin |
fork |
begin |
runBitSet<=1'b1; |
run<=1'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
run<=1; |
end |
begin |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
#(CLK_PERIOD*(9+stopBit2)*(clocksPerBit+1)); |
end |
join |
end |
end |
end |
|
always@(posedge runBitSet) begin:RUN_BIT_CLEAR |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
#(CLK_PERIOD*(((10+stopBit2)*(clocksPerBit+1))-2)); |
if(runBitSet) |
endOfRx<=1'bx; |
#(CLK_PERIOD); |
if(runBitSet) begin//might be cleared by nReset |
run<=1'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/4); |
endOfRx<=1'b0; |
run<=0; |
end |
end |
|
//overrun bit spec |
reg internalOv; |
wire [31:0] minOvCount=(clocksPerBit+1);//WARNING: DATA_OUT block rely on this |
wire [31:0] maxOvCount=((clocksPerBit+1)/2)+(clocksPerBit+1)+(clocksPerBit+1)/4; |
always@(posedge syncClk) begin:OVERRUN_BIT |
if(clockCounter<maxOvCount) begin//internal requests to set the flag have priority over clear by ackFlags |
if(clockCounter==minOvCount) |
if(dataOutReadyFlag) |
setOverrunErrorFlag <= 1'bx; |
end else if(clockCounter==maxOvCount) begin |
if(1'bx===overrunErrorFlag) |
setOverrunErrorFlag <= 1; |
end else |
if(ackFlags) |
nResetOverrunErrorFlag <= 1; |
end |
|
reg [7:0] dataStorage; |
reg waitStartBit; |
//dataOut spec |
//frameErrorFlag spec (1/2) |
always@(negedge internalIn) begin:DATA_OUT |
if(frameErrorFlag | overrunErrorFlag) begin |
//nothing to do, wait clear from outside |
end else begin |
waitStartBit<=1'b0; |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
if(internalIn==0) begin |
#(CLK_PERIOD*(minOvCount-((clocksPerBit+1)/2))); |
fork |
if(0==dataOutReadyFlag) begin |
dataOut<=8'bx; |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
#(CLK_PERIOD*8*(clocksPerBit+1));//wait 8 bits + parity |
parityBit <= ^dataStorage; |
if(0==(^dataStorage) ^ internalIn ^ PARITY_POLARITY ^ 1'b1) begin |
setDataOutReadyFlag<=1'bx; |
dataOutReadyFlagAckDone<=1'b0; |
#(CLK_PERIOD*2);//#(CLK_PERIOD*(clocksPerBit+1)/4);//allow 1/4 bit time latency |
dataOut<=dataStorage; |
if(~dataOutReadyFlagAckDone) |
setDataOutReadyFlag<=1'b1; |
else |
nResetDataOutReadyFlag<=1'b1; |
end else begin |
setFrameErrorFlag <= 1'bx; |
frameErrorFlagAckDone<=1'b0; |
#(CLK_PERIOD*2);//#(CLK_PERIOD*(clocksPerBit+1)/4);//allow 1/4 bit time latency |
if(~frameErrorFlagAckDone) |
setFrameErrorFlag<=1'b1; |
else |
nResetFrameErrorFlag<=1'b1; |
end |
end |
begin |
#(CLK_PERIOD*(clocksPerBit+1)/4);//we can detect start bit a 1/4 of bit time before the actual end of the transfer |
#(CLK_PERIOD*(9+stopBit2)*(clocksPerBit+1)); |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
end |
join |
end |
waitStartBit<=1'b1; |
end |
end |
|
//frameErrorFlag spec (2/2) |
always@(negedge internalIn) begin:FRAME_ERROR |
if(frameErrorFlag | overrunErrorFlag) begin |
//nothing to do, wait clear from outside |
end else begin |
if(isInStop) begin |
setFrameErrorFlag <= 1'bx; |
frameErrorFlagAckDone<=1'b0; |
#(CLK_PERIOD*(clocksPerBit+1)/1);//allow 1 bit time latency |
if(~frameErrorFlagAckDone) |
setFrameErrorFlag<=1'b1; |
else |
nResetFrameErrorFlag<=1'b1; |
end |
end |
end |
|
initial begin |
internalStart=0; |
clockCounter=0; |
abortStart=0; |
internalOv=0; |
end |
|
always @(negedge internalIn, negedge nReset) begin:MAIN |
if(~nReset) begin |
bitCounter <= 0; |
parityBit <= 0; |
nResetOverrunErrorFlag <= 1'b1; |
setOverrunErrorFlag <= 1'b0; |
nResetDataOutReadyFlag <= 1'b1; |
setDataOutReadyFlag <= 1'b0; |
nResetFrameErrorFlag <= 1'b1; |
setFrameErrorFlag<=1'b0; |
endOfRx<=1'b0; |
run <= 0; |
startBit <= 0; |
runBitSet<=0; |
end else if(frameErrorFlag | overrunErrorFlag) begin |
//nothing to do, wait clear from outside |
end else begin |
rxStarted<=1'b1; |
#(CLK_PERIOD*(clocksPerBit+1)/2); |
if(internalIn == 0) begin |
@(posedge clk); |
for(bitCounter=0;bitCounter<8;bitCounter=bitCounter+1) begin |
#(CLK_PERIOD*(clocksPerBit+1)/1); |
if(~dataOutReadyFlag) begin |
dataStorage[bitCounter]<=internalIn; |
end |
end |
#(CLK_PERIOD*(clocksPerBit+1)/1); |
#(CLK_PERIOD*(clocksPerBit+1)/1); |
if(stopBit2) begin |
#(CLK_PERIOD*(clocksPerBit+1)/1); |
end |
rxStarted <= 1'b0; |
end |
end |
end |
|
endmodule |
/trunk/sources/Counter.v
0,0 → 1,88
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 08/31/2010 |
// Design Name: |
// Module Name: Counter |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: A counter with increment and clear operation |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module Counter( |
output reg [WIDTH-1:0] counter, |
output earlyMatch, |
output reg match, |
output dividedClk, |
input [DIVIDER_WIDTH-1:0] divider, // clock divide factor |
input [WIDTH-1:0] compare, |
input inc, |
input clear, |
input [WIDTH_INIT-1:0] initVal, |
input clk, |
input nReset |
); |
|
//parameters to override |
parameter DIVIDER_WIDTH = 16; |
parameter WIDTH = 8; |
parameter WIDTH_INIT = 1; |
|
wire divideBy1; |
wire divMatch; |
wire divRisingMatch; |
wire divFallingMatch; |
|
ClkDivider #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
clkDivider( |
.nReset(nReset), |
.clk(clk), |
.divider(divider), |
.dividedClk(dividedClk), |
.divideBy1(divideBy1), |
.match(divMatch), |
.risingMatch(divRisingMatch), |
.fallingMatch(divFallingMatch) |
); |
|
wire [WIDTH-1:0] nextCounter = counter+1'b1; |
|
wire doInc = divideBy1 ? inc :inc & divRisingMatch; |
wire doEarlyMatch = divideBy1 ? (compare == nextCounter) : (compare == counter) & divRisingMatch; |
|
reg earlyMatchReg; |
assign earlyMatch = divideBy1 ? earlyMatchReg : doEarlyMatch; |
|
always @(posedge clk, negedge nReset) begin |
if(~nReset) begin |
counter <= 0;//initVal; |
earlyMatchReg <= 0; |
match <= 0; |
end else begin |
if(clear) begin |
counter <= initVal; |
end else if(doInc) begin |
if(compare == counter) |
counter <= initVal; |
else |
counter <= nextCounter; |
end |
if(doEarlyMatch) |
earlyMatchReg <= 1; |
else begin |
earlyMatchReg <= 0; |
end |
match <= divideBy1 ? earlyMatchReg : doEarlyMatch; |
end |
end |
|
endmodule |
/trunk/sources/ClkDivider.v
0,0 → 1,75
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 18:05:27 01/09/2011 |
// Design Name: |
// Module Name: clkDivider |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
|
/* |
Basic clock divider |
|
if divider=0 |
dividedClk=clk |
else |
F(dividedClk)=F(clk)/(divider*2) |
dividedClk has a duty cycle of 50% |
|
WARNING: |
To change divider on the fly: |
1. set it to 0 at least for one cycle |
2. set it to the new value. |
*/ |
module ClkDivider( |
input nReset, |
input clk, // input clock |
input [DIVIDER_WIDTH-1:0] divider, // divide factor |
output dividedClk, // divided clock |
output divideBy1, |
output match, |
output risingMatch, |
output fallingMatch |
); |
//parameters to override |
parameter DIVIDER_WIDTH = 16; |
|
reg out;//internal divided clock |
reg [DIVIDER_WIDTH-1:0] cnt; |
|
// if divider=0, dividedClk = clk. |
assign divideBy1 = |divider ? 1'b0 : 1'b1; |
assign dividedClk = divideBy1 ? clk : out; |
|
assign match = (cnt==(divider-1)); |
assign risingMatch = match & ~out; |
assign fallingMatch = match & out; |
|
always @(posedge clk, negedge nReset) |
begin |
if(~nReset | divideBy1) begin |
cnt <= 0; |
out <= 1'b0; |
end else if(~divideBy1) begin |
if(match) begin |
cnt <= 0; |
out <= ~out; |
end else begin |
cnt <= cnt + 1'b1; |
end |
end |
end |
|
endmodule |
/trunk/sources/RxCoreSelfContained.v
0,0 → 1,98
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 08/31/2010 |
// Design Name: |
// Module Name: RxCore |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module RxCoreSelfContained( |
output [7:0] dataOut, |
output overrunErrorFlag, //new data has been received before dataOut was read |
output dataOutReadyFlag, //new data available |
output frameErrorFlag, //bad parity or bad stop bits |
output endOfRx, //one cycle pulse: 1 during last cycle of last stop bit |
output run, //rx is definitely started, one of the three flag will be set |
output startBit, //rx is started, but we don't know yet if real rx or just a glitch |
input [DIVIDER_WIDTH-1:0] clkPerCycle, |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input oddParity, //if 1, parity bit is such that data+parity have an odd number of 1 |
input msbFirst, //if 1, bits order is: startBit, b7, b6, b5...b0, parity |
input ackFlags, |
input serialIn, |
input comClk,//not used yet |
input clk, |
input nReset |
); |
|
//parameters to override |
parameter DIVIDER_WIDTH = 1; |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
//parameter IN_POLARITY = 1'b0; |
//parameter PARITY_POLARITY = 1'b1; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
wire [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounter; |
wire bitClocksCounterEarlyMatch; |
wire bitClocksCounterMatch; |
wire [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounterCompare; |
wire bitClocksCounterInc; |
wire bitClocksCounterClear; |
wire bitClocksCounterInitVal; |
Counter #( .DIVIDER_WIDTH(DIVIDER_WIDTH), |
.WIDTH(CLOCK_PER_BIT_WIDTH), |
.WIDTH_INIT(1)) |
bitClocksCounterModule( |
.counter(bitClocksCounter), |
.earlyMatch(bitClocksCounterEarlyMatch), |
.match(bitClocksCounterMatch), |
.divider(clkPerCycle), |
.compare(bitClocksCounterCompare), |
.inc(bitClocksCounterInc), |
.clear(bitClocksCounterClear), |
.initVal(bitClocksCounterInitVal), |
.clk(clk), |
.nReset(nReset)); |
|
RxCore rxCore ( |
.dataOut(dataOut), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.endOfRx(endOfRx), |
.run(run), |
.startBit(startBit), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.oddParity(oddParity), |
.msbFirst(msbFirst), |
.ackFlags(ackFlags), |
.serialIn(serialIn), |
.clk(clk), |
.nReset(nReset), |
.bitClocksCounterEarlyMatch(bitClocksCounterEarlyMatch), |
.bitClocksCounterMatch(bitClocksCounterMatch), |
.bitClocksCounterCompare(bitClocksCounterCompare), |
.bitClocksCounterInc(bitClocksCounterInc), |
.bitClocksCounterClear(bitClocksCounterClear), |
.bitClocksCounterInitVal(bitClocksCounterInitVal) |
); |
|
endmodule |
/trunk/sources/RxCore.v
0,0 → 1,255
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 08/31/2010 |
// Design Name: |
// Module Name: RxCore |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module RxCore( |
output reg [7:0] dataOut, |
output reg overrunErrorFlag, //new data has been received before dataOut was read |
output reg dataOutReadyFlag, //new data available |
output reg frameErrorFlag, //bad parity or bad stop bits |
output reg endOfRx, //one cycle pulse: 1 during last cycle of last stop bit |
output reg run, //rx is definitely started, one of the three flag will be set |
output startBit, //rx is started, but we don't know yet if real rx or just a glitch |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input oddParity, //if 1, parity bit is such that data+parity have an odd number of 1 |
input msbFirst, //if 1, bits order is: startBit, b7, b6, b5...b0, parity |
input ackFlags, |
input serialIn, |
input clk, |
input nReset, |
//to connect to an instance of Counter.v (see RxCoreSelfContained.v for example) |
output reg [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounterCompare, |
output reg bitClocksCounterInc, |
output reg bitClocksCounterClear, |
output bitClocksCounterInitVal, |
input bitClocksCounterEarlyMatch, |
input bitClocksCounterMatch |
); |
|
//parameters to override |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
//parameter IN_POLARITY = 1'b0; |
//parameter PARITY_POLARITY = 1'b1; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
//constant definition for states |
localparam IDLE_STATE = 3'b000; |
localparam START_STATE = 3'b001; |
localparam DATA_STATE = 3'b011; |
localparam PARITY_STATE = 3'b010; |
localparam STOP1_STATE = 3'b110; |
localparam STOP2_STATE = 3'b111; |
localparam END_STATE = 3'b101; |
localparam END2_STATE = 3'b100; |
|
localparam IDLE_BIT = ~START_BIT; |
|
reg [2:0] nextState; |
|
reg [2:0] bitCounter; |
wire [2:0] bitIndex = msbFirst ? 7-bitCounter : bitCounter; |
reg parityBit; |
|
wire internalIn; |
wire parityError; |
|
assign startBit = (nextState == START_STATE); |
assign internalIn = serialIn; |
assign parityError= parityBit ^ internalIn ^ 1'b1; |
reg flagsSet; |
|
assign bitClocksCounterInitVal=(nextState==IDLE_STATE); |
always @(nextState, clocksPerBit, run, bitClocksCounterMatch) begin |
case(nextState) |
IDLE_STATE: begin |
bitClocksCounterCompare = (clocksPerBit/2); |
bitClocksCounterInc = run & ~bitClocksCounterMatch;//stop when reach 0 |
bitClocksCounterClear = ~run; |
end |
START_STATE: begin |
bitClocksCounterCompare = (clocksPerBit/2); |
bitClocksCounterInc = 1; |
bitClocksCounterClear = 0; |
end |
STOP2_STATE: begin |
//make the rx operation is one cycle shorter, |
//since we detect the start bit at least one cycle later it starts. |
bitClocksCounterCompare = clocksPerBit-1; |
bitClocksCounterInc = 1; |
bitClocksCounterClear = 0; |
end |
default: begin |
bitClocksCounterCompare = clocksPerBit; |
bitClocksCounterInc = 1; |
bitClocksCounterClear = 0; |
end |
endcase |
end |
|
always @(posedge clk, negedge nReset) begin |
if(~nReset) begin |
nextState <= #1 IDLE_STATE; |
bitCounter <= #1 0; |
parityBit <= #1 0; |
overrunErrorFlag <= #1 0; |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
run <= #1 0; |
endOfRx <= #1 0; |
end else begin |
case(nextState) |
IDLE_STATE: begin |
if(bitClocksCounterEarlyMatch) |
endOfRx <= #1 1'b1; |
if(bitClocksCounterMatch) |
endOfRx <= #1 0; |
if(ackFlags) begin |
//overrunErrorFlag is auto cleared at PARITY_STATE |
//meanwhile, it prevent dataOutReadyFlag to be set by the termination of the lost byte |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
end |
if(START_BIT == internalIn) begin |
if(frameErrorFlag | overrunErrorFlag) begin |
//wait clear from outside |
if(bitClocksCounterMatch) begin |
//endOfRx <= #1 0; |
run <= #1 0; |
end |
end else begin |
parityBit <= #1 oddParity; |
run <= #1 0; |
nextState <= #1 START_STATE; |
end |
end else begin |
if(bitClocksCounterMatch) begin |
//endOfRx <= #1 0; |
run <= #1 0; |
end |
end |
end |
START_STATE: begin |
if(ackFlags) begin |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
end |
if(bitClocksCounterMatch) begin |
if(START_BIT != internalIn) begin |
nextState <= #1 IDLE_STATE; |
end else begin |
run <= #1 1; |
nextState <= #1 DATA_STATE; |
end |
end |
end |
DATA_STATE: begin |
if(ackFlags) begin |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
end |
if(bitClocksCounterMatch) begin |
if(dataOutReadyFlag) begin |
overrunErrorFlag <= #1 1; |
end else |
dataOut[bitIndex] <= #1 internalIn; |
parityBit <= #1 parityBit ^ internalIn; |
bitCounter <= #1 (bitCounter + 1'b1) & 3'b111; |
if(bitCounter == 7) |
nextState <= #1 PARITY_STATE; |
end |
end |
PARITY_STATE: begin |
if(bitClocksCounterMatch) begin |
if(~overrunErrorFlag) begin |
frameErrorFlag <= #1 parityError; |
dataOutReadyFlag <= #1 ~parityError; |
end else if(ackFlags) begin |
frameErrorFlag <= #1 0; |
end |
flagsSet=1; |
if(stopBit2) |
nextState <= #1 STOP1_STATE; |
else |
nextState <= #1 STOP2_STATE; |
end else if(ackFlags) begin |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
end |
end |
STOP1_STATE: begin |
if(ackFlags) begin |
dataOutReadyFlag <= #1 0; |
end |
if(bitClocksCounterMatch) begin |
if(STOP_BIT1 != internalIn) begin |
frameErrorFlag <= #1 parityError; |
end else if(ackFlags) begin |
frameErrorFlag <= #1 0; |
end |
nextState <= #1 STOP2_STATE; |
end else if(ackFlags) begin |
frameErrorFlag <= #1 0; |
end |
end |
STOP2_STATE: begin |
if(ackFlags) begin |
dataOutReadyFlag <= #1 0; |
end |
if(bitClocksCounterMatch) begin |
if(STOP_BIT2 != internalIn) begin |
frameErrorFlag <= #1 1; |
end else if(ackFlags) begin |
frameErrorFlag <= #1 0; |
end |
nextState <= #1 IDLE_STATE; |
end else if(ackFlags) begin |
frameErrorFlag <= #1 0; |
end |
end |
default: nextState <= #1 IDLE_STATE; |
endcase |
end |
end |
|
//how to use an internal counter rather than an external one: |
//(need to be moved at top of the module) |
/*wire [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounter; |
wire bitClocksCounterMatch; |
reg [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounterCompare; |
reg bitClocksCounterInc; |
reg bitClocksCounterClear; |
wire bitClocksCounterInitVal; |
Counter #( .WIDTH(CLOCK_PER_BIT_WIDTH), |
.WIDTH_INIT(1)) |
bitClocksCounterModule( |
.counter(bitClocksCounter), |
.match(bitClocksCounterMatch), |
.compare(bitClocksCounterCompare), |
.inc(bitClocksCounterInc), |
.clear(bitClocksCounterClear), |
.initVal(bitClocksCounterInitVal), |
.clk(clk), |
.reset(reset));*/ |
|
endmodule |
/trunk/sources/TxCore.v
0,0 → 1,179
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 21:16:10 08/29/2010 |
// Design Name: |
// Module Name: TxCore |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module TxCore( |
output comClk, |
output serialOut, |
output run, |
output full, |
output stopBits, //1 during stop bits |
input [7:0] dataIn, |
input [DIVIDER_WIDTH-1:0] clkPerCycle, |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input loadDataIn, //evaluated only when full=0, when full goes to one, dataIn has been read |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input oddParity, //if 1, parity bit is such that data+parity have an odd number of 1 |
input msbFirst, //if 1, bits will be send in the order startBit, b7, b6, b5...b0, parity |
input clk, |
input nReset |
); |
|
//parameters to override |
parameter DIVIDER_WIDTH = 1; |
parameter CLOCK_PER_BIT_WIDTH = 13;//allow to support default speed of ISO7816 |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
|
//constant definition for state |
localparam IDLE_STATE = 0; |
localparam START_STATE = 1; |
localparam SEND_DATA_STATE = 2; |
localparam SEND_PARITY_STATE = 3; |
localparam SEND_STOP1_STATE = 4; |
localparam SEND_STOP2_STATE = 5; |
|
localparam IDLE_BIT = ~START_BIT; |
localparam STOP_BIT2 = STOP_BIT1; |
|
wire [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounter; |
wire bitClocksCounterEarlyMatch; |
wire bitClocksCounterMatch; |
reg [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounterCompare; |
reg bitClocksCounterInc; |
reg bitClocksCounterClear; |
wire bitClocksCounterInitVal; |
Counter #( .DIVIDER_WIDTH(DIVIDER_WIDTH), |
.WIDTH(CLOCK_PER_BIT_WIDTH), |
.WIDTH_INIT(1)) |
bitClocksCounterModule( |
.counter(bitClocksCounter), |
.earlyMatch(bitClocksCounterEarlyMatch), |
.match(bitClocksCounterMatch), |
.dividedClk(comClk), |
.divider(clkPerCycle), |
.compare(bitClocksCounterCompare), |
.inc(bitClocksCounterInc), |
.clear(bitClocksCounterClear), |
.initVal(bitClocksCounterInitVal), |
.clk(clk), |
.nReset(nReset)); |
|
reg [2:0] nextState; |
reg [2:0] bitCounter; |
reg [7:0] dataBuffer; |
|
reg parityBit; |
|
wire internalOut; |
wire dataBit; |
//after a tx operation, during the first cycle in IDLE_STATE, run bit must be still set |
//(it is entered one cycle before the completion of the operation, so we use bitClocksCounter[0] |
//to implement this behavior) |
assign run = (nextState == IDLE_STATE) ? bitClocksCounter[0] : 1'b1; |
assign full = (nextState != IDLE_STATE); |
assign stopBits = (nextState == SEND_STOP1_STATE)|(nextState == SEND_STOP2_STATE)|((nextState == IDLE_STATE) & bitClocksCounter[0]); |
|
assign serialOut = internalOut; |
wire [2:0] bitIndex = msbFirst ? 7-bitCounter : bitCounter; |
assign dataBit = dataBuffer[bitIndex]; |
wire [0:5] bitSel; |
assign bitSel = {IDLE_BIT, START_BIT, dataBit, parityBit, STOP_BIT1, STOP_BIT2}; |
assign internalOut = bitSel[nextState]; |
|
assign bitClocksCounterInitVal=0; |
|
always @(nextState) begin |
case(nextState) |
START_STATE: |
assign bitClocksCounterCompare = clocksPerBit-1; |
SEND_STOP2_STATE: |
assign bitClocksCounterCompare = clocksPerBit-1; |
default: |
assign bitClocksCounterCompare = clocksPerBit; |
endcase |
end |
|
always @(nextState) begin |
case(nextState) |
IDLE_STATE: begin |
bitClocksCounterInc = 0; |
bitClocksCounterClear = 1; |
end |
default: begin |
bitClocksCounterInc = 1; |
bitClocksCounterClear = 0; |
end |
endcase |
end |
|
always @(posedge clk, negedge nReset) begin |
if(~nReset) begin |
nextState <= #1 IDLE_STATE; |
bitCounter <= #1 0; |
end else begin |
case(nextState) |
IDLE_STATE: begin |
if(loadDataIn) begin |
dataBuffer <= #1 dataIn; |
parityBit <= #1 oddParity; |
nextState <= #1 START_STATE; |
end |
end |
START_STATE: begin |
if(bitClocksCounterMatch) begin |
nextState <= #1 SEND_DATA_STATE; |
end |
end |
SEND_DATA_STATE: begin |
if(bitClocksCounterMatch) begin |
bitCounter <= #1 (bitCounter + 1'b1) & 3'b111; |
parityBit <= #1 parityBit ^ dataBit; |
if(bitCounter == 7) |
nextState <= #1 SEND_PARITY_STATE; |
end |
end |
SEND_PARITY_STATE: begin |
if(bitClocksCounterMatch) begin |
if(stopBit2) |
nextState <= #1 SEND_STOP1_STATE; |
else |
nextState <= #1 SEND_STOP2_STATE;//if single stop bit, we skip STOP1 state |
end |
end |
SEND_STOP1_STATE: begin |
if(bitClocksCounterMatch) |
nextState <= #1 SEND_STOP2_STATE; |
end |
SEND_STOP2_STATE: begin |
/* if(bitClocksCounter[1:0]==2'b10) |
nextState <= #1 SEND_STOP2_STATE2; |
end |
SEND_STOP2_STATE2: begin*/ |
if(bitClocksCounterMatch) |
nextState <= #1 IDLE_STATE; |
end |
default: nextState <= #1 IDLE_STATE; |
endcase |
end |
|
end |
|
endmodule |
/trunk/sources/HalfDuplexUartIf.v
0,0 → 1,134
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: |
// |
// Create Date: 19:57:35 10/31/2010 |
// Design Name: |
// Module Name: HalfDuplexUartIf |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module HalfDuplexUartIf( |
input nReset, |
input clk, |
input [DIVIDER_WIDTH-1:0] clkPerCycle, |
input [7:0] dataIn, |
input nWeDataIn, |
output [7:0] dataOut, |
input nCsDataOut, |
output [7:0] statusOut, |
input nCsStatusOut, |
input serialIn, |
output serialOut, |
output isTx, |
output comClk |
); |
//parameters to override |
parameter DIVIDER_WIDTH = 1; |
|
reg [7:0] dataReg; |
|
// Inputs |
wire [7:0] txData; |
wire [12:0] clocksPerBit; |
wire stopBit2=1; |
wire oddParity=0; //if 1, parity bit is such that data+parity have an odd number of 1 |
wire msbFirst=0; //if 1, bits will be send in the order startBit, b7, b6, b5...b0, parity |
reg txPending; |
wire ackFlags; |
|
// Outputs |
wire [7:0] rxData; |
wire overrunErrorFlag; |
wire dataOutReadyFlag; |
wire frameErrorFlag; |
wire txRun; |
wire endOfRx; |
wire rxRun; |
wire rxStartBit; |
wire txFull; |
//wire isTx; |
|
wire rxFlagsSet = dataOutReadyFlag | overrunErrorFlag | frameErrorFlag; |
reg bufferFull; |
reg [1:0] flagsReg; |
|
assign txData = dataReg; |
assign clocksPerBit = 7; |
|
assign dataOut=dataReg; |
assign statusOut[7:0]={txRun, txPending, rxRun, rxStartBit, isTx, flagsReg, bufferFull}; |
|
reg waitTxFull0;//internal reg for managing bufferFull bit in Tx |
|
assign ackFlags=~txPending & ~txRun & rxFlagsSet & ((bufferFull & ~nCsDataOut)| ~bufferFull); |
|
always @(posedge clk, negedge nReset) begin |
if(~nReset) begin |
bufferFull <= 1'b0; |
flagsReg <= 1'b0; |
txPending <= 1'b0; |
end else begin |
if(ackFlags) begin |
dataReg <= rxData; |
flagsReg <= {overrunErrorFlag, frameErrorFlag}; |
if(rxFlagsSet) |
bufferFull <= 1'b1; |
else |
bufferFull <= 1'b0; |
end else if(txPending) begin |
if(waitTxFull0) begin |
if(~txFull) |
waitTxFull0 <= 1'b0; |
end else if(txFull) begin//tx actually started, clear txPending and free buffer |
txPending <= 1'b0; |
bufferFull <= 1'b0; //buffer is empty |
end |
end else if(~nCsDataOut) begin |
bufferFull <= 1'b0; |
end else if(~nWeDataIn) begin |
dataReg <= dataIn; |
bufferFull <= 1'b1; |
txPending <= 1'b1; |
waitTxFull0 <= txFull; |
end |
end |
end |
|
BasicHalfDuplexUart #(.DIVIDER_WIDTH(DIVIDER_WIDTH)) |
uart ( |
.rxData(rxData), |
.overrunErrorFlag(overrunErrorFlag), |
.dataOutReadyFlag(dataOutReadyFlag), |
.frameErrorFlag(frameErrorFlag), |
.txRun(txRun), |
.endOfRx(endOfRx), |
.rxRun(rxRun), |
.rxStartBit(rxStartBit), |
.txFull(txFull), |
.isTx(isTx), |
.serialIn(serialIn), |
.serialOut(serialOut), |
.txData(txData), |
.clocksPerBit(clocksPerBit), |
.stopBit2(stopBit2), |
.oddParity(oddParity), |
.msbFirst(msbFirst), |
.startTx(txPending), |
.ackFlags(ackFlags), |
.clkPerCycle(clkPerCycle), |
.clk(clk), |
.nReset(nReset) |
); |
|
endmodule |
/trunk/sources/RxCore - private counter.v
0,0 → 1,206
`timescale 1ns / 1ps |
////////////////////////////////////////////////////////////////////////////////// |
// Company: |
// Engineer: Sebastien Riou |
// |
// Create Date: 23:57:02 08/31/2010 |
// Design Name: |
// Module Name: RxCore |
// Project Name: |
// Target Devices: |
// Tool versions: |
// Description: |
// |
// Dependencies: |
// |
// Revision: |
// Revision 0.01 - File Created |
// Additional Comments: |
// |
////////////////////////////////////////////////////////////////////////////////// |
module RxCore( |
output reg [7:0] dataOut, |
output reg overrunErrorFlag, //new data has been received before dataOut was read |
output reg dataOutReadyFlag, //new data available |
output reg frameErrorFlag, //bad parity or bad stop bits |
output reg run, //rx is definitely started, one of the three flag will be set |
output startBit, //rx is started, but we don't know yet if real rx or just a glitch |
input [CLOCK_PER_BIT_WIDTH-1:0] clocksPerBit, |
input stopBit2,//0: 1 stop bit, 1: 2 stop bits |
input ackFlags, |
input serialIn, |
input clk, |
input reset |
); |
|
//parameters to override |
parameter CLOCK_PER_BIT_WIDTH = 13; //allow to support default speed of ISO7816 |
//invert the polarity of the output or not |
parameter IN_POLARITY = 1'b0; |
parameter PARITY_POLARITY = 1'b0; |
//default conventions |
parameter START_BIT = 1'b0; |
parameter STOP_BIT1 = 1'b1; |
parameter STOP_BIT2 = 1'b1; |
|
//constant definition for states |
localparam IDLE_STATE = 3'b000; |
localparam START_STATE = 3'b001; |
localparam DATA_STATE = 3'b011; |
localparam PARITY_STATE = 3'b010; |
localparam STOP1_STATE = 3'b110; |
localparam STOP2_STATE = 3'b111; |
localparam END_STATE = 3'b101; |
localparam END2_STATE = 3'b100; |
|
localparam IDLE_BIT = ~START_BIT; |
|
reg [2:0] nextState; |
reg [CLOCK_PER_BIT_WIDTH-1:0] bitClocksCounter; |
//Counter #()bitClocksCounter(); |
|
reg [2:0] bitCounter; |
//reg [7:0] dataBuffer; |
|
reg parityBit; |
|
wire internalIn; |
wire parityError; |
|
//assign run = (nextState != IDLE_STATE) && (nextState != START_STATE); |
assign startBit = (nextState == START_STATE); |
assign internalIn = serialIn ^ IN_POLARITY; |
assign parityError= parityBit ^ internalIn ^ PARITY_POLARITY ^ 1'b1; |
reg flagsSet; |
|
always @(posedge clk, negedge reset) begin |
if(~reset) begin |
nextState <= #1 IDLE_STATE; |
bitCounter <= #1 0; |
parityBit <= #1 0; |
overrunErrorFlag <= #1 0; |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
run <= #1 0; |
end else begin |
if(ackFlags) begin |
//overrunErrorFlag is auto cleared at PARITY_STATE |
//meanwhile, it prevent dataOutReadyFlag to be set by the termination of the lost byte |
//VERILOG_QUESTION: is that bad to assign flags here AND in PARITY_STATE ? |
//If this is a problem, how to avoid to duplicate those assignement in all states ?? |
//TODO: check what happens if ackFlags=1 while PARITY_STATE, and decide what is the spec ! |
dataOutReadyFlag <= #1 0; |
frameErrorFlag <= #1 0; |
end |
flagsSet=0; |
case(nextState) |
IDLE_STATE: begin |
if(START_BIT == internalIn) begin |
if(frameErrorFlag | overrunErrorFlag) begin |
//wait clear from outside |
if(run) |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
if((clocksPerBit/2)+1 == bitClocksCounter)//TODO: make a new state to avoid the +1 in comparison |
run <= #1 0; |
end else begin |
bitClocksCounter <= #1 1; |
parityBit <= #1 0; |
run <= #1 0; |
nextState <= #1 START_STATE; |
end |
end else begin |
if(run) |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
if((clocksPerBit/2)+1 == bitClocksCounter)//TODO: make a new state to avoid the +1 in comparison |
run <= #1 0; |
end |
end |
START_STATE: begin |
if(clocksPerBit/2 == bitClocksCounter) begin |
if(START_BIT != internalIn) begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
nextState <= #1 IDLE_STATE; |
end else begin |
bitClocksCounter <= #1 0; |
run <= #1 1; |
nextState <= #1 DATA_STATE; |
end |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end |
DATA_STATE: begin |
if(clocksPerBit == bitClocksCounter) begin |
if(dataOutReadyFlag) begin |
overrunErrorFlag <= #1 1; |
//nextState <= #1 IDLE_STATE; |
end else |
dataOut[bitCounter] <= #1 internalIn; |
|
parityBit <= #1 parityBit ^ internalIn; |
bitCounter <= #1 (bitCounter + 1'b1) & 3'b111; |
if(bitCounter == 7) |
nextState <= #1 PARITY_STATE; |
bitClocksCounter <= #1 0; |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end |
PARITY_STATE: begin |
if(clocksPerBit == bitClocksCounter) begin |
if(~overrunErrorFlag) begin |
frameErrorFlag <= #1 parityError; |
dataOutReadyFlag <= #1 ~parityError; |
end |
flagsSet=1; |
if(stopBit2) |
nextState <= #1 STOP1_STATE; |
else |
nextState <= #1 STOP2_STATE; |
bitClocksCounter <= #1 0; |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end |
STOP1_STATE: begin |
if(clocksPerBit == bitClocksCounter) begin |
if(STOP_BIT1 != internalIn) begin |
frameErrorFlag <= #1 parityError; |
flagsSet=1; |
end |
bitClocksCounter <= #1 0; |
nextState <= #1 STOP2_STATE; |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end |
STOP2_STATE: begin |
if(clocksPerBit == bitClocksCounter) begin |
if(STOP_BIT2 != internalIn) begin |
frameErrorFlag <= #1 1; |
flagsSet=1; |
end |
bitClocksCounter <= #1 0; |
nextState <= #1 IDLE_STATE; |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end |
/*END_STATE: begin |
if((clocksPerBit/2) == bitClocksCounter) begin |
nextState <= #1 IDLE_STATE; |
bitClocksCounter <= #1 1; |
end else begin |
bitClocksCounter <= #1 bitClocksCounter+1'b1; |
end |
end*/ |
/*END2_STATE: begin//just wait one last cycle to get exact timing for RUN bit |
nextState <= #1 IDLE_STATE; |
end*/ |
default: nextState <= #1 IDLE_STATE; |
endcase |
end |
|
end |
|
endmodule |