FIFO:输出在发送下一个字节之前处于亚稳定状态
FIFO: Output is at meta-stable state before sending next byte
Objective: 使用并行输入 -> 串行输出实现 15 字节 FIFO。
预期结果:
- 在data_available信号的上升沿接收8位数据
- 一旦收到 15 个字节
- 在输出上按顺序(逐位)发送每个字节,直到发送完所有数据
- 传输到data_out时,新数据可以进来
- 如果有新数据可用,存储它
FIFO 模块:
//`timescale 1 ns / 100 ps
module fifo(rd_clk, data_out, data_in, rst, data_available);
// input & output ports
output data_out; // 1b serial out
input [7:0] data_in; // 8b parallel in
input rd_clk;
input rst;
input data_available;
// registers
reg [3:0] cs, rp, wp; // 4b(max=15)
reg data_out;
// internal only
reg data_out_ready;
reg [7:0] data_ram[0:14]; // Buffer 15 x 8bit
// common reset
always @(posedge rd_clk or posedge rst)
begin:Reset
if(rst) begin
wp <= 4'b0;
rp <= 4'b0;
cs <= 4'b0;
data_out <= 1'b0;
data_out_ready <= 1'b0;
end
end
always @(posedge data_available)
begin:Writing
if(!eql_addr) begin
data_ram[wp] = data_in;
#1 wp <= wp + 4'b0001;
if(wp == 14) begin
#1 data_out_ready <= 1'b1;
#1 wp <= 4'b0;
end
end
end
always @(posedge rd_clk)
begin:Reading
if(data_out_ready)
begin
data_out = data_ram[cs][rp];
rp <= rp + 4'b0001;
if(rp == 4'b1000) begin
cs <= cs + 4'b0001;
rp <= 4'b0;
end
if(cs == 15) begin
cs <= 4'b0;
data_out_ready <= 1'b0;
end
end
else
data_out <= 0;
end
assign eql_addr = (cs == wp) && data_out_ready;
endmodule
以下是我的测试平台模块
// `timescale 1 ns / 1 ps
module fifo_tb;
reg rst, clk, wr_en;
wire data_out;
reg [7:0] data_in;
// waveform dump for gtkwave
initial
begin
$dumpfile("fifo.vcd");
$dumpvars(0,fifo_tb);
end
fifo f1 (clk, data_out, data_in, rst, wr_en);
initial
begin
wr_en <= 0;
rst <= 1;
clk <= 0;
data_in <= 8'b0;
end
always #100 clk =~ clk; // flip clock every 100time-units
initial
begin
#100 rst = 1'b1;
#100 rst = 1'b0;
#100 data_in = 8'b01010110;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11001101;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11011100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00110011;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11001100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b10110011;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11111111;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00001111;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111010;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b01100110;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00110000;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b01100010;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11000001;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#50000 ; // wait
$finish;
end
endmodule
这是波形研究:
问题:
- data_out如果 wp 与 15 比较,则永远不会启用_ready,仅与 14
- 在串行输出端,发送完每个字节后,会发出元稳定 (x) 状态,直到发送下一个字节
我试图弄清楚为什么在每个字节(在 data_out 处)之后都会引入这种亚稳态,我还注意到 data_out 很好但是被移动了 1 位,即第 0 个位置 (rp = 0) 的位在读取时显示在第 1 个位置 (rp = 1)。
谢谢。
rp 递增到 8,因为读取 data_ram[n][8] 的数组元素(最多 7)正在生成 x。这也可能是位被移动的原因。
也可以更新 cs 比较以生成所有 15 个字节。
两个变化 - begin:Reading
if(rp == 4'b0111) begin
if(cs == 14 && rp == 4'b0111) begin
您可能不想在代码中使用#delay。
写接口是异步接口吗?
Objective: 使用并行输入 -> 串行输出实现 15 字节 FIFO。
预期结果:
- 在data_available信号的上升沿接收8位数据
- 一旦收到 15 个字节
- 在输出上按顺序(逐位)发送每个字节,直到发送完所有数据
- 传输到data_out时,新数据可以进来
- 如果有新数据可用,存储它
FIFO 模块:
//`timescale 1 ns / 100 ps
module fifo(rd_clk, data_out, data_in, rst, data_available);
// input & output ports
output data_out; // 1b serial out
input [7:0] data_in; // 8b parallel in
input rd_clk;
input rst;
input data_available;
// registers
reg [3:0] cs, rp, wp; // 4b(max=15)
reg data_out;
// internal only
reg data_out_ready;
reg [7:0] data_ram[0:14]; // Buffer 15 x 8bit
// common reset
always @(posedge rd_clk or posedge rst)
begin:Reset
if(rst) begin
wp <= 4'b0;
rp <= 4'b0;
cs <= 4'b0;
data_out <= 1'b0;
data_out_ready <= 1'b0;
end
end
always @(posedge data_available)
begin:Writing
if(!eql_addr) begin
data_ram[wp] = data_in;
#1 wp <= wp + 4'b0001;
if(wp == 14) begin
#1 data_out_ready <= 1'b1;
#1 wp <= 4'b0;
end
end
end
always @(posedge rd_clk)
begin:Reading
if(data_out_ready)
begin
data_out = data_ram[cs][rp];
rp <= rp + 4'b0001;
if(rp == 4'b1000) begin
cs <= cs + 4'b0001;
rp <= 4'b0;
end
if(cs == 15) begin
cs <= 4'b0;
data_out_ready <= 1'b0;
end
end
else
data_out <= 0;
end
assign eql_addr = (cs == wp) && data_out_ready;
endmodule
以下是我的测试平台模块
// `timescale 1 ns / 1 ps
module fifo_tb;
reg rst, clk, wr_en;
wire data_out;
reg [7:0] data_in;
// waveform dump for gtkwave
initial
begin
$dumpfile("fifo.vcd");
$dumpvars(0,fifo_tb);
end
fifo f1 (clk, data_out, data_in, rst, wr_en);
initial
begin
wr_en <= 0;
rst <= 1;
clk <= 0;
data_in <= 8'b0;
end
always #100 clk =~ clk; // flip clock every 100time-units
initial
begin
#100 rst = 1'b1;
#100 rst = 1'b0;
#100 data_in = 8'b01010110;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11001101;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11011100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00110011;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11001100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111100;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b10110011;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11111111;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00001111;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00111010;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b01100110;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b00110000;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b01100010;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#100 data_in = 8'b11000001;
#10 wr_en = 1'b0;
#10 wr_en = 1'b1;
#50000 ; // wait
$finish;
end
endmodule
这是波形研究:
问题:
- data_out如果 wp 与 15 比较,则永远不会启用_ready,仅与 14
- 在串行输出端,发送完每个字节后,会发出元稳定 (x) 状态,直到发送下一个字节
我试图弄清楚为什么在每个字节(在 data_out 处)之后都会引入这种亚稳态,我还注意到 data_out 很好但是被移动了 1 位,即第 0 个位置 (rp = 0) 的位在读取时显示在第 1 个位置 (rp = 1)。
谢谢。
rp 递增到 8,因为读取 data_ram[n][8] 的数组元素(最多 7)正在生成 x。这也可能是位被移动的原因。 也可以更新 cs 比较以生成所有 15 个字节。
两个变化 - begin:Reading
if(rp == 4'b0111) begin
if(cs == 14 && rp == 4'b0111) begin
您可能不想在代码中使用#delay。 写接口是异步接口吗?