I'm trying to design cycles of Read and Write between CPU and SRAM. Initial memory values are mem(0) = 000f, mem(1) = 000e. I want to design by 5cycles Cycle 1 : Assigning addr = 0 Cycle 2 : Read value from SRAM, mem(0) -> IR Cycle 3 : Assigning addr = 1 Cycle 4 : Write value in SRAM, IR -> mem(1) Cycle 5 : Read value from 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
This is my simulation. Select value can mean cycle number. As I expected, When cycle 2 is started, mem(0) value 000f assign to dout, so dout becomes 000f, and IR should get this value at next rising edge, but DR value is unexpectedly change simultaneously with IR. Where is the problem?
At the bottom of the always block, you have an if
without begin
/end
:
if(select==3'b101) //cycle5, read
we <= 1; dr[15:0] <= dout[15:0];
This means that the assignment to dr
will always happen; only we <= 1
is covered by the condition.