I have a question related to a Verilog implementation of an SRAM memory. Module sram_1port is supposed to be a clocked address addressable SRAM memory which has a read enable signal and a write enable signal. Module control_sram is supposed to read/write data in SRAM. Data is stored contiguously, at consecutive memory addresses. The issue occurs when I try to simulate the circuit behaviour, thus the rd_data signal is undetermined during the whole simulation. So, the memory content couldn't be output, and I don't even know why. Is there a problem when data is stored, or when the content should be output, or both are problematic?
module sram_1port(
input clk,
input [15:0] address,
input wr,rd,
input [2:0] wr_data,
output reg [2:0] rd_data
);
reg [2:0] mem_reg [15:0];
always # (posedge clk) begin
if(wr) mem_reg[address] <= wr_data;
else if(rd) rd_data <= mem_reg[address];
end
endmodule
//automaton
module control_sram(
input clk, wr, rd,
input [2:0] wr_data,//read 1 instruction/clk
output [2:0] rd_data,//output
output reg [15:0] out//outputs address
);
reg [15:0] address,address_rd,address_wr;
initial address = 16'd0;
initial address_wr = 16'd0;
initial address_rd = 16'd0;
sram_1port i0(.clk(clk),.address(address),.wr(wr),
.rd(rd),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(wr) begin
address_wr = address_wr + 1;
address = address_wr;
address_rd = 16'd0;
end
else if(rd) begin
address_rd = address_rd + 1;
address = address_rd;
address_wr = 16'd0;
end
end
always # * out = address;
endmodule
//tb for control_sram
module control_sram_tb(
output reg clk,wr,rd,
output reg [2:0] wr_data,
output [2:0] rd_data,
output [15:0] out
);
control_sram cut(.clk(clk),.wr(wr),.rd(rd),.wr_data(wr_data),
.rd_data(rd_data),.out(out));
initial $dumpvars(0,control_sram_tb);
initial begin
clk = 1'd1;
repeat (260000)
#100 clk = ~clk;
end
initial begin
wr_data = 3'd1;
#3000000 wr_data = 3'd2;
#1000000 wr_data = 3'd1;
#3000000 wr_data = 3'd0;
#2000000 wr_data = 3'd3;
#1000000 wr_data = 3'd1;
end
initial begin
rd = 1'b0;
#13000000 rd = 1'b1;
end
initial begin
wr = 1'b1;
#13000000 wr = 1'b0;
end
endmodule
When I run your simulation, I see rd_data go from X to 1 at time 13_000_200ns, and it stays at 1 for 3_000ns, then it returns to X. You should see that if you zoom in on your waveforms to that time interval. If you don't see that with icarus, run your simulation on edaplayground with different simulators.
Also, you declared your memory (mem_reg) to have 16 locations ([15:0]). However, I see your address take on the values of 17, 18, 19, etc. for your writes and reads. It seems strange that you are trying to access locations that are not in your memory. When you do this for reads, you get X (as expected). It seems like you only need a 4-bit address, not a 16-bit address.
Related
I created a microsystem which is composed of two clocked SRAMs, one designed for storing instruction-codes, and another to store some output values. The instruction SRAM has an interface module, named "user" which provides a mechanism to ease the writing process, consequently, when writing data in the memory, there is no need to specify the corresponding memory address at which those instructions have to be stored. Similarly, when reading data from the second SRAM, there is no need to specify the corresponding memory address from which data is extracted, thanks to "display" module. To be more specific, when writing data in the instructions memory, a counter increments the address pointer after each writing, while the second memory has another counter which increments the address pointer value after each reading. When one tries to read information from the instruction memory, they have to specify the memory address from which data should be read, and, as expected, when one tries to write information in the output memory, they have to specify the memory address in which data should be written. Furthermore, the microsystem has an automaton which takes input data from the instruction memory and processes it. After processing information, the automaton stores some output values in the output memory. I come across an issue when simulating, because, apparently, the read values from the SRAM memory cannot be seen, namely, rd_data_instrucions, thus, neither the input values "in" for the automaton cannot be found, nor the output values, as long as they depend on the data read from the first SRAM. I posted the code below and a diagram.
//wishbone module
module wishbone(
input clk,rst,
output reg [2:0]in,
output reg wr_en_instructions,wr_en_display,
input [2:0] wr_data_instructions,//created for usr, in order to make possible to write data
output reg [3:0] wr_data_display,
output [2:0] rd_data_instructions,
output [3:0] rd_data_display,//created for user, in order to make possible the display
output [12:0]o
);
reg [15:0] pointer_instructions,pointer_display;
initial wr_en_instructions = 1'b1;//?
control_unit i0(.clk(clk),.rst(rst),.in(in),.o(o));
user i1(.clk(clk),.wr_en(wr_en_instructions),.address_in(pointer_instructions),.wr_data(wr_data_instructions),.rd_data(rd_data_instructions));
display i2(.clk(clk),.wr_en(wr_en_display),.address_in(pointer_display),.wr_data(wr_data_display),.rd_data(rd_data_display));
integer i = 0;
always # * begin
wr_en_display = ~wr_en_instructions;
end
always #(posedge clk) begin
if(rst) begin
wr_en_instructions <= 1'b1;
pointer_instructions <= 16'd0;
pointer_display <= 16'd0;
end
else begin
if(wr_en_instructions) begin
if(wr_data_instructions[2] == 1'b1) begin
pointer_instructions <= 16'd0;
pointer_display <= 16'd0;
wr_en_instructions <= 1'b0;
end
end
else begin
in <= rd_data_instructions;
pointer_instructions <= pointer_instructions + 1;
if(rd_data_instructions == 3'b010) begin
wr_data_display <= o;
pointer_display <= pointer_display + 1;
end
else if(rd_data_instructions == 3'b100) begin
wr_en_instructions <= 1'b1;
end
end
end
end
endmodule
//testbench for top module
module wishbone_tb(
output reg clk,rst,
output [2:0]in,
output wr_en_instructions,wr_en_display,
output reg [2:0] wr_data_instructions,//created for usr, in order to make possible to write data
output [3:0] wr_data_display,
output [2:0] rd_data_instructions,
output [3:0] rd_data_display,//created for user, in order to make possible the display
output [12:0]o
);
wishbone cut(
.clk(clk),.rst(rst),
.in(in),
.wr_en_instructions(wr_en_instructions),.wr_en_display(wr_en_display),
.wr_data_instructions(wr_data_instructions),
.wr_data_display(wr_data_display),
.rd_data_instructions(rd_data_instructions),
.rd_data_display(rd_data_display),
.o(o)
);
initial $dumpvars(0,wishbone_tb);
initial begin
clk = 1'b1;
repeat (600000)
#100 clk = ~clk;
end
initial begin
rst = 1'b1;
#400 rst = 1'b0;
end
initial begin
wr_data_instructions = 3'd1;
#3000400 wr_data_instructions = 3'd2;
#1000000 wr_data_instructions = 3'd1;
#3000000 wr_data_instructions = 3'd0;
#2000000 wr_data_instructions = 3'd3;
#1000000 wr_data_instructions = 3'd1;
#3000000 wr_data_instructions = 3'd4;//halt
end
endmodule
//code for the first memory:
//stores instructions
module sram_1port_instructions(
input clk,//clocked memory
input wr_en,//when high, data is writeen, otherwise is read
input [15:0] address_in,//suppose timer cannot count more than 13ms
input [2:0] wr_data,//3 bit instructions
output reg [2:0] rd_data
);
reg [2:0] memory [2 ** 15 - 1 : 0];
always #(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//user interface designed for the first memory
module user(
input clk,
input wr_en,
input [15:0] address_in,
input [2:0] wr_data,
output [2:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_instructions i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else begin
address <= address_in;
pointer <= 16'd0;
end
end
endmodule
//user tb
module user_tb(
output reg clk, wr_en,
output reg [15:0] address_in,
output reg [2:0] wr_data,
output [2:0] rd_data
);
user cut(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,user_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 wr_data = i;
end
end
initial begin
address_in = 16'd0;
#100000 address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 address_in = i;
end
end
endmodule
//code for the second memory:
//stores output data
module sram_1port_data(
input clk,//clocked memory
input wr_en,//when high, data is written, otherwise is read
input [15:0] address_in,//suppose timer cannout count more than 13ms
input [3:0] wr_data,//memory does not sotre values greater than 13(ms)
output reg [3:0] rd_data
);
reg [3:0] memory [2 ** 15 - 1 : 0];
always #(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//display interfacedesigned for the second memory
module display(
input clk,
input wr_en,
input [15:0] address_in,
input [3:0] wr_data,
output [3:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_data i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(!wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else begin
address <= address_in;
pointer <= 16'd0;
end
end
endmodule
//tb for display
module display_tb(
output reg clk,
output reg wr_en,
output reg [15:0] address_in,
output reg [3:0] wr_data,
output [3:0] rd_data
);
display i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,display_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200;
wr_data = i;
address_in = i;
end
end
endmodule
//code for the control unit:
//control unit
module control_unit(
input clk,rst,
input [2:0]in,
output [12:0]o
);
wire f,g;
automaton i0(.clk(clk),.rst(rst),.in(in),.clr(f),.en(g));
circuit i1(.clk(clk),.clr(f),.en(g),.o(o));
endmodule
//code for automaton:
//atuomaton
module automaton(
input clk,rst,
input [2:0]in,
output reg clr,en
);
localparam S0_ST = 2'b00;
localparam S1_ST = 2'b01;
localparam S2_ST = 2'b10;
reg [1:0] st_reg,st_nxt;
always # * begin
case(st_reg)
S0_ST: if(!in[1]) st_nxt = S0_ST;
else if(in[0]) st_nxt = S2_ST;
else st_nxt = S1_ST;
S1_ST: if(!in[0]) st_nxt = S1_ST;
else if(in[1]) st_nxt = S2_ST;
else st_nxt = S0_ST;
S2_ST: if(in == 2'd1) st_nxt = S0_ST;
else st_nxt = S2_ST;
endcase
end
always # * begin
case(st_reg)
S0_ST: {clr,en} = 2'd1;
S1_ST: {clr,en} = 2'd0;
S2_ST: clr = 1'd1;
endcase
end
always #(posedge clk) begin
if(rst) st_reg <= S2_ST;
else st_reg <= st_nxt;
end
endmodule
//code for circuit:
//circuit
module circuit(
input clk,clr,en,
output [12:0] o
);
wire f;
generator i0(.clk(clk),.clr(clr),.en(en),.o(f));
counter i1(.clk(clk),.clr(clr),.en(f),.o(o));
endmodule
//code for counter:
//counter
module counter(
input clk,clr,en,
output reg [12:0] o
);
reg [12:0] st_nxt;
always # (posedge clk) begin
if(clr) o <= 13'd0;
else o <= st_nxt;
end
always # *
if(en) st_nxt = o + 1;
else st_nxt = o;
endmodule
//code for generator:
//pulse generator
module generator(
input clk,clr,en,
output reg o
);
reg [12:0] st_reg,st_nxt;
always #(posedge clk) begin
if(clr) st_reg <= 13'd0;
else st_reg <= st_nxt;
end
always # * begin
if(en) begin
if(st_reg == 13'd4999) begin
st_nxt = 13'd0;
o = 1'b1;
end
else begin
st_nxt = st_reg + 1;
o = 1'b0;
end
end
else begin
if(st_reg == 13'd4999) begin
st_nxt = 13'd0;
o = 1'b0;
end
else begin
st_nxt = st_reg;
o = 1'b0;
end
end
end
endmodule
When you read from address 0x8001, that is beyond the limit of your memory size. You could increase your memory. Change:
reg [2:0] memory [2 ** 15 - 1 : 0];
to:
reg [2:0] memory [2 ** 16 - 1 : 0];
This gets rid of the unknown (X) when you read from address 0x8001.
Or, if you don't want to enlarge the memory, make sure you limit your addresses.
I have a question related to the implementation of a clocked SRAM memory which is is supposed to store data written by user and then display the memory content. In addition, I created a module named display which eases the reading process so that there is no need to provide the memory address from which data should be extracted, by incrementing a register after each reading. Nevertheless, when I simulate the circuit, I cannot see the correct output; thus, when I read the memory, I notice some undefined output sequences. I posted the corresponding code below.
//stores output data
module sram_1port_data(
input clk,//clocked memory
input wr_en,//when high, data is written, otherwise is read
input [15:0] address_in,//suppose timer cannout count more than 13ms
input [3:0] wr_data,//memory does not sotre values greater than 13(ms)
output reg [3:0] rd_data
);
reg [3:0] memory [2 ** 15 - 1 : 0];
always #(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//display interfacedesigned for the second memory
module display(
input clk,
input wr_en,
input [15:0] address_in,
input [3:0] wr_data,
output [3:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_data i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(!wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else address <= address_in;
end
endmodule
//tb for display
module display_tb(
output reg clk,
output reg wr_en,
output reg [15:0] address_in,
output reg [3:0] wr_data,
output [3:0] rd_data
);
display i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,display_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 wr_data = i;
end
end
initial begin
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 address_in = i;
end
end
endmodule
When I look at waveforms, I see that rd_data is unknown (X) on every other read. Looking at an internal address signal, I see that the unknowns are only for even addresses. Early in the simulation, you are only writing to even addresses.
In your testbench, you are using the same variable (i) in 2 different for loops. In your 2nd for loop, use a different variable name (j, for example):
integer j;
initial begin
address_in = 16'd0;
for(j = 1;j < 500;j = j + 1) begin
#200 address_in = j;
end
end
Now, all reads have known values because it writes to all addresses (even and odd).
You could also set the address inside the same for loop as the write data. This is likely a better approach in this case.
initial begin
wr_data = 3'd0;
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200;
wr_data = i;
address_in = i;
end
end
I encountered an issue trying to design a SRAM memory. To be more specific, the memory is clocked, has a write enable - when high, one could write data and when low, one could read data - , an address input, which specifies the memory address to/from which data is written/read. Then, I created a module named user, which facilitates the write operation; thus, there is no need to provide a memory address when writing data.
My problem occurs when I try to simulate the circuit, because there cannot be seen anything when accessing the content of the memory. Within the test bench, I specified some values to be stored in the memory, then, I extracted data, but no success.
I attached the code here.
//stores instructions
module sram_1port_instructions(
input clk,//clocked memory
input wr_en,//when high, data is writeen, otherwise is read
input [15:0] address_in,//suppose timer cannot count more than 13ms
input [2:0] wr_data,//3 bit instructions
output reg [2:0] rd_data
);
reg [2:0] memory [2 ** 15 - 1 : 0];
always #(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//user interface designed for the first memory
module user(
input clk,
input wr_en,
input [15:0] address_in,
input [2:0] wr_data,
output [2:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_instructions i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else address <= address_in;
end
endmodule
//user tb
module user_tb(
output reg clk, wr_en,
output reg [15:0] address_in,
output reg [2:0] wr_data,
output [2:0] rd_data
);
user cut(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,user_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 wr_data = i;
end
end
initial begin
address_in = 16'd0;
#100000 address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 address_in = i;
end
end
endmodule
When I run your simulation and look at waveforms, I see rd_data=3 at time 100000. At that time, you read address 0, and that is the last value you wrote to address 0. Otherwise, all your reads of other addresses return X (unknown). When you do all your writes, you only write to address 0. From time=0 to time=100000, wr_en=1, and address_in=0 (inside your sram_1port_instructions module). You can see this when you look at the waveforms in your VCD file.
wr_data changes every clock cycle, but you write to the same address every cycle.
But, in user, if you connect the address signal to the to address_in port of the sram_1port_instructions module, you will write to different addresses.
Change:
sram_1port_instructions i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
to:
sram_1port_instructions i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
Your code has the constant address_in signal connected to the address_in port.
When I make that change, I see all different values being read from the RAM.
module testing123(Clk, Rst_n);
. . .
wire [7:0] port1_data;
wire [7:0] port2_data;
wire [7:0] port3_data;
wire [7:0] port4_data;
wire [7:0] port5_data;
wire [7:0] port6_data;
wire [7:0] port7_data;
wire [7:0] port8_data;
wire [7:0] port9_data;
wire [7:0] port10_data;
wire [7:0] port11_data;
wire [7:0] port12_data;
wire [7:0] port13_data;
wire [7:0] port14_data;
wire [7:0] port15_data;
reg [flit_port_width-1:0] flit_out1;
reg [flit_port_width-1:0] flit_out2;
reg [flit_port_width-1:0] flit_out3;
reg [flit_port_width-1:0] flit_out4;
reg [flit_port_width-1:0] flit_out5;
reg [flit_port_width-1:0] flit_out6;
reg [flit_port_width-1:0] flit_out7;
reg [flit_port_width-1:0] flit_out8;
reg [flit_port_width-1:0] flit_out9;
reg [flit_port_width-1:0] flit_out10;
reg [flit_port_width-1:0] flit_out11;
reg [flit_port_width-1:0] flit_out12;
reg [flit_port_width-1:0] flit_out13;
reg [flit_port_width-1:0] flit_out14;
reg [flit_port_width-1:0] flit_out15;
. . .
RAM_Memory #(/*addr_width*/ 32'd16,
/*data_width*/ 32'd8,
/*lo*/ 32'd0,
/*hi*/ 32'd63) Memory1(.clk(Clk)
,.rst(Rst_n)
,.flit_out(flit_out1)
,.dataout(port1_data)
);
RAM_Memory #(/*addr_width*/ 32'd16,
/*data_width*/ 32'd8,
/*lo*/ 32'd0,
/*hi*/ 32'd63) Memory2(.clk(Clk)
,.rst(Rst_n)
,.flit_out(flit_out2)
,.dataout(port2_data)
);
RAM_Memory #(/*addr_width*/ 32'd16,
/*data_width*/ 32'd8,
/*lo*/ 32'd0,
/*hi*/ 32'd63) Memory3(.clk(Clk) ...
);
. . .
endmodule
module RAM_Memory(
flit_out,
rst,
clk,
dataout
);
parameter addr_width = 1;
parameter data_width = 1;
parameter lo = 0;
parameter hi = 1;
integer count, i;
input [34:0] flit_out;
input rst,clk;
output [data_width - 1 : 0] dataout;
reg we;
reg [data_width - 1 : 0] dataout;
reg [addr_width - 1 : 0] addr;
reg [data_width - 1 : 0] data_in;
reg [data_width - 1 : 0] mem [lo:hi];
initial begin
count =0; i=0;
end
always #(posedge clk)begin
count<=count+1;
we<=0;
if(count>=1) begin
we<=1;
end
end
always #(we)begin
assign data_in = flit_out[7:0];
assign addr = flit_out[23:8];
mem[addr]<= data_in;
assign dataout = mem[addr];
end
always #(count)begin
if(count>=68)begin
count<=0;
end
end
endmodule
Here, one RAM_Memory module is given which is use in to other module testing123 by port mapping for storing data to 64 wide memory from 15 ports. But only one port memory module store 64 datas, "mem" register is not refreshing for others mapping module. Data will be loss. How to refresh the "mem" register or start from 0 value for all mapping port?
Accessing instance of one module from inside of several other modules? (verilog)
I do not fully understand the question but have spotted some errors. Your code contains :
always #(we)begin
assign data_in = flit_out[7:0];
assign addr = flit_out[23:8];
mem[addr]<= data_in;
assign dataout = mem[addr];
end
Which contains a few issues.
Your triggering the always on we but not using we inside the block. This does not represent anything in hardware. It is more likely that you want a flipflop to update when enable is high.
code example
always #(posedge clk) begin
if (en) begin
//..
end
end
Using assign inside always probably does not do what you expect.
You most likely just want :
always #* begin
data_in = filt_out[7:0]
addr = flit_out[23:8];
dataout = mem[addr];
It is best practice not to mix non-blocking (<=) and blocking (=) assignments. If they are all meant to be flipflops (#(posedge clk)) then use non-blocking (<=) if it is combinatorial (always #*) then use blocking (=).
The block of code in question would become
always #(posedge clk)begin
if (we) begin
data_in <= flit_out[7:0];
addr <= flit_out[23:8];
mem[addr] <= data_in;
dataout <= mem[addr];
end
end
Looking at the code I expect that is not what you want data_in and addr decoding should be done outside of this block.
//Semantically split the bus
assign data_in = flit_out[7:0];
assign addr = flit_out[23:8];
always #(posedge clk)begin
if (we) begin
mem[addr] <= data_in;
dataout <= mem[addr];
end
end
Some recommendations to make reading your code easier.
Using modern port declarations makes a big difference to readability.
module RAM_Memory(
flit_out,
rst,
clk,
dataout
);
parameter addr_width = 1;
parameter data_width = 1;
parameter lo = 0;
parameter hi = 1;
input [34:0] flit_out;
input rst,clk;
output [data_width - 1 : 0] dataout;
reg [data_width - 1 : 0] dataout;
becomes
module RAM_Memory#(
parameter ADDR_WIDTH = 1, //They don not have to be upper case
parameter DATA_WIDTH= 1, // But most languages semantically define upper case as constants
parameter LO = 0;
parameter HI = 1;
)(
input [34:0] flit_out,
input rst,
input clk,
output [DATA_WIDTH-1:0] dataout
);
Your instance can move from :
RAM_Memory #(/*addr_width*/ 32'd16,
/*data_width*/ 32'd8,
/*lo*/ 32'd0,
/*hi*/ 32'd63) Memory2(.clk(Clk)
,.rst(Rst_n)
,.flit_out(flit_out2)
,.dataout(port2_data)
);
to
RAM_Memory #(
.ADDR_WIDTH( 6 ), //No need to specify the width of parameter
.DATA_WIDTH( 8 ),
.LO ( 0 ),
.HI ( 63 )
) Memory2 (
.clk ( Clk )
,.rst ( Rst_n )
,.flit_out ( flit_out2 )
,.dataout ( port2_data)
);
I've been working on coding a simple stack memory. It has 4 address bits and thus can store 16 elements. Everything works fine, but the problem is that when all 16 memory elements have been written to, the counter that keeps track of the memory location overflows and resets it to 0000. I cannot find out the reason for this. All my registers are of correct width.
reg_push and reg_pop are incremented and decremented together, and these are the registers that keep track of the memory location.
Here is the simulation showing the overflow.
Here is the code:
module stack # (parameter dbits = 3, abits = 4)(
input clock,
input reset,
input push,
input pop,
input [dbits-1:0] din,
output [dbits-1:0] dout,
output full,
output empty
);
reg [dbits-1:0] regarray[2**abits-1:0]; //number of words in fifo = 2^(number of address bits)
reg [abits-1:0] reg_push, reg_pop, next_push, next_pop;
reg full_reg, empty_reg, full_next, empty_next;
reg [dbits-1:0] out;
wire wr_en;
wire db_push, db_pop;
reg dffpop1, dffpop2, dffpush1, dffpush2;
always # (posedge clock) dffpush1 <= push;
always # (posedge clock) dffpush2 <= dffpush1;
assign db_push = ~dffpush2 & dffpush1; //monostable multivibrator to detect only one pulse of the button
always # (posedge clock) dffpop1 <= pop;
always # (posedge clock) dffpop2 <= dffpop1;
assign db_pop = ~dffpop2 & dffpop1; //monostable multivibrator to detect only one pulse of the button
assign wr_en = db_push & ~full; //only push if write signal is high and stack is not full
//always block for write operation
always # (posedge clock)
if(wr_en) regarray[reg_push] = din;
//always block for read operation
always # (posedge clock)
begin
if(db_pop)
out <= regarray[reg_pop];
end
always # (posedge clock or posedge reset)
begin
if(reset)
begin
full_reg <= 0;
empty_reg <= 1;
reg_push <= 0;
reg_pop <= 0;
end
else
begin
full_reg <= full_next;//created the next registers to avoid the error of mixing blocking and non blocking assignment to the same signal
empty_reg <= empty_next;
reg_push <= next_push;
reg_pop <= next_pop;
end
end
always # (*)
begin
full_next = full_reg; //default values stay the same
empty_next = empty_reg;
next_push = reg_push;
next_pop = reg_pop;
if(db_push)
begin
if(~full) //if stack is not full continue
begin
empty_next = 0;
next_push = reg_push + 1;
next_pop = reg_pop + 1;
if(reg_push == (2**abits - 1)) full_next = 1; //all registers have been written to
end
end
else if (db_pop)
begin
if(~empty) //if stack is not empty continue
begin
full_next = 0;
next_pop = reg_pop - 1;
next_push = reg_push - 1;
if(reg_pop == 0) empty_next = 1; //all data has been read
end
end
end
assign full = full_reg;
assign empty = empty_reg;
assign dout = out;
endmodule
Now if I use this stack without making it reach its full capacity, it will work perfectly. It's only when I store all 16 elements into it that the problem arises.
Extend your pop pointer an extra bit.
A 4-bit register can only store the a value 0 through 15. Any value above that will ignore the upper bits, effectively doing a mod 16. Hence assigning 16 will result in 0.
Option 1: expand to a 5-bit register:
Try changing:
reg [abits-1:0] reg_push, reg_pop, next_push, next_pop;
To:
reg [abits:0] reg_push, reg_pop, next_push, next_pop;
Option 2: Use full_reg are the 5th bit in evaluations:
Change:
if(reg_push == (2**abits - 1)) full_next = 1; //all registers have been written to
...
if(reg_pop == 0) empty_next = 1; //all data has been read
To:
if({full_reg,reg_push} >= (2**abits - 1)) full_next = 1; //all registers have been written to
...
if({full_reg,reg_pop} == 0) empty_next = 1; //all data has been read