📄 pl4_lite_stimulus.v
字号:
begin
tasks.send_idles(1);
SendingAutoTraining = 1'b1;
end
tasks.send_training(1);
SentUserIdle = 1'b0;
end
// If a control word is being sent with SOP set and it has been
// longer than SnkDataMaxT cycles since the last training pattern,
// then training should be sent after the control word.
// The control word should be stripped of the payload
// control bit, the SOP bit, and the address and these should be
// inserted into DataInterrupt. This ensures that the burst before
// training terminates properly (it either ends with an EOP or an idle)
// and the next burst (after training) starts properly (with a Payload
// control word). However, if Rctl != 0
// (the previous output was a control word) then do not take this
// branch, as either an EOP or IDLE was just sent or this is a forced
// SOP-spacing violation
else if ((TCCtlFF[TCDatFFBottom] == 1'b1) &&
(TCDatFF[TCDatFFBottom][12] == 1'b1) &&
(CtlEmpty == 1'b0) &&
(RCtl == 1'b0) &&
(TrainingCnt >= SnkDataMaxT && SnkDataMaxT > 0) &&
(SnkAlphaData != 0 && DataInterrupt == 0) )
begin
DataInterrupt <= #`TFF {4'h9, TCDatFF[TCDatFFBottom][11:4], 4'hF};
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
FFReadEn <= #`TFF 1'b1;
SopCnt <= #`TFF (SopCnt + 1'b1) % 8;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b1;
tasks.send_control({TCDatFF[TCDatFFBottom][17:16], 1'b0,
TCDatFF[TCDatFFBottom][14:13], 9'b0,
TCDatFF[TCDatFFBottom][3:0]});
SentUserIdle = 1'b0;
SendingAutoTraining = 1'b1;
end
// If SnkDataMaxT cycles have passed since the last training
// patterns were sent and the data transfer is on a credit
// boundary then send training
else if ((TrainingCnt >= SnkDataMaxT) &&
(SnkDataMaxT > 0) &&
(CreditBoundary == 1'b1) &&
(SnkAlphaData != 0) )
//---------------------------------------------------------------
// If data was being sent then a payload resume control word
// will need to be sent once training is complete. The following
// if structure creates the control word DataInterrupt
//---------------------------------------------------------------
// If the last thing sent was an IDLE, EOP, or abort, then the
// data stream is already in a state where it's ready for
// a training sequence, so launch right into that. Note:
// even though this doesn't check for it, the last word
// couldn't have indicated an SOP or a continue because
// CreditBoundary is set
begin
if ((RCtl == 1'b1) &&
((RDat[15:12] == 4'h0) || (RDat[14:13] != 2'b00)) )
DataInterrupt <= #`TFF DataInterrupt;
else
begin
// If DataInterrupt is already set, don't change it. This branch
// should never get hit, but it's here for clarity
if (DataInterrupt != 0)
DataInterrupt <= #`TFF DataInterrupt;
// If there's an EOP or an abort in the FIFO and the FIFO's not
// empty then send out the EOP and store the rest of the control
// word into DataInterrupt
else if ((TCDatFF[TCDatFFBottom][14:13] != 2'b00) &&
(TCCtlFF[TCDatFFBottom] == 1'b1) &&
(CtlEmpty == 1'b0) )
begin
FFReadEn <= #`TFF 1'b1;
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
// If there's an SOP or Payload Control, save that part of the
// control word into DataInterrupt
if ((TCDatFF[TCDatFFBottom][15] == 1'b1) ||
(TCDatFF[TCDatFFBottom][12] == 1'b1) )
DataInterrupt <= #`TFF {TCDatFF[TCDatFFBottom][15], 2'b00,
TCDatFF[TCDatFFBottom][12:0]};
tasks.send_control({TCDatFF[TCDatFFBottom][17:16], 1'b0,
TCDatFF[TCDatFFBottom][14:13], 1'b0,
12'h00F});
end
// Either the FIFO is empty or the next thing in it is either
// an SOP/continue or data
else
begin
// If the FIFO is non-empty and the next item is data, then
// store a resume into DataInterrupt and send out an idle
// before going into training
if ((TCCtlFF[TCDatFFBottom] == 1'b0) &&
(CtlEmpty == 1'b0) )
begin
DataInterrupt <= #`TFF {4'h8, CurrentAddress, 4'hF};
FFReadEn <= #`TFF 1'b0;
tasks.send_idles(1);
end
// If the FIFO is empty or the next item is non-data,
// do nothing before going into training
else
DataInterrupt <= #`TFF DataInterrupt;
end
end
// Send the actual training pattern
SopCnt <= #`TFF 3'd7;
FFReadEn <= #`TFF 1'b0;
tasks.send_training(SnkAlphaData);
SentUserIdle = 1'b0;
SendingAutoTraining = 1'b1;
end
// No need to send training
else
begin
HasCredit = 1'b0;
HasEOP = 1'b0;
SendingUserTraining = 1'b0;
SendingAutoTraining = 1'b0;
SentUserIdle = 1'b0;
// If the next word out of the FIFO is a payload control word and
// the FIFO read pointer is less than 8 behind the write pointer then
// set the HasCredit variable to false (there is less than a credit of
// data in the FIFO) and check to see if the FIFO contains and EOP
// control word. If so, set HasEOP to true. This check implicitly
// fails if the FIFO is empty.
if ((((TCDatFF[TCDatFFBottom][15] == 1'b1) &&
(TCCtlFF[TCDatFFBottom] == 1'b1)) ||
(DataInterrupt[15] == 1'b1)) &&
(((TCDatFFBottom < TCDatFFTop) &&
((TCDatFFBottom + 'd9) % 1024 > TCDatFFTop))
||
(((TCDatFFBottom + 'd9) % 1024 < 'd9) &&
((TCDatFFBottom + 'd9) % 1024 > TCDatFFTop))))
begin
// If the FIFO write pointer has wrapped around
if (TCDatFFBottom + 'b1 > TCDatFFTop)
// Check every FIFO location between the read and write pointers
// for an EOP
for (x = TCDatFFBottom + 1; x < (TCDatFFTop + 1024); x = x + 1)
if ((TCDatFF[x % 1024][14:13] != 2'b00) &&
(TCCtlFF[x % 1024] == 1'b1) )
HasEOP = 1'b1;
// If the FIFO write pointer has not wrapped around
else
// Check every FIFO location between the read and write pointers
// for an EOP
for (x = TCDatFFBottom + 1; x < TCDatFFTop; x = x + 1)
if (TCDatFF[x][14:13] != 2'b00 && TCCtlFF[x] == 1'b1)
HasEOP = 1'b1;
end
// Else FIFO is empty or there is is at least a credit in the FIFO
else
HasCredit = 1'b1;
// If there is a payload control word at the head of the FIFO and less
// than a credit of data available with no EOP, then don't start
// sending the packet out since it is not certain that the entire
// packet will be written to the FIFO in time to be sent out.
// Instead, send whatever EOP information is in the payload control
// word (since it would go with the packet already sent out. The
// remainder of the payload control word is stored in DataInterrupt
// to be sent out once a full credit (or EOP) is available in the
// FIFO.
if ((HasCredit == 1'b0) && (HasEOP == 1'b0))
begin
if ((TCDatFF[TCDatFFBottom][14:13] != 2'b00) &&
(TCCtlFF[TCDatFFBottom] == 1'b1) &&
DataInterrupt == 0)
begin
DataInterrupt <= #`TFF {TCDatFF[TCDatFFBottom][15], 2'b00,
TCDatFF[TCDatFFBottom][12:0]};
FFReadEn <= #`TFF 1'b1;
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b1;
if (SopCnt < 7)
SopCnt <= #`TFF (SopCnt + 1) % 8;
else
SopCnt <= #`TFF 3'd7;
tasks.send_control({TCDatFF[TCDatFFBottom][17:16], 1'b0,
TCDatFF[TCDatFFBottom][14:13], 1'b0, 12'h00f});
end
// The next item in the FIFO is a non-EOP, or DataInterrupt is
// already set
else
begin
FFReadEn <= #`TFF 1'b0;
if (SopCnt < 7)
SopCnt <= #`TFF (SopCnt + 1) % 8;
else
SopCnt <= #`TFF 'd7;
tasks.send_idles(1);
SentUserIdle = 1'b1;
end
end
// Either:
// a) A credit is currently in progress (bottom of FIFO isn't
// a control word)
// b) A full credit is available
// c) Less than a credit is available, but there is an EOP in
// the FIFO, or
// d) The FIFO is empty
else
begin
// Empty ------------------------------------------------------------
// If the FIFO is empty then just send idles
if (CtlEmpty == 1'b1)
begin
FFReadEn <= #`TFF 1'b0;
if (SopCnt < 'd7)
SopCnt <= #`TFF (SopCnt + 1) % 8;
else
SopCnt <= #`TFF 3'd7;
tasks.send_idles(1);
SentUserIdle = 1'b1;
end
// SOP --------------------------------------------------------------
// If the current control word is an SOP or the control word in
// DataInterrupt is a SOP then make sure that there
// has been at least one credit sent since the last SOP. If there
// hasn't then send idles until this requirement is met.
else if (((TCDatFF[TCDatFFBottom][12] == 1'b1) &&
(TCDatFF[TCDatFFBottom][15] == 1'b1) &&
(TCCtlFF[TCDatFFBottom] == 1'b1)) ||
((DataInterrupt[15] == 1'b1) &&
(DataInterrupt[12] == 1'b1)))
begin
// Check to see if less than one credit has been sent since the
// last SOP and SOPErr is not set
if ((SopCnt < 'd7) &&
(TCDatFF[TCDatFFBottom][18] != 1'b1))
begin
SopCnt <= #`TFF (SopCnt + 1) % 8;
// If there is an EOP then strip off the payload control and
// store it in DataInterrupt to send after the idles complete
if ((TCDatFF[TCDatFFBottom][14:13] != 2'b00) &&
(DataInterrupt[15] == 1'b0))
begin
DataInterrupt <= #`TFF {4'h9, TCDatFF[TCDatFFBottom][11:4],
4'hF};
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
FFReadEn <= #`TFF 1'b1;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b1;
tasks.send_control({TCDatFF[TCDatFFBottom][17:16], 1'b0,
TCDatFF[TCDatFFBottom][14:13], 1'b0,
12'h00F});
if (SopCnt < 6)
begin
FFReadEn <= #`TFF 1'b0;
SopCnt <= #`TFF (SopCnt + 1) % 8;
tasks.send_idles(1);
SentUserIdle = 1'b1;
end
end
else
begin
FFReadEn <= #`TFF 1'b0;
tasks.send_idles(1);
SentUserIdle = 1'b1;
end
end
// If the minimum SOP spacing is met then check to see if
// DataInterrupt is set. If it is, send out the control word
// on it before sending the next data word. Otherwise send
// the next word.
else
begin
SopCnt <= #`TFF 1'b0;
CreditCnt <= #`TFF 3'd7;
CreditBoundary <= #`TFF 1'b0;
if (DataInterrupt[15] != 1'b0)
begin
DataInterrupt <= #`TFF 16'h0;
FFReadEn <= #`TFF 1'b0;
tasks.send_control({2'b00, DataInterrupt});
end
else
begin
TCDatFFBottom <= #`TFF (TCDatFFBottom + 1) % 1024;
FFReadEn <= #`TFF 1'b1;
tasks.send_control(TCDatFF[TCDatFFBottom][17:0]);
end
end
end
// DataInterrupt Flag -----------------------------------------------
// If the DataInterrupt register is set then send it on RDat and
// reset the register to zero.
else if (DataInterrupt != 0)
begin
FFReadEn <= #`TFF 1'b0;
if (DataInterrupt[12] == 1'b1)
SopCnt <= #`TFF 3'd0;
else
if (SopCnt < 3'd7)
SopCnt <= #`TFF (SopCnt + 1) % 8;
else
SopCnt <= #`TFF SopCnt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -