Writing random data to a RAM in a testbench - verilog

I am working with RAM in Verilog, and I need to implement a test bench where I will confirm the correct operation of the three memory processes (write data, read data and read commands). I have written a testbench where it seems to be writing and reading some integer numbers, but is there any way to fill the memory with words or strings to be more clear randomly?
This is my testbench:
module ramtest();
parameter WORD_SIZE=8;
parameter ADDR_WIDTH=8;
parameter RAM_SIZE=1<<ADDR_WIDTH;
reg we;
reg re;
reg [ADDR_WIDTH-1:0] addr;
reg [ADDR_WIDTH-1:0] instraddr;
reg [WORD_SIZE-1:0] datawr;
reg Clk;
reg [WORD_SIZE-1:0] mem[RAM_SIZE-1:0];
wire [WORD_SIZE-1:0] datard;
wire [WORD_SIZE-1:0] instrrd;
MCPU_RAMController raminst (.we(we),.datawr(datawr),.re(re),.addr(addr),.datard(datard),.instraddr(instraddr),.instrrd(instrrd));
integer i;
initial begin
we=0;
datawr=0;
instraddr=0;
addr=1;
#20;
for(i=0;i<RAM_SIZE;i=i+1) begin
datawr=i;
addr=i-1;
#10;
end
we=0;
addr=1;
instraddr=0;
for(i=0;i<RAM_SIZE;i=i+1) begin
addr=i-1;
#10;
end
end
endmodule
And here is the RAM controller code where I need to test:
module MCPU_RAMController(we, datawr, re, addr, datard, instraddr, instrrd);
parameter WORD_SIZE=8;
parameter ADDR_WIDTH=8;
parameter RAM_SIZE=1<<ADDR_WIDTH;
input we, re;
input [WORD_SIZE-1:0] datawr;
input [ADDR_WIDTH-1:0] addr;
input [ADDR_WIDTH-1:0] instraddr;
output [WORD_SIZE-1:0] datard;
output [WORD_SIZE-1:0] instrrd;
reg [WORD_SIZE-1:0] mem[RAM_SIZE-1:0];
reg [WORD_SIZE-1:0] datard;
reg [WORD_SIZE-1:0] instrrd;
always # (addr or we or re or datawr)
begin
if(we)begin
mem[addr]=datawr;
end
if(re) begin
datard=mem[addr];
end
end
always # (instraddr)
begin
instrrd=mem[instraddr];
end
endmodule

Currently, you are filling the memory with incrementing values (0, 1, 2, etc.) at incrementing addresses. One way to fill the memory with random data values is to use the $random system function.
In the testbench, change:
datawr=i;
to:
datawr=$random;
See also IEEE Std 1800-2017, section 18.13 Random number system functions and methods for more modern random functions ($urandom, etc.).

Related

Quartus does not allow using a Generate block in Verilog

Pretty simple problem. Given the following code:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
generate
genvar k;
for(k=0; k<2; k=k+1) begin: m
always #(posedge clk) begin
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endgenerate
endmodule
quarus 13.0sp1 gives this error (and its 20 other ill-begotten fraternally equivalent siblings):
Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)
But if I manually un-roll the generate loop:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
always #(posedge clk) begin
if(wren[0])
ram[addr[0]] <= dIn[0];
dOut[0] <= ram[addr[0]];
end
always #(posedge clk) begin
if(wren[1])
ram[addr[1]] <= dIn[1];
dOut[1] <= ram[addr[1]];
end
endmodule
It all becomes okay with the analysis & synthesis step.
What's the cure to get the generate loop running?
I think the correct way is in the lines of what it's explained in this question: Using a generate with for loop in verilog
Which would be transferred to your code as this:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
integer k;
always #(posedge clk) begin
for(k=0; k<2; k=k+1) begin:
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endmodule
Keeping all accesses to your dual port RAM in one always block is convenient so the synthesizer can safely detect that you are efefctively using a dual port RAM at register ram.
Both the generate loop and unrolled versions should not have passed synthesis. In both cases the same address in ram can be assigned by both always blocks. Worse, if both bits of wren are high with both addresses being the same and data being different, then the result is indeterminable. The Verilog LRM states last assignment on a register wins and always blocks with the same trigger could be evaluated in any order.
Synthesis requires assignments to registers to be deterministic. Two (or more) always blocks having write access to the same bit is illegal because nondeterministic. If the unrolled is synthesizing correctly, then that means there are constants on wren and addr outside of the shown module that make it logically impossible for write conflict; for some reason the generate loop version is not getting the same optimization. Example of constraints that would allow optimization to prevent multi-always block write access:
One wren is hard coded to 0. Therefore only one block has exclusive access
Address have non overlapping sets of possible values. Ex addr[0] can only be even while addr[1] can only be odd, or addr[0] < 2**(ADDR_WIDTH/2) and addr[1] >= 2**(ADDR_WIDTH/2).
Synthesis is okay with dOut being assigned by two always blocks because each block has exclusive write access to its target bits (non overlapping sets of possible address values).
The single always block in mcleod_ideafix answer is the preferred solution. If both bits of wren are high with both addresses being the same, then wren[1] will always win. If wren[0] should have priority, then make the for-loop a count down.

Why are the outputs not changing/not getting loaded in my single cycle architecture implementation?

I've written the code for the single cycle MIPS Architecture which implements add, sub, multiply and divide. There's a 2D Reg array, A control unit, an ALU. I think I've written it all right, but the opcode I've put in the test bench doesn't seem to be going into the process: the outputs aren't changing at all and I can't understand why. Can anyone tell me why?
////////////////////////////////////////////fixed
module registermemory(
input [3:0]Ra, Rb, Wa, Wd,
input write, input clk,
output [3:0] A,B
);
reg [15:0] memarray [3:0];
integer i;
initial begin
for(i=0;i<=15;i=i+1)
memarray[i]<=4'b0101; ///when the entire 2D array has same value?
end
integer r1,r2,w1;
always#(clk)
begin
r1=Ra;r2=Rb;w1=Wa;
end
assign A = memarray[r1];
assign B = memarray[r2];//assign used outside always. equal to used inside always.
always#(Wd)
begin
if(write)
memarray[w1]=Wd;
end
endmodule
///////////////////////////////
module controlblock(opcode,cntrl,Ra,Rb,Wa,write);
input [13:0]opcode;
output reg[1:0]cntrl;
output reg[3:0]Ra;
output reg[3:0]Rb;
output reg[3:0]Wa;
output reg write; //control signal tells that register has to be written in reg file
always#(opcode) ///why #opcode tho?
begin
cntrl=opcode[13:12];
Ra=opcode[11:8];
Rb=opcode[7:4];
Wa=opcode[3:0];
write=1; //why tho?
end
endmodule
///////////////////////////////
module alu_arith(input[3:0]A, input[1:0] cntrl,
input clk,
input[3:0]B,
output reg[3:0]Wd
);
always#(clk)
begin
case(cntrl)
00:Wd=A+B;
01:Wd=A-B;
10:Wd=A*B;
11:Wd=A/B;
default: Wd=4'b0000;
endcase
end
endmodule
///////////////////////////////////////////////////////
module concat(input [0:13]opcode, input clk, output[3:0]Wd);
wire[3:0]Ra;wire[3:0]Rb;wire[3:0]Wa;wire written;wire[1:0]cntrl;
wire[3:0]A;wire[3:0]B;wire[3:0]Wd;
controlblock a1(opcode,cntrl,Ra,Rb,Wa,write); //
registermemory a2(Ra, Rb, Wa, Wd,write,clk,A,B
); //
alu_arith a3(A,cntrl,clk,B,Wd); //
endmodule
//////////////////////////////////////////////////////////////
module testbench;
reg clk;
reg[13:0]opcode;
wire[3:0]Wd;
wire[1:0] cntrl;
reg[3:0]A,B;
concat a4(opcode,clk,Wd);
initial
clk=0;
always
#2 clk=!clk;
initial begin
$display("\ttime \tclk \tcntrl \tA \tB \tWd ");
$monitor("%d,\t \t%b \t%b \t%b \t%b \t%b",
$time, clk, cntrl, A, B, Wd);
#10 opcode=14'b00010010110100;
#20 opcode=14'b01100010101010;
end
initial
#50 $finish;
endmodule
You declared memarray incorrectly as a 16-bit wide by 4 word deep memory. You want a 4-bit wide by 16 deep:
reg [3:0] memarray [0:15];
When I make this change, I see the Wd output changing.

Why is iverilog complaining about my testbench module?

