Mips DataMemory with Verilog - verilog

I'm trying to make MIPS Data Memory with Verilog.
The code does not work properly. It is unable to read and write as of right now. I thought the code that I made is correct, but if there is any flaw in here, please make it work. The code below is what I made and used.
//WORD_LEN = 32
//MEM_CELL_SIZE = 8
//DATA_MEM_SIZE = 1024
module DataMemory(CLK, rst, Addr, WriteData, ReadData, MemRead, MemWrite);
input CLK, rst;
input MemRead, MemWrite; //switch
input [`WORD_LEN-1:0] Addr, WriteData;
output reg[`WORD_LEN-1:0] ReadData;
reg [`MEM_CELL_SIZE-1:0] DataMem [0:`DATA_MEM_SIZE];
wire [`WORD_LEN-1:0] Pointer;
integer i;
always #(negedge CLK) //Write on memory needs CLK
begin
if(rst)
for (i = 0; i < `DATA_MEM_SIZE; i = i + 1)
DataMem[i] <= 0;
/*
// Identify each DataMem
*/
else if(MemWrite == 1 && MemRead == 0) // Store Word
{DataMem[Pointer], DataMem[Pointer+1], DataMem[Pointer+2], DataMem[Pointer+3]} <= WriteData;
else if(MemWrite == 0 && MemRead == 1) // Load Word
ReadData <= ((Addr >= 1024) ? 0 : {DataMem[Pointer], DataMem[Pointer+1], DataMem[Pointer+2], DataMem[Pointer+3]});
end
// Pointer must be added 4 shifter >>2 << 2 helps to flush 1~3
assign Pointer = (Addr >> 2) << 2;
endmodule
And Testbench which I use below here.
`include "Defines.v"
//WORD_LEN = 32
//MEM_CELL_SIZE = 8
//DATA_MEM_SIZE = 1024
module DataMemoryTest;
reg CLK, rst;
reg MemRead, MemWrite;
reg [`WORD_LEN-1:0] Addr, WriteData;
wire [`WORD_LEN-1:0]ReadData;
DataMemory TestDataMemory(.CLK(CLK), .rst(rst), .Addr(Addr), .WriteData(WriteData),
.ReadData(ReadData), .MemRead(MemRead), .MemWrite(MemWrite));
initial begin
CLK = 1;
repeat(5000) #50 CLK = ~CLK;
end
initial begin
rst = 1;
#100;
MemRead = 0;
MemWrite = 1;
Addr = 32'd0;
WriteData = 32'd123;
#100;
MemRead = 0;
MemWrite = 1;
Addr = 32'd4;
WriteData = 0;
#100;
MemRead = 0;
MemWrite = 1;
Addr = 32'd8;
WriteData = 32'd17;
#100;
MemRead = 1;
MemWrite = 0;
Addr = 32'd12;
WriteData = 32'd123;
#100;
MemRead = 1;
MemWrite = 0;
Addr = 32'd16;
WriteData = 0;
#100;
MemRead = 1;
MemWrite = 0;
Addr = 32'd20;
WriteData = 32'd17;
end
endmodule

The testbench keeps the design in reset. You need to set rst=0 after some delay.
initial begin
rst = 1;
#500;
rst = 0;
#100;
MemRead = 0;
MemWrite = 1;
Addr = 32'd0;
WriteData = 32'd123;

Related

Sync RAM related

I am trying to simulate the following code for an synchronous ram in Verilog.
When I am trying to write in a specific address, dataOut is not coming the way I was expecting. It is skipping 1 address while reading data in the specified address.
Can anyone tell me the problem?
Here is GtkWave simulation result:
module ram
# (parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 10,
parameter DEPTH = 1 << ADDR_WIDTH
)
( input clk,
input [ADDR_WIDTH-1:0] addr,
input [DATA_WIDTH-1:0] dataIn,
input enable,
input write,
input read,
input resetRam,
output[DATA_WIDTH-1:0] dataOut
);
reg [DATA_WIDTH-1:0] tmp_data;
reg [DATA_WIDTH-1:0] mem [DEPTH-1:0];
//reset
always #(posedge clk) begin
if(enable & resetRam) begin
for (integer i = 0; i < 2**ADDR_WIDTH; i = i + 1)
begin
mem[i] = {DATA_WIDTH{1'b0}};
end
end
end
//write
always # (posedge clk) begin
if (enable & write & !read)
mem[addr] <= dataIn;
end
//read
always # (posedge clk) begin
if (enable & !write & read)
tmp_data <= mem[addr];
end
assign dataOut = enable & read & !write ? tmp_data : 'hz || enable & resetRam ? 10'b0 : 'hz;
endmodule
module ram_tb;
parameter ADDR_WIDTH = 4;
parameter DATA_WIDTH = 10;
parameter DEPTH = 1 << ADDR_WIDTH;
reg clk;
reg enable;
reg write;
reg read;
reg resetRam;
reg [ADDR_WIDTH-1:0] addr;
wire [DATA_WIDTH-1:0] dataIn;
wire [DATA_WIDTH-1:0] dataOut;
reg [DATA_WIDTH-1:0] tb_data;
ram #(.DATA_WIDTH(DATA_WIDTH)) iram(
.clk(clk),
.addr(addr),
.dataIn(dataIn),
.enable(enable),
.write(write),
.read(read),
.resetRam(resetRam),
.dataOut(dataOut)
);
always #10 clk = ~clk;
assign dataIn = !read ? tb_data : 'hz ;
initial begin
$monitor("addrs = %b resetRam=%b Write = %b read=%b dataIn = %b dataOut = %b", addr,resetRam,write,read,dataIn,dataOut);
$dumpfile("ram_tb.vcd");
$dumpvars(0,ram_tb);
{clk, enable, write, addr, tb_data, read,resetRam} <= 0;
// //writing all the adrress with random value
// for (integer i = 0; i < DEPTH; i= i+1) begin
// #(posedge clk) addr <= i; write = 1; enable =1; read = 0; tb_data <= $random;
// end
// //reading them
// for (integer i = 0; i < DEPTH; i= i+1) begin
// #(posedge clk) addr = i; write = 0; enable = 1; read = 1;
// end
//Writing at specific address
#(posedge clk) addr = 4'b1000; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b1111; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b1001; write = 1; enable =1; read = 0; tb_data <= $random;
#(posedge clk) addr = 4'b0001; write = 1; enable =1; read = 0; tb_data <= $random;
//reading them
#(posedge clk) addr = 4'b1000;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b1111;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b1001;write = 0; enable =1; read = 1;
#(posedge clk) addr = 4'b0001;write = 0; enable =1; read = 1;
// //reset memory
// for (integer i = 0; i < DEPTH; i= i+1) begin
// repeat (1) #(posedge clk) addr <= i; enable <= 1; resetRam <=1;
// end
#200 $finish;
end
endmodule
//iverilog -o ram_tb.vpp ram.v
//vvp ram_tb.vpp
You have a race condition. You should use nonblocking assignments (<=) in your design and testbench for all synchronous signals.
In the design, change:
mem[i] = {DATA_WIDTH{1'b0}};
to:
mem[i] <= {DATA_WIDTH{1'b0}};
In the testbench, use:
//Writing at specific address
#(posedge clk) addr <= 4'b1000; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b1111; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b1001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
#(posedge clk) addr <= 4'b0001; write <= 1; enable <=1; read <= 0; tb_data <= $random;
//reading them
#(posedge clk) addr <= 4'b1000;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b1111;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b1001;write <= 0; enable <=1; read <= 1;
#(posedge clk) addr <= 4'b0001;write <= 0; enable <=1; read <= 1;
With the above changes, I get your expected output with iverilog on edaplayground.

Verilog if statement inconsistency

I'm trying to write a simple 4-bit stack of depth 8 with push/pop signals but it's behaving in a very odd manner. One of my if statements works fine and the other one does not run at all. Here's my code:
module Stack_8x4(
input wire clk,
input wire reset,
input wire push,
input wire pop,
input wire [3:0] data_in,
output reg [3:0] data_out,
output reg empty,
output reg full
);
reg [3:0] index;
reg [3:0] stack [7:0];
always #(posedge reset) begin
index <= -1;
data_out = 4'd0;
empty = 1;
full = 0;
end
always #(posedge clk) begin
if (push & !pop) begin
empty = 0;
if(!full) begin
index = index + 1;
stack[index] = data_in;
if(index > 6) full = 1;
end
end
if (pop & !push) begin
full = 0;
if(!empty) begin
data_out = stack[index];
index = index - 1;
if(index < 0) empty= 1;
end else data_out = 0;
end
end
endmodule
As you can see, the logic for push and pop is almost the same. My question is why does the line if(index < 0) empty= 1; does not work while if(index > 6) full = 1; works just fine?
Here's a test bench and simulation for more details:
module sim();
reg clk;
reg reset;
reg push;
reg pop;
reg [3:0] data_in;
wire [3:0] data_out;
wire full;
wire empty;
//wire [3:0]i;
always begin
clk = 0;
#5
clk = 1;
#5
clk = 0;
end
initial begin
// setup
reset = 1;
push = 0;
pop = 0;
data_in = 0;
#10
reset = 0;
// idle
#20
// push 1, 2, 3, 4, 5, 6, 7, 8, 9 to fill the module and test for idling at full
push = 1;
data_in = 1;
#10
data_in = 2;
#10
data_in = 3;
#10
data_in = 4;
#10
data_in = 5;
#10
data_in = 6;
#10
data_in = 7;
#10
data_in = 8;
#10
data_in = 9;
#10
data_in = 10;
#10
data_in = 11;
#10
pop = 1;
#10
push = 0;
#30
pop = 0;
push = 1;
#30
push = 0;
#20
pop = 1;
// pop
//pop = 1;
end
Stack_8x4 S (
.clk(clk),
.push(push),
.pop(pop),
.reset(reset),
.data_in(data_in),
.data_out(data_out),
.full(full),
.empty(empty)
);
endmodule
Your main issue is in the attempt to use signed data with unsigned variables. So, index <= -1;, index < 0 just do not work as you expect. My suggestion is to forget about signed arithmetic and do unsigned only.
Other issues:
you should use only a single always block to do reset and non-reset work.
you should use non-blocking assignments everywhere in your always #posedge blocks
for some reason you do not use 2 elements in your stack (6, 7) due to 'index < 6'.
So, here is my re-write of your code:
always #(posedge clk) begin
if (reset) begin
index <= 0;
data_out <= 4'd0;
empty <= 1;
full <= 0;
end
else if (push & !pop) begin
if(index < 8) begin
full<= 0;
stack[index] <= data_in;
index <= index + 1;
end
else
full <= 1;
end
else if (pop & !push) begin
if(index == 0) begin
empty <= 1;
data_out <= 0;
end
else begin
empty <= 0;
index <= index - 1;
data_out <= stack[index];
end
end // if (pop & !push)
end // always # (posedge clk)

Illegal reference to net rddata in FIFO

The below code is for a FIFO. It is showing an error as illegal reference to net datatype as rddata at line 38 in tb (highlighted by adding a comment "//error line").
Why do I get this error?
module fifo(clk,rst,error,empty,full,rddata,wrdata,wr_en,rd_en);
parameter WIDTH = 8;
parameter DEPTH = 16;
input clk,rst,rd_en,wr_en;
input [WIDTH-1:0]wrdata;
output reg [WIDTH-1:0]rddata;
output reg empty,full,error;
reg [WIDTH-1:0]mem[DEPTH-1:0];
reg [3:0]rd_ptr;
reg [3:0]wr_ptr;
reg wr_toggle,rd_toggle;
integer i;
always#(posedge clk)
begin
if(rst==1)
begin
empty = 1;
full = 0;
error = 0;
rd_ptr = 0;
wr_ptr = 0;
wr_toggle = 0;
rd_toggle = 0;
for(i=1;i<DEPTH;i=i+1)
begin
mem[i] = 0;
end
end
else
begin
if(wr_en ==1)begin
if(full==1)begin
$display("ERROR:Writing to full FIFO");
error = 1;
end
else
begin
mem[wr_ptr] = wrdata;
if(wr_ptr == DEPTH-1)begin
wr_toggle = ~wr_toggle;
wr_ptr = 0;
end
else begin
wr_ptr = wr_ptr + 1;
end
end
end
if(rd_en ==1)begin
if(empty==1)begin
$display("ERROR:REading from EMPTY FIFO");
error = 1;
end
end
else
begin
mem[rd_ptr] = rddata;
if(rd_ptr == DEPTH-1)begin
rd_toggle = ~rd_toggle;
rd_ptr = 0;
end
else begin
rd_ptr = rd_ptr + 1;
end
end
end
end
always#(wr_ptr or rd_ptr)
begin
full = 0;
empty = 0;
if(wr_ptr == rd_ptr && wr_toggle == rd_toggle)begin
empty = 1;
full = 0;
end
if(wr_ptr == rd_ptr && wr_toggle != rd_toggle)begin
empty = 0;
full = 1;
end
end
endmodule
//TEST BENCH
`include "fifo.v"
module tbfifo();
parameter WIDTH = 8;
parameter DEPTH = 16;
reg clk,rst,rd_en,wr_en;
reg [WIDTH-1:0]wrdata;
wire [WIDTH-1:0]rddata;
wire empty,full,error;
integer i;
fifo_buff dut (clk,rst,error,empty,full,rddata,wrdata,wr_en,rd_en);
initial
begin
clk = 0;
forever #5 clk = ~clk;
end
initial
begin
rst = 1;
repeat(2) #(posedge clk);
rst = 0;
for(i=0;i<DEPTH;i=i+1)begin
#(posedge clk);
wr_en = 1;
wrdata = $random;
end
#(posedge clk);
wr_en = 0;
wrdata= 0;
for(i=0;i<DEPTH;i=i+1)begin
#(posedge clk);
rd_en = 1;
rddata <= $random; //error line
end
#(posedge clk);
rd_en = 0;
#100;
$finish;
end
endmodule
rddata is an output port of the fifo_buff module. In the testbench, there is a wire named rddata which connects to the fifo instance.
The problem is that the testbench then tries to drive the signal:
rddata <= $random; //error line
That is illegal. You can not make a procedural assignment (inside an initial block, for example) to a wire. And, you should not try to drive that signal from the testbench since it is already driven by the module instance, because that would results in multiple drivers (contention). You must remove this line.
for (i=0; i<DEPTH; i=i+1) begin
#(posedge clk);
rd_en = 1;
end
#(posedge clk);
rd_en = 0;
Typically, you would monitor an output signal in the testbench (display its value or compare it against a reference model). This is usually done in a separate process (always block, for example) from the input driving process.

Pattern Generator (verilog)

I need to program a sequential circuit in Verilog code as a pattern generator which generates, instead of binary counts, your Firstname (space) Lastname (space), character by character. I need to display the pattern sequence for at least two cycles.
diagram
This is the sample output:
sampleoutput
I know that the issue my program has is in the CoderMod module, but I'm not sure where the issues are.
Thanks for the help!
//pattern.v
module TestMod;
reg CLK;
wire [0:11] Q;
wire [6:0] ascii;
initial begin
#1;
forever begin
CLK=0;
#1;
CLK=1;
#1;
end
end
RippleMod my_ripple(CLK, Q);
CoderMod my_coder(Q, ascii);
initial #27 $finish;
initial begin
$display("Time CLK Q Name");
$monitor("%4d %b %b %c %x %b", $time, CLK, Q, ascii, ascii, ascii);
end
endmodule
module CoderMod(Q, ascii);
input [0:13]Q;
output [13:0] ascii;
assign ascii[0] = "F";
assign ascii[1] = "i";
assign ascii[2] = "r";
assign ascii[3] = "s";
assign ascii[4] = "t";
assign ascii[5] = " ";
assign ascii[6] = "L";
assign ascii[7] = "a";
assign ascii[8] = "s";
assign ascii[9] = "t";
assign ascii[10] = "n";
assign ascii[11] = "a";
assign ascii[12] = "m";
assign ascii[13] = "e";
or(ascii[0], Q[13]);
or(ascii[1], Q[12]);
or(ascii[2], Q[11]);
or(ascii[3], Q[10]);
or(ascii[4], Q[9]);
or(ascii[5], Q[8]);
or(ascii[6], Q[7]);
or(ascii[7], Q[6]);
or(ascii[8], Q[5]);
or(ascii[9], Q[4]);
or(ascii[10], Q[3]);
or(ascii[11], Q[2]);
or(ascii[12], Q[1]);
or(ascii[13], Q[0]);
endmodule
module RippleMod(CLK, Q);
input CLK;
output [0:15]Q;
reg [0:15]Q;
always #(posedge CLK) begin
Q[0] <= Q[15];
Q[1] <= Q[0];
Q[2] <= Q[1];
Q[3] <= Q[2];
Q[4] <= Q[3];
Q[5] <= Q[4];
Q[6] <= Q[5];
Q[7] <= Q[6];
Q[8] <= Q[7];
Q[9] <= Q[8];
Q[10] <= Q[9];
Q[11] <= Q[10];
Q[12] <= Q[11];
Q[13] <= Q[12];
Q[14] <= Q[13];
Q[15] <= Q[14];
end
initial begin
Q[0] = 1;
Q[1] = 0;
Q[2] = 0;
Q[3] = 0;
Q[4] = 0;
Q[5] = 0;
Q[6] = 0;
Q[7] = 0;
Q[8] = 0;
Q[9] = 0;
Q[10] = 0;
Q[11] = 0;
Q[12] = 0;
Q[13] = 0;
Q[14] = 0;
Q[15] = 0;
end
endmodule
There are actually multiple issues with your program. i.e. you declare an ascii arraya as wire [6:0] ascii; but later you connect it to the module as CoderMod my_coder(Q, ascii); where it is an output port of width 14. You also assig 8-bit characters to a one-bit ascii, like here: ascii[1] = "i";
as a hint, you need to declare it as
wire [6:0] ascii [13:0];
you shold be able to figure out the rest.

Programming help for Verilog beginner. Debugging in ISE

I have experience in VHDL and SystemC, and now I'm training to learn Verilog, but I'm having trouble getting started.
I'm currently trying to make a 8 bit adder.
module alu(
input [7:0] a,
input [7:0] b,
input clk,
input op,
output reg [7:0] out,
output reg overflow
);
integer myA;
integer myB;
always #(negedge clk)
begin
myA = a;
myB = b;
overflow = 0;
if (op == 0) begin
//Subtract
out = myA - myB;
if (myA - myB <0) begin
overflow = 1;
end
end
else begin
//Add
out = myA + myB;
if (myA + myB > 255) begin
overflow = 1;
end
end
end
endmodule
But in testing it doesn't work properly.
I used ISE to generate a test bench, and since I don't know how to setup a clock, I set it up manually:
// Add stimulus here
a = 255;
b = 45;
clk = 1;
op = 1;
#100
clk = 0;
// Add stimulus here
a = 0;
b = 255;
clk = 1;
op = 1;
#100
clk = 0;
// Add stimulus here
a = 255;
b = 0;
clk = 1;
op = 0;
#100
clk = 0;
// Add stimulus here
a = 90;
b = 45;
clk = 1;
op = 1;
#100
clk = 0;
The last instruction, 45+90 gives me the correct result, but every other result gives me 0.
I've tried several variations of the main if, but there always errors in the output.
if (op == 0) begin
out = a + b;
if (myA-myB <0) begin
//overflow
out = 7;
end
end else begin
out = a-b;
if (myA+myB>255) begin
//overflow
out = 8;
end
end
Here's the full test bench code. Edited to include #100 between clk = 0 and clk = 1.
`timescale 1ns / 1ps
module a;
// Inputs
reg [7:0] a;
reg [7:0] b;
reg clk;
reg op;
// Outputs
wire [7:0] out;
// Instantiate the Unit Under Test (UUT)
alu uut (
.a(a),
.b(b),
.clk(clk),
.op(op),
.out(out)
);
initial begin
// Initialize Inputs
a = 0;
b = 0;
clk = 0;
op = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
a = 55;
b = 45;
clk = 1;
op = 1;
#100
clk = 0;
#100
// Add stimulus here
a = 255;
b = 45;
clk = 1;
op = 1;
#100
clk = 0;
#100
// Add stimulus here
a = 0;
b = 255;
clk = 1;
op = 1;
#100
clk = 0;
#100
// Add stimulus here
a = 255;
b = 0;
clk = 1;
op = 0;
#100
clk = 0;
#100
// Add stimulus here
a = 90;
b = 45;
clk = 1;
op = 1;
#100
clk = 0;
#100
end
endmodule
#X in Verilog means "delay X time steps before continuing". So in your code
#100
clk = 0;
// Add stimulus here
a = 255;
b = 0;
clk = 1;
there's no delay between the clock going low and going high again, which might be your problem. Try adding a #100 somewhere between clk = 0; and clk = 1;
Just a tip. I think in most cases the clock is created in an always block and then the inputs are changed in another initial block so
always begin
#5 clk = ~ clk; // here the clock period is 10
end
initial begin
clk = 0;
a = 255;
b = 45;
op = 1;
#10;
a = 90;
b = 45;
op = 1;
end

Resources