reading multiple block ram indexes in one write clock cycle - arrays

I have an application where I'm continuously writing to a block ram at a slow clock speed (clk_a) and within this slow clock cycle need to read three indexes from the block ram at a fast clock speed (clk_b) to use these values as operands in a math module, the result being written back to the block ram on the next slow clock. These three indexes are the current address written to at posedge of the slow clock, plus the two immediate neighbouring addresses (addr_a -1 and addr_a +1).
What is an efficient way to synthesize this? My best attempt to date uses a small counter (triplet) running at fast clock rate that increments the addresses but I end up running out of logic as it looks like Yosys does not infer the ram properly. What is a good strategy for this?
here is what I have:
module myRam2 (
input clk_a,
input clk_b,
input we_a,
input re_a,
input [10:0] addr_a,
input [10:0] addr_b,
input [11:0] din_a,
output [11:0] leftNeighbor,
output [11:0] currentX,
output [11:0] rightNeighbor
);
parameter MEM_INIT_FILE2 = "";
initial
if (MEM_INIT_FILE2 != "")
$readmemh(MEM_INIT_FILE2, ram2);
reg [11:0] ram2 [0:2047];
reg [1:0] triplet = 3;
reg [10:0] old_addr_a;
reg [11:0] temp;
always #(posedge clk_a) begin
ram2[addr_a] <= din_a;
end
always#(posedge clk_b)
if (old_addr_a != addr_a) begin
triplet <= 0;
old_addr_a <= addr_a;
end
else
if(triplet < 3) begin
triplet <= triplet +1;
end
always #(posedge clk_b) begin
temp <= ram2[addr_a + (triplet - 1)];
end
always #(posedge clk_b) begin
case(triplet)
0: leftN <= temp;
1: X <= temp;
2: rightN <= temp;
endcase
end
reg signed [11:0] leftN;
reg signed [11:0] X;
reg signed [11:0] rightN;
assign leftNeighbor = leftN;
assign currentX = X;
assign rightNeighbor = rightN;
endmodule

Regarding the efficiency the following approach should work and removes the need for a faster clock:
module myRam2 (
input wire clk,
input wire we,
input wire re,
input wire [10:0] addr_a,
input wire [10:0] addr_b,
input wire [11:0] din_a,
output reg [11:0] leftNeighbor,
output reg [11:0] currentX,
output reg [11:0] rightNeighbor
);
reg [11:0] ram2 [2047:0];/* synthesis syn_ramstyle = "no_rw_check" */;
always #(posedge clk) begin
if(we) ram2[addr_a] <= din_a;
if(re) {leftNeighbor,currentX,rightNeighbor} <= {ram2[addr_b-1],ram2[addr_b],ram2[addr_b+1]};
end
endmodule
The synthesis keyword helped me in the past to increase the likelyhood of correctly inferred ram.
EDIT: removed second example suggesting a 1D mapping. It turned out that at least Lattice LSE cannot deal with that approach. However the first code snipped should work according to Active-HDL and Lattice LSE.

Related

Making my output be an 8-bit output from a pre-defined array

