📄 s_fifo.txt
字号:
`define fifo_size_lg 10
`define fifo_size (1<<`fifo_size_lg)
`define fifo_addr_bits (`fifo_size_lg-1):0
`define fifo_high_addr (`fifo_size_lg-1):(`fifo_size_lg>>1)
`define fifo_low_addr ((`fifo_size_lg>>1)-1):0
// Fifo using declared registers for storage.
module fifo(dout,empty,full,ready,op,din,clk);
input op, din, clk;
output dout, empty, full, ready;
// Note: Clock ignored.
wire [31:0] dout;
reg empty,full;
wire ready;
wire [1:0] op;
wire [31:0] din;
parameter op_nop = 0;
parameter op_insert = 1;
parameter op_remove = 2;
parameter op_reset = 3;
reg [31:0] fifo_mem [0:`fifo_size-1];
reg [`fifo_addr_bits] head; // Head of queue.
reg [`fifo_addr_bits] tail; // Next empty place to be filled.
assign ready = op === op_nop;
assign dout = fifo_mem[head];
always @( op )
case ( op )
op_nop:;
op_insert: if( !full ) begin
fifo_mem[tail] = din; tail = tail + 1;
full = head === tail;
empty = 0;
end
op_remove: if( !empty ) begin
head = head + 1;
full = 0;
empty = head === tail;
end
op_reset: begin head = 0; tail = 0; empty = 1; full = 0; end
endcase // case( op )
endmodule // fifo
// Fifo using (model of) standard memory chip for storage.
module fifom(dout,empty,full,ready,op,din,clk);
input op, din, clk;
output dout, empty, full, ready;
reg [31:0] dout;
reg empty, full, ready;
wire [1:0] op;
wire [31:0] din;
reg [31:0] dbuffer;
parameter op_nop = 0;
parameter op_insert = 1;
parameter op_remove = 2;
parameter op_reset = 3;
tri [31:0] dq;
reg ras, cas, we, oe;
reg [4:0] addr;
reg write;
/* Emacs Common Lisp routine generating instantiations.
(loop for i from 31 downto 3 by 4
do (insert (format "memchip2 fifo_mem%d(dq[%d:%d], ras, cas, addr, we, oe);\n"
(/ i 4) i (- i 3)))) */
memchip fifo_mem7(dq[31:28], ras, cas, addr, we, oe);
memchip fifo_mem6(dq[27:24], ras, cas, addr, we, oe);
memchip fifo_mem5(dq[23:20], ras, cas, addr, we, oe);
memchip fifo_mem4(dq[19:16], ras, cas, addr, we, oe);
memchip fifo_mem3(dq[15:12], ras, cas, addr, we, oe);
memchip fifo_mem2(dq[11:8], ras, cas, addr, we, oe);
memchip fifo_mem1(dq[7:4], ras, cas, addr, we, oe);
memchip fifo_mem0(dq[3:0], ras, cas, addr, we, oe);
assign dq = write ? dbuffer : 32'bz;
reg [`fifo_addr_bits] head; // Head of queue.
reg [`fifo_addr_bits] tail; // Next empty place to be filled.
always
begin
wait( op === op_nop ) ready = 1;
@( op ) begin
ready = 0; dbuffer = din;
case ( op )
op_nop: begin $display("Unexpected nop."); $stop; end
op_insert: if( !full ) begin
@(posedge clk);
addr = tail[`fifo_high_addr];
ras = 0;
@(posedge clk);
addr = tail[`fifo_low_addr];
cas = 0; write = 1; we = 0;
@(posedge clk);
ras = 1; cas = 1; write = 0; we = 1;
if( empty ) dout = dbuffer;
tail = tail + 1;
full = head === tail;
empty = 0;
end // if ( !full )
op_remove: if( !empty ) begin
head = head + 1;
@(posedge clk);
addr = head[`fifo_high_addr];
ras = 0;
@(posedge clk);
addr = head[`fifo_low_addr];
cas = 0; oe = 0;
@(posedge clk);
dout = dq; ras = 1; cas = 1; oe = 1;
full = 0;
empty = head === tail;
end // if ( !empty )
op_reset: begin
head = 0; tail = 0; empty = 1; full = 0; dout = 0;
ras = 1; cas = 1; write = 0; oe = 1; we = 1;
end
endcase // case( op )
end // @ ( op )
end // always begin
endmodule // fifo
// Testbench for fifo.
module test_fifo();
wire [31:0] dout;
wire empty, full;
reg [1:0] op;
wire [31:0] din;
reg clk;
wire ready;
fifo f1(dout,empty,full,ready,op,din,clk);
function integer ctoval;
input [31:0] c;
ctoval = c * 3 + 1;
endfunction // ctoval
integer errors;
task estop;
input [400:0] msg;
begin
errors = errors + 1;
$display("Error %d: %s\n",errors,msg);
$stop;
end
endtask // estop
task fifo_command;
input [1:0] command;
begin
wait( ready ) op = command;
wait( !ready ) op = f1.op_nop;
wait( ready );
end
endtask // fifo_command
integer dini;
assign din = ctoval(dini);
initial begin:I
integer i, inside, tail_c, head_c;
errors = 0;
clk = 0;
op = f1.op_nop;
wait( ready ) op = f1.op_reset;
wait( !ready ) op = f1.op_nop;
op = f1.op_reset; #1 op = f1.op_nop; #1;
// Fill
if( !empty || full ) estop("Before fill, should be empty.");
for( dini = 0; dini < `fifo_size; dini = dini + 1 ) begin
if( full ) estop("Fill, shouldn't be full.");
#1;
fifo_command( f1.op_insert );
if( dout!==ctoval(0) ) estop("Fill, expecting first input at head.");
end
if( !full || empty ) estop("After fill, should be full.");
// Try to overfill
for( dini = `fifo_size; dini < `fifo_size+10; dini = dini + 1 ) begin
if( !full || empty ) estop("Overfill, should be full.");
#1 fifo_command( f1.op_insert );
if( dout!==ctoval(0) )
estop("Overfill, expecting first input at head.");
end
// Drain
for( dini = 0; dini < `fifo_size; dini = dini + 1 ) begin
if( empty ) estop("Drain, shouldn't be empty.");
if( dout!==ctoval(dini) )
estop("Drain, expecting previous input at head.");
#1 fifo_command( f1.op_remove );
end
if( !empty || full ) estop("After drain, should be empty.");
// Fill partway
for( dini = `fifo_size; dini < `fifo_size+10; dini = dini + 1 ) begin
#1 fifo_command( f1.op_insert );
if( dout!==ctoval(`fifo_size) )
estop("Fill partway, expecting first input at head.");
end
// Drain
for( dini = `fifo_size; dini < `fifo_size+10; dini = dini + 1 ) begin
if( empty ) estop("Drain, shouldn't be empty.");
if( dout!==ctoval(dini) )
estop("Drain, expecting previous input at head.");
#1 fifo_command( f1.op_remove );
end
// Random;
tail_c = dini;
head_c = tail_c;
for( i=0; i<1000; i=i+1 ) begin
case( $random & 1 )
0: begin
#1 fifo_command( f1.op_remove );
if( head_c !== tail_c ) head_c = head_c + 1;
end
1: begin
dini = tail_c;
if( !full ) tail_c = tail_c + 1;
#1 fifo_command( f1.op_insert );
end
endcase
if( head_c === tail_c ) begin
if( !empty || full ) estop("Random, expected to be empty.");
end else begin
if( dout !== ctoval(head_c) ) estop("Random, unexpected value.");
end
if( tail_c - head_c === `fifo_size &&
( !full || empty ) ) estop("Random, expected to be full.");
end // for ( i=0; i<1000; i=i+1 )
$display("Done testing.");
$stop;
end // block: I
always #30 clk = ~clk;
endmodule // test_fifo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -