Fifo block implementation - verilog

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

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.

Module instantiation with the "number sign"

I have the main module with FIFO stuff.
Here it is:
module syn_fifo #(
parameter DATA_WIDTH = 8, // inpit capacity
parameter DATA_DEPTH = 8 // the depth of the FIFO
)
(
input wire clk,
input wire rst,
// Write_______________________________________________
input wire [DATA_WIDTH-1:0]din, // the input data
input wire wren, // Write anable
output wire full,
// Read________________________________________________
output wire [DATA_WIDTH-1:0]dout, // The output data
input wire rden, // Read enable
output wire empty
);
integer q_size; // The queue size(length)
integer golova; // The queue beginning
integer hvost; // The end of queue
reg [DATA_WIDTH-1:0]fifo[DATA_DEPTH-1:0];
assign full = (q_size == DATA_DEPTH) ? 1'b1: 1'b0; // FIFO is full
/*
True { full = (q_size==DATA_TEPTH) = 1 }, then wire "full" goes to "1" value
False { full = (q_size==DATA_TEPTH) = 0 }, then wire "full" goes to "0" value
*/
assign empty = (golova == hvost); // FIFO is empty
assign dout = fifo[hvost]; // FWFT (other write mode)
integer i;
//___________(The queue fullness)___________________
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
for (i = 0; i < DATA_DEPTH; i = i + 1) // incrementing the FIFO
fifo[i] <= 0; // Resetting the FIFO
golova <= 0; // Resetting the queue start variable
end
else
begin //Write_______________________________________
if (wren && ~full)
begin
fifo[golova] <= din; // putting data in to the golova
if (golova == DATA_DEPTH-1) // restrictions for the queue beginning
golova <= 0; // Reset the beginning
else
golova <= golova + 1; // other occurence incrementing
end
end
end
//Reading
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
hvost <= 0;
end
else
begin
if (rden && !empty)
/*for staying inside the queue limits - make the check of non equality of the "hvost" & "queue size"*/
begin
if (hvost == DATA_DEPTH-1) // if hvost = DATA_DEPTH-1, then
hvost <= 0; // Reset hvost
else
hvost <= hvost + 1;
end
end
end
always # (posedge clk)
begin
if (rst == 1'b1) begin
q_size <= 0;
end
else
begin
case ({wren && ~full, rden && ~empty} )
2'b01: q_size <= q_size + 1; // RO
2'b10: q_size <= q_size - 1; // WO
default: q_size <= q_size; // read and write at the same time
endcase
end
end
endmodule
Also i've got the testbench module down delow:
`timescale 1ns / 1ps
module fifo_tb();
localparam CLK_PERIOD = 10;
reg clk;
reg rst;
always begin
clk <= 1'b0;
#(CLK_PERIOD / 2);
clk <= 1'b1;
#(CLK_PERIOD / 2);
end
localparam DATA_WIDTH = 8;
localparam DATA_DEPTH = 4;
reg [DATA_WIDTH-1:0]din;
reg wren;
reg rden;
wire [DATA_WIDTH-1:0]dout;
wire empty;
wire full;
wire wr_valid;
wire rd_valid;
task write;
input integer length;
begin
if (length) begin
#(posedge clk);
wren <= 1'b1;
while (length) begin
#(posedge clk);
if (wr_valid) begin
length <= length - 1;
if (length == 1) begin
wren <= 1'b0;
end
end
end
end
end
endtask
task read;
input integer length;
begin
if (length) begin
#(posedge clk);
rden <= 1'b1;
while (length) begin
#(posedge clk);
if (rd_valid) begin
length <= length - 1;
if (length == 1) begin
rden <= 1'b0;
end
end
end
end
end
endtask
initial begin
rst <= 1'b0;
wren <= 1'b0;
rden <= 1'b0;
#50;
rst <= 1'b1;
#50;
rst <= 1'b0;
#200;
/* Test Start */
//write(4);
//read(4);
/* Test Stop */
#1000;
$finish;
end
assign wr_valid = wren & ~full;
assign rd_valid = rden & ~empty;
always #(posedge clk) begin
if (rst == 1'b1) begin
din <= 0;
end else begin
if (wr_valid == 1'b1) begin
din <= din + 1;
end
end
end
// write?
always begin
#400;
write(5);
#15;
write(7);
#25;
write(3);
#15;
write(9);
#15;
write(1);
#10000;
end
// read?
always begin
#420;
read(3);
#37;
read(13);
#21;
read(7);
#15;
read(9);
#15;
read(4);
#20;
read(7);
#10000;
end
initial begin
$dumpfile("test.vcd");
$dumpvars(0,fifo_tb);
end
syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
.rst(rst),
.din(din),
.wren(wren),
.full(full),
.dout(dout),
.rden(rden),
.empty(empty));
endmodule
Trying to compile all of it with iVerilog + GTKwave + Win10 by next command:
C:\Program Files\iverilog\bin>iverilog -o fifo.v fifo_tb.v
The compiler gives me the next message:
fifo_tb.v:138:error: Unknown module type:syn_fifo
2 error(s) during elaboration.
These modules were missing:syn_fifo referenced 1 times
At the necessary line "138" maybe the main mistake is covered by the "Number sign" in module instantiation?
/*132|*/ initial begin
/*133|*/ $dumpfile("test.vcd");
/*134|*/ $dumpvars(0,fifo_tb);
/*135|*/ end
/*136|*/
/*137|*/ syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
/*138|*/ .DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
/*139|*/ .rst(rst),
/*140|*/ .din(din),
/*141|*/ .wren(wren),
/*142|*/ .full(full),
/*143|*/ .dout(dout),
/*144|*/ .rden(rden),
/*145|*/ .empty(empty));
/*146|*/
/*147|*/ endmodule
I'm not shure of that.
Seems like you are indicating fifo.v to be your output file, try:
iverilog -o syn_fifo.tb -s fifo_tb fifo_tb.v fifo.v
-o -> output file
-s -> top module (in this case, the test one)
(after everything, include all the files)
Then, to run it:
vvp syn_fifo.tb
Thank you, dear #m4j0rt0m
I just forgot to type in the output file name at the CMD window. Was very exhausted so haven't noticed such a detail)))
Usually it looks like:
iverilog -o OUTPUT_FILE_NAME fifo_tb.v fifo.v
And also I tried your advice, and it's finally done!

Change code to use block RAMs

I want to implement in Verilog the following Matlab code:
symBuf = [symBuf(numFFT/2+1:end); zeros(numFFT/2,1)];
symBuf(KF+(1:KF)) = symBuf(KF+(1:KF)) + txSymb;
It is a simple overlap and add operation.
Here is my implementation:
module overlap
#(K = 3,
FFT = 128
)
(
input signed [15:0] symbInReal ,
input signed [15:0] symbInImag ,
input clock ,
input reset ,
input readyIn ,
input validIn ,
input lastIn ,
output signed [15:0] outReal ,
output signed [15:0] outImag ,
output reg lastOut ,
output wire readyOut ,
output reg validOut
);
reg signed [15:0] previousSymbolReal [2*FFT*K-1:0] ;
reg signed [15:0] previousSymbolImag [2*FFT*K-1:0] ;
reg signed [15:0] txSymbolBuffReal [K*FFT-1:0] ;
reg signed [15:0] txSymbolBuffImag [K*FFT-1:0] ;
reg [15:0] counter ;
reg [1:0] state ;
reg [3:0] nextstate ;
reg [15:0] clockcount ;
reg signed [15:0] outputValueReal ;
reg signed [15:0] outputValueImag ;
reg [15:0] buffcount ;
reg [7:0] symboutcount ;
reg [7:0] symbincount ;
reg last ;
reg lastvalidout ;
wire lastout ;
integer i;
initial begin
for (i=0; i<2*FFT*K ; i = i + 1) begin
previousSymbolReal[i] = 0;
previousSymbolImag[i] = 0;
end
end
always#(posedge clock) begin
if(~reset) begin
counter <= 0;
end else begin
counter <= counter +1;
if(nextstate != state)
counter <= 0;
end
end
always#(*) begin
if(~reset) begin
nextstate = 0;
end else begin
nextstate = state;
if(readyIn) begin
case(state)
4'd0: begin
if(validIn || last) begin
nextstate = 1;
end
end
4'd1: begin
if (counter == (FFT*K-2)) begin
nextstate = 2;
end
end
4'd2: begin
nextstate = 0;
end
endcase
end
end
end
always#(posedge clock) begin
if(~reset) begin
state <= 0;
end else begin
if(readyIn)
state <= nextstate;
end
end
always#(posedge clock) begin
if(~reset) begin
clockcount <= 0;
symboutcount <= 0;
lastOut <= 0;
end else begin
if(readyIn) begin
clockcount <= clockcount +1 ;
case(state)
4'd0: begin
validOut <= 0;
clockcount <= 0;
lastOut <= 0;
end
4'd1: begin
if(~lastvalidout)
validOut <= 1;
outputValueReal <= previousSymbolReal[clockcount+ FFT/2];
outputValueImag <= previousSymbolImag[clockcount+ FFT/2];
end
4'd2: begin
outputValueReal <= previousSymbolReal[clockcount + FFT/2];
outputValueImag <= previousSymbolImag[clockcount + FFT/2];
clockcount <= 0;
if(~lastvalidout)
validOut <= 1;
if(symboutcount == symbincount + 1 && last)
lastOut <= 1;
symboutcount <= symboutcount +1 ;
end
endcase
end
end
end
assign readyOut = readyIn;
genvar M;
generate
for(M=0;M<K*FFT;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= previousSymbolReal[M+FFT/2];
previousSymbolImag[M] <= previousSymbolImag[M+FFT/2];
end
end
end
for(M=K*FFT;M<2*K*FFT-FFT/2;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= previousSymbolReal[M+FFT/2]+txSymbolBuffReal[M-K*FFT];
previousSymbolImag[M] <= previousSymbolImag[M+FFT/2]+txSymbolBuffImag[M-K*FFT];
end
end
end
for(M=2*K*FFT-FFT/2;M<2*K*FFT;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= txSymbolBuffReal[M-K*FFT];
previousSymbolImag[M] <= txSymbolBuffImag[M-K*FFT];
end
end
end
endgenerate
always#(posedge clock) begin
if(~reset) begin
buffcount <= 0;
symbincount <= 0;
last <= 0;
end else begin
if(validIn) begin
txSymbolBuffReal[buffcount] <= symbInReal;
txSymbolBuffImag[buffcount] <= symbInImag;
buffcount <= buffcount +1;
if(buffcount == K*FFT-1) begin
symbincount <= symbincount + 1;
buffcount <= 0;
end
if(lastIn)
last <= 1;
end
end
end
always#(posedge clock) begin
if(~reset)
lastvalidout <= 0;
else begin
if(last && lastOut)
lastvalidout <= 1;
end
end
assign outReal = outputValueReal;
assign outImag = outputValueImag;
endmodule
The problem here is that I have 4 huge arrays which take up to 4 times what is available in my FPGA.
Hence, I want to be able to use block RAMs. However, I don't think it's possible due to the number of read and write operations performed.
Does anyone have a solution for this?
However, I don't think it's possible due to the number of read and write operations performed.
Correct. At least, not without major changes to your design.
A typical block RAM element can only read or write one (or sometimes two) values per clock cycle, but your generate loops are trying to update every element in the RAM at once!
To make this operation use a block RAM, you will need to implement a state machine to update one element per clock cycle, and to sequence operations such that other states wait until the updates have completed.
If you want to accelerate this, you may be able to split the array into multiple block RAMs so that multiple values can be updated in parallel. (You will need to carefully consider which elements need to be read/written to avoid conflicts.)

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 .

XXX on output ports

I have written an asynchronous fifo buffer but when I run it I get XXX on output ports. I referred to concerned questions on SO which said asserting reset signals should make it work but despite of doing it I am still facing the same issue.
Any help will be appreciated.
Thanks
module fifo
#(parameter width =8,
addr_width = 4,
depth = (1 << addr_width)
)
( // Read port
output [width - 1:0] dout,
output reg empty_out,
input wire rd_en,
input wire rclk,
//write port
input wire [width-1:0] din,
output reg full,
input wire wr_en,
input wire wclk,
input wire rst
);
(* ram_style = "bram" *)
reg [width-1:0] memory_s[depth-1:0];
reg [31:0] push_ptr;
reg [31:0] pop_ptr;
assign dout = memory_s[pop_ptr]; // assign cannot assign values to registers
always #(posedge wclk)
begin
if (rst == 1)
push_ptr <= 0;
else if(wr_en == 1)
begin
memory_s\[push_ptr\] <= din;
//$display("w: %d", push_ptr);
if (push_ptr == (depth -1))
push_ptr <= 0;
else
push_ptr <= push_ptr + 1;
end
end
always # (posedge rclk)
if (rst == 1)
pop_ptr <= 0;
else if (rd_en ==1)
begin
//dout <= memory_s\[pop_ptr\];
//$display("r: %d", pop_ptr);
if (pop_ptr == depth-1)
pop_ptr <=0;
else
pop_ptr <= pop_ptr+1;
end
reg full_s;
reg overflow;
always #*
begin
if (rst == 1)
full_s <= 0;
else if (push_ptr <= pop_ptr)
if (push_ptr + 1 == pop_ptr)
begin
full_s <= 1;
$display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s);
end
else
full_s <=0;
else
if(push_ptr + 1 == pop_ptr + depth)
begin
full_s <= 1;
$display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s);
end
else
full_s <= 0;
end
endmodule]
Here is a waveform:
(external link)
Added Testbench
module fifoTb;
// Inputs
reg rd_en;
reg rclk;
reg [7:0] din;
reg wr_en;
reg wclk;
reg rst;
// Outputs
wire[7:0] dout;
wire empty_out;
wire full;
// Instantiate the Unit Under Test (UUT)
fifo uut (
.dout(dout),
.empty_out(empty_out),
.rd_en(rd_en),
.rclk(rclk),
.din(din),
.full(full),
.wr_en(wr_en),
.wclk(wclk),
.rst(rst)
);
initial begin
// Initialize Inputs
rd_en = 0;
rclk = 0;
wr_en = 0;
wclk = 0;
rst = 1;
din = 8'h0;
// Wait 100 ns for global reset to finish
#100;
rst = 0;
wr_en = 1;
din = 8'h1;
#101 din = 8'h2;
rd_en = 1;
// Add stimulus here
end
always begin #10 wclk = ~wclk; end
always begin #10 rclk = ~rclk; end
endmodule
I would suggest adding additional logic on your output dout signal
to avoid having 'bxxx values because memory_s has an initial value
of 'bxxx:
assign dout = (rd_en) ? memory_s[pop_ptr] : 0;
Additional tips in creating your testbench:
First, it is very important to try to understand how your
device works.
Upon reading your RTL code, I concluded that your fifo works in the
following manner:
Write operation
always #(posedge wclk)
begin
if (rst == 1)
push_ptr <= 0;
else if(wr_en == 1)
begin
memory_s[push_ptr] <= din;
if (push_ptr == (depth -1))
push_ptr <= 0;
else
push_ptr <= push_ptr + 1;
end
end
When wr_en is high, two operations are performed.
The value from din will be written on memory_s pointed by
push_ptr at the next positive edge of wclk.
If push_ptr is equal with (depth -1), 0 will be written to
the register push_ptr else register push_ptr is incremented by 1
instead.
Write operation will not be performed when wr_en is low.
Read operation
assign dout = memory_s[pop_ptr];
always # (posedge rclk)
if (rst == 1)
pop_ptr <= 0;
else if (rd_en ==1)
begin
if (pop_ptr == depth-1)
pop_ptr <=0;
else
pop_ptr <= pop_ptr+1;
end
When rd_en is high, increment the register pop_ptr by 1 if
pop_ptr is not equal to depth-1 else write it with 0 instead.
dout will all the time hold the value of memory_s pointed by the register
pop_ptr.
Creating tasks for every operation that you are going to perform
is usually convenient.
wr_en = 1;
din = 8'h1;
#101 din = 8'h2;
rd_en = 1;
I created write and read tasks for you as an example and you might want
to substitute your code above.
task write(input [7:0] pdin);
$display("[ testbench ] writing data: %0x", pdin);
din <= pdin;
wr_en <= 1;
#(posedge wclk);
din <= 0;
wr_en <= 0;
endtask
task read(output [7:0] prdata);
rd_en <= 1;
#(posedge rclk);
prdata = dout;
rd_en <= 0;
$display("[ testbench ] reading data: %0x", prdata);
endtask
Here is how to use the tasks:
write(8'hAA);
read(read_data);
write(8'hCC);
read(read_data);
write(8'hBC);
read(read_data);
In writing a combinational circuit, it is not recommended to add
a reset logic on to it.
always #*
begin
if (rst == 1)
full_s <= 0; . . .
Also, most of the EDA tool vendors recommend to use blocking (=) assignment
in writing a combinational circuit and non-blocking assignment (<=) in a
sequential circuit.
End you're simulation when you're done by calling $finish.
initial begin
#1000; $finish;
end

Resources