I'm trying to make a program that works like an up-down counter as it reads values from an array equivalent to what the counter is at, where this counter value can be adjusted whether the up or down function is active. This is my code below, where I have excluded my 1_Hz counter that already has proven to work. The errors I receive so far during synthesis is that mem has not been declared and I am unsure how to fix that. Advice appreciated, thank you.
module reader (
output reg [7:0] out , // Output of the counter
input wire up_down , // up_down control for counter
input wire clk_1Hz , // clock input
input wire reset // reset input
mem
);
//-------------Code Starts Here-------
reg [16:0] i;
reg [7:0][0:16] mem;
initial begin
assign {mem[0],mem[1],mem[2],mem[3],mem[4],mem[5],mem[6],mem[7],mem[8],mem[9],mem[10],mem[11],mem[12],mem[13],mem[14],mem[15],mem[16]}={8'b0000000,8'b00000001,8'b00000100,8'b00001001,8'b00010000,8'b00011001,8'b00100100,8'b00110001,8'b01000000,8'b01010001,8'b01101000,8'b01111001,8'b10010000,8'b10101001,8'b11000100,8'b11100001,8'b11111111};
end
always #(posedge clk_1Hz)
if (reset) begin // active high reset
out <= 8'b0 ;
end else if (up_down) begin
i <= i+1;
out <= mem[i];
end else begin
i <= i-1;
out <=mem[i];
end
endmodule
initial blocks are not synthesizable, try below code.
module reader (
output reg [7:0] out , // Output of the counter
input wire up_down , // up_down control for counter
input wire clk_1Hz , // clock input
input wire reset // reset input
// mem //Removed this from port list
);
//-------------Code Starts Here-------
reg [4:0] i; //Address range is 0-16 hence only 5 bits needed
reg [7:0]mem[16:0]; //2-D wire declaration
always#(*) begin {mem[0],mem[1],mem[2],mem[3],mem[4],mem[5],mem[6],mem[7],mem[8],mem[9],mem[10],mem[11],mem[12],mem[13],mem[14],mem[15],mem[16]}={8'b0000000,8'b00000001,8'b00000100,8'b00001001,8'b00010000,8'b00011001,8'b00100100,8'b00110001,8'b01000000,8'b01010001,8'b01101000,8'b01111001,8'b10010000,8'b10101001,8'b11000100,8'b11100001,8'b11111111};
end
always #(posedge clk_1Hz)
begin
if (reset) begin // active high reset
out <= 8'b0 ;
end
else if (up_down)
begin
i <= i+1;
out <= mem[i];
end
else
begin
i <= (i == 0) ? i : i-1; //Added cond to avoid underflow
out <= mem[i];
end
end
endmodule

how to preset the register arrays in Verilog?

I am trying to define a register file, 32-bit wide 32-bit deep, in Verilog. How to preset all the values to zero or to any value I want with/without a for loop?
Here's my code, I tried but failed:
module register_file(rna, rnb, qa, qb);
input [4:0]rna;
input [4:0]rnb;
output [31:0]qa;
output [31:0]qb;
genvar i;
reg [31:0]registers[0:31];
assign registers[0]=32'b0;
registers[1]=32'b0;
registers[2]=32'b0;
registers[3]=32'b0;
endmodule
A usual way to preset register values is done using clocks and a reset signal. For example:
reg [31:0]registers[0:31];
integer i;
always #(posedge clk) begin
if (reset) begin
for (i = 0; i < 31; i = i + 1)
registers[i] <= 0;
end
else begin
// do some real work with registers here
end
end
in some cases you might want to do some initial setting in your testbench initial block
initial begin
for (i = 0; ...) registers[i]= 0;
end
The above is not usually synthesizable.
There are few other ways available in System Verilog.

Converting a fixed point Matlab code to Verilog

I have a fixed point Matlab code and it needs to be converted to Verilog. Below is the Matlab code. yfftshift is 5000x0 and y2shape 100x50.
rows=100;
colms=50;
r=1;
for m=0:colms-1
for n=0:rows-1
y2shape(n+1,m+1)=yfftshift(r,1);
r=r+1;
end
end
How can I create memories in Verilog and call them inside the for loop?
The easiest way to handle fixed precision in Verilog is to introduce a scale factor and allocate sufficiently large registers to hold the maximum value. For example, if you know that the maximum value of your numbers will be 40, and three digits of precision to the right of the decimal place are OK, a scaling factor of 1000 can be used with 16-bit registers. Verilog treats unsigned numbers, so if values can be negative, it's necessary to add "signed" to the declarations. The Verilog could be:
`define NUMBER_ROWS 100
`define NUMBER_COLS 50
`define MAX_ROW (`NUMBER_ROWS-1)
`define MAX_COL (`NUMBER_COLS-1)
module moveMemory();
reg clk;
reg [15:0] y2shape [`MAX_ROW:0][`MAX_COL:0];
reg [15:0] yfftshift [`NUMBER_ROWS * `NUMBER_COLS:0];
integer rowNumber, colNumber;
always #(posedge clk)
begin
for (rowNumber = 0; rowNumber < `NUMBER_ROWS; rowNumber = rowNumber + 1)
for (colNumber = 0; colNumber < `NUMBER_COLS; colNumber = colNumber + 1)
y2shape[rowNumber][colNumber] <= yfftshift[rowNumber * `NUMBER_COLS + colNumber];
end
endmodule
This is OK for an FPGA or simulation project, but for full custom work, an SRAM macro would be used to avoid the die area associated with 16,000 registers. For an FPGA implementation, you've probably already paid for the 16K registers, or you may be able to do some extra work get the synthesizer to map the registers to an on-chip SRAM.
The test bench:
// Testing code
integer loadCount, rowShowNumber, colShowNumber;
initial
begin
// Initialize array with some data
for (loadCount=0; loadCount < (NUMBER_ROWS *NUMBER_COLS); loadCount = loadCount + 1)
yfftshift[loadCount] <= loadCount;
clk <= 0;
// Clock the block
#1
clk <= 1;
// Display the results
#1
$display("Y2SHAPE has these values at time ", $time);
for (rowShowNumber = 0; rowShowNumber < `NUMBER_ROWS; rowShowNumber = rowShowNumber + 1)
for (colShowNumber = 0; colShowNumber < `NUMBER_COLS; colShowNumber = colShowNumber + 1)
$display("y2shape[%0d][%0d] is %d ", rowShowNumber, colShowNumber, y2shape[rowShowNumber][colShowNumber]);
end
The simulation results for NUMBER_ROWS=10, NUMBER_COLS=5
Y2SHAPE has these values at time 2
y2shape[0][0] is 0
y2shape[0][1] is 1
y2shape[0][2] is 2
y2shape[0][3] is 3
y2shape[0][4] is 4
.
.
.
y2shape[9][2] is 47
y2shape[9][3] is 48
y2shape[9][4] is 49

Counter based memory array in Verilog

I got a problem.
I am a Verilog newbie, and I have to write a counter based memory array. Basically, my array is 16 x 8 bits (16 x 1 byte). I have 8 bit data coming into my memory, 16 times. So I made a memory block, and a counter which supplies addresses to this memory block by incrementing with the positive edge of the clock (actually, on each positive edge, 8 bit data is fed into the memory, so I increment my counter). Now I have done this process 16 times, and now 128 bits of data are stored and provided by my memory block. But now I want to reset my counter, and repeat the whole process again after a small delay. I am confused as to how I do this. Please have a look at my code and advise.
Thanking all of you in advance.
// creation of counter & a dummy variable
wire cnt;
wire cnt_next;
reg [3:0] counter;
always #(posedge clock)
assign cnt_next=cnt+1'b1;
counter <= cnt_next
wire [3:0] write_address = counter;
//creation of ram function
module single_port_ram
(
input [7:0] data,
input [3:0] addr,
input wr, clk, rd
output [127:0] q
);
reg [15:0] ram[0:7];
always # (posedge clk or posedge reset)
begin
// Code for writing the data
if (wr)
{
addr <= write_address
case {addr}
4'b0000: ram[0] <= data
4'b0001: ram[1] <= data
4'b0010: ram[2] <= data
4'b0011: ram[3] <= data
4'b0100: ram[4] <= data
4'b0101: ram[5] <= data
4'b0110: ram[6] <= data
4'b0111: ram[7] <= data
4'b1000: ram[8] <= data
4'b1001: ram[8] <= data
4'b1010: ram[10] <= data
4'b1011: ram[11] <= data
4'b1100: ram[12] <= data
4'b1101: ram[13] <= data
4'b1110: ram[14] <= data
4'b1111: ram[15] <= data
end
always # (posedge clk or posedge reset)
begin
//Code for reading the data
if (rd)
{
q <= {ram[15],ram[14],ram[13],ram[12],ram[11],ram[10],ram[9],ram[8],ram[7],ram[6],ram[5],ram[4],ram [3],ram[2],ram[1],ram[0]}
}
Make your counter a little bigger, say up to 31 instead of 15. For the first 16 clocks, write the memory address like you are doing, for the next 16 clocks just do nothing but increment (the small delay you wanted), and then when the counter reaches 31 just reset it back to 0. Then the process should restart.
to have 16 x 8 bits (16 x 1 byte)
first you declare the size of your RAM width then you declare the actual depth of your RAM for example if i want an array of 512 reg variables (depth) and each is 8 bits (width) then it will be written like:
reg [7:0] ram[511:0];
so your code should look like:
reg [7:0] ram[15:0];

Implementing a closed loop in verilog

I'm trying to implement a loop without using loop instructions in verilog so i made a counter module and the simulation went perfectly but when i tried to implement it on the FPGA i got a lot of errors in the mapping , like this one
ERROR:MapLib:979 - LUT4 symbol
"Inst_Count/Mcompar_GND_1105_o_xcount[7]_LessThan_25_o_lut<0>" (output
signal=Inst_Count/Mcompar_GND_1105_o_xcount[7]_LessThan_25_o_lut<0>) has
input signal "Inst_Count/Madd_x[9]_GND_1105_o_add_0_OUT_cy<0>" which will be
trimmed. See Section 5 of the Map Report File for details about why the input
signal will become undriven.
These errors only occurred when i replaced this module with the loop instruction module so does anyone no what's the problem with this one ?
Thanks for giving this your time :)
module average( input rst , output reg [7:0]
reg [7:0] count;
reg [7:0] prv_count;
reg clk;
initial
begin
count = 8'd0;
end
always # (posedge rst)
begin
clk = 1'b0;
end
always # (clk)
begin
prv_count = count ;
count = prv_count + 1'b1;
end
always # (count)
begin
if (count == 8'd255)
G_count= count;
else
begin
clk = ~clk;
G_count= count;
end
end
endmodule
Oh, this is just plain wrong. I don't really think anybody can help here without giving you a lecture on Verilog, but... some things that are noticeable right away are:
You have an obvious syntax error in your module parameter list where you do not close it (i.e. ) went missing).
Clock should be an input to your module. Even if you depend on reset input only and use a register as a "clock", it won't work (logically and you have combinatorial loop that must be broken or else...).
Do not use initial block in the code that should be synthesizable.
prv_count is useless.
No need to manually take care of the overflow (check for 255? 8'd255 is exactly 8'b11111111 and it resets to 0 if you add 1'b1, etc).
And tons of other things, which raise the obvious question — have you tried reading some books on Verilog, preferably those covering synthesizable part of the language? :) Anyhow, what you are trying to do (as far as I can understand) would probably look something like this:
module average(input clk, input rst, output reg [7:0] overflow_count);
reg [7:0] count;
always #(posedge clk or negedge rst) begin
if (~rst) begin
count <= 8'b0;
overflow_count <= 8'b0;
end else begin
count <= (count + 1'b1);
if (count == 8'b0)
overflow_count <= (overflow_count + 1'b1);
end
end
endmodule
Hope it helps and really suggest you take a look at some good books on HDL.

Resources