1
votes

Our assignment is to build a rudimentary single-cycle CPU in Verilog, but I'm not getting even more fundamental modules of it correct. For instance, to test the Instruction Memory module, we've been given a text file "hw3Test.txt" with instructions in hex, and I'm trying to slurp that into the IM.

00221820
AC010000
8C240000
10210001
00001820
00411822

When I run a testbench, I see that the only instructions that get into memory are the second, third, and fourth lines. Here's the IM module:

module IM(addr, clk, inst);

   input [31:0] addr;
   input clk;
   output reg [31:0] inst;


   reg [31:0] mem [255:0];
   initial begin
          $readmemh("hw3Test.txt", mem);
   end
   always @( posedge clk) begin
          inst=mem[addr[31:2]];
   end
endmodule

And the testbench:

module imtest;
    // Inputs
    reg [31:0] addr;
    reg clk;
    // Outputs
    wire [31:0] inst;
    // Instantiate the Unit Under Test (UUT)
    IM uut (
        .addr(addr), 
        .clk(clk), 
        .inst(inst)
    );
    initial begin
        // Initialize Inputs
        addr = 0;
        clk = 0;
        // Wait 100 ns for global reset to finish
        #100;
        // Add stimulus here
        clk = 0;
        addr = 0;
        #100;
        forever begin
            #20;
            clk = ~clk;
            addr = addr + 4;
        end 
    end      
endmodule

I'm also not sure I'm even getting the PC-to-IM module correct, because aside from the initialized values, everything but the rst and clk signals show no valid values. Can anyone point out where I'm going wrong?

module pc_im(
    // Inputs
    rst, clk, PCin,

    // Outputs
    inst, PCout
    );

    input clk, rst;
    input [31:0] PCin;
    output reg [31:0] inst;
    output reg [31:0] PCout;

    PC mypc (
        .clk(clk),
        .rst(rst),
        .PCin(PCin),
        .PCout(PCout)
    );

    IM myim(
        .clk(clk),
        .addr(PCout),
        .inst(inst)
    );

endmodule

Here's the PC.v module:

module PC(rst, clk, PCin, PCout);
    input clk, rst;
    input [31:0] PCin;
    output reg [31:0] PCout;

    always @(posedge clk) begin
        if (rst) PCout <= 0;
        else PCout <= PCin + 4;
    end

endmodule

And finally, the testbench:

module pcimtest;

    // Inputs
    reg rst;
    reg clk;
    reg [31:0] PCin;

    // Outputs
    wire [31:0] inst;
    wire [31:0] PCout;

    // Instantiate the Unit Under Test (UUT)
    pc_im uut (
        .rst(rst), 
        .clk(clk), 
        .PCin(PCin), 
        // Outputs
        .inst(inst), 
        .PCout(PCout)
    );

    initial begin
        // Initialize Inputs
        rst = 1;
        clk = 0;
        PCin = 0;

        // Wait 100 ns for global reset to finish
        #100;
        rst = 0;

        forever begin
            #100;
            clk <= ~clk;
            PCin <= PCout;
        end

        // Add stimulus here

    end

endmodule
1

1 Answers

2
votes

Here are a few things that look suspect.

Problem 1

It is normally good to use non-blocking assignments in blocks intended to infer registers.

i.e. change

always @( posedge clk) begin
      inst=mem[addr[31:2]];
end

to

always @( posedge clk) begin
      inst<=mem[addr[31:2]];
end

Problem 2

You are changing signals twice per clock cycle, once on negative edge and once on positive edge.

Change:

    forever begin
        #20;
        clk = ~clk;
        addr = addr + 4;
    end 

to

    forever begin
        #20;
        clk = 1;
        #20;
        clk = 0;
        addr = addr + 4;
    end

Problem 3

You are using synchronous resets but not supplying a clock during reset.

Consider the code

always @(posedge clk) begin
    if (rst) PCout <= 0;
    else PCout <= PCin + 4;
end

This block will only activate on positive clock edges. However, you make reset high while the clock is paused so no reset will happen.

Change

    rst = 1;
    clk = 0;
    PCin = 0;

    // Wait 100 ns for global reset to finish
    #100;

to

    rst = 1;
    clk = 0;
    PCin = 0;
    #20
    clk = 1;
    #20
    clk = 0;

    // Wait 100 ns for global reset to finish
    #100;