I'm very new to Verilog and I've tried to create single-cycle 32bit MIPS processor.
Instructions I want to implement are

add, and, addi, addu.qb, addu_s.qb, beq, jal, jr, lw, or, slt, sub, sw

but I slightly changed the encoding in instruction jr ( opcode = 6'b000111 ).

The processor should look like this:

processor structure

I've created that structure in Verilog and also translated a little program to hexa instructions which I want to run in this processor, so I can say if the processor works correctly or not. The problem is when I want to simulate processor in gtkwave and basically debug it, almost all of my "variables" shows their values as "xxxxxx" (picture below) and I don't know why. I would appreciate a little help. I've tried also Google but unfortunately didn't help.

gtkwave example

Also below you can find my code describing cpu, instruction and data memory and testbench. Components I'm using in cpu description are correct, only problem is with the simulation.
Thank you for your advice.

module cpu ( input clk, reset, output [31:0] PC, address_to_mem, data_to_mem, input [31:0] instruction, data_from_mem, output WE )

wire Zero, c32, c32_1, c0, c0_1, PCSrcBeq_true, PCSrcJal, PCSrcJr, RegWrite, MemToReg, MemWrite, ALUSrc, RegDst, Branch;    
    wire [3:0] ALUControl;
    wire [4:0] shamt;
    wire [5:0] opCode, funct;
    wire [15:0] in;
    wire [31:0] SignImm, SrcB, ALUOut, ResultMult, PCPlus4, PCBranch, DataIn,four, Rt, Rd, mux_regf_result, thirty_one, res, rd1, rd2, WD3, Result, PCJal, WriteReg;

    reg [31:0] PC_reset;
    always @(posedge reset )
        if ( reset )
            PC_reset <= 0;
    assign PC = PC_reset;

    assign thirty_one = 31; 
    assign four = 4;
    mux_4_1 mux_instmem ( rd1, Result, PCBranch, PCPlus4, PCSrcJr, PCSrcJal, PCSrcBeq_true, DataIn ); 

    register_32_bit PC_reg ( DataIn, clk, PC );

    adder_32bit adder_PC ( PC, four, c0_1, PCPlus4, c32_1 );

    register_file reg_file ( instruction[25:21], instruction[20:16], res[4:0], RegWrite, clk, WD3, rd1, rd2 );
    assign data_to_mem = rd2;

    controlUnit control_unit ( instruction[31:26], instruction[5:0], instruction[10:6], RegWrite, RegDst, ALUSrc, Branch, MemWrite, MemToReg, PCSrcJal, PCSrcJr, ALUControl );
    assign WE = MemWrite;

    mux_2_1 mux_left_up_regf ( WriteReg, thirty_one, PCSrcJal, res );

    mux_2_1 mux_left_down_regf ( Result, PCPlus4, PCSrcJal, WD3 );

    assign Rt = instruction[20:16];
    assign Rd = instruction[15:11];
    multiplexor_2_1 mux_regf ( Rt, Rd, RegDst, WriteReg );

    ext_to_32bit sign_ext ( instruction[15:0], SignImm ); 

    multiplier mult_by4 ( SignImm, ResultMult );

    adder_32bit adder ( ResultMult, PCPlus4, c0, PCBranch, c32 ); 

    multiplexor_2_1 mux_alu ( rd2, SignImm, ALUSrc, SrcB ); 

    alu_32bit alu_right ( rd1, SrcB, ALUControl, Zero, ALUOut );
    assign address_to_mem = ALUOut;

    mux_2_1 mux_datamem ( ALUOut, data_from_mem, MemToReg, Result );

    assign PCJal[31:28] = PCPlus4[31:28];
    assign PCJal[27:2] = instruction[25:0];
    assign PCJal[1:0] = 0;

    assign PCSrcBeq_true = Zero & Branch;


data memory

module datamemory ( input clk, we, input [31:0] address, wd, output [31:0] rd );

reg [31:0] mem[63:0];

initial begin

assign rd=mem[address[31:2]]; //word aligned

always @(posedge clk)
    if (we)

instruction memory

module instructionmemory(input [5:0] address, output[31:0] rd);
reg [31:0] mem[63:0];
initial begin
assign rd=mem[address]; //word aligned



module top_module(input clk, reset, output[31:0] data_to_mem, address_to_mem, output write_enable);

wire [31:0] pc, instruction, data_from_mem;

instructionmemory imemory(pc[7:2], instruction);
datamemory dmemory(clk, write_enable, address_to_mem, data_to_mem, data_from_mem);
cpu mipsCPU (clk, reset, pc, instruction, write_enable, address_to_mem, data_to_mem, data_from_mem );



module testbench();
reg clk, reset;
wire[31:0] data_to_mem, address_to_mem;
wire memwrite;

top_module simulation(clk, reset, data_to_mem, address_to_mem, memwrite);

initial begin
   reset<=1; #2; reset<=0;
   #80 $finish;

always begin
   clk<=1; #1; clk<=0; #1;


EDIT: register code

module register_32_bit(input [31:0] datain,
                       input clk, reset,
                       output reg [31:0] dataout);

always @ ( posedge clk or posedge reset ) 
    if ( reset )
        dataout <= 0;
        dataout <= datain;

reg_file code

module register_file( input[4:0] a1, a2, a3,
                      input we3, clk, reset,
                      input[31:0] wd3,
                      output reg [31:0] rd1, rd2 );

reg [31:0] reg_file[31:0];

always@ ( posedge clk or posedge reset )
    if ( reset ) begin
        reg_file[0]  <= 0;
        reg_file[31] <= 0;
    else begin
        if ( we3 )
            if ( a3 != 0 )          
                reg_file[a3] <= wd3;
                reg_file[a3] <= 0;   //register $0 has always to be 0

always @ ( a1 or a2 )
    if ( a1 == 0 )
        rd1 <= 0;
    else if ( a2 == 0 )
        rd2 <= 0;
    else if ( a1 != 0 )
        rd1 <= reg_file[a1];
    else if ( a2 != 0 )
        rd2 <= reg_file[a2];    


1 Answer 1


An X means a register is not initialized.

You have NOT provided the code for the registers or register banks. Thus the code most likely to cause your problem is missing.

However some of the code you did provide is wrong. This does not work:

always @(posedge reset )
    if ( reset )
        PC_reset <= 0;
assign PC = PC_reset;
register_32_bit PC_reg ( DataIn, clk, PC );

I also noticed the reset missing from register_file.

There are a few basic code templates which you have to follow each and every time you make a register. The most standard one is:

always @(posedge clock or posedge reset )
   if (reset)
      reg <= 0;
     // your clocked code e.g.
     reg <= reg + 1;
  end // clocked 
end // always 

Thus the reset and clock of your registers all have to be in the same always block and all assignments to the register(s) have to be in there too.

Start with converting all your register to that format and then check again what your MIPS does.

  • \$\begingroup\$ No, this is wrong: always @ ( a1 or a2 ) for combinatorial circuits use always @( * ) and blocking assignments: rd1 = reg_file[a1]; I can't help you with the rest. \$\endgroup\$
    – Oldfart
    Commented Nov 11, 2019 at 6:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.