📄 pl4_lite_stimulus.v
字号:
reg SendTraining; //Indicates control is sending training
reg SendingAutoTraining; //Indicates periodic training
reg SendingUserTraining; //Indicates user-initiated training
reg SendingUserIdle; //Indicates user-initiated idle
reg SentUserIdle; //Post-indicates user-initiated idle
//Signals for DIP-4 calculation
reg [15:0] DataControlDIP4; //Data to be outputted with DIP-4 inserted
reg ControlEnableDIP4; //Control to be outputted
reg [17:0] Data_d1; //Data without the DIP4 inserted
reg Ctl_d1; //Control signal used by DIP4 calculation
reg [15:0] DIP16; //Dip16 calculation
wire [3:0] DIP4; //Dip4 Calculation
reg Training; //Indicates in training during DIP4 calc
//Signals for Testcase Status Capture
reg [1:0] TCStatArray [NumLinks - 1:0];
reg [8:0] TCIndex;
//Signals for DIP-2 calculation
reg [9:0] LenCnt; //Index for position in calendar sequence
reg [15:0] MCnt; //Counter for number of repititions of cal.
reg [1:0] Dip2; //Dip2 calculation
reg FFReadEn; //Indicates data has been read from the FF
reg First;
/*****************************************************************************
* Instantiate procedures module
*****************************************************************************/
pl4_lite_procedures tasks (
.RDat (RDat),
.RCtl (RCtl),
.RDClk2x (RDClk2x),
.SopErr (),
.TCDIP4Request (),
.Stat (),
.Chan (),
.TSClk (TSClkIn),
.FFWriteEn (),
.GetStatusChan (),
.FullVec (),
.FFFull (1'b0),
.SnkAlmostFull_n (SnkAlmostFull_n) ,
.CheckRStat (CheckRStat),
.RandomSeed (RandomSeed)
);
/*****************************************************************************
* Initial Conditions
*****************************************************************************/
initial
begin
RDClk_P = 1'b0;
RDClk_N = 1'b1;
TrainingCnt = 16'b0;
SopCnt = 3'd7;
CurrentAddress = 8'h00;
DataInterrupt = 16'h0000;
CreditBoundary = 1'b1;
SendTraining = 1'b0;
Training = 1'b0;
MCnt = 8'h01;
Dip2 = 2'b00;
GetStatus = 2'b00;
end
/*****************************************************************************
* Create RDClk
* Divides the RDClk2x clock by 2 to create RDClk
*****************************************************************************/
always @(posedge RDClk2x)
begin: RDClk_gen
RDClk_P = !RDClk_P;
RDClk_N = !RDClk_N;
end
/*****************************************************************************
* Assign TSClk
*****************************************************************************/
assign TSClk = TSClkIn;
assign SnkDip2ErrRequest = TCSnkDip2ErrRequest;
assign TrainingRequest = TCTrainingRequest;
assign IdleRequest = TCIdleRequest;
/*****************************************************************************
* Capture Calendar
* Captures the calendar sequence that is loaded from the file so that the
* control module knows the sequence of the channels.
*****************************************************************************/
always @(posedge UserClk)
begin:capture_calendar
if (!CalWrEn_n)
CalSeq [CalAddr] <= #`TFF CalData;
else
CalSeq [CalAddr] <= #`TFF CalSeq [CalAddr];
end
/*****************************************************************************
* Generate FIFO flags asynchronously
*****************************************************************************/
always @(Reset_n or TCDatFFTop or TCDatFFBottom)
begin: fifo_flags
if (!Reset_n)
begin
CtlEmpty <= 1'b1;
CtlFull_i <= 1'b0;
AlmostEmpty <= 1'b0;
AlmostFull <= 1'b0;
end
else
begin
// If the write index is one greater than the read index, the FIFO is
// almost empty
if (TCDatFFTop == ((TCDatFFBottom + 1) % 1024))
begin
CtlEmpty <= 1'b0;
CtlFull_i <= 1'b0;
AlmostEmpty <= 1'b1;
AlmostFull <= 1'b0;
end
// If the read index is one greater than the write index, the FIFO is
// almost full
else if (TCDatFFBottom == ((TCDatFFTop + 1) % 1024))
begin
CtlEmpty <= 1'b0;
CtlFull_i <= 1'b0;
AlmostEmpty <= 1'b0;
AlmostFull <= 1'b1;
end
// If the write index and read index are equal, the FIFO is either full
// or empty - determine which one
else if (TCDatFFBottom == TCDatFFTop)
begin
// If AlmostEmpty or CtlEmpty was previously asserted, FIFO is now
// (still) empty
if (AlmostEmpty || CtlEmpty)
begin
CtlEmpty <= 1'b1;
CtlFull_i <= 1'b0;
AlmostEmpty <= 1'b0;
AlmostFull <= 1'b0;
end
// Otherwise FIFO is now full
else
begin
CtlEmpty <= 1'b0;
CtlFull_i <= 1'b1;
AlmostEmpty <= 1'b0;
AlmostFull <= 1'b0;
end
end
// If read and write are more than one index apart, deassert all flags
else
begin
CtlEmpty <= 1'b0;
CtlFull_i <= 1'b0;
AlmostEmpty <= 1'b0;
AlmostFull <= 1'b0;
end
end
end
// Assert external CtlFull one clock early to prevent overflow
assign CtlFull = CtlFull_i | AlmostFull;
/*****************************************************************************
* Capture data on TCDat
* Captures the data coming from the testcase module and stores it in
* TCDatFF. SOPErr is stored in TCDatFF[x][18], DIP4 Error Request is stored
* in TCDatFF[x][16] and TCDatFF[x][17] is reserved for future use.
*****************************************************************************/
always @(posedge RDClk2x or negedge Reset_n)
begin
if (!Reset_n)
begin
TCDatFFTop <= #`TFF 1'b0;
for (i=0; i <= 1023; i = i+1)
begin
TCDatFF[i] <= #`TFF {19{1'b0}};
TCCtlFF[i] <= #`TFF {1{1'b0}};
end
end
else
begin
// If the Merge Payload constant is set to 1 then merge the current
// word with the last one written to the FIFO if:
// * The last word in written was an EOP w/o Payload Control
// * The word being written is a Payload Control word w/o any EOP
// bits set
// * The last word written hasn't been read out yet
// * Neither control word has the DIP4Request bit set
// If all these conditions are met, merge the two control words into
// one control word and don't increment the top index.
if ((MergePayload) &&
(FFWriteEn == 1'b1) &&
(TCCtlFF[TCDatFFTop - 1'b1] == 1'b1) &&
(TCDatFF[TCDatFFTop - 1'b1][12] == 1'b0) &&
(TCDatFF[TCDatFFTop - 1'b1][14:13] != 2'b00) &&
(TCDatFF[TCDatFFTop - 1'b1][15] == 1'b0) &&
(TCDatFF[TCDatFFTop - 1'b1][16] == 1'b0) &&
(TCCtl == 1'b1) &&
(TCDat[14:13] == 2'b00) &&
(TCDat[15] == 1'b1) &&
(TCDat[16] == 1'b0) &&
!((CtlEmpty == 1'b1) ||
(AlmostEmpty == 1'b1)))
begin
// Replace the top word with the merged control word
TCDatFF[TCDatFFTop - 1'b1] =
{SopErr, TCDatFF[TCDatFFTop - 1'b1][17:16], TCDat[15],
TCDatFF[TCDatFFTop - 1'b1][14:13], TCDat[12:0]};
TCDatFFTop = TCDatFFTop;
end
// If write is asserted and the FIFO isn't full, store the input and
// increment the write pointer
else if (FFWriteEn == 1'b1 && CtlFull_i == 1'b0)
begin
TCDatFF[TCDatFFTop] <= #`TFF {SopErr, TCDat};
TCCtlFF[TCDatFFTop] <= #`TFF TCCtl;
TCDatFFTop <= #`TFF TCDatFFTop + 1;
end
end
end
/*****************************************************************************
* Create RDat signal
* Creates the signal that will be passed to the core on the RDat bus.
* If the core is in reset it sends all zeros. If the core is out of frame
* or SnkDataMaxT cycles have passed since the last training patterns
* were sent it sends training. If the minimum number of cycles have not
* passed since the last SOP control word then it sends idles. In all other
* cases it sends the data from the testcase FIFO. In the case where it sends
* idles or training, if it interrupted a data burst a payload resume burst
* should be send after the idles or training completes. Note: All clocking
* for this process is done in the procedures module. All outgoing data is
* synchronous with RDClk2x.
*****************************************************************************/
always
begin: send_data_block
if (!Reset_n)
begin
tasks.reset;
TCDatFFBottom <= #`TFF 'b0;
SopCnt <= #`TFF 3'b111;
CreditCnt <= #`TFF 3'b111;
CreditBoundary <= #`TFF 1'b1;
DataInterrupt <= #`TFF 16'b0;
CurrentAddress <= #`TFF 8'b0;
FFReadEn <= #`TFF 1'b0;
HasEOP <= #`TFF 1'b0;
HasCredit <= #`TFF 1'b0;
SendingAutoTraining <= #`TFF 1'b0;
SendingUserTraining <= #`TFF 1'b0;
SendingUserIdle <= #`TFF 1'b0;
end
else
begin
//If the current word is a control word then capture the current address
if ((TCCtlFF[TCDatFFBottom] == 1'b1) &&
(TCDatFF[TCDatFFBottom][15] == 1'b1))
CurrentAddress <= #`TFF TCDatFF[TCDatFFBottom][11:4];
else
CurrentAddress <= #`TFF CurrentAddress;
// If the user is trying to send a training pattern, allow it through
// even if the core is out of sync, as long as an IDLE has just been
// sent (a prerequisite for sending training) and the process isn't
// already in the middle of sending automatic (periodic) training
if ((!SendingAutoTraining) &&
(SentUserIdle) &&
(((TCCtlFF[TCDatFFBottom] == 1'b1) &&
(TCDatFF[TCDatFFBottom] == {2'b0, `TRAINING_CTL})) ||
((SendingUserTraining) &&
(TCCtlFF[TCDatFFBottom] == 1'b0) &&
(TCDatFF[TCDatFFBottom] == {2'b0, !(`TRAINING_CTL)}))) &&
(CtlEmpty == 1'b0))
begin
SopCnt <= #`TFF 3'd7;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b1;
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
FFReadEn <= #`TFF 1'b1;
if (TCCtlFF[TCDatFFBottom] == 1'b1)
tasks.send_control(TCDatFF[TCDatFFBottom][17:0]);
else
tasks.send_data(TCDatFF[TCDatFFBottom][17:0]);
SendingUserTraining = 1'b1;
SendingAutoTraining = 1'b0;
end
// If the user is trying to send a training pattern and hasn't preceded
// it with an IDLE, insert an idle
else if ((SendingAutoTraining == 1'b0) &&
(SendingUserTraining == 1'b0) &&
(SentUserIdle == 1'b0) &&
(((TCCtlFF[TCDatFFBottom] == 1'b1) &&
(TCDatFF[TCDatFFBottom] == {2'b00, `TRAINING_CTL}))) &&
(CtlEmpty == 1'b0))
begin
FFReadEn <= #`TFF 1'b0;
if (SopCnt < 7)
SopCnt <= #`TFF (SopCnt + 1) % 8;
else
SopCnt <= #`TFF SopCnt;
tasks.send_idles(1);
SendingUserTraining = 1'b0;
SendingAutoTraining = 1'b0;
SentUserIdle = 1'b1;
end
// If the sink core is out of frame then send training patterns until
// it comes into frame
else if (SnkInFrame == 1'b0)
begin
SopCnt <= #`TFF 3'd7;
FFReadEn <= #`TFF 1'b0;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b1;
// If an idle hasn't been sent yet (currently not sending training)
// then send one before sending training
if (SendingAutoTraining == 1'b0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -