异步FIFO的写时钟和读时钟为异步时钟,FIFO内部的写逻辑和读逻辑的交互需要异步处理,异步FIFO常用于跨时钟域交互。异步FIFO的设计重点有两个,第一个就是跨时钟域的转换及同步;第二个就是状态信号的产生采用相对保守的方式。
异步 FIFO的输入/输出 ,如下图所示:
wclk : 该时钟为异步FIFO写操作的工作时钟。
w_rst_ : 该信号为异步FIFO的写时钟域复位信号,低电平有效。
wren : 该信号为异步FIFO的写使能。
full : 该信号为FIFO已满标志。如果 FIFO 为满状态,则禁止再写数据。
wdata : 该总线为写数据总线。
rclk : 该时钟为异步FIFO读操作的工作时钟。
r_rst_: 该信号为异步FIFO的读时钟域复位信号,低电平有效。
rden: 该信号为异步FIFO的读使能。
empty: 该信号为异步FIFO的空标志。
rdata: 该总线为读数据总线。
FIFO还提供其他标识,如almost_full和almost_empty,用于提供关于FIFO再写人多少会满以及再读出多少会空的信息。
异步FIFO基本上分为7个部分,分别是写时钟域的地址管理、读时钟域的地址管理、读时钟域读地址到写时钟域的格雷码方式同步、写时钟域写地址到读时钟域的格雷码方式同步、写时钟域的满和将满信号的产生、读时钟域的空和将空信号产生以及FIFO Memory。
复位后,读和写地址指针均指在0地址处,同时almost empty 和empty信号均有效。
在写时钟域,当写请求wren有效时,如果此时写时钟域的状态正常(即还未满),则RAM写使能信号wr_ram有效,数据将会写入RAM里,同时在下一个clk原来的写地址加1,指向下一个写地址。
在读时钟域侧,当读请求rden有效时,如果此时读时钟域的状态正常(即还未空),则RAM读使能信号rd_ram有效,数据将会从RAM里被读出,同时在下一个clk原来的读地址加1,指向下一个读地址。
在写时钟域FIFO状态的判断及产生是使用了格雷码同步的方法实现多比特跨时钟域的转换、把读地址从读时钟rd_clk同步到wr_clk,然后判断写地址和读地址之间的差从而判断FIFO是否被写满。
在读时钟域FIFO状态的判断及产生也使用了格雷码同步的方法实现多比特跨时钟域的转换、把写地址从写时钟wr_clk到rd_clk的转换,然后判断写地址和读地址之差进而得出FIFO是否为空的结论。
在 FIFO 中常用的RAM包括单口RAM、简单双口RAM、真双口RAM、单口ROM、双口ROM这5种类型的RAM,也可以使用寄存器来实现FIFO的存储器。寄存器实现的方式比较适合深度和位宽较小的情况,一般在FPGA里还是推荐使用Block RAM来实现异步FIFO的存储器。这里介绍简单双口RAM来做FIFO内部的RAM,双口RAM的接口如下图所示。
wclk : 该时钟为双口RAM写操作的工作时钟。
wren : 该信号为双口RAM的写使能。
waddr : 该总线为双口RAM的写地址总线。
wdata : 该总线为双口RAM的写数据总线。
rclk : 该时钟为双口RAM读操作的工作时钟。
rden : 该信号为双口RAM的读使能。
raddr : 该总线为双口RAM的读地址总线。
rdata: 该总线为双口RAM的读数据总线。
实现代码
module dual_port_RAM #( parameter DEPTH = 16, parameter WIDTH = 8 )( input wclk , //写数据时钟 input wenc , //写使能 input [$clog2(DEPTH)-1:0] waddr, //写地址 input [WIDTH-1:0] wdata, //输入数据 input rclk , //读数据时钟 input renc , //读使能 input [$clog2(DEPTH)-1:0] raddr, //读地址 output reg [WIDTH-1:0] rdata //输出数据 ); /********************参数定义********************/ /*********************IO 说明********************/ /********************** 内部信号声明 **********************/ reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; //RAM大小定义 /*************************功能定义*************************/ //RAM写操作 always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end //RAM读操作 always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule
主要在写时钟域中产生FIFO Memory写地址和写有效信号,当写使能有效且FIFO没有写满时,FIFO写地址的递增应。实现代码如下:
always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}}; else if (wren && !full) w_bin_waddr <= w_bin_waddr + 1'd1; else w_bin_waddr <= w_bin_waddr; end
读控制逻辑主要产生FIFO Memory读地址和读有效信号,当读使能有效且FIFO没有读空时,FIFO读地址的递增应。实现代码如下:
always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}}; else if (rden && !empty) r_bin_raddr <= r_bin_raddr + 1'd1; else r_bin_raddr <= r_bin_raddr; end
二进制码转换成二进制格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。N位二进制码到N位格雷码的生成公式为:
{
G
i
=
B
i
⨁
B
i
+
1
(
i
=
0
,
1
,
.
.
.
,
n
−
2
)
G
n
−
1
=
B
n
−
1
module binary_to_gray#(parameter WIDTH = 8) ( input [WIDTH-1:0] binary_value, //二进制编码数值 output [WIDTH-1:0] gray_value //格雷编码数值 ); /*************************功能定义*************************/ generate genvar i; for(i=0;i<(WIDTH-1);i=i+1) begin: gray assign gray_value[i] = binary_value[i]^binary_value[i+1]; end endgenerate assign gray_value[WIDTH-1] = binary_value[WIDTH-1]; endmodule
二进制格雷码转换成二进制码,其法则是保留格雷码的最高位作为自然二进制码的最高位,而次高位自然二进制码为高位自然二进制码与次高位格雷码相异或,而自然二进制码的其余各位与次高位自然二进制码的求法相类似。
{
B
n
−
1
=
G
n
−
1
B
i
=
B
i
+
1
⨁
G
i
(
i
=
n
−
2
,
.
.
.
,
1
)
module gray_to_binary #(parameter WIDTH = 8) ( input [WIDTH-1:0] gray_value, //格雷编码数值 output [WIDTH-1:0] binary_value //二进制编码数值 ); /*************************功能定义*************************/ genvar i; generate for(i=0;i<(WIDTH-1);i=i+1) begin: binary assign binary_value[i] = gray_value[i]^binary_value[i+1]; end endgenerate assign binary_value[WIDTH-1] = gray_value[WIDTH-1]; endmodule
由于异步FIFO读写时钟非同一个,那么写地址计数值在从写时钟域往读时钟域和读地址计数器在从读时钟域往写时钟域传递的过程中会存在重汇聚(re-convergence)的问题。异步FIFO的地址进行跨时钟域的电路示意图如下:
binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U1 ( .binary_value (w_bin_waddr), .gray_value (w_gray_waddr) ); //写时钟域寄存 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else w_gray_waddr_reg <= w_gray_waddr; end //读时钟域两级同步 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) begin r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin r_gray_waddr_sync1 <= w_gray_waddr_reg ; r_gray_waddr_sync2 <= r_gray_waddr_sync1 ; end end
//二进制码转格雷码 binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U2 ( .binary_value (r_bin_raddr), .gray_value (r_gray_raddr) ); //读时钟域寄存 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else r_gray_raddr_reg <= r_gray_raddr; end //写时钟域两级同步 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) begin w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin w_gray_raddr_sync1 <= r_gray_raddr_reg ; w_gray_raddr_sync2 <= w_gray_raddr_sync1 ; end end
当读写地址指针在复位操作期间被重置为零时,或者当读指针在从FIFO中读取了最后一个字之后赶上写指针时,此时读指针和写指针相等代表着FIFO为读空。而当写指针再次追赶上读指针时,此时读指针和写指针相等代表着FIFO为写满。也就是说当读写指针相等时,FIFO要么为空,要么为满。
因此将地址位扩展一位,地址为二进制编码时,则用最高位来判断空满,其余低位还是正常用于读写地址索引。当写指针递增超过FIFO的最大地址时,写指针的MSB位将置为1,同时将其余低位设置回零。读指针也是如此。如果读指针和写指针的MSB不同,则意味着写指针比读指针多绕了一次,表示FIFO写满。如果两个指针的MSB相同,则表示两个指针的回绕次数相同,表示FIFO读空。采用二进制码时电路结构如下所示:
若不产生almost_full(FIFO再写人多少会满)和almost_empty(FIFO再读出多少会空)标志。则可以在将地址扩展一位后,用地址为格雷码格雷码编码时,当写地址和读地址的格雷码的最高位和次高位相反,其余低位相同时,表示FIFO写满,当写地址和地读地址的格雷码的相同时,表示FIFO读空。采用格雷码时电路结构如下所示:
这里采用读写地址的格雷码进行比较,判断空满标志。实现代码如下所示:
/*写满标志判断*/ assign full = ({~w_gray_waddr_reg[ADDR_WIDTH:ADDR_WIDTH-1],w_gray_waddr_reg[ADDR_WIDTH-2:0]} == w_gray_raddr_sync2)?1'b1:1'b0; /*读空标志判断*/ assign empty = (r_gray_raddr_reg == r_gray_waddr_sync2)? 1'b1:1'b0;
不产生almost_full(FIFO再写人多少会满)和almost_empty(FIFO再读出多少会空)标志采用读写地址的格雷码进行比较,判断空满标志;
module async_fifo #( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , //写时钟 input rclk , //读时钟 input w_rst_ , //写时钟域异步复位,低电平有效 input r_rst_ , //写时钟域异步复位,低电平有效 input wren , //写使能 input rden , //写使能 input [WIDTH-1:0] wdata , //写数据 output wire full , //写满信号 output wire empty , //读空信号 output wire [WIDTH-1:0] rdata //读数据 ); /********************参数定义********************/ /*********************IO 说明********************/ /********************** 内部信号声明 **********************/ localparam ADDR_WIDTH = $clog2(DEPTH); //地址位宽 wire wenc ; //双端口RAM写使能 wire renc ; //双端口RAM读使能 reg [ADDR_WIDTH:0] w_bin_waddr ; //写地址(二进制) reg [ADDR_WIDTH:0] r_bin_raddr ; //读地址(二进制) wire [ADDR_WIDTH:0] w_gray_waddr ; //写地址(格雷码) wire [ADDR_WIDTH:0] r_gray_raddr ; //读地址(格雷码) reg [ADDR_WIDTH:0] w_gray_waddr_reg ; //写地址(格雷码)写时钟域暂存寄存器 reg [ADDR_WIDTH:0] r_gray_raddr_reg ; //读地址(格雷码)读时钟域暂存寄存器 reg [ADDR_WIDTH:0] r_gray_waddr_sync1; //写地址(格雷码)写时钟域到读时钟域第一级同步 reg [ADDR_WIDTH:0] r_gray_waddr_sync2; //写地址(格雷码)写时钟域到读时钟域第二级同步 reg [ADDR_WIDTH:0] w_gray_raddr_sync1; //读地址(格雷码)读时钟域到写时钟域第一级同步 reg [ADDR_WIDTH:0] w_gray_raddr_sync2; //读地址(格雷码)读时钟域到写时钟域第二级同步 /*************************功能定义*************************/ assign wenc = wren && !full; assign renc = rden && !empty; /*双端口RAM*/ dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH)) dual_port_RAM_U1 ( .wclk (wclk ), //写数据时钟 .wenc (wenc ), //写使能 .waddr (w_bin_waddr), //写地址 .wdata (wdata ), //输入数据 .rclk (rclk ), //读数据时钟 .renc (renc ), //读使能 .raddr (r_bin_raddr), //读地址 .rdata (rdata ) //输出数据 ); /*写控制逻辑*/ always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}}; else if (wren && !full) w_bin_waddr <= w_bin_waddr + 1'd1; else w_bin_waddr <= w_bin_waddr; end /*读控制逻辑*/ always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}}; else if (rden && !empty) r_bin_raddr <= r_bin_raddr + 1'd1; else r_bin_raddr <= r_bin_raddr; end /*写地址从写时钟域到读时钟域的格雷码方式同步*/ //二进制码转格雷码 binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U1 ( .binary_value (w_bin_waddr), .gray_value (w_gray_waddr) ); //写时钟域寄存 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else w_gray_waddr_reg <= w_gray_waddr; end //读时钟域两级同步 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) begin r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin r_gray_waddr_sync1 <= w_gray_waddr_reg ; r_gray_waddr_sync2 <= r_gray_waddr_sync1 ; end end /*读时钟域读地址到写时钟域的格雷码方式同步*/ //二进制码转格雷码 binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U2 ( .binary_value (r_bin_raddr), .gray_value (r_gray_raddr) ); //读时钟域寄存 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else r_gray_raddr_reg <= r_gray_raddr; end //写时钟域两级同步 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) begin w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin w_gray_raddr_sync1 <= r_gray_raddr_reg ; w_gray_raddr_sync2 <= w_gray_raddr_sync1 ; end end /*写满标志判断*/ assign full = ({~w_gray_waddr_reg[ADDR_WIDTH:ADDR_WIDTH-1],w_gray_waddr_reg[ADDR_WIDTH-2:0]} == w_gray_raddr_sync2)?1'b1:1'b0; /*读空标志判断*/ assign empty = (r_gray_raddr_reg == r_gray_waddr_sync2)? 1'b1:1'b0; endmodule
产生almost_full(FIFO再写人多少会满)和almost_empty(FIFO再读出多少会空)标志采用读写地址的二进制码进行比较,判断空满标志;
module async_fifo #( parameter WIDTH = 8, parameter DEPTH = 16, parameter ALMOST_FULL_GAP = 3, //离满还有ALMOST_FULL_GAP时,almost_full有效 parameter ALMOST_EMPTY_GAP = 3 //离满还有ALMOST_EMPTY_GAP时,almost_empty有效 )( input wclk , //写时钟 input rclk , //读时钟 input w_rst_ , //写时钟域异步复位,低电平有效 input r_rst_ , //写时钟域异步复位,低电平有效 input wren , //写使能 input rden , //写使能 input [WIDTH-1:0] wdata , //写数据 output wire almost_full , //将满信号 output wire almost_empty, //将空信号 output wire full , //写满信号 output wire empty , //读空信号 output wire [WIDTH-1:0] rdata //读数据 ); /********************参数定义********************/ /*********************IO 说明********************/ /********************** 内部信号声明 **********************/ localparam ADDR_WIDTH = $clog2(DEPTH); //地址位宽 wire wenc ; //双端口RAM写使能 wire renc ; //双端口RAM读使能 reg [ADDR_WIDTH:0] w_bin_waddr ; //写地址(二进制) reg [ADDR_WIDTH:0] r_bin_raddr ; //读地址(二进制) wire [ADDR_WIDTH:0] w_gray_waddr ; //写地址(格雷码) wire [ADDR_WIDTH:0] r_gray_raddr ; //读地址(格雷码) reg [ADDR_WIDTH:0] w_gray_waddr_reg ; //写地址(格雷码)写时钟域暂存寄存器 reg [ADDR_WIDTH:0] r_gray_raddr_reg ; //读地址(格雷码)读时钟域暂存寄存器 reg [ADDR_WIDTH:0] r_gray_waddr_sync1; //写地址(格雷码)写时钟域到读时钟域第一级同步 reg [ADDR_WIDTH:0] r_gray_waddr_sync2; //写地址(格雷码)写时钟域到读时钟域第二级同步 reg [ADDR_WIDTH:0] w_gray_raddr_sync1; //读地址(格雷码)读时钟域到写时钟域第一级同步 reg [ADDR_WIDTH:0] w_gray_raddr_sync2; //读地址(格雷码)读时钟域到写时钟域第二级同步 wire [ADDR_WIDTH:0] r_bin_waddr ; //读时钟域二进制写地址 wire [ADDR_WIDTH:0] w_bin_raddr ; //写时钟域二进制读地址 reg [ADDR_WIDTH:0] w_bin_raddr_reg ; //写时钟域读地址(二进制)暂存寄存器 reg [ADDR_WIDTH:0] r_bin_waddr_reg ; //读时钟域写地址(二进制)暂存寄存器 reg [ADDR_WIDTH:0] room_avail ; //FIFO内剩余空间 reg [ADDR_WIDTH:0] data_avail ; //FIFO内已存入数据个数 /*************************功能定义*************************/ /*RAM写使能*/ assign wenc = wren && !full; /*RAM读使能*/ assign renc = rden && !empty; /*双端口RAM*/ dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH)) dual_port_RAM_U1 ( .wclk (wclk ), //写数据时钟 .wenc (wenc ), //写使能 .waddr (w_bin_waddr), //写地址 .wdata (wdata ), //输入数据 .rclk (rclk ), //读数据时钟 .renc (renc ), //读使能 .raddr (r_bin_raddr), //读地址 .rdata (rdata ) //输出数据 ); /*写控制逻辑*/ always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_bin_waddr <= {(ADDR_WIDTH+1){1'b0}}; else if (wren && !full) w_bin_waddr <= w_bin_waddr + 1'd1; else w_bin_waddr <= w_bin_waddr; end /*读控制逻辑*/ always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_bin_raddr <= {(ADDR_WIDTH+1){1'b0}}; else if (rden && !empty) r_bin_raddr <= r_bin_raddr + 1'd1; else r_bin_raddr <= r_bin_raddr; end /*写地址从写时钟域到读时钟域的格雷码方式同步*/ //二进制码转格雷码 binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U1 ( .binary_value (w_bin_waddr), .gray_value (w_gray_waddr) ); //写时钟域写地址(格雷码)寄存 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) w_gray_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else w_gray_waddr_reg <= w_gray_waddr; end //读时钟域两级同步 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) begin r_gray_waddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; r_gray_waddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin r_gray_waddr_sync1 <= w_gray_waddr_reg ; r_gray_waddr_sync2 <= r_gray_waddr_sync1 ; end end //格雷码转二进制 gray_to_binary #(.WIDTH(ADDR_WIDTH+1)) gray_to_binary_U1 ( .gray_value (r_gray_waddr_sync2), .binary_value (r_bin_waddr) ); //读时钟域写地址(二进制)寄存 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_bin_waddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else r_bin_waddr_reg <= r_bin_waddr; end /*读时钟域读地址到写时钟域的格雷码方式同步*/ //二进制码转格雷码 binary_to_gray #(.WIDTH(ADDR_WIDTH+1)) binary_to_gray_U2 ( .binary_value (r_bin_raddr), .gray_value (r_gray_raddr) ); //读时钟域寄存 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) r_gray_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else r_gray_raddr_reg <= r_gray_raddr; end //写时钟域两级同步 always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) begin w_gray_raddr_sync1 <= {(ADDR_WIDTH+1){1'b0}} ; w_gray_raddr_sync2 <= {(ADDR_WIDTH+1){1'b0}} ; end else begin w_gray_raddr_sync1 <= r_gray_raddr_reg ; w_gray_raddr_sync2 <= w_gray_raddr_sync1 ; end end //格雷码转二进制 gray_to_binary #(.WIDTH(ADDR_WIDTH+1)) gray_to_binary_U2 ( .gray_value (w_gray_raddr_sync2), .binary_value (w_bin_raddr) ); //读时钟域写地址(二进制)寄存 always@(posedge rclk or negedge r_rst_) begin if(!r_rst_) w_bin_raddr_reg <= {(ADDR_WIDTH+1){1'b0}} ; else w_bin_raddr_reg <= w_bin_raddr; end /*FIFO内剩余空间计算*/ always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) room_avail <= {(ADDR_WIDTH+1){1'b0}}; else if(~w_bin_waddr[ADDR_WIDTH]==w_bin_raddr_reg[ADDR_WIDTH])//回卷时 room_avail <= w_bin_raddr_reg[ADDR_WIDTH-1:0]- w_bin_waddr[ADDR_WIDTH-1:0]; else //未回卷时 room_avail <= DEPTH + w_bin_raddr_reg - w_bin_waddr; end /*FIFO内已存入数据个数计算*/ always@(posedge wclk or negedge w_rst_) begin if(!w_rst_) data_avail <= {(ADDR_WIDTH+1){1'b0}}; else if(~r_bin_raddr[ADDR_WIDTH]==r_bin_waddr_reg[ADDR_WIDTH])//回卷时 data_avail <= DEPTH + r_bin_waddr_reg[ADDR_WIDTH-1:0]- r_bin_raddr[ADDR_WIDTH-1:0]; else //未回卷时 data_avail <= r_bin_waddr_reg - r_bin_raddr; end /*将满信号判断*/ assign almost_full = room_avail<ALMOST_FULL_GAP ? 1'b1:1'b0; /*将空信号判断*/ assign almost_empty = data_avail<ALMOST_EMPTY_GAP ? 1'b1:1'b0; /*写满标志判断*/ assign full = ({~w_bin_waddr[ADDR_WIDTH],w_bin_waddr[ADDR_WIDTH-1:0]} == w_bin_raddr_reg)?1'b1:1'b0; /*读空标志判断*/ assign empty = (r_bin_raddr == r_bin_waddr_reg)? 1'b1:1'b0; endmodule
联系客服