I'm writing a verilog module for my CompSci class and this module specifically is the data memory module. Structurally and analytically, I'm looking at it and it should work based off of the other files that I have, but I'm not sure why this one specifically is acting up and giving me all x's. Hoping a fresh set of eyes can help find the error I missed. Thanks in advance.
datamem.v:
module datamem(Ina, Inb, enable, readwrite, dataOut, clk, rst);
input wire [31:0] Ina;
input wire [31:0] Inb;
input wire enable;
input wire readwrite;
input wire clk;
input wire rst;
reg [31:0] memory[0:65535];
output reg [31:0] dataOut;
always #(memory[Ina]) begin
dataOut = memory[Ina];
end
always #(posedge clk) begin
if(1'b1 == readwrite) begin
memory[Ina] = Inb;
end
end
endmodule
datamem_tb.v:
module datamem_tb();
reg [31:0] Ina;
reg [31:0] Inb;
reg enable;
reg readwrite;
reg clk;
reg rst;
wire [31:0] dataOut;
datamem DUT (Ina, Inb, enable, readwrite, dataOut, clk, rst);
initial
begin
Ina <= 32'd0;
Inb <= 32'd0;
enable <= 0;
readwrite <= 0;
#20 Ina <= 32'd1234;
#20 Inb <= 32'd1234;
#20 Ina <= 32'd0517;
#20 Inb <= 32'd10259;
end
always #(Ina or Inb)
#1 $display("| Ina = %d | Inb = %d | dataOut = %d |", Ina, Inb, dataOut);
endmodule
A few things as to why you are getting all 'x:
You never run the clock, you need to add something like the following to have the clock toggle:
initial begin
clk = 1'b0;
forever #5 clk = ~clk;
end
You never assert readwrite which is required to write to your memory module (you set it to 0 on line 20 and never change it). Without being written to, memory will retain its original value of 'x for every element
Aside from that, there are a few other issues with your module:
Use implicit sensitive lists (instead of always #(memory[inA]) use always #(*))
Use non-blocking assignment for your memory write (memory[inA] <= inB)
Consider using $monitor instead of $display for your print statements to avoid timing issues, and you only need call it at the beginning of your initial block in your testbench (http://referencedesigner.com/tutorials/verilog/verilog_09.php)
Your rst and enable arent connected to anything.
Another example of a memory unit implementation can be found here:
Data memory unit

verilog generate instances from another module in always #(posedge clk)

module save_random (clk,in,out);
parameter size=10;
parameter k=10;
input clk;
input [k-1:0] in;
output [k-1:0]out;
wire [size:0] cout;
genvar i;
generate
for(i=0;i<size;i=i+1)
begin: level1
always#(posedge clk) begin
random ins(clk,in[i],cout[i+1]);//generte 10 instances from module random to save it //in registers
end
end
endgenerate
assign cout[0]=in[0];
assign out=cout[k];
endmodule
I am just starting to learn verilog,
i have a task to write synthesis code that generate 10 random values and save each value in register or Dflipflop or sth like this.
The first(save_random) module that generate 10 instances from module random(the 2nd one) and connected ..but still have error when I am using clk input with generate i..
module random(clk,d,cout);
parameter size=8;
input [size-1:0] d;
input clk;
output [size-1:0]cout;
reg [size-1:0]cout;
integer i;
always#(posedge clk)
begin
cout<=d;
end
endmodule
You cannot instantiate modules inside an always block. As you have a module random which is a register of size size, you only need to instantiate that module inside your generate if you need more than one:
genvar i;
generate begin
for(i=0;i<size;i=i+1) begin: level1
random ins(clk,in[i],cout[i+1]);
end
end
However, note that in[i] and cout[i+1] are not an 8-bit values. So if you want to use the full 8-bit register, you need to declare them to be 10 (or 11 for cout) 8-bit vectors:
input [7:0] in [9:0];
wire [7:0] cout [10:0];
This tutorial might give you a better idea how generate blocks work: https://www.youtube.com/watch?v=5CKfP4n9ge0

< bit half-byte byte ... > memory access in 32-bit memory using verilog

This is my synthesizable memory model in Verilog.
module memory(
output reg [31:0] data_out,
input [31:0] address,
input [31:0] data_in,
input write_enable,
input clk
);
reg [31:0] memory [0:255];
always #(posedge clk) begin
if (write_enable) begin
memory[address] <= data_in;
end
data_out <= memory[address];
end
endmodule
For example:
memory[32'h10] contains 0xAAAAAAAA
I just want to write one byte of data 0xFF in memory address 0x10 so that
memory[32'h10] contains 0xFFAAAAAA
Can you recommend a good way to change my code so that I can access only one bit, half-byte, byte, halfword, or word in my memory module?
You only declared 256 words of 32-bits, but your address bus is 32-bits wide, allowing up to 2^32 words of 32-bits. You might want to reduce your address bus width to 8-bits to match the number of words you declared.
For Xilinx FPGAs I use the CORE Generator tool to instantiate one or more BlockRAMs of the right width and depth. BlockRAMs have an option to support individual byte enables.
This code might work, but I haven't tried it
module memory (
output reg [31:0] data_out,
input [7:0] address,
input [31:0] data_in,
input [3:0] write_enable,
input clk
);
reg [31:0] memory [0:255];
reg [31:0] memory_in = 0; // wire reg
always #* begin : combinational_logic
memory_in = memory[address];
if (write_enable[3])
memory_in[31:24] = data_in[31:24];
if (write_enable[2])
memory_in[23:16] = data_in[23:16];
if (write_enable[1])
memory_in[15:8] = data_in[15:8];
if (write_enable[0])
memory_in[7:0] = data_in[7:0];
end
always #(posedge clk) begin : sequential_logic
if (|write_enable) begin
memory[address] <= memory_in;
end
data_out <= memory[address];
end
endmodule
What 'a good way' is depends on your synthesis target. If it's an FPGA you should consider that bit-wise write access for large memories is generally not a good idea. This will possibly prevent the memory from mapping to RAM resources, dramatically increasing routing costs.
Byte enables are generally directly supported. You can view the Xilinx coding guidelines here where it describes byte enables on page 159.

Resources