Search code examples
verilogxilinx

Unexpected waveform is coming out, designing CPU


enter image description here

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?


Solution

  • 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.