verilog - 出乎意料的波形出来了,设计CPU
问题描述
我正在尝试设计 CPU 和 SRAM 之间的读写周期。初始内存值为 mem(0) = 000f,mem(1) = 000e。我想按 5 个周期进行设计 周期 1:分配 addr = 0 周期 2:从 SRAM 读取值,mem(0) -> IR 周期 3:分配 addr = 1 周期 4:在 SRAM 中写入值,IR -> mem(1)周期 5:从 SRAM 读取值,mem(1) -> DR
module sram(addr,clk,din,dout,we); //sram.v
parameter addr_width = 12, word_depth = 4096, word_width = 16;
input clk,we;
input [addr_width-1:0] addr;
input [word_width-1:0] din;
output [word_width-1:0] dout;
reg [word_width-1:0]mem[0:word_depth-1];
reg [word_width-1:0]dout;
always @ (posedge clk) begin
if(!we)
mem[addr] <= din[word_width-1:0];
end
always @ (posedge clk) begin
if(we)
dout[word_width-1:0] <= mem[addr];
end
endmodule
module cpu(clk,reset,select); //cpu.v
input clk,reset;
input [2:0]select;
reg[15:0] ir,dr,ac;
reg[11:0] ar,pc;
reg [11:0]addr;
reg[15:0] din;
reg we;
wire[15:0] dout;
sram sram(addr,clk,din,dout,we);
always @ (posedge clk or negedge reset) begin
if(!reset) begin
ar <= 12'b0; ir <= 16'b0; pc <= 12'b0; dr <= 16'b0; ac <= 16'b0;
end
if(select==3'b001) //cycle1, address assign
addr <= 12'b0;
if(select==3'b010) //cycle2, read
we <= 1;ir[15:0] <= dout[15:0];
if(select==3'b011) //cycle1, address assign
addr <= 12'b1;
if(select==3'b100) //cycle4, write
we <= 0; din[15:0] <= ir[15:0];
if(select==3'b101) //cycle5, read
we <= 1; dr[15:0] <= dout[15:0];
end
endmodule
module tb_cpu(); //tb_cpu.v
parameter addr_width = 12, word_depth = 4096, word_width = 16;
reg clk,reset;
reg [2:0] select;
integer sram_pointer;
integer reg_pointer;
cpu cpu(clk,reset,select);
always #5 clk = ~clk;
initial begin
clk = 0; reset = 1;
$readmemb("sram.dat", tb_cpu.cpu.sram.mem);
sram_pointer = $fopen("sram_aftercycle.dat");
reg_pointer = $fopen("reg.dat");
#1 reset = 0;
#1 reset = 1;
#3 select = 3'b001; //cycle 1
#20 select = 3'b010; //cycle 2
#20 select = 3'b011; //cycle 3
#20 select = 3'b100; //cycle 4
#20 select = 3'b101; //cycle 5
#10
$fdisplay(reg_pointer, "AR = %b", tb_cpu.cpu.ar);
$fdisplay(reg_pointer, "IR = %b", tb_cpu.cpu.ir);
$fdisplay(reg_pointer, "PC = %b", tb_cpu.cpu.pc);
$fdisplay(reg_pointer, "DR = %b", tb_cpu.cpu.dr);
$fdisplay(reg_pointer, "AC = %b", tb_cpu.cpu.ac);
$fdisplay(sram_pointer, "mem[0000 0000 0000] = %b",tb_cpu.cpu.sram.mem[0]);
$fdisplay(sram_pointer, "mem[0000 0000 0001] = %b",tb_cpu.cpu.sram.mem[1]);
$fdisplay(sram_pointer, "mem[0000 0000 0010] = %b",tb_cpu.cpu.sram.mem[2]);
$fdisplay(sram_pointer, "mem[0000 0000 0011] = %b",tb_cpu.cpu.sram.mem[3]);
$fclose(sram_pointer);
$fclose(reg_pointer);
#5 $finish;
end
endmodule
这是我的模拟。选择值可以表示循环数。正如我所料,当周期 2 开始时,mem(0) 值 000f 分配给dout,所以dout 变为000f,IR 应该在下一个上升沿得到这个值,但是 DR 值意外地与 IR 同时变化。问题出在哪里?
解决方案
在 always 块的底部,您有一个if
没有begin
/ end
:
if(select==3'b101) //cycle5, read
we <= 1; dr[15:0] <= dout[15:0];
这意味着分配 todr
将始终发生;只有we <= 1
被条件覆盖。
推荐阅读
- javascript - Vue - 从不同的组件调用方法(使用 vue-routes)
- google-cloud-storage - 如何在 googleapis.com 中创建公共存储桶?
- reactjs - 如何将项目从平面列表传递给孙子?
- liferay - 有没有办法只为liferay中的某些用户禁用多重登录?
- firebase - 访问 firebase firestore 数据库仪表板是否会被视为读取操作?
- javascript - 在 React Native 中调用 Alert 后,UI 挂起
- php - 如何为帖子创建一个工厂,它还在 laravel 中为该帖子的元表输入数据
- c++ - 调用 glibc/openssl 函数的 gtest C++ 函数
- angular - 如何在 Angular 8 中仅重新加载或刷新子组件
- typescript - 为什么这个映射声明会引发类型错误?