UDP--DDR--SFP,FPGA实现之指令监测模块实现

指令监测模块实现介绍

如下图所示,为指令监测模块的运行框图

将指令设置为8bytes数据,故需要一个64位寄存器进行缓存,在进行数据缓存时,数据不可以输出至下一级模块,故对数据和有效指示信号也应该进行相应延迟,指令缓存8周期,检验一周期,为了数据的稳定输出,故延迟10周期,使用shift_ram ip实现该功能即可。

当监测到头部8个数据不属于指令数据后,进行有效数据输出,而若监测到为指令数据,则在输出有效信号置0,下一级模块即不会进行数据缓存,避免数据文件缓存错误。

指令监测模块代码编写

根据上述框图的介绍,以及逻辑的梳理,本节代码可以清晰写出,其代码实现如下:

c 复制代码
module udp_cmd_check(
    input               i_clk           ,
    input               i_rst           ,
    input   [7 :0]      i_udp_data      ,
    input               i_udp_valid     ,
    output  [7 :0]      o_udp_data      ,
    output              o_udp_valid     ,
    output              o_store_done    ,
    output              o_raddr_clear   
    );

reg     [63:0]          r_check_data    ;
reg     [1 :0]          r_check_res     ;
reg     [1 :0]          r_clear_res     ;
reg     [1 :0]          ro_raddr_clear  ;
wire    [8 :0]          w_dly_din       ;
wire    [8 :0]          w_dly_dout      ;
wire                    w_store_done    ;
wire                    w_raddr_clear   ;

assign  w_dly_din       = {i_udp_data,i_udp_valid};

dly_w9d10 dly_w9d10_u0 (
    .D      (w_dly_din  ),
    .CLK    (i_clk      ),
    .Q      (w_dly_dout )
);

assign  w_store_done = &r_check_res ? 1'b1 : 1'b0;
assign  w_raddr_clear= &r_clear_res ? 1'b1 : 1'b0;
assign  o_udp_data   = w_dly_dout[8 :1] ;
assign  o_udp_valid  = (w_store_done == 1'b1 || w_raddr_clear == 1'b1) ? 1'b0 : w_dly_dout[0];
assign  o_store_done = w_store_done     ;
assign  o_raddr_clear= w_raddr_clear    ;

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        r_check_data <= 64'd0;
    else if(i_udp_valid) 
        r_check_data <= {r_check_data[55:0],i_udp_data};
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        r_check_res <= 2'b00;
    else if(r_check_data[63:32] == 32'HA5A5A5A5 && r_check_data[31 :0] == 32'HBCBCBCBC) 
        r_check_res <= 2'b11;
    else
        r_check_res <= 2'b00;
end

always @(posedge i_clk,posedge i_rst) begin
    if(i_rst)
        r_clear_res <= 2'b00;
    else if(r_check_data[63:32] == 32'HD5D5D5D5 && r_check_data[31 :0] == 32'HFCFCFCFC) 
        r_clear_res <= 2'b11;
    else if(r_dly_valid & ~w_dly_dout[0])
        r_clear_res <= 2'b00;
end

endmodule

实际r_check_res 和 r_clear_res 只需1bit也可,笔者之前为了降低逻辑位宽过大,曾对高32位和低32位进行分别判断,测试来看,上述代码也可以正常运转,时序不存在问题。

指令监测模块仿真

在代码编写完成后,便需要进行仿真测试,编写仿真文件,因为在之后的各个模块检验中,都需要进行udp数据接收的模拟,笔者便将udp数据发送、指令发送,编写为对应的任务块,方便进行复用,tb文件代码如下

