在做实验用verilog编写RTL8211EG的接口代码时候我们遇到一个问题就是最后8个字节是多余的,这里我们就考虑去掉这8个字节。
如上图,就是希望DV信号在蓝箭头处拉低。同时满足下图DV在第一个数据到来处依然为1.
这实际是头部不变化,尾部去掉最后8个字节,记得有“掐头去尾”一词,咱们这是“去尾不掐头”
这里所说的去掉实际就是控制一下DV(Data Valid)信号,使得在尾部多余8个字节出现的时候,作为DV=0将这8个字节忽略。
单纯考虑尾部,将数据延迟8周期,DV不延迟就可以实现,但是这样实现的话,头部8个数据就会在DV为1之前被丢弃。所以我们考虑变通一下:
就是所数据固定的8个周期延迟,而使能信号dv的延迟是可变的,可以选择无延迟或者延迟后的。这个选择是用状态机实现的,思路就是dv=0的时候作为空闲状态选择输出的是延迟八周期后的,当延迟8周期后的dv变成1之后,说明我们保留头部的工作已经完成,接下来进入去尾的状态,也将输入的dv直接作为dv_out的输出。
为了防止逻辑路径过长,延迟过大,影响工作频率,这里习惯在输出加一级延迟,实际就是数据保持9级延迟,dv是9级或者1级延迟。
module rx_cut_tail(
input clk ,rst ,
input [7:0] din ,
output reg [7:0]dout ,
input dv_i,
output reg dv_o
);
parameter CUT_TAIL_LEN = 8;
reg [7:0] ram[0:CUT_TAIL_LEN-1] ; always @ (posedge clk) ram[0] <= din;
integer i; always @ (posedge clk) for (i = 1; i < CUT_TAIL_LEN; i= i+1) ram[i] <= ram[i-1];
reg [CUT_TAIL_LEN-1:0]dv_r; always @ (posedge clk) dv_r[CUT_TAIL_LEN-1:0] <= { dv_r[CUT_TAIL_LEN-2:0],dv_i };
reg [4:0]c ;always @ (posedge clk) case (st)2,4: c<=c+1;default c<=0;endcase
reg [2:0] st ;
always @ (posedge clk or posedge rst ) if (rst ) st<=0; else case (st)
0: st<=1;
1: if ( dv_r[CUT_TAIL_LEN-1] ) st<=2;
2: st<=3;
3: if ( ~ dv_i ) st<=4;
4 : if (c == (CUT_TAIL_LEN-1) ) st<=5;
5:st<=1;
default st<=0;endcase
always @ (posedge clk) case (st)
0,1,2 : dv_o<= dv_r[CUT_TAIL_LEN-1];
3 : dv_o<=dv_i; //or <=1;
4 : dv_o<=0;
default dv_o<=0;endcase
always @ (posedge clk) dout <= ram[CUT_TAIL_LEN-1] ;
endmodule
上述CUT_TAIL_LEN=8对应以上的分析。做成参数化可以跟方便修改,比如我们在这个8211EG接口中CUT_TAIL_LEN=12实际也是吃掉了最后四个字节的CHECK SUM。
直接上板子跑,抓处来信号看,看截图:
{{aAxvOXMOIvVUoXMxvoxiowMwWV8xxWTxoxOIOVIUUOvwVOUiIoUvvTMMVMwovWHWX8vOUOwXwwiIwoTmwMMMx8UImVMVXTmmM8ivOxmXIT8HHHw8HOMoiHIoVU8VvmvIWXTvvOvv8xvMovOWimmVvxHo8UZz}}