Search code examples
verilogxilinx

Having trouble in simulating data on verilog


I made new question sheet for more details. I'm designing some codes of data bus-system by using ideal SRAM and CPU. I want to write memory mem[0] -> IR, and read memory IR -> mem[1], and finally write memory mem[1] -> DR.

I think that dumping data on mem is not normal now because memory and dout value is coming out ZZZZ all times. Data on SRAMs aren't moving well. How can I fix this?

module sram(addr,clk,din,dout,we);

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

     dout[word_width-1:0] <= mem[addr];
 end

endmodule




module cpu(clk,load,reset,select,ir,dr,ac,ar,pc,addr,we);

input clk,reset;
input [1:0]select;
input [1:0]load;

output reg[15:0] ir,dr,ac;
output reg[11:0] ar,pc;

input we;
input [11:0] addr;

reg[15:0] din;
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==2'b01 && load==2'b01 && we==1) //read
        ir[15:0] <= dout[15:0];
    else if(select==2'b11 && load==2'b10 && we==0) //write
        din[15:0] <= ir[15:0];
    else if(select==2'b10 && load==2'b11 && we==1) //read
        dr[15:0] <= dout[15:0];
    end

endmodule




module tb_cpu();
parameter addr_width = 12, word_depth = 4096, word_width = 16;

reg clk,reset,we;
reg [1:0]select;
reg [1:0]load;
reg [addr_width-1:0] addr;
wire [word_width-1:0] ir,dr,ac;
wire [word_width-5:0] ar,pc;
integer file_pointer;
integer file_pointer2;

wire [word_width-1:0]mem[0:word_depth-1];
wire [word_width-1:0] dout;

cpu cpu(clk,load,reset,select,ir,dr,ac,ar,pc,addr,we);

always #5 clk = ~clk;

initial begin
    clk = 0; we = 0; reset = 1;
    #2 reset = 0; 
    #2 reset = 1;

    file_pointer = $fopen("reg.dat");
    file_pointer2 = $fopen("memory.dat");

    $readmemb("sram.dat", tb_cpu.cpu.sram.mem);

    #10 select = 2'b01; load = 2'b01; we = 1; addr = 12'b000000000000; //cycle 1
    #10 select = 2'b11; load = 2'b10; we = 0; addr = 12'b000000000001; //cycle 2
    #10 select = 2'b10; load = 2'b11; we = 1; addr = 12'b000000000001; //cycle 3

    $fdisplay(file_pointer, "AR = %b", tb_cpu.cpu.ar);
    $fdisplay(file_pointer, "IR = %b", tb_cpu.cpu.ir);
    $fdisplay(file_pointer, "PC = %b", tb_cpu.cpu.pc);
    $fdisplay(file_pointer, "DR = %b", tb_cpu.cpu.dr);
    $fdisplay(file_pointer, "AC = %b", tb_cpu.cpu.ac);

    $fdisplay(file_pointer2, "mem[0000 0000 0000] = %b",tb_cpu.cpu.sram.mem[000000000000]);
    $fdisplay(file_pointer2, "mem[0000 0000 0001] = %b",tb_cpu.cpu.sram.mem[000000000001]);
    $fdisplay(file_pointer2, "mem[0000 0000 0010] = %b",tb_cpu.cpu.sram.mem[000000000010]);

     $fclose(file_pointer);
     $fclose(file_pointer2);

    #10 $finish;
end    
endmodule

Solution

  • I think the reason is that you need 2 clock cycles to propagate mem->dout->ir.

    In your case sram reads dout at posedge clk. At the same posedge you push its value into ir. But hardware and simulation push the old value of dout which was xxx.... You need to give it more time to settle down. So, if you use #20 instead of #10 in your test bench, you should see different results.