Search code examples
verilogriscicarus

Verilog Icarus giving undefined values


I'm working on a project in which I'm designing a simple RISC machine in Icarus Verilog 0.9.7.

This code is modular and I'm going to put together the several components in the end, but I've run into an issue while working on the Memory Controller. For all of my test values I'm getting undefined output, or 'Z'. How can I fix this? I don't see any reason why these values are not being populated.

Defining all the behaviors the memory controller should have would be beyond the context of this question, so I'll try to keep it brief and on the topic of Verilog.

Here's my current Verilog code. The workbench has two files, mem.sv and SrcMemoryController.sv:

    `default_nettype none

module SrcMemoryController(
    inout [31:0] cpu_bus,
    inout [31:0] mem_bus,
    input ma_in,
    input md_in, 
    input md_out, 
    input read,
    input enable,
    output [15:0] address
);

  reg [31:0] ma = 32'bz;
  reg [31:0] md = 32'bz;
  wire [31:0] cpb = cpu_bus;
  wire [31:0] meb = mem_bus;

  always @(*) begin

    if(ma_in) ma = cpb;

    if(md_in) md = cpb;

    if(read) begin
      if(enable) md = meb;
    end

  end

  assign cpu_bus = (md_out) ? md : 32'bz;
  assign mem_bus = (~read && enable) ? md : 32'bz;
  assign address = ma;

endmodule

mem.sv currently works and is not the root of this problem. I will include it anyway incase it helps.

`default_nettype none

module Memory (
  inout [31:0] mem_bus,
  input [15:0] address,
  input read, 
  input enable
);

  reg [31:0] storage [65535:0];

  always @(enable) begin
    if(enable) begin
      if(read) begin

      end
      if(!read) begin
        storage[address] = mem_bus;
      end
    end
  end

  assign mem_bus = (read) ? storage[address] : 32'bz;

endmodule

Here's the testbench as well. It may not be needed but posting it could help.

    `default_nettype none
`include "mem.sv"

module tb_MemoryController;

  wire [31:0] mem_bus;
  wire [31:0] cpu_bus;
  reg [31:0] bus_sim;
  reg bus_sim_out = 0;

  // Tri-state buffer
  assign cpu_bus = bus_sim_out ? bus_sim : 32'bz; 

  reg ma_in, md_in, md_out;
  reg read, enable;
  wire [15:0] address;

  Memory vmem( mem_bus, address, read, enable );
  SrcMemoryController dut( cpu_bus, mem_bus, ma_in, md_in, md_out,
                       read, enable, address );

  initial begin
    $dumpfile("mem_file.vcd");
    $dumpvars(0, dut);
    $dumpvars(0, vmem);

    test_memory(0, 0);
    test_memory(10, 0);
    #1 assert_empty(mem_bus);
    #1 assert_empty(cpu_bus);
    test_memory(65535, 65535);
    test_memory(1231, 123);
    test_memory(1231231, 65535);
    test_memory(0, 65535);
    test_memory(100, 100);
    test_memory(515, 515);
    #1 assert_empty(mem_bus);
    #1 assert_empty(cpu_bus);
    $finish();
  end

  task test_memory;
    input [31:0] data;
    input [15:0] addr;
    begin
      #1
      zero_inputs();
      #1
      write_value(data, addr);
      #1
      load_spoof(); 
      #1
      read_value(addr);
      #1
      assertEquals(cpu_bus, data);
      zero_inputs();
    end
  endtask

  task write_value;
    input [31:0] data;
    input [15:0] addr;
    begin
      #1
      enable <= 0;
      bus_sim <= addr;
      bus_sim_out <= 1;
      ma_in <= 1;
      #1
      bus_sim <= data;
      bus_sim_out <= 1;
      ma_in <= 0;
      md_in <= 1;
      read <= 0;
      enable <= 1; 
    end
  endtask

  task read_value;
    input [15:0] addr;
    begin
      #1 
      enable <= 0;
      bus_sim <= addr;
      bus_sim_out <= 1;
      ma_in <= 1;
      #1
      ma_in <= 0;
      read <= 1;
      enable <= 1;
      bus_sim_out <= 0;
      md_out <= 1;
    end
  endtask

  task load_spoof;
    begin
      #1
      bus_sim <= 32'hABCDABCD;
      bus_sim_out <= 1;
      ma_in <= 1;
      md_in <= 1;
      read <= 0;
      enable <= 0; 
      #1
      zero_inputs();
    end
  endtask

  task zero_inputs;
    begin
      ma_in <= 0;
      md_in <= 0;
      md_out <= 0;
      read <= 0;
      enable <= 0;
      bus_sim_out <= 0;
    end
  endtask

  task pulseClock;
    begin
    end
  endtask

  task assertEquals;
    input [31:0] val;
    input [31:0] exp;
    begin
      if (val == exp) $display("[TEST][PASSED] %d", val);
      else $display("[TEST][FAILED] Got %d, expected %d", val, exp);
    end
  endtask


  task assert_empty;
    input [31:0] a;
    begin
      if (a === 32'bz) $display("[TEST][PASSED] (Bus empty)", a);
      else $display("[TEST][FAILED] (Value on bus)", a, 32'bz);
    end
  endtask

endmodule

All help is appreciated. Thanks!


Solution

  • Answer given in comments by Kevin, I will detail how it was fixed.

    I changed the always @(enable) in mem.sv to always @(*), after this was changed the rest of the code started working immediately and with full functionality. Thanks a ton Kevin1494!