出乎意料的波形出来了,设计CPU
Unexpected waveform is coming out, designing CPU
我正在尝试设计 CPU 和 SRAM 之间的读写周期。
初始内存值为 mem(0) = 000f,mem(1) = 000e。
我想按 5cycles 设计
周期 1:分配地址 = 0
周期 2:从 SRAM 读取值,mem(0) -> IR
周期 3:分配地址 = 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
这是我的模拟。 Select 值可以表示循环数。正如我所料,当周期 2 开始时,mem(0) 值 000f 分配给 dout,因此 dout 变为 000f,IR 应该在下一个上升沿获得该值,但是 DR 值意外地与 IR 同时变化。问题出在哪里?
在 always 块的底部,你有一个没有 begin
/end
的 if
:
if(select==3'b101) //cycle5, read
we <= 1; dr[15:0] <= dout[15:0];
这意味着对dr
的赋值总是会发生;只有 we <= 1
符合条件。
我正在尝试设计 CPU 和 SRAM 之间的读写周期。 初始内存值为 mem(0) = 000f,mem(1) = 000e。 我想按 5cycles 设计 周期 1:分配地址 = 0 周期 2:从 SRAM 读取值,mem(0) -> IR 周期 3:分配地址 = 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
这是我的模拟。 Select 值可以表示循环数。正如我所料,当周期 2 开始时,mem(0) 值 000f 分配给 dout,因此 dout 变为 000f,IR 应该在下一个上升沿获得该值,但是 DR 值意外地与 IR 同时变化。问题出在哪里?
在 always 块的底部,你有一个没有 begin
/end
的 if
:
if(select==3'b101) //cycle5, read
we <= 1; dr[15:0] <= dout[15:0];
这意味着对dr
的赋值总是会发生;只有 we <= 1
符合条件。