Sync RAM related - verilog

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.

Related

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.

Vivado just points out that there is an exception

I'm trying to write a module which performs convolution on 24 by 24 bitmap image.
And here is the DUT and testbench.
Maybe there are some problems and I spend couple of hours to find what is problem but I can't figure it out.
Additionally, RTL Anaylsis works well without any error which makes me think that there is no problem on DUT.
Is there anyone who can help me?
module top_conv(clk,resetn,start,load_image_0,load_image_1,load_image_2,done,result);
input clk,resetn,load_image_0,load_image_1,load_image_2,start;
output done,result;
reg [1:0] st;
reg [1:0] nst;
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
wire [7:0] load_image_0;
wire [7:0] load_image_1;
wire [7:0] load_image_2;
reg [7:0] result;
reg done;
integer load_cnt, row_cnt, col_cnt , result_cnt ;
parameter IDLE = 2'b00, LOAD = 2'b01, MAC = 2'b10, DONE = 2'b11;
always#(posedge clk or negedge resetn)begin
case(st)
LOAD:begin
input_buffer_0[load_cnt] <= load_image_0;
input_buffer_1[load_cnt] <= load_image_1;
input_buffer_2[load_cnt] <= load_image_2;
end
MAC:begin
input_buffer_0[0] <= input_buffer_0[1];
input_buffer_1[0] <= input_buffer_1[1];
input_buffer_2[0] <= input_buffer_2[1];
input_buffer_0[1] <= input_buffer_0[2];
input_buffer_1[1] <= input_buffer_0[2];
input_buffer_2[1] <= input_buffer_0[2];
input_buffer_0[2] <= load_image_0;
input_buffer_1[2] <= load_image_1;
input_buffer_2[2] <= load_image_2;
end
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) load_cnt <= 0;
else if(st == LOAD) load_cnt <= load_cnt + 1;
else load_cnt <= 0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= 0;
row_cnt <= 0;
end
else if(st == MAC) begin
if(col_cnt == 21) begin
col_cnt <= 0;
row_cnt <= row_cnt +1;
end
end
else begin
col_cnt <= 0;
row_cnt <= 0;
end
end
always#(posedge clk or negedge resetn)begin
if( st == MAC ) begin
result <= (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 + (input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 + (input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16;
done <= 1'b1;
end
else done <=1'b0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) st <= 0;
else st <= nst;
end
always#(*)begin
case(st)
IDLE:begin
if(start) nst = LOAD;
else nst = IDLE;
end
LOAD:begin
if(load_cnt == 2)nst = MAC;
else nst = LOAD;
end
MAC:begin
if((row_cnt == 21)&&(col_cnt == 21)) nst = DONE;
else if(col_cnt == 21) nst = LOAD;
else nst = MAC;
end
DONE:begin
nst = IDLE;
end
endcase
end
endmodule
module testbench;
reg clk,resetn,start;
reg[7:0] val;
reg [7:0] b_load_image_0,g_load_image_0,r_load_image_0;
reg [7:0] b_load_image_1,g_load_image_1,r_load_image_1;
reg [7:0] b_load_image_2,g_load_image_2,r_load_image_2;
wire [2:0] done;
wire [7:0] b_result,g_result,r_result;
integer index;
top_conv blue_result (clk,resetn,start,b_load_image_0,b_load_image_1,b_load_image_2,done[0],b_result);
top_conv green_result (clk,resetn,start,g_load_image_0,g_load_image_1,g_load_image_2,done[1],g_result);
top_conv red_result (clk,resetn,start,r_load_image_0,r_load_image_1,r_load_image_2,done[2],r_result);
parameter read_fileName1 = "D:/blur_filter_unit/test.bmp" ;
localparam ARRAY_LEN = 24*24*3 + 54;
reg [7:0] data1 [0:ARRAY_LEN-1];
integer size,start_pos,width,height,bitcount;
task readBMP;
integer fileID1;
begin
fileID1 = $fopen(read_fileName1, "rb");
$display("%d" ,fileID1);
if(fileID1 == 0) begin
$display("Error: please check file path");
$finish;
end
else begin
$fread(data1, fileID1);
$fclose(fileID1);
size = {data1[5],data1[4],data1[3],data1[2]};
$display("size - %d", size);
start_pos = {data1[13],data1[12],data1[11],data1[10]};
$display("startpos : %d", start_pos);
width = {data1[21],data1[20],data1[19],data1[18]};
height = {data1[25],data1[24],data1[23],data1[22]};
$display("width - %d; height - %d",width,height);
bitcount = {data1[29],data1[28]};
if(bitcount != 24) begin
$display("Error: Please check the image file. It may be corrupted");
end
if(width%4)begin
$display("width is not suitable");
$finish;
end
end
end
endtask
integer i,j;
localparam RESULT_ARRAY_LEN = 24*24*3;
reg[7:0] result[0:RESULT_ARRAY_LEN - 1];
always #(posedge clk or negedge resetn)begin
if(!resetn)begin
j <= 8'b0;
end
else begin
if(&done[2:0]) begin
result[j] <= b_result;
result[j+1] <= g_result;
result[j+2] <= r_result;
j <= j+3;
end
end
end
parameter write_fileName1 = "D:/blur_filter_unit/result.bmp";
task writeBMP;
integer fileID, k;
begin
fileID = $fopen(write_fileName1,"wb");
for(k = 0; k < start_pos; k=k+1)begin
$fwrite(fileID, "%c",data1[k]);
end
for(k = start_pos; k<size; k=k+1)begin
$fwrite(fileID,"%c",result[k-start_pos]);
end
$fclose(fileID);
$display("Result.bmp is generated \n");
end
endtask
always begin
#1 clk = ~clk;
end
initial begin
clk = 1;
resetn = 0;
start = 0;
index = 1;
b_load_image_0 = 0;
g_load_image_0 = 0;
r_load_image_0 = 0;
b_load_image_1 = 0;
g_load_image_1 = 0;
r_load_image_1 = 0;
b_load_image_2 = 0;
g_load_image_2 = 0;
r_load_image_2 = 0;
readBMP;
#10;
resetn = 1;
start = 1;
for(i = start_pos; i<size; i=i+3)begin
{r_load_image_0, r_load_image_1, r_load_image_2} ={data1[i+2],data1[i+2+width*3],data1[i+2+width*6]};
{g_load_image_0, g_load_image_1, g_load_image_2} = {data1[i+1],data1[i+1+width*3],data1[i+1+width*6]};
{b_load_image_0, b_load_image_1, b_load_image_2} = {data1[i],data1[i+width*3],data1[i+width*6]};
#1;
end
#10;
#writeBMP;
#10
$stop;
end
endmodule
Even though this is not a complete answer, for figuring out the error you can use the below code which is revised version of your code for ease of debugging.
i think when synthesizing your design you might have faced this issue
Due to line numbers 25 & 71 in your code.You are declaring edge sensitive signal in sensitivity list and u are not using it in the always block. so tool cannot understand how to map it and throwing an error.
module top_conv(
input clk,resetn,start,
input [7:0] load_image_0,load_image_1,load_image_2,
output reg done,
output reg [7:0] result
);
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
reg [4:0] row_cnt, col_cnt;
reg [1:0] load_cnt;
parameter IDLE = 2'b00,
LOAD = 2'b01,
MAC = 2'b10,
DONE = 2'b11;
reg [1:0] state,next;
always#(posedge clk or negedge resetn)begin
if(!resetn) state <= #10 IDLE ;
else state <= #10 next ;
end
always#(*)begin
next = 'bx; // default undefined state
case(state)
IDLE: next = start ? LOAD : IDLE ;
LOAD: next = (load_cnt == 2) ? MAC : LOAD ;
MAC : next = ((row_cnt == 21)&&(col_cnt == 21)) ? DONE :
(col_cnt == 21) ? LOAD : MAC ;
DONE: next = IDLE ;
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
end else begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
case(next)
LOAD:load_cnt <= #10 load_cnt + 1'b1 ;
MAC :begin
col_cnt <= #10 (col_cnt == 21) ? 0 : col_cnt + 1'b1 ;
row_cnt <= #10 (col_cnt == 21) ? row_cnt : row_cnt + 1'b1 ;
end
DONE:begin
result <= #10 (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 +
(input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 +
(input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16 ;
done <= #10 1'b1;
end
endcase
end
end
always#(posedge clk)begin
case(next)
LOAD:begin
input_buffer_0[load_cnt] <= #10 load_image_0;
input_buffer_1[load_cnt] <= #10 load_image_1;
input_buffer_2[load_cnt] <= #10 load_image_2;
end
MAC:begin
input_buffer_0[0] <= #10 input_buffer_0[1];
input_buffer_1[0] <= #10 input_buffer_1[1];
input_buffer_2[0] <= #10 input_buffer_2[1];
input_buffer_0[1] <= #10 input_buffer_0[2];
input_buffer_1[1] <= #10 input_buffer_0[2];
input_buffer_2[1] <= #10 input_buffer_0[2];
input_buffer_0[2] <= #10 load_image_0;
input_buffer_1[2] <= #10 load_image_1;
input_buffer_2[2] <= #10 load_image_2;
end
endcase
end
endmodule

Fifo block implementation

i wrote a fifo in system verilog
i try to push some data to this fifo (i wrote a tb) and when i push data the fifo_wr_ptr, fifo_fre_space,fifo_used_space don't update (only data write to mem[0])
i will be glad for help (why my ptr don't increment by 1 for example)
Thanks alot!
and here is my simulation that shows my problem:
i attached my code:
module fifo
#(parameter WIDTH = 32, parameter DEPTH = 64 ) ( clk, rst_l, sw_rst, fifo_din, fifo_push_en, fifo_pop_en, fifo_dout, fifo_o_full, fifo_o_empty, fifo_used_space, fifo_free_space );
function integer log2; //can use the $clog2() function
input [31:0] value;
reg [31:0] value_tmp;
begin value_tmp = value; for(log2=0; value_tmp>0; log2=log2+1)
value_tmp=(value_tmp>>1);
end endfunction
localparam DEPTH_LOG2 = log2(DEPTH);
//interface input clk; input rst_l; input sw_rst; input[WIDTH-1:0] fifo_din; input fifo_push_en; input fifo_pop_en; output logic[WIDTH-1:0] fifo_dout; output logic fifo_o_full; output logic fifo_o_empty; output logic[DEPTH_LOG2-1:0] fifo_used_space; output logic[DEPTH_LOG2-1:0] fifo_free_space; logic debug_flag; //internal logic logic[WIDTH-1:0] mem[DEPTH_LOG2-1:0]; logic[DEPTH_LOG2-1:0] fifo_rd_ptr,fifo_wr_ptr;
assign fifo_o_empty = (fifo_used_space==0); assign fifo_o_full = (fifo_free_space==0);
always # (posedge clk or negedge rst_l) begin if(~rst_l) begin
fifo_free_space <= DEPTH;
fifo_used_space <= 0;
fifo_rd_ptr <= 0;
fifo_wr_ptr <= 0;
debug_flag <=0 ;
end else if (~sw_rst) begin
fifo_free_space <= DEPTH;
fifo_used_space <= 0;
fifo_rd_ptr <= 0;
fifo_wr_ptr <= 0;
debug_flag <= 0;
end else if(fifo_push_en==1 && fifo_o_full==0 && fifo_pop_en==0) begin //the fifo isn't full and can perform the write trasaction (and no read transaction)
fifo_used_space <= fifo_used_space + 1;
fifo_free_space <= fifo_free_space - 1;
mem[fifo_wr_ptr]<= fifo_din;
debug_flag <= 1;
if(fifo_wr_ptr == (DEPTH - 1))
fifo_wr_ptr <= 0;
else
fifo_wr_ptr++;
end else if (fifo_pop_en==1 && fifo_o_empty==0 && fifo_push_en==0) begin // the fifo isn't empty and can perform the read trasaction (and no write trasaction)
fifo_used_space <= fifo_used_space - 1;
fifo_free_space <= fifo_free_space + 1;
fifo_dout <= mem[fifo_rd_ptr];
if(fifo_rd_ptr == (DEPTH - 1)) begin
fifo_rd_ptr <= 0;
end else begin
fifo_rd_ptr <= fifo_rd_ptr + 1;
end end else begin
fifo_rd_ptr <= fifo_rd_ptr;
//fifo_wr_ptr <= fifo_wr_ptr;
//fifo_dout <= fifo_dout;
//fifo_used_space <= fifo_used_space;
fifo_free_space <= fifo_free_space; end end
endmodule
and here is the tb code:
`define WIDTH 32
`define DEPTH 64
module fifo_tb();
function integer log2; //can use the $clog2() function
input [31:0] value;
reg [31:0] value_tmp;
begin
value_tmp = value;
for(log2=0; value_tmp>0; log2=log2+1)
value_tmp=(value_tmp>>1);
end
endfunction
localparam DEPTH_LOG2 = log2(`DEPTH);
logic clk,rst_l,sw_rst,fifo_push_en,fifo_pop_en,fifo_o_full,fifo_o_empty;
logic[`WIDTH-1:0] fifo_din,fifo_dout,tempdata;
logic[DEPTH_LOG2-1:0] fifo_used_space,fifo_free_space;
fifo #(`WIDTH,`DEPTH) ff(.clk(clk), .rst_l(rst_l), .sw_rst(sw_rst), .fifo_din(fifo_din),
.fifo_push_en(fifo_push_en), .fifo_pop_en(fifo_pop_en),
.fifo_dout(fifo_dout), .fifo_o_full(fifo_o_full), .fifo_o_empty(fifo_o_empty),
.fifo_used_space(fifo_used_space), .fifo_free_space(fifo_free_space) );
initial
begin
clk =0;
rst_l = 0;
sw_rst= 0;
fifo_push_en=0;
fifo_pop_en=0;
fifo_din=0;
tempdata=0;
#15 rst_l=1;
#1 sw_rst=1;
push(10);
push(20);
push(30);
push(40);
pop(tempdata);
push(tempdata);
end
always
#5 clk=~clk;
task push;
input[`WIDTH-1:0] data;
if(fifo_o_full)
$display("--- Cannot push: Buffer full ----");
else begin
$display("Pushed: ",data);
#(posedge clk);
fifo_din = data;
fifo_push_en=1;
#(posedge clk);
fifo_push_en=0;
end
endtask
task pop;
output [`WIDTH-1:0] data;
if(fifo_o_empty)
$display("Cannot pop: buffer empty ---");
else begin
#(posedge clk);
fifo_pop_en=1;
#(posedge clk);
fifo_pop_en=0;
data=fifo_dout;
$display("----- Poped : ",data);
end
endtask
endmodule
Taking aside the oddity related to pointer incrementation, the code itself is confusing and difficult to deal with. Pasting reference FIFO module that should do the job, this also should help you to grasp on basics of coding style.
//----------------------------------------------------
// Module Name: fifo_sync.v
//----------------------------------------------------
// Description: generic sync FIFO module
//----------------------------------------------------
module fifo_sync #
(
parameter FIFO_DATA_WIDTH = 'd32,
parameter FIFO_PTR_WIDTH = 'd6
)
(
//------------------------------------------------
// Inputs
//------------------------------------------------
input clk,
input rst_n,
input wr_en,
input [FIFO_DATA_WIDTH-1:0] wr_data,
input rd_en,
//------------------------------------------------
// Outputs
//------------------------------------------------
output reg [FIFO_DATA_WIDTH-1:0] rd_data,
output stat_full,
output stat_empty,
output [ FIFO_PTR_WIDTH-1:0] stat_occupancy
);
//------------------------------------------------
// Local Parameters
//------------------------------------------------
localparam FIFO_DEPTH = 2**(FIFO_PTR_WIDTH-1);
//------------------------------------------------
// Internal Register(s)/Wire(s)/Integer(s)
//------------------------------------------------
reg [ FIFO_PTR_WIDTH-1:0] wr_ptr;
reg [ FIFO_PTR_WIDTH-1:0] rd_ptr;
reg [FIFO_DATA_WIDTH-1:0] fifo_array [FIFO_DEPTH-1:0];
integer int_i;
//------------------------------------------------
// Write Pointer Logic
//------------------------------------------------
always #(posedge clk or negedge rst_n)
begin: p_wr_ptr
if (!rst_n)
wr_ptr <= {FIFO_PTR_WIDTH{1'b0}};
else if (wr_en & !stat_full)
wr_ptr <= wr_ptr + 1'b1;
end
//------------------------------------------------
// Read Pointer Logic
//------------------------------------------------
always #(posedge clk or negedge rst_n)
begin: p_rd_ptr
if (!rst_n)
rd_ptr <= {FIFO_PTR_WIDTH{1'b0}};
else if (rd_en & !stat_empty)
rd_ptr <= rd_ptr + 1'b1;
end
//------------------------------------------------
// Status Interface
//------------------------------------------------
// FIFO full status flag
assign stat_full = (wr_ptr[FIFO_PTR_WIDTH-1] ^ rd_ptr[FIFO_PTR_WIDTH-1]) & (wr_ptr[FIFO_PTR_WIDTH-2:0] == rd_ptr[FIFO_PTR_WIDTH-2:0]);
// FIFO empty status flag
assign stat_empty = (wr_ptr == rd_ptr);
// FIFO occupancy status
assign stat_occupancy = wr_ptr - rd_ptr;
//-----------------------------------------------
// FIFO Write
//-----------------------------------------------
always #(posedge clk or negedge rst_n)
begin: p_fifo_write
if (!rst_n)
for (int_i = 0; int_i < FIFO_DEPTH - 1; int_i = int_i + 1)
fifo_array[int_i] <= {FIFO_DATA_WIDTH{1'b0}};
else if (wr_en & !stat_full)
fifo_array[wr_ptr] <= wr_data;
end
//-----------------------------------------------
// FIFO Read
//-----------------------------------------------
always #(posedge clk or negedge rst_n)
begin: p_fifo_read
if (!rst_n)
rd_data <= {FIFO_DATA_WIDTH{1'b0}};
else if (rd_en & !stat_empty)
rd_data <= fifo_array[rd_ptr];
end
endmodule

inout verilog protocol I2C

I'm creating the I2C protocol in verilog to read data from a sensor (BMP180), AS you know, the sensor sends me a bit of ack recognition. How do I use the inout i2c_sda port to send and how do I receive.
As delivery and receipt i2c_sda the same line, if my variable is declared of type inout.
module stepPrueba(
input wire clk1,
input wire reset,
input wire start,
inout i2c_sda,
inout i2c_scl,
output wire ready,
output reg led1,
output reg led2
);
reg i2c_scl_out;
assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_scl_in = i2c_scl;
assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : clk1;
reg clk;
assign clk1 = (clk == 1)? 1'bz:1'b0;
reg i2c_sda_out;
assign i2c_sda = (i2c_sda_out == 1'b0) ? 1'b0 : 1'bz;
wire i2c_sda_in = i2c_sda ;
reg [6:0] addr;
reg [7:0] data;
reg enable; //(read=1, write=0)
reg datas;
reg enable2; //(read=1, write = 0)
reg [7:0] state;
reg [7:0] count;
reg i2c_scl_enable = 0;
reg [6:0] saved_addr;
reg [7:0] saved_data;
//goal es escribir al dispositivo direccion 0X55, 0Xaa
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR =2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_WACK2 = 6;
localparam STATE_STOP = 7;
always#(posedge clk)
begin
//enable2 <= 0; //i2c_scl==zetas & c_lectura=z;
if(reset == 1)
begin
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
if((state == STATE_IDLE) || (state == STATE_START) )
begin
//i2c_scl_enable <= 0; //dats == 1 --> ztas == z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
end
else
begin
i2c_scl_enable <= 1; // dats==clk;
clk<=clk1;
end
end
end
always#(posedge clk)
begin
if(reset == 1)
begin
led1 <=0;
led2 <=0;
state <=0;
i2c_sda_out <= 1;// i2c_sda ==z;
addr <= 7'b1110111; // direccion del sensor
count <= 8'd0;
data <= 8'b11110100; //direccion interna PRESION
end
else //reset ==0
begin
case (state)
STATE_IDLE:
begin //idle
//datas <= 1; //zetas==z
i2c_scl_out<=1;
i2c_scl_enable <= 0;
i2c_sda_out <= 1;
if(start)
begin
state <= STATE_START;
saved_addr <= addr;
saved_data <= data;
// reg i2c_scl_out;
// assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
// wire i2c_scl_in = i2c_scl;
// assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : ~clk;
end
else
begin
state <= STATE_IDLE;
end
end
STATE_START:
begin // start
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= 0;
//datas <= 0; // zetas==0
state<= STATE_ADDR;
count <= 6;
end
STATE_ADDR:
begin //msb addres bit
//enable <= 0; // lectura==z; --> i2c_sda==zetas
i2c_sda_out <= saved_addr[count]; // datas ==0 --> zetas==0 || datas==1 --> zetas==z
if (count == 0)
begin
state <= STATE_RW;
end
else
begin
count <= count - 1;
end
end
STATE_RW:
begin
//enable <= 0; //enable==0 --> i2c_sda==zetas
i2c_sda_out <= 0;//datas <= 0;
state <= STATE_WACK;
end
STATE_WACK:
begin
//enable <= 1; //enable==1 lee i2c_sda==z & lectura==i2c_sda
//enable <= 0;
//if(APA)
if(i2c_sda_in==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_DATA;
led1 <= 1;
end
count <= 7;
end
STATE_DATA:
begin
//enable <= 0;
i2c_sda_out <= saved_data[count];
if(count ==0)
begin
state <= STATE_WACK2;
end
else
begin
count <= count - 1;
end
end
STATE_WACK2:
begin
//enable <= 1;
if(i2c_sda_in ==1)
begin
state <= STATE_IDLE;
end
else
begin
state <= STATE_STOP;
led2 <= 1;
end
end
STATE_STOP:
begin
//enable <= 0;
i2c_sda_out <= 0;
state <= STATE_IDLE;
end
endcase
end
end
endmodule
If you have a module pin defined as
inout wire pin
then you can access it like so
wire pin_input = pin;
assign pin = pin_oe ? pin_output : 1'bz;
this should infer a tristate buffer.
However, I would be careful when doing this, as if you infer a tristate buffer too early, it can limit what you can do with the module. For example, it would be possible to connect multiple internal I2C components together, such as allowing multiple masters inside the FPGA access to the same pins. However, tristate signals cannot be routed inside the FPGA, so if you implement the tristate inside the I2C master module, this becomes impossible. Instead, what you might consider is implementing each pin as three module pins: input, output, and output enable/tristate. This allows multiple modules to be connected with an emulated tristate bus, and allows them to share one set of tristate buffers to the actual I/O pin on the chip.
For a good example of how this works, see the comments in https://github.com/alexforencich/verilog-i2c/blob/master/rtl/i2c_master.v .

Resources