定制framing接口的IP核
很簡(jiǎn)單,靈活配置如下參數(shù)即可:
本例選擇小端模式。
FLow Control 暫時(shí)選擇為None。(有必要后面專門研究,暫時(shí)最主要的還是弄懂用戶接口信號(hào)的用法!)
為分析方面,選擇單通道傳輸數(shù)據(jù)。
生成示例工程并分析
如圖,右擊IP核,打開例子程序,保存到一個(gè)位置,即可自動(dòng)打開例子工程。
對(duì)于我們用戶來(lái)說(shuō),最重要還是我們的用戶程序,通過用戶程序模塊與Aurora IP核交互,生成數(shù)據(jù)發(fā)出以及接收IP核傳輸?shù)臄?shù)據(jù)。
文末同樣會(huì)分享示例工程,所以這里就不把源碼貼出來(lái),占用篇幅,給閱讀帶來(lái)不便。
GEN模塊分析
先打開gen模塊,對(duì)于該模塊,有一段描述:
// Description: This module is a pattern generator to test the Aurora
// designs in hardware. It generates data and passes it
// through the Aurora channel. If connected to a framing
// interface, it generates frames of varying size and
// separation. LFSR is used to generate the pseudo-random
// data and lower bits of LFSR are connected to REM bus.
翻譯過來(lái):
該模塊是一個(gè)模式生成器,用于在硬件中測(cè)試Aurora設(shè)計(jì)。它生成數(shù)據(jù)并將其通過Aurora通道。如果連接到成幀接口,它將生成大小和間隔不同的幀。LFSR用于生成偽隨機(jī)數(shù)據(jù),并且LFSR的低位連接到REM總線。
首先,讀了這段描述,一般肯定不知道具體干啥的,但是大概知道是生成一系列數(shù)據(jù),并發(fā)送出去,而且用的是framing數(shù)據(jù)格式。
讓我們看看具體內(nèi)容:
看程序首先看輸入輸出:
// User Interface
output [0:15] TX_D;
output TX_REM;
output TX_SOF_N;
output TX_EOF_N;
output TX_SRC_RDY_N;
input TX_DST_RDY_N;
// System Interface
input USER_CLK;
input RESET;
input CHANNEL_UP;
從這幾個(gè)信號(hào)用戶接口,可見,有一些我們熟悉的接口,但是和axi接口的名字起的不一樣罷了;
讓我們對(duì)應(yīng)下:
從如下接口方向可以斷定:
s_axi_tx_tready為
input TX_DST_RDY_N;
二者之間的關(guān)系:
作為gen模塊用戶邏輯的條件,無(wú)論是tready還是RDY_N,有效即可。
tready為RDY_N的反,從以N結(jié)尾也該明白了。
也不賣關(guān)子了,其他的等價(jià):
// User Interface
output [0:15] TX_D; //data
output TX_REM; //?
output TX_SOF_N; // start of frame
output TX_EOF_N; // end of frame
output TX_SRC_RDY_N; // valid
input TX_DST_RDY_N; //tready
當(dāng)Aurora通道還未準(zhǔn)備好時(shí),需要設(shè)計(jì)復(fù)位,讓通道出于復(fù)位狀態(tài):
always @ (posedge USER_CLK)
begin
if(RESET)
channel_up_cnt <= `DLY 5'd0;
else if(CHANNEL_UP)
if(&channel_up_cnt)
channel_up_cnt <= `DLY channel_up_cnt;
else
channel_up_cnt <= `DLY channel_up_cnt + 1'b1;
else
channel_up_cnt <= `DLY 5'd0;
end
assign dly_data_xfer = (&channel_up_cnt);
//Generate RESET signal when Aurora channel is not ready
assign reset_c = RESET || !dly_data_xfer;
從上面的計(jì)數(shù)條件,可見CHANNEL_UP為通道準(zhǔn)備好的標(biāo)志,當(dāng)其有效時(shí),channel_up_cnt則從0一直計(jì)數(shù)到5'b1111_1并保持;否則,channel_up_cnt為0;這樣的話,當(dāng)CHANNEL_UP無(wú)效時(shí),dly_data_xfer為0,那么reset_c為1,即處于復(fù)位狀態(tài)。
當(dāng)CHANNEL_UP為1,也即有效時(shí),也會(huì)計(jì)數(shù)一段時(shí)間,確保穩(wěn)定,之后dly_data_xfer為1,那么reset_c的值取決于RESET,RESET無(wú)效時(shí),停止復(fù)位。這樣確保了,RESET早就停止了復(fù)位,而通道還未準(zhǔn)備好,等通道準(zhǔn)備好了之后,才停止復(fù)位,發(fā)送邏輯開始有效執(zhí)行。
下面繼續(xù)分析數(shù)據(jù)傳輸?shù)牟糠郑?/p>
//______________________________ Transmit Data __________________________________
//Generate random data using XNOR feedback LFSR
always @(posedge USER_CLK)
if(reset_c)
begin
data_lfsr_r <= `DLY 16'hABCD; //random seed value
end
else if(!TX_DST_RDY_N && !idle_r)
begin
data_lfsr_r <= `DLY {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},
data_lfsr_r[0:14]};
end
//Connect TX_D to the DATA LFSR
assign TX_D = {1{data_lfsr_r}};
可見,要發(fā)送的數(shù)據(jù)是一個(gè)有規(guī)則產(chǎn)生的隨機(jī)數(shù)據(jù),data_lfsr_r的初始值作為隨機(jī)數(shù)的種子,之后通過異或非的方式產(chǎn)生隨機(jī)數(shù)。
這種產(chǎn)生隨機(jī)數(shù)的方式屬于線性反饋移位寄存器
上面出現(xiàn)了一個(gè)陌生的變量idle_r:
//State registers for one-hot state machine
reg idle_r;
reg single_cycle_frame_r;
reg sof_r;
reg data_cycle_r;
reg eof_r;
wire reset_c;
//*********************************Wire Declarations**********************************
wire ifg_done_c;
//Next state signals for one-hot state machine
wire next_idle_c;
wire next_single_cycle_frame_c;
wire next_sof_c;
wire next_data_cycle_c;
wire next_eof_c;
它是狀態(tài)機(jī)變量,眾多為了描述狀態(tài)機(jī)而設(shè)的變量之一。下面便是狀態(tài)機(jī)部分,可以看出,是一個(gè)三段式狀態(tài)機(jī),很講究!
使用狀態(tài)機(jī)的目的在于確定 frame的起始,結(jié)束以及要發(fā)送數(shù)據(jù)還是什么也不發(fā)送等。
//_____________________________ Framing State machine______________________________
//Use a state machine to determine whether to start a frame, end a frame, send
//data or send nothing
//State registers for 1-hot state machine
always @(posedge USER_CLK)
if(reset_c)
begin
idle_r <= `DLY 1'b1;
single_cycle_frame_r <= `DLY 1'b0;
sof_r <= `DLY 1'b0;
data_cycle_r <= `DLY 1'b0;
eof_r <= `DLY 1'b0;
end
else if(!TX_DST_RDY_N)
begin
idle_r <= `DLY next_idle_c;
single_cycle_frame_r <= `DLY next_single_cycle_frame_c;
sof_r <= `DLY next_sof_c;
data_cycle_r <= `DLY next_data_cycle_c;
eof_r <= `DLY next_eof_c;
end
//Nextstate logic for 1-hot state machine
assign next_idle_c = !ifg_done_c &&
(single_cycle_frame_r || eof_r || idle_r);
assign next_single_cycle_frame_c = (ifg_done_c && (frame_size_r == 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_sof_c = (ifg_done_c && (frame_size_r != 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_data_cycle_c = (frame_size_r != bytes_sent_r) &&
(sof_r || data_cycle_r);
assign next_eof_c = (frame_size_r == bytes_sent_r) &&
(sof_r || data_cycle_r);
//Output logic for 1-hot state machine
always @(posedge USER_CLK)
if(reset_c)
begin
TX_SOF_N <= `DLY 1'b1;
TX_EOF_N <= `DLY 1'b1;
TX_SRC_RDY_N <= `DLY 1'b1;
end
else if(!TX_DST_RDY_N)
begin
TX_SOF_N <= `DLY !(sof_r || single_cycle_frame_r);
TX_EOF_N <= `DLY !(eof_r || single_cycle_frame_r);
TX_SRC_RDY_N <= `DLY idle_r;
end
程序設(shè)計(jì)的是一個(gè)所謂的獨(dú)熱碼狀態(tài)機(jī),且不是一般的獨(dú)熱碼設(shè)計(jì)方法,類似于:hdlbits,獨(dú)熱碼狀態(tài)機(jī)設(shè)計(jì),非常重要
這個(gè)狀態(tài)機(jī)有5個(gè)狀態(tài),每循環(huán)一次,就可以發(fā)送一幀數(shù)據(jù)。
五個(gè)狀態(tài)如下:
reg idle_r; // 空閑狀態(tài)
reg single_cycle_frame_r; //單字幀,也就是一幀數(shù)據(jù)只有一個(gè)字或者少于一個(gè)字長(zhǎng)
reg sof_r; //幀起始
reg data_cycle_r; //有效賦值數(shù)據(jù)
reg eof_r; //幀結(jié)束
由于是獨(dú)熱碼,故都是一位變量;
次態(tài)變量:
//Next state signals for one-hot state machine
wire next_idle_c;
wire next_single_cycle_frame_c;
wire next_sof_c;
wire next_data_cycle_c;
wire next_eof_c;
對(duì)應(yīng)的次態(tài)部分代碼:
//Nextstate logic for 1-hot state machine
assign next_idle_c = !ifg_done_c &&
(single_cycle_frame_r || eof_r || idle_r);
assign next_single_cycle_frame_c = (ifg_done_c && (frame_size_r == 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_sof_c = (ifg_done_c && (frame_size_r != 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_data_cycle_c = (frame_size_r != bytes_sent_r) &&
(sof_r || data_cycle_r);
assign next_eof_c = (frame_size_r == bytes_sent_r) &&
(sof_r || data_cycle_r);
可見,出現(xiàn)了很多條件來(lái)組成獨(dú)熱碼:如:
ifg_done_c
frame_size_r
bytes_sent_r
要搞清楚這些輸入的含義,才能更好理解,根據(jù)次態(tài)生成部分以及輸出生成部分,還可以畫出狀態(tài)轉(zhuǎn)移圖或者狀態(tài)轉(zhuǎn)移表,這是后面的工作(看心情)。
都在這里 :
//Use a counter to determine the size of the next frame to send
always @(posedge USER_CLK)
if(reset_c)
frame_size_r <= `DLY 8'h00;
else if(single_cycle_frame_r || eof_r)
frame_size_r <= `DLY frame_size_r + 1;
//Use a second counter to determine how many bytes of the frame have already been sent
always @(posedge USER_CLK)
if(reset_c)
bytes_sent_r <= `DLY 8'h00;
else if(sof_r)
bytes_sent_r <= `DLY 8'h01;
else if(!TX_DST_RDY_N && !idle_r)
bytes_sent_r <= `DLY bytes_sent_r + 1;
//Use a freerunning counter to determine the IFG
always @(posedge USER_CLK)
if(reset_c)
ifg_size_r <= `DLY 4'h0;
else
ifg_size_r <= `DLY ifg_size_r + 1;
//IFG is done when ifg_size register is 0
assign ifg_done_c = (ifg_size_r == 4'h0);
frame_size_r是一個(gè)計(jì)數(shù)器變量,使用計(jì)數(shù)器確定要發(fā)送的一幀數(shù)據(jù)的大小;
同理,bytes_sent_r 使用第二個(gè)計(jì)數(shù)器來(lái)確定已經(jīng)發(fā)送了多少個(gè)幀字節(jié);
最難理解的屬于ifg了?
這是什么玩意?
通過查閱資料恍然大悟:IFG是Interframe Gap的縮寫,意思是幀與幀之間的間距。
為什么要有這個(gè)東西呢?簡(jiǎn)單地說(shuō),就是為了防止幀間距過小,而導(dǎo)致丟幀等,也就是說(shuō)發(fā)送完一幀數(shù)據(jù)后,給下一幀數(shù)據(jù)的發(fā)送預(yù)留緩沖時(shí)間。
從程序中也能看出來(lái):
第一部分:
//Use a freerunning counter to determine the IFG
always @(posedge USER_CLK)
if(reset_c)
ifg_size_r <= `DLY 4'h0;
else
ifg_size_r <= `DLY ifg_size_r + 1;
//IFG is done when ifg_size register is 0
assign ifg_done_c = (ifg_size_r == 4'h0);
第二部分:
//Nextstate logic for 1-hot state machine
assign next_idle_c = !ifg_done_c &&
(single_cycle_frame_r || eof_r || idle_r);
assign next_single_cycle_frame_c = (ifg_done_c && (frame_size_r == 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_sof_c = (ifg_done_c && (frame_size_r != 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
ifg_size_r為計(jì)數(shù)變量,一直計(jì)數(shù),計(jì)數(shù)滿了之后溢出,自身 變?yōu)榱悖^續(xù)計(jì)數(shù),一直如此。
當(dāng)ifg_size_r不為零的時(shí)候,狀態(tài)機(jī)出于idle狀態(tài),也就是空閑狀態(tài),等溢出之后的下一個(gè)周期,就可以進(jìn)入下一個(gè)狀態(tài)了,發(fā)送數(shù)據(jù)。
說(shuō)了這么多,其實(shí)狀態(tài)機(jī) 描述的就是一個(gè)幀數(shù)據(jù)的發(fā)送過程:
idle_r狀態(tài)不發(fā)送數(shù)據(jù);
single_cycle_frame_r這個(gè)狀態(tài)什么時(shí)候會(huì)進(jìn)入呢?就是要發(fā)送的數(shù)據(jù)就一個(gè)字或者更少,就進(jìn)入這個(gè)狀態(tài),因?yàn)閒raming協(xié)議要求,其實(shí)標(biāo)志sof和結(jié)束標(biāo)志eof都要有效(此時(shí));
sof_r:如果要發(fā)送的數(shù)據(jù)多于一個(gè)字,那么安裝情況就要分為幾個(gè)周期完成數(shù)據(jù)發(fā)送;那么此時(shí)就會(huì)進(jìn)入發(fā)送首字的狀態(tài);
data_cycle_r:這個(gè)狀態(tài),繼續(xù)發(fā)送中間字;
eof_r:這就是要發(fā)送最后一個(gè)字了。
好了,我們的發(fā)送過程就講完了。
CHECK模塊分析
如果你知道了發(fā)送的過程,那收還不容易嗎?
通信雙方要按規(guī)矩辦事,這個(gè)規(guī)矩就是協(xié)議!
首先看下輸入輸出定義,這也是看程序的第一步:
// User Interface
input [0:15] RX_D;
input RX_REM;
input RX_SOF_N;
input RX_EOF_N;
input RX_SRC_RDY_N;
// System Interface
input USER_CLK;
input RESET;
input CHANNEL_UP;
output [0:7] ERR_COUNT;
通過發(fā)送的過程,這里我們也心照不宣地領(lǐng)會(huì)到,CHANNEL_UP和復(fù)位有關(guān);
RX_D是要收的數(shù)據(jù);
RX_SOF_N是首字;
RX_EOF_N是末字;
RX_SRC_RDY_N為有效信號(hào),即Valid,它有效的時(shí)候我們才能采樣到有效的數(shù)據(jù)。
如果SOF以及EOF同時(shí)有效,那么我們知道這個(gè)幀就一個(gè)字,或者更少。
繼續(xù)看:
// SLACK registers
always @ (posedge USER_CLK)
begin
RX_D_SLACK <= `DLY RX_D;
RX_SRC_RDY_N_SLACK <= `DLY RX_SRC_RDY_N;
RX_REM_1SLACK <= `DLY RX_REM;
RX_REM_2SLACK <= `DLY RX_REM;
RX_SOF_N_SLACK <= `DLY RX_SOF_N;
RX_EOF_N_SLACK <= `DLY RX_EOF_N;
end
程序?qū)斎氲淖兞慷技拇媪艘慌模瑸槭裁茨兀亢芎?jiǎn)單,還不是為了改善時(shí)序,這樣讓布局布線更加容易。
接著給出了一些標(biāo)志信號(hào):
assign data_in_frame_c = data_in_frame_r || (!RX_SRC_RDY_N_SLACK && !RX_SOF_N_SLACK);
其中有:
//Start a multicycle frame when a frame starts without ending on the same cycle. End
//the frame when an EOF is detected
always @(posedge USER_CLK)
if(reset_c)
data_in_frame_r <= `DLY 1'b0;
else if(CHANNEL_UP)
begin
if(!data_in_frame_r && !RX_SOF_N_SLACK && !RX_SRC_RDY_N_SLACK && RX_EOF_N_SLACK)
data_in_frame_r <= `DLY 1'b1;
else if(data_in_frame_r && !RX_SRC_RDY_N_SLACK && !RX_EOF_N_SLACK)
data_in_frame_r <= `DLY 1'b0;
end
先解釋下data_in_frame_r:
有條件:!data_in_frame_r && !RX_SOF_N_SLACK && !RX_SRC_RDY_N_SLACK && RX_EOF_N_SLACK
可知,在幀開始后,為1;
又:data_in_frame_r && !RX_SRC_RDY_N_SLACK && !RX_EOF_N_SLACK 表示,在幀結(jié)束后,又變?yōu)?;
這點(diǎn),在后面的行為仿真中,我們可以拉出來(lái)看看。
由這段分析可以知道data_in_frame_r在幀內(nèi)(不包括sof有效的第一個(gè)周期)為1;那么:
data_in_frame_c呢?
assign data_in_frame_c = data_in_frame_r || (!RX_SRC_RDY_N_SLACK && !RX_SOF_N_SLACK);
表示如果數(shù)據(jù)是單周期幀或已啟動(dòng)多周期幀,則數(shù)據(jù)在該幀中。
它把幀的第一個(gè)周期也納進(jìn)去了。
怎么理解呢?
它等于data_in_frame_r與 !RX_SRC_RDY_N_SLACK && !RX_SOF_N_SLACK的或,也就是二者有其一就為1;
在幀的第一個(gè)周期內(nèi),!RX_SRC_RDY_N_SLACK && !RX_SOF_N_SLACK有效;在后面的周期內(nèi),二者均有效。這二者都有效了,肯定數(shù)據(jù)就在幀內(nèi)了。那么這個(gè)信號(hào)data_in_frame_c就有效;
assign data_valid_c = data_in_frame_c && !RX_SRC_RDY_N_SLACK;
這個(gè)就是把data_in_frame_c與!RX_SRC_RDY_N_SLACK進(jìn)行一個(gè)與操作。作用于data_in_frame_c無(wú)異。
無(wú)論是單字幀(單周期幀)還是多周期幀,這個(gè)data_valid_c有效,數(shù)據(jù)一定是幀內(nèi)有效數(shù)據(jù)。
//Register and decode the RX_D data with RX_REM bus
always @ (posedge USER_CLK)
begin
if((!RX_EOF_N_SLACK) && (!RX_SRC_RDY_N_SLACK))
begin
case(RX_REM_1SLACK)
1'd0 : RX_D_R <= `DLY {RX_D_SLACK[0:7], 8'b0};
1'd1 : RX_D_R <= `DLY RX_D_SLACK;
default : RX_D_R <= `DLY RX_D_SLACK;
endcase
end
else if(!RX_SRC_RDY_N_SLACK)
RX_D_R <= `DLY RX_D_SLACK;
end
這段代碼,包括后面的幾乎都不用說(shuō)了,就是把數(shù)據(jù)接收過來(lái)處理,換做你的工程,肯定按照自己的方式處理接收的數(shù)據(jù)。
那CHECK的分析到此結(jié)束吧。
示例工程仿真
仿真文件也就是例化兩次例子程序,之后將二者的收發(fā)相接,形成一個(gè)環(huán)路。
總體仿真
這里直接仿真看我們想看的結(jié)果。
首先還是從宏觀上看:
可以看出,1發(fā)2收,2發(fā)1收;
不過串行數(shù)據(jù)只能看到一個(gè)大概情況,更多 的細(xì)節(jié),繼續(xù)拉出來(lái)看:
可見,發(fā)的第一個(gè)數(shù)據(jù)和收的第一個(gè)數(shù)據(jù)一致!
后面的數(shù)據(jù)也是一致的。
發(fā)送模塊仿真
從這里開始,我將關(guān)注gen模塊的幀組成情況:
第一幀數(shù)據(jù)只有一個(gè)字,因此在發(fā)送的時(shí)候sof以及eof同時(shí)有效;第二幀:
第二幀數(shù)據(jù)有兩個(gè)字:如上圖,因此,第一個(gè)字sof有效,第二字eof有效。
我還想看看第一幀數(shù)據(jù)和第二幀數(shù)據(jù)之間的間隔是不是ifg_size_r 進(jìn)行了計(jì)數(shù):
確實(shí)在計(jì)數(shù)!
和代碼對(duì)應(yīng)起來(lái):
//Use a freerunning counter to determine the IFG
always @(posedge USER_CLK)
if(reset_c)
ifg_size_r <= `DLY 4'h0;
else
ifg_size_r <= `DLY ifg_size_r + 1;
//IFG is done when ifg_size register is 0
assign ifg_done_c = (ifg_size_r == 4'h0);
計(jì)數(shù)是一直進(jìn)行的過程。
assign next_idle_c = !ifg_done_c &&
(single_cycle_frame_r || eof_r || idle_r);
計(jì)數(shù)值不為0的時(shí)候,一直處于空閑狀態(tài)。
assign next_single_cycle_frame_c = (ifg_done_c && (frame_size_r == 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
assign next_sof_c = (ifg_done_c && (frame_size_r != 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
計(jì)數(shù)值為0的時(shí)候,如果是單周期幀,則進(jìn)入單周期幀狀態(tài),發(fā)送單周期數(shù)據(jù)。對(duì)于第一幀數(shù)據(jù)就是如此,直接進(jìn)入單周期幀狀態(tài)發(fā)送數(shù)據(jù)。將當(dāng)前狀態(tài)變量拉出來(lái)看看:
可見,一開始處于idle狀態(tài),之后進(jìn)入單周期幀狀態(tài),在下一個(gè)周期便發(fā)送數(shù)據(jù)了。
assign next_single_cycle_frame_c = (ifg_done_c && (frame_size_r == 0)) &&
(idle_r || single_cycle_frame_r || eof_r);
由于進(jìn)入單周期幀,需要另一個(gè)計(jì)數(shù),就是幀長(zhǎng)計(jì)數(shù)frame_size_r == 0;這個(gè)計(jì)數(shù)量的條件是:
//Use a counter to determine the size of the next frame to send
always @(posedge USER_CLK)
if(reset_c)
frame_size_r <= `DLY 8'h00;
else if(single_cycle_frame_r || eof_r)
frame_size_r <= `DLY frame_size_r + 1;
可見,確實(shí)應(yīng)該進(jìn)入了單周期幀狀態(tài):
在分析下,下一幀不是單周期幀的情況:
在sof之后直接進(jìn)入eof也很顯而易見:
assign next_eof_c = (frame_size_r == bytes_sent_r) &&
(sof_r || data_cycle_r);
滿足了frame_size = bytes_size的條件。這兩個(gè)計(jì)數(shù)器有什么關(guān)系呢?
//Use a counter to determine the size of the next frame to send
always @(posedge USER_CLK)
if(reset_c)
frame_size_r <= `DLY 8'h00;
else if(single_cycle_frame_r || eof_r)
frame_size_r <= `DLY frame_size_r + 1;
//Use a second counter to determine how many bytes of the frame have already been sent
always @(posedge USER_CLK)
if(reset_c)
bytes_sent_r <= `DLY 8'h00;
else if(sof_r)
bytes_sent_r <= `DLY 8'h01;
else if(!TX_DST_RDY_N && !idle_r)
bytes_sent_r <= `DLY bytes_sent_r + 1;
frame計(jì)數(shù)器呢?
如果發(fā)送單周期幀,則遇到單周期幀狀態(tài)加1;
如果發(fā)送多周期幀,則遇到eof狀態(tài)就加1;
可見,是不斷加的。
而bytes呢?
是每次的幀開始就置1,然后一直加到eof狀態(tài);
assign next_data_cycle_c = (frame_size_r != bytes_sent_r) &&
(sof_r || data_cycle_r);
bytes計(jì)數(shù)的含義是已經(jīng)發(fā)送的數(shù)據(jù)字?jǐn)?shù),如何和要發(fā)送的字?jǐn)?shù)不符合,就處于next_data_cycle_c狀態(tài),這個(gè)狀態(tài)是要一直發(fā)送數(shù)據(jù)的狀態(tài);
assign next_eof_c = (frame_size_r == bytes_sent_r) &&
(sof_r || data_cycle_r);
如果等于了,則進(jìn)入最后一個(gè)eof狀態(tài),發(fā)完最后一個(gè)字,結(jié)束。
//Output logic for 1-hot state machine
always @(posedge USER_CLK)
if(reset_c)
begin
TX_SOF_N <= `DLY 1'b1;
TX_EOF_N <= `DLY 1'b1;
TX_SRC_RDY_N <= `DLY 1'b1;
end
else if(!TX_DST_RDY_N)
begin
TX_SOF_N <= `DLY !(sof_r || single_cycle_frame_r);
TX_EOF_N <= `DLY !(eof_r || single_cycle_frame_r);
TX_SRC_RDY_N <= `DLY idle_r;
end
有輸出代碼可知,輸出都是在狀態(tài)的基礎(chǔ)上延遲一個(gè)時(shí)鐘。
當(dāng)sof_r狀態(tài)的時(shí)候,下一個(gè)周期將TX_SOF_N置有效;
當(dāng)eof_r狀態(tài)的時(shí)候,下一個(gè)周期置TX_EOF_N有效;
而TX_SRC_RDY_N則在非空閑狀態(tài)下有效,空閑狀態(tài)下無(wú)效。
如果處于空閑狀態(tài),則下一個(gè)時(shí)鐘無(wú)效,如果不處于空閑狀態(tài),則下一個(gè)周期有效。總之,等價(jià)于狀態(tài)延遲一個(gè)時(shí)鐘。
接收模塊仿真
有了上面的發(fā)送模塊仿真的分析,我想接收模塊的仿真也不再話下了。
我們就看看仿真結(jié)果就好了,至于結(jié)合程序分析,沒有必要了,因?yàn)槲覀兘邮胀陻?shù)據(jù)后,按照自己的方式處理了。這個(gè)自己最清楚。
接收真的比發(fā)送要簡(jiǎn)單多了。畢竟發(fā)送要設(shè)計(jì)狀態(tài)機(jī)來(lái)組合要發(fā)送的數(shù)據(jù)。
評(píng)論
查看更多