带选通信号的同步FIFO
我们常见的同步FIFO一般都是固定位宽输入,固定位宽输出的,因此他们之间的关系一般来说都是固定的,比较容易理解,网上也有很多类似的代码去指导怎么编写,在此不再赘述。
如果突发奇想,添加一个选通信号wstrb呢?那么这个世界是不是就不太一样了呀~~
假设题目如下:编写代码,实现如下的同步FIFO功能,示意图如下:
其中,clock为输入时钟;reset_n为复位信号,低有效;valid_in为输入有效信号,当输入信号为无效信号时,数据不写进FIFO;wstrb为选通信号,当其为0时,输入数据的低8位有效,当其为1时,输入数据的低16位有效,当其为2时,输入数据的低32位有效,当其为3时,输入数据全部有效;data_in为输入数据,每次数据为64位;valid_out为输出有效信号;ready_in为FIFO状态信号,当为高时,证明FIFO内部有足够的空间存储数据;data_out为输出数据,32位宽。
解题思路如下:
因为输入可能是8位,也可能是16位,32位,64位有效,而输出永远都是32位的,那么我们把fifo宽度定义为8位,深度定义为32位。
从实际情况出发,假设每当数据存储大于24byte时,发送ready_in为0信号;每当fifo中数据大于4byte时,就立即取出;每个时钟存储的数据,至少等待一个时钟周期才能取出,不能同时刻取出...
最简单的方法是使用sv编写,因为sv中有quene,完美解决了Verilog需要读写指针或者计数器等问题,请注意,这种写法是不可综合的,可作为Testbench中的reference model 使用。
参考代码如下所示:(本次仅给出SV代码,下次给可综合的RTL代码,代码仅供参考,不保证没bug,有问题欢迎交流~)
`timescale 1ns / 100ps //****************************************************************** // Author:SJTU_chen // Date: 2019/10/26 // Version: v1.0 // Module Name: fifo-systemverilog // Project Name: SystemVerilog Lab1 //******************************************************************* module fifo_ref( clock, reset_n, valid_in,wstrb,data_in,valid_out,ready_in,data_out ); input clock; input reset_n; input valid_in; input [1:0] wstrb; input [63:0] data_in; output [31:0] data_out; output valid_out; output ready_in; logic [31:0] data_out; logic valid_out; logic ready_in; logic [7:0] stack [$]; always@(posedge clock&nbs***bsp;negedge reset_n) begin if(!reset_n) begin stack.delete(); end else if (valid_in&&ready_in) begin casex (wstrb) 2'b00: begin stack.push_back(data_in[7:0]); end 2'b01: begin stack.push_back(data_in[7:0]); stack.push_back(data_in[15:8]); end 2'b10: begin stack.push_back(data_in[7:0]); stack.push_back(data_in[15:8]); stack.push_back(data_in[23:16]); stack.push_back(data_in[31:24]); end 2'b11: begin stack.push_back(data_in[7:0]); stack.push_back(data_in[15:8]); stack.push_back(data_in[23:16]); stack.push_back(data_in[31:24]); stack.push_back(data_in[39:32]); stack.push_back(data_in[47:40]); stack.push_back(data_in[55:48]); stack.push_back(data_in[63:56]); end endcase end end always@(posedge clock&nbs***bsp;negedge reset_n) begin if(!reset_n) begin data_out <=32'b0; valid_out <='0; end else if(wstrb==3&&valid_in==1&&stack.size>11) fork valid_out <= '1; begin data_out[7:0] =stack.pop_front; data_out[15:8] =stack.pop_front; data_out[23:16]=stack.pop_front; data_out[31:24]=stack.pop_front; end join else if(wstrb==2&&valid_in==1&&stack.size>7) fork valid_out <= '1; begin data_out[7:0] =stack.pop_front; data_out[15:8] =stack.pop_front; data_out[23:16]=stack.pop_front; data_out[31:24]=stack.pop_front; end join else if(wstrb==1&&valid_in==1&&stack.size>5) fork valid_out <= '1; begin data_out[7:0] =stack.pop_front; data_out[15:8] =stack.pop_front; data_out[23:16]=stack.pop_front; data_out[31:24]=stack.pop_front; end join else if(wstrb==0&&valid_in==1&&stack.size>4) fork valid_out <= '1; begin data_out[7:0] =stack.pop_front; data_out[15:8] =stack.pop_front; data_out[23:16]=stack.pop_front; data_out[31:24]=stack.pop_front; end join else if(valid_in==0&&stack.size>=4) fork valid_out <= '1; begin data_out[7:0] =stack.pop_front; data_out[15:8] =stack.pop_front; data_out[23:16]=stack.pop_front; data_out[31:24]=stack.pop_front; end join else begin valid_out <='0; end end assign ready_in=(stack.size<=24); endmodule