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!
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!