I want to create and define a localparam array in SystemVerilog. The size of the array should be configurable, and the value of each localparam array cell calculated based on its location. Essentially this code:
localparam [7:0] [ADDR_BITS-1:0] ADDR_OFFSET = '{
7*PAGE_SIZE,
6*PAGE_SIZE,
5*PAGE_SIZE,
4*PAGE_SIZE,
3*PAGE_SIZE,
2*PAGE_SIZE,
1*PAGE_SIZE,
0
};
but where the first '7' is replaced with a parameter, and where the parameter initialization is extended to the generic case. So I need a way to loop from 0 to (N-1) and set ADDR_OFFSET(loop) = loop*PAGE_SIZE.
The "obvious" option in SystemVerilog would be generate, but I read that placing a parameter definition inside a generate block generates a new local parameter relative to the hierarchical scope within the generate block (source).
Any suggestions?
For background reference: I need to calculate an actual address based on a base address and a number. The calculation is simple:
real_address = base_address + number*PAGE_SIZE
However, I don't want to have the "*" in my code since I am afraid the synt tool will generate a multiplier, that it will then try to simplify since PAGE_SIZE is a constant value. I am guessing that this can lead to more logic than if I try to do all calculations when generating the localparam array, since this for sure will not give any multiplier in logic.
So with the above localparam definition, I perform the desired address calculation like this:
function [ADDR_BITS-1:0] addr_calc;
input [ADDR_BITS-1:0] base_addr;
input [NBITS-1:0] num;
addr_calc = base_addr + ADDR_OFFSET[num];
endfunction
I think perhaps I found a solution. Wouldn't I essentially accomplish the same by not defining a localparam array, but rather performing the address calculation inside a loop? Since systemverilog sees the loop variable as "constant" (when it comes to generating logic) that seems to accomplish the same? Like this (inside the function I wrote above):
for (int loop1 = 0; loop1 < MAXNUM ; loop1++) begin
if (num == loop1) begin
addr_offset = CSP_PAGE_SIZE*loop1;
end
addr_calc = base_addr + addr_offset;
end
You can set your localparam with the return value of a function.
localparam bit [7:0] [ADDR_BITS-1:0] ADDR_OFFSET = ADDR_CALC();
function bit [7:0] [ADDR_BITS-1:0] ADDR_CALC();
for(int ii=0;ii<$size(ADDR_CALC,1); ii++)
ADDR_CALC[ii] = ii * PAGE_SIZE;
endfunction
Related
I have the following signals:
logic [X-1:0][Y-1:0] twoDim;
logic [(X*Y)-1:0] oneDim;
I want to assign the entirety of twoDim to oneDim i.e. if I wrote something like this:
assign oneDim = twoDim;
And parameter X = 5 then I would expect the behaviour to be the same as the following:
assign oneDim = { twoDim[4], twoDim[3], twoDim[2], twoDim[1], twoDim[0] };
How would this be accomplished succintly in Synthesizable SystemVerilog for all possible values of X, Y (which are int unsigned) ?
If you try such assignment you will get an error because the synthetizer does not know about the structure of your 2D array and how it can flatten it. In your case you want to store the rows one after the other, which is called row-major arrangement.
You can produce synthetizable code with a generate for loop:
localparam X = 10; // N rows
localparam Y = 20; // N cols
// Note I swapped X and Y dimensions
logic [Y-1:0][X-1:0] twoDim;
logic [(X*Y)-1:0] oneDim;
genvar i;
generate
for (i = 0; i < X; i = i + 1) begin
assign oneDim[i*Y +: Y] = twoDim[i];
end
endgenerate;
For packed aggregate types, you do not need to go through all this trouble. The following will be sufficient. System verilog allows assigning arrays of compatible types (7.6).
assign oneDim = twoDim;
I was trying to store two specific spans of an array inside another array, but I get an error.
What I want to do:
I have [8-1:0]A as module input, and I wanna store :
logic [8-1:0]temp = {A[4:7],A[0:3]};
but, when I simulate my module in test bench, I get an error in modelSim:
error: Range of part-select into 'A' is reversed.
Ways I tried:
Convert logic to wire,
Use assign
I think the idea is problematic.
example :
A = 8'b11000101 -> I want temp to be -> temp=8'b00111010
->explain:
A[0]=1,A[1]=0,A[2]=1,A[3]=0,A[4]=0,A[5]=0,A[6]=1,A[7]=1.
A[4..7]=4'b0011,A[0..3]=4'b1010
`timescale 1ns/1ns
module examp(input [7:0]A,output [7:0]O);
logic [7:0]temp = {A[4:7],A[0:3]};
// I wanna temp be 8'b00111010.
assign O = temp;
endmodule
`timescale 1ns/1ns
module examp_tb();
logic [7:0]aa=8'b11000101;
wire [7:0]ww;
examp MUX_TB(.A(aa),.O(ww));
initial begin
#200 aa=8'b01100111;
#200 $stop;
end
endmodule
Note : In the example above, I have a compile error, but in the main question, I have simulation error.
The streaming operator can be used to reverse a group of bits. So you could do:
logic [8-1:0]temp = { {<<{A[7:4]}} , {<<{A[3:0]}} };
The streaming operator also takes a slice argument, which is used to preserve a grouping of bits before performing the bit reversal. The problem with what you want is you are trying to reverse the bits within the slice. You can accomplish this by nesting the streaming operators. This approach with be more useful when dealing with larger vectors
logic [7:0] temp1 = {<<{A}}; // A[0:7]
logic [7:0] temp2 = {<<4{temp1}}; // A[4:7],A[03];
or in a single line
logic [7:0] temp = {<<4{ {<<{A}} }};
One way to swap bits within a nibble is to use a function:
module examp (input [7:0] A, output [7:0] O);
assign O = {swap_nib(A[7:4]), swap_nib(A[3:0])};
function logic [3:0] swap_nib (logic [3:0] in);
swap_nib[3] = in[0];
swap_nib[2] = in[1];
swap_nib[1] = in[2];
swap_nib[0] = in[3];
endfunction
endmodule
How do I create an 2D array in Verilog? To be precise, I wanted a 32x100 matrix. Then, how do I define the values of each position of this array?
I tried some stuff I found on the web, but my code needs to be synthesised , simulating is not enought.
Thanks
My attempt so far (I'm new to verilog)
module top(
input a
);
integer i;
reg [31:0] arr[0:99];
initial begin
for(i=0;i<100;i=i+1) begin
assign arr[i] = 22;
end
end
endmodule
Don't use assign within an initial block or always bock. It is procedural assign a simulation feature scheduled for depletion (IEEE Std 1800-2012 C.4 Constructs identified for deprecation).
I'm guessing you are targeting FPGA, you can initialize the array with:
initial begin
for(i=0;i<100;i=i+1) begin
arr[i] = 22;
end
end
IC design ignore initial the code would have to go into the reset condition of an always block. Alternatively if it is a ROM you can use a generate block:
genvar i;
generate
for(i=0;i<100;i=i+1) begin
assign arr[i] = 22;
end
endgenerate
I'm looking to perform the cross-correlation* operation using an FPGA.
The secific part that I am currently struggling with is the multiplication piece. I want to multiply each 8-bit element of a nx8 shift register that uses excess or offset representation** against a nx1 shift register where I treat 0s as a -1 for the purposes of multiplication.
Now if I was doing that for a single element, I might do something like this for the operation:
input [7:0] dataIn;
input refIn;
output [7:0] dataOut;
wire [7:0] dataOut;
wire [7:0] invertedData;
assign invertedData = 8'd0 - dataIn;
assign dataOut <= refIn ? dataIn : invertedData;
What I'm wondering is how do I scale this to 4, 8, n elements?
My first though was to use a for loop like this:
for(loop=0; loop < n; loop = loop+1)
begin
assign invertedData[loop*8+7:loop*8] = 8'd0 - dataIn[loop*8+7:n*8];
assign dataOut[loop*8+7:loop*8] <= refIn[loop] ? dataIn[loop*8+7:loop*8] : invertedData[loop*8+7:loop*8];
end
This doesn't compile, but that's more or less the idea, and I can't seem to find the right syntax to do what I want.
https://en.wikipedia.org/wiki/Cross-correlation
** http://www.cs.auckland.ac.nz/~patrice/210-2006/210%20LN04_2.pdf
for(loop=0; loop < n; loop = loop+1)
begin
assign invertedData[n*8+7:n*8] = 8'd0 - dataIn[n*8+7:n*8];
assign dataOut[n*8+7:n*8] <= refIn[n] ? dataIn[n*8+7:n*8] : invertedData[n*8+7:n*8];
end
There's a few issues with this, but I think you can make this work.
You can't have 'assign' statements in a for loop. A for loop is meant to be used inside a begin/end block, so you need to change invertedData/dataOut from wire type to reg type, and remove the assign statements.
You generally can't have variable part-selects, unless you use the special constant-width selection operator (verilog-2001 support required). That would look like this: dataIn[n*8 +:8], which means: select 8 bits starting from n*8.
I don't know about your algorithm, but it looks like loop/n are backwards in your statement. You should be incrementing n, not loop variable (or else all statements will be operating on the same part-select).
So considering those points I believe this should compile for you:
always #* begin
for(n=0; n< max_loops ; n=n+1)
begin
invertedData[n*8 +:8] = 8'd0 - dataIn[n*8 +:8];
dataOut[n*8 +:8] <= refIn[n] ? dataIn[n*8 +:8] : invertedData[n*8 +:8];
end
end
Suppose I have an array like this:
parameter n=100;
reg array[0:n-1];
How would one get the logic-OR value of each and every bit in the array?
The resulted circuit must be combinatorial.
This is a follow up question from this one.
(see discussion below the answer)
I don't know if this meets your design requirements, but you might have a much easier time with a hundred bit bus reg [n-1:0] array; than by using an array of 1 bit wires. Verilog does not have the greatest syntax to support arrays. If you had a bus instead you could just do assign result = |array;
If you must use an array, than I might consider first turning it into a bus with a generate loop, and then doing the same:
parameter n=100;
reg array[0:n-1];
wire [n-1:0] dummywire;
genvar i;
generate
for (i = 0; i < n; i = i+1) begin
assign dummywire[i] = array[i];
end
endgenerate
assign result = |dummywire;
I'm not aware of a more elegant way to do this on arrays.