c 复制代码
reg                 i_udp_clk       = 1'b0;
reg                 i_udp_rst       = 1'b0;
wire    [7 :0]      w_store_udp_data    ;
wire                w_store_udp_valid   ;
wire                w_store_done        ;
wire                w_raddr_clear       ;
integer i = 0;
integer j = 0;
always #4   i_udp_clk = ~i_udp_clk;
initial begin
    i_udp_rst = 1;
    i_sfp_rst = 1;
    i_ui_rst  = 1;
    #100
    @(i_sfp_clk) begin
        i_udp_rst <= 1'b0;
        i_sfp_rst <= 1'b0;
        i_ui_rst  <= 1'b0;
    end
    #100
    /*传输擦除指令*/
    @(posedge i_udp_clk)
        udp_cmd(64'HD5D5D5D5_FCFCFCFC);
    /*传输32KB*/
    @(posedge i_udp_clk)
    for(i = 0;i < 32; i = i + 1) begin
        @(posedge i_udp_clk)
            udp_send(1024);
        #500
        @(posedge i_udp_clk);
    end
    /*传输完成指令*/
    @(posedge i_udp_clk)
        udp_cmd(64'HA5A5A5A5_BCBCBCBC);
/*指令监测,输出监测后数据*/
udp_cmd_check udp_cmd_check_u0(
    .i_clk              (i_udp_clk          ),
    .i_rst              (i_udp_rst          ),
    .i_udp_data         (i_udp_data         ),
    .i_udp_valid        (i_udp_valid        ),
    .o_udp_data         (w_store_udp_data   ),
    .o_udp_valid        (w_store_udp_valid  ),
    .o_store_done       (w_store_done       ),
    .o_raddr_clear      (w_raddr_clear      )
    );
task udp_send(input    [15:0]  byte_len);begin : data
    integer i;
    i_udp_data   = 8'd0;
    i_udp_valid  = 1'd0;
    @(posedge i_udp_clk);
    for(i = 0;i < byte_len ;i = i + 1)
    begin
        i_udp_data  <= i_udp_data + 1'b1;
        i_udp_valid <= 1'b1;
        @(posedge i_udp_clk);
    end
    i_udp_data   <= 8'd0;
    i_udp_valid  <= 1'd0;
end
endtask

task udp_cmd(input    [63:0]  i_cmd);begin : cmd
    integer i;
    i_udp_data   = 8'd0;
    i_udp_valid  = 1'd0;
    @(posedge i_udp_clk);
    for(i = 0;i < 8 ;i = i + 1)
    begin
        i_udp_data  <= i_cmd[63:56];
        i_cmd <= {i_cmd[55:0],8'h0};
        i_udp_valid <= 1'b1;
        @(posedge i_udp_clk);
    end
    i_udp_data   <= 8'd0;
    i_udp_valid  <= 1'd0;
end
endtask

其模拟过程即是,首先发送擦除指令,然后进行数据发送,在数据传输完成后,发送数据完成指令,在仿真过程中,就这三项测试做验证,监测模块是否成功识别指令,阻止指令数据输出,以及是否成功输出有效数据。

由图片可知,模块成功监测到DDR擦除指令,并将清除信号输出置高多周期,数据输出有效信号置低,在标准以太网中帧长间隔为12bytes,在仿真测试中,并未严格要求该参数,但实际模块工作可以适应这类情况。

由图片可知,成功对数据进行了下一级模块转发。

观察文件传输完成,发送结束码,模块成功监测出结束码,拉高传输完成信号,并且数据未进行有效输出,避免了错误缓存。

经过上述仿真,可以看出该模块正常工作,对于该模块的编写是较为简单的,但指令识别功能,在开发中,是十分常用的模块,有必要进行掌握。关于本节代码的问题,以及优化意见,欢迎大家在评论区指出,如果想要对应工程进行学习,欢迎大家私信。

相关推荐
purrrew1 小时前
【Java ee初阶】网络编程 UDP socket
java·网络·网络协议·udp·java-ee
9527华安2 小时前
紫光同创FPGA实现AD7606数据采集转UDP网络传输,提供PDS工程源码和技术支持和QT上位机
网络·qt·fpga开发·udp·紫光同创·ad7606
szxinmai主板定制专家3 小时前
基于TI AM6442+FPGA解决方案,支持6网口,4路CAN,8个串口
arm开发·人工智能·fpga开发
7yewh4 小时前
FPGA前瞻篇-计数器设计与实现实例
arm开发·驱动开发·嵌入式硬件·fpga开发·硬件架构·硬件工程·精益工程
小诸葛的博客6 小时前
Flannel UDP 模式的优缺点
网络协议·udp·php
碎碎思8 小时前
FPGA+ESP32 = GameBoy 是你的童年吗?
fpga开发
搬砖的小码农_Sky9 小时前
FPGA:XILINX FPGA产品线以及器件选型建议
嵌入式硬件·fpga开发·硬件架构·硬件工程
YprgDay9 小时前
【Lattice FPGA 开发】Diamond在线调试Reveal逻辑乱跳的解决
fpga开发·diamond·reveal
MVP-curry-萌神9 小时前
FPGA图像处理(六)------ 图像腐蚀and图像膨胀
图像处理·人工智能·fpga开发