From c81d916a28e0f0b0a3fb87bebd1816d657b977bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=B3=E5=85=89=E5=B0=91=E5=B9=B4?= <849317537@qq.com> Date: Fri, 17 May 2024 18:24:47 +0800 Subject: [PATCH] =?UTF-8?q?fifo=E5=AE=8C=E6=88=90=E4=BA=86,=20=E5=87=86?= =?UTF-8?q?=E5=A4=87=E4=B8=8A=E6=9D=BF=E5=AD=90=E5=AE=9E=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fifo/fifo_rd.v | 47 +++++++++++++++++ fifo/fifo_rd.v.out | 94 +++++++++++++++++++++++++++++++++ fifo/fifo_wr.v | 66 ++++++++++++++++++++++++ fifo/fifo_wr.v.out | 126 +++++++++++++++++++++++++++++++++++++++++++++ fifo/tb_fifo.v | 22 ++++++++ fifo/test_fifo.v | 79 ++++++++++++++++++++++++++++ 6 files changed, 434 insertions(+) create mode 100644 fifo/fifo_rd.v create mode 100755 fifo/fifo_rd.v.out create mode 100644 fifo/fifo_wr.v create mode 100755 fifo/fifo_wr.v.out create mode 100644 fifo/tb_fifo.v create mode 100644 fifo/test_fifo.v diff --git a/fifo/fifo_rd.v b/fifo/fifo_rd.v new file mode 100644 index 0000000..abd9399 --- /dev/null +++ b/fifo/fifo_rd.v @@ -0,0 +1,47 @@ +// 该模块会在写满了fifo之后, 开始读, 直到读空 + +module fifo_rd( + input rd_clk, + input rst, + + input [7:0] fifo_rd_data, // fifo 读到的数据 + input is_full, // 是否写满了, 这个是 写时钟域的信号 + input is_almost_empty, // 快空了 + input is_rd_rst_busy, // 是否正在初始化读 + output reg fifo_rd_en // 是否能够读了 +); + +reg is_full_0; +reg is_full_1; +always @(posedge rd_clk or negedge rst) begin + if (!rst) begin + is_full_0 <= 1'b0; + is_full_1 <= 1'b0; + end + else begin + is_full_0 <= is_full; + is_full_1 <= is_full_0; + end +end + + +// 控制是否可读 +always @(posedge rd_clk or negedge rst) begin + if (!rst) begin + fifo_rd_en <= 1'b0; + end + else if (!is_rd_rst_busy) begin // 功能已经准备就绪 + if (is_full_1) begin // 打两拍确定是满的, 在进行读取 + fifo_rd_en <= 1'b1; + end + else if(is_almost_empty) begin // 上个时钟周期快空了, 其实当前时钟周期已经空了 + fifo_rd_en <= 1'b0; + end + else begin + end + end + else begin + end +end + +endmodule \ No newline at end of file diff --git a/fifo/fifo_rd.v.out b/fifo/fifo_rd.v.out new file mode 100755 index 0000000..64189d8 --- /dev/null +++ b/fifo/fifo_rd.v.out @@ -0,0 +1,94 @@ +#! /usr/local/Cellar/icarus-verilog/12.0/bin/vvp +:ivl_version "12.0 (stable)"; +:ivl_delay_selection "TYPICAL"; +:vpi_time_precision + 0; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/system.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/vhdl_sys.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/vhdl_textio.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/v2005_math.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/va_math.vpi"; +S_0x7f7d3cf06130 .scope module, "fifo_rd" "fifo_rd" 2 3; + .timescale 0 0; + .port_info 0 /INPUT 1 "rd_clk"; + .port_info 1 /INPUT 1 "rst"; + .port_info 2 /INPUT 8 "fifo_rd_data"; + .port_info 3 /INPUT 1 "is_full"; + .port_info 4 /INPUT 1 "is_almost_empty"; + .port_info 5 /INPUT 1 "is_rd_rst_busy"; + .port_info 6 /OUTPUT 1 "fifo_rd_en"; +o0x7f7d3dc32008 .functor BUFZ 8, C4; HiZ drive +v0x7f7d3cf06980_0 .net "fifo_rd_data", 7 0, o0x7f7d3dc32008; 0 drivers +v0x7f7d3cf16970_0 .var "fifo_rd_en", 0 0; +o0x7f7d3dc32068 .functor BUFZ 1, C4; HiZ drive +v0x7f7d3cf16a10_0 .net "is_almost_empty", 0 0, o0x7f7d3dc32068; 0 drivers +o0x7f7d3dc32098 .functor BUFZ 1, C4; HiZ drive +v0x7f7d3cf16aa0_0 .net "is_full", 0 0, o0x7f7d3dc32098; 0 drivers +v0x7f7d3cf16b40_0 .var "is_full_0", 0 0; +v0x7f7d3cf16c20_0 .var "is_full_1", 0 0; +o0x7f7d3dc32128 .functor BUFZ 1, C4; HiZ drive +v0x7f7d3cf16cc0_0 .net "is_rd_rst_busy", 0 0, o0x7f7d3dc32128; 0 drivers +o0x7f7d3dc32158 .functor BUFZ 1, C4; HiZ drive +v0x7f7d3cf16d60_0 .net "rd_clk", 0 0, o0x7f7d3dc32158; 0 drivers +o0x7f7d3dc32188 .functor BUFZ 1, C4; HiZ drive +v0x7f7d3cf16e00_0 .net "rst", 0 0, o0x7f7d3dc32188; 0 drivers +E_0x7f7d3cf06390/0 .event negedge, v0x7f7d3cf16e00_0; +E_0x7f7d3cf06390/1 .event posedge, v0x7f7d3cf16d60_0; +E_0x7f7d3cf06390 .event/or E_0x7f7d3cf06390/0, E_0x7f7d3cf06390/1; + .scope S_0x7f7d3cf06130; +T_0 ; + %wait E_0x7f7d3cf06390; + %load/vec4 v0x7f7d3cf16e00_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_0.0, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7f7d3cf16b40_0, 0; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7f7d3cf16c20_0, 0; + %jmp T_0.1; +T_0.0 ; + %load/vec4 v0x7f7d3cf16aa0_0; + %assign/vec4 v0x7f7d3cf16b40_0, 0; + %load/vec4 v0x7f7d3cf16b40_0; + %assign/vec4 v0x7f7d3cf16c20_0, 0; +T_0.1 ; + %jmp T_0; + .thread T_0; + .scope S_0x7f7d3cf06130; +T_1 ; + %wait E_0x7f7d3cf06390; + %load/vec4 v0x7f7d3cf16e00_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_1.0, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7f7d3cf16970_0, 0; + %jmp T_1.1; +T_1.0 ; + %load/vec4 v0x7f7d3cf16cc0_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_1.2, 8; + %load/vec4 v0x7f7d3cf16c20_0; + %flag_set/vec4 8; + %jmp/0xz T_1.4, 8; + %pushi/vec4 1, 0, 1; + %assign/vec4 v0x7f7d3cf16970_0, 0; + %jmp T_1.5; +T_1.4 ; + %load/vec4 v0x7f7d3cf16a10_0; + %flag_set/vec4 8; + %jmp/0xz T_1.6, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7f7d3cf16970_0, 0; +T_1.6 ; +T_1.5 ; +T_1.2 ; +T_1.1 ; + %jmp T_1; + .thread T_1; +# The file index is used to find the file name in the following table. +:file_names 3; + "N/A"; + ""; + "fifo_rd.v"; diff --git a/fifo/fifo_wr.v b/fifo/fifo_wr.v new file mode 100644 index 0000000..f390280 --- /dev/null +++ b/fifo/fifo_wr.v @@ -0,0 +1,66 @@ +// 该模块根据外部传进来的fifo部分的管脚, 控制fifo的写入 +// 复位完毕之后, 且fifo中式空的, 才开始写一些临时生成的数据, 直到写满 +module fifo_wr( + input wr_clk, + input rst, + + input is_empty, // fifo中是否是空的, 该信号不是wr_clk时钟控制, 属于外部的读时钟域 + input is_almost_full, // 快满了 + input is_wr_rst_busy, // 是否还在复位中, 可以进行写入操作本身了 + + // + output reg fifo_wr_en, // 是否打开写功能 + output reg [7:0] fifo_wr_data // 需要写入的数据 +); + +// 对外部时钟域, is_empty 打拍, 获取同步到当前时钟域的 is_empty +reg is_empty_0; +reg is_empty_1; + +always @(posedge wr_clk or negedge rst) begin + if (!rst) begin + is_empty_0 <= 1'b0; + is_empty_1 <= 1'b0; + end + else begin + is_empty_0 <= is_empty; + is_empty_1 <= is_empty_0; + end +end + + +// 对是否打开写功能, 进行控制 +always @(posedge wr_clk or negedge rst) begin + if (!rst) begin + fifo_wr_en <= 1'b0; + end + else if (!is_wr_rst_busy) begin // fifo 复位完毕 + if (is_empty_1) begin // // 打两拍确定是空的, 才可以写入 + fifo_wr_en <= 1'b1; + end + else if(is_almost_full) begin // 这其实是上个时钟周期的值了快写满了,还有1个空位, + // 如果当上个时钟周期和当前时钟周期之间有写入, 那当前时钟周期实际已经满了, 再写就溢出了 + fifo_wr_en <= 1'b0; + end + else begin + end + end + else begin + end +end + + +// 模拟生成写入的数据 +always @(posedge wr_clk or negedge rst) begin + if (!rst) begin + fifo_wr_data <= 8'b0; + end + else if(fifo_wr_en && fifo_wr_data < 8'd254) begin // ip核你输入256的深度, 但是只能写255个数据, 也是就是0~254 + fifo_wr_data <= fifo_wr_data + 8'b1; // 最后253会走到这个分支, 进行加1 变成254, 也就是0~254 + end + else begin + fifo_wr_data <= 8'b0; + end +end + +endmodule \ No newline at end of file diff --git a/fifo/fifo_wr.v.out b/fifo/fifo_wr.v.out new file mode 100755 index 0000000..234baf0 --- /dev/null +++ b/fifo/fifo_wr.v.out @@ -0,0 +1,126 @@ +#! /usr/local/Cellar/icarus-verilog/12.0/bin/vvp +:ivl_version "12.0 (stable)"; +:ivl_delay_selection "TYPICAL"; +:vpi_time_precision + 0; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/system.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/vhdl_sys.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/vhdl_textio.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/v2005_math.vpi"; +:vpi_module "/usr/local/Cellar/icarus-verilog/12.0/lib/ivl/va_math.vpi"; +S_0x7fde7b104830 .scope module, "fifo_wr" "fifo_wr" 2 3; + .timescale 0 0; + .port_info 0 /INPUT 1 "wr_clk"; + .port_info 1 /INPUT 1 "rst"; + .port_info 2 /INPUT 1 "is_empty"; + .port_info 3 /INPUT 1 "is_almost_full"; + .port_info 4 /INPUT 1 "is_wr_rst_busy"; + .port_info 5 /OUTPUT 1 "fifo_wr_en"; + .port_info 6 /OUTPUT 8 "fifo_wr_data"; +v0x7fde7b104b00_0 .var "fifo_wr_data", 7 0; +v0x7fde7b114bc0_0 .var "fifo_wr_en", 0 0; +o0x7fde7b232068 .functor BUFZ 1, C4; HiZ drive +v0x7fde7b114c60_0 .net "is_almost_full", 0 0, o0x7fde7b232068; 0 drivers +o0x7fde7b232098 .functor BUFZ 1, C4; HiZ drive +v0x7fde7b114cf0_0 .net "is_empty", 0 0, o0x7fde7b232098; 0 drivers +v0x7fde7b114d90_0 .var "is_empty_0", 0 0; +v0x7fde7b114e70_0 .var "is_empty_1", 0 0; +o0x7fde7b232128 .functor BUFZ 1, C4; HiZ drive +v0x7fde7b114f10_0 .net "is_wr_rst_busy", 0 0, o0x7fde7b232128; 0 drivers +o0x7fde7b232158 .functor BUFZ 1, C4; HiZ drive +v0x7fde7b114fb0_0 .net "rst", 0 0, o0x7fde7b232158; 0 drivers +o0x7fde7b232188 .functor BUFZ 1, C4; HiZ drive +v0x7fde7b115050_0 .net "wr_clk", 0 0, o0x7fde7b232188; 0 drivers +E_0x7fde7b104aa0/0 .event negedge, v0x7fde7b114fb0_0; +E_0x7fde7b104aa0/1 .event posedge, v0x7fde7b115050_0; +E_0x7fde7b104aa0 .event/or E_0x7fde7b104aa0/0, E_0x7fde7b104aa0/1; + .scope S_0x7fde7b104830; +T_0 ; + %wait E_0x7fde7b104aa0; + %load/vec4 v0x7fde7b114fb0_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_0.0, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7fde7b114d90_0, 0; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7fde7b114e70_0, 0; + %jmp T_0.1; +T_0.0 ; + %load/vec4 v0x7fde7b114cf0_0; + %assign/vec4 v0x7fde7b114d90_0, 0; + %load/vec4 v0x7fde7b114d90_0; + %assign/vec4 v0x7fde7b114e70_0, 0; +T_0.1 ; + %jmp T_0; + .thread T_0; + .scope S_0x7fde7b104830; +T_1 ; + %wait E_0x7fde7b104aa0; + %load/vec4 v0x7fde7b114fb0_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_1.0, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7fde7b114bc0_0, 0; + %jmp T_1.1; +T_1.0 ; + %load/vec4 v0x7fde7b114f10_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_1.2, 8; + %load/vec4 v0x7fde7b114e70_0; + %flag_set/vec4 8; + %jmp/0xz T_1.4, 8; + %pushi/vec4 1, 0, 1; + %assign/vec4 v0x7fde7b114bc0_0, 0; + %jmp T_1.5; +T_1.4 ; + %load/vec4 v0x7fde7b114c60_0; + %flag_set/vec4 8; + %jmp/0xz T_1.6, 8; + %pushi/vec4 0, 0, 1; + %assign/vec4 v0x7fde7b114bc0_0, 0; +T_1.6 ; +T_1.5 ; +T_1.2 ; +T_1.1 ; + %jmp T_1; + .thread T_1; + .scope S_0x7fde7b104830; +T_2 ; + %wait E_0x7fde7b104aa0; + %load/vec4 v0x7fde7b114fb0_0; + %nor/r; + %flag_set/vec4 8; + %jmp/0xz T_2.0, 8; + %pushi/vec4 0, 0, 8; + %assign/vec4 v0x7fde7b104b00_0, 0; + %jmp T_2.1; +T_2.0 ; + %load/vec4 v0x7fde7b114bc0_0; + %flag_set/vec4 9; + %flag_get/vec4 9; + %jmp/0 T_2.4, 9; + %load/vec4 v0x7fde7b104b00_0; + %cmpi/u 254, 0, 8; + %flag_get/vec4 5; + %and; +T_2.4; + %flag_set/vec4 8; + %jmp/0xz T_2.2, 8; + %load/vec4 v0x7fde7b104b00_0; + %addi 1, 0, 8; + %assign/vec4 v0x7fde7b104b00_0, 0; + %jmp T_2.3; +T_2.2 ; + %pushi/vec4 0, 0, 8; + %assign/vec4 v0x7fde7b104b00_0, 0; +T_2.3 ; +T_2.1 ; + %jmp T_2; + .thread T_2; +# The file index is used to find the file name in the following table. +:file_names 3; + "N/A"; + ""; + "fifo_wr.v"; diff --git a/fifo/tb_fifo.v b/fifo/tb_fifo.v new file mode 100644 index 0000000..f941d55 --- /dev/null +++ b/fifo/tb_fifo.v @@ -0,0 +1,22 @@ +`timescale 1ns/1ns +module tb_fifo() + +reg sys_clk; +reg sys_rst; +always #10 sys_clk = ~sys_clk; + + +initial begin + sys_clk <= 1'b0; + sys_rst <= 1'b0; + #50 + sys_rst <= 1'b1; +end + + +test_fifo u_test_fifo( + .sys_clk(sys_clk), + .sys_rst(sys_rst) +); + +endmodule \ No newline at end of file diff --git a/fifo/test_fifo.v b/fifo/test_fifo.v new file mode 100644 index 0000000..8dec416 --- /dev/null +++ b/fifo/test_fifo.v @@ -0,0 +1,79 @@ +// 本次实验, 是通过fifo的自己例化的两个功能模块, 通过这两个功能模块 控制fifo的ip核实验 +// 写模块: 在写功能可用之后, 判断是否是空的, 如果是空的, 就持续写直到写满 +// 读模块: 写功能写满之后, 取数据, 只到获取完毕 +// 注意本实验 读和写实不同的时钟域, 是否可读写, 需要通过打拍判断外部时钟域的值 +// 判断即将写满/即将为空时, 要注意时钟周期, 能给出状态1, 说明上上个周期的一次写入导致快满/空了 +// 上个周期再当前周期如果继续进行操作, 虽然 这个标志位还没转变为0, 但是他实际内部已经是full或者emtpy了, 再写就溢出了 +module test_fifo( + input wire sys_clk, // U18 + input wire sys_rst //J15 +); + + +wire clk_100m; +wire clk_50m; +wire locked; +wire logic_rst; + +assign logic_rst = sys_rst && locked; // 需要在高电平(按下并弹开按钮) 之后且 时钟稳定之后对子模块进行逻辑复位 + + +wire is_empty; +wire is_almost_full; +wire is_wr_rst_busy; +wire fifo_wr_en; +wire fifo_wr_data; + +fifo_wr u_fifo_wr( + .wr_clk(clk_50m), + .rst(logic_rst), + .is_empty(is_empty), + .is_almost_full(is_almost_full), + .is_wr_rst_busy(is_wr_rst_busy), + .fifo_wr_en(fifo_wr_en), + .fifo_wr_data(fifo_wr_data) +); + +wire is_full; +wire is_almost_empty; +wire is_rd_rst_busy; +wire fifo_rd_en; +wire fifo_rd_data; + + +fifo_rd u_fifo_rd( + .rd_clk(clk_100m), + .rst(logic_rst), + .is_full(is_full), + .is_almost_empty(is_almost_empty), + .is_rd_rst_busy(is_rd_rst_busy), + .fifo_rd_en(fifo_rd_en), + .fifo_rd_data(fifo_rd_data) +); + +clk_wiz_0 u_clk_wiz_0( + .clk_in1(sys_clk), + .clk_out1(clk_100m), + .clk_out2(clk_50m), + .locked(locked) +); + +wire [7:0]rd_data_count; +wire [7:0]wr_data_count; +fifo_generator_0 u_fifo_generator_0( + .rst(~logic_rst), // 该ip核内是高电平时钟信号有效, 平时需要低电平, 我们取logic_rst(这个是高电平)反 + .wr_clk(clk_50m), + .rd_clk(clk_100m), + .din(fifo_wr_data), + .wr_en(fifo_wr_en), + .rd_en(fifo_rd_en), + .dout(fifo_rd_data), + .full(is_full), + .almost_full(is_almost_empty), + .rd_data_count(rd_data_count), + .wr_data_count(wr_data_count), + .wr_rst_busy(is_wr_rst_busy), + .rd_rst_busy(is_rd_rst_busy) +); + +endmodule \ No newline at end of file