My input consists of a parameterized number of units. The output I need is to remove the first bit of each unit.
For example if the input has units of size 3-bits each and the input value was 011011, the output should be 1111
Here is the solution i used for this:
parameter data_in_size = 11;
parameter data_out_size = 10;
parameter units = 4;
parameter skip_bits = 1;
input [data_in_size * units - 1 : 0] data_in;
output [data_in_size * units - 1 : 0] data_out;
genvar i;
generate
for (i = 0; i < units; i = i + 1) begin
assign data_out[data_out_size * i +: data_out_size] = data_in [(data_in_size * i + skip_bits) +: data_out_size];
end
endgenerate
But I get the following error The left-hand-side of continuous assignment is illegal
How can i get through this error and why i am getting it ?
Your code works perfectly well. Might be a simulator issue.
But I would like to focus on logic implementation in your code. The logic seems to be wrong.
First error seems to be in declaration of data_out and the slicing logic : data_in [(data_in_size * i + skip_bits) +: data_out_size] must be replaced with: data_in [(data_in_size * i + skip_bits) +: data_in_size]
Lets suppose i=0; data_out_size=3; data_in_size=4 then the LHS evaluates to data_out[2:0] = data_in[4:1]. When i=1, data_out[5:3] = data_in[8:5]. As you can see the bit slicing seems to be incorrect. Since LSB is sliced.
I think you might need to have following logic for bit slicing:
assign data_out[data_out_size * i +: data_out_size] = data_in[(data_in_size * i) +: (data_in_size - skip_bits)];
This will slice the MSB bit of every unit chunk, keeping the rest of bits as it is.
I simulated your code at EdaPlayground here. As an example, you will have following data_out and data_in values. Note the sliced MSB from each unit.
data_int = 1100101010010101
data_out = 100010001101
Related
I'm trying to write a synthesizable code in .sv to meet my requirements, but got stuck at the very end without a solution;
I've an incoming wire which is 99 bit wide and 10 (MAX) deep
I need to feed this to a module and get its output which is 99 bit
the output needs to be assigned to an array (99 bit wide ) from 0 .. max
I can't paste the snippet, but this is what I've coded:
--
param MAX = 10;
param TOT_INST = 45 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0]
genvar x,y,z ;
generate
for (x = 0, z=0; x<=MAX-1; x=x+1, z=z+1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
some_module mod_inst ( .in1(inwire[x]), .in2(inwire[y]), .y(outwire[z]) );
end
end
endgenerate
--
The expectation is to get outwire[0] to be an output of inwire[0] and inwire[1], outwire[1] to be a function of inwire[0], inwire[1] etc. So, it becomes necessary to increment the index of outwire.
I used another genvar z for this purpose (to increment from 0 to 44). But, it looks like the SV doesn't support multiple genvar variables to be incremented? im getting compilation error at the for loop itself.
Is there any way to achieve what i need? I really appreciate you taking time to go through this question. Any insight would be really helpful.
Thanks
Jr.
I understand your intent. It seems you are trying to use comma expressions, but they wont work here.
Also, it seems that the genvar can only be assigned in the initialization and increment of the for loop, otherwise it would be easy to increment them on the innermost loop.
Since you must have unique drivers to the outwires, and the number of entries you declared (45) matches the number of instances you will create I assume you simply want them to be set incrementally.
What I would do is to calculate the number of iterations algebraically and create a local parameter. If you can't see how, review triangular numbers.
parameter MAX = 10;
// Generalizing your TOT_INST
parameter TOT_INST = MAX * (MAX - 1) / 2 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0];
genvar x,y;
generate
for (x = 0; x <= MAX-1; x = x + 1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
localparam z = TOT_INST - ((MAX - x - 2) * (MAX - x - 1)) / 2 + y - MAX;
initial begin
$display("%d %d %d", x, y, z);
end
end
end
endgenerate
The formula would be simpler if we used the x in the inner loop.
In the following Verilog module, I'd like to understand why the blocking assignment using concatenation doesn't give the same result as the 2 commented out blocking assignments.
When I run the program on the FPGA, it gives the expected result with the 2 blocking assignments (the leds blink), but not with the blocking assignment using concatenation (the leds stay off).
Bonus points for answers pointing to the Verilog specification explaining what is at play here!
/* Every second, the set of leds that are lit will change */
module blinky(
input clk,
output [3:0] led
);
reg [3:0] count = 0;
reg [27:0] i = 0;
localparam [27:0] nTicksPerSecond = 100000000;
assign led = {count[3],count[2],count[1],count[0]};
always # (posedge(clk)) begin
// This works:
//count = i==nTicksPerSecond ? (count + 1) : count;
//i = i==nTicksPerSecond ? 0 : i+1;
// But this doesn't:
{count,i} = i==nTicksPerSecond ?
{count+1, 28'b0 } :
{count , i+1};
end
endmodule
PS: I use Vivado 2018.2
The reason is because the widths of count+1 and i+1 are both 32 bits. An unsized number is 32 bits wide (1800-2017 LRM section 5.7.1) and the width of the addition operator is the size of the largest operand (LRM section 11.6.1). To make your code work, add a proper size to your numeric literals
{count,i} = i==nTicksPerSecond ?
{count+4'd1, 28'b0 } :
{count , i+28'd1};
A simpler way to write this code is
always # (posedge clk)
if (i== nTicksPerSecond)
begin
count <= count + 1;
i <= 0;
end
else
begin
i <= i + 1;
end
I'm trying to write a test_bench for a dynamic size register.
I defined a parameter variable like this and instantiated a register module:
parameter integer regSize = 8;
register #(.size(regSize)) R1 (
.clock(clk),
.reset(rst),
.enable(enb),
.regIn(in),
.regOut(outp)
);
now forexample I want to define "in" variable ( the 4th input of module )
reg [regSize - 1: 0] in = (regSize)'b0;
I expect this works as : reg [regSize - 1: 0] in = 8'b0;
But it doesn't.
I get this error:
near "'b": syntax error, unexpected BASE, expecting ';' or ','
How should I write this?
Thanks for any help.
Use the concatenation repeat structure:
reg [regSize - 1: 0] in = {regSize{1'b0}};
Or in System Verilog you can do :
reg [regSize - 1: 0] in = '0;
You might also need something similar for adding e.g. 1 to a counter with variable length:
...
counter <= counter + {{(regSize-1){1'b0}},1'b1}; // regSize>1!
As that becomes difficult to read I prefer to use a localparam :
localparam [regSize-1:0] value_1 = {{(regSize-1){1'b0}},1'b1}; // regSize>1!
...
counter <= counter + value_1;
Note that it can get rather messy if you also want to have a width of 1 bit as but I assume adding 1 to a 1 bit counter is likely to be a design error.
There is no need to pad 0's to a number in Verilog, it does that automatically for you. You can just do
reg [regSize - 1: 0] in = 0;
I have a vector like this
wire [N:0] Vector[M:0];
and I want to convert it into an array of size M*N. A pseudocode could be:
Array={Vector[M],Vector[M-1],Vector[M-2],...,Vector[0]}
So I want to concatenate the elements of the vector in an array.
I tried to do it using a loop, but when I try to simulate it gives a fatal error without description. Is there a simpler way of doing it? Thanks!!!
I guessing you tried something like this: Array[N*(index+1) : N*index ] = Vector[index]; in an always block. This will not work because Verilog requires both sides of the range to be constants (during simulation).
There are three Verilog approaches to get the desired assignment:
Bit assignment
Array slice assignment
Generate loop assignment
Bit assignment
In Verilog-95 (IEEE1364-1995), the only ways achieve this was bit assignments with a double for-loop:
Array[N*index_m+index_n] = Vector[index_m][index_n];
reg [M*N:0] Array;
integer index_m, index_n;
always #(Vector) begin // Verilog-95 style sensitivity list
for(index_m=0; index_m <= M; index_m = index_m + 1) begin
for(index_n=0; index_n <= N; index_n = index_n + 1) begin
Array[N*index_m+index_n] = Vector[index_m][index_n];
end
endgenerate
Array slice assignment
Another approach is vector slicing with +: (A feature added in IEEE1364-2001. Refer to Indexing vectors and arrays with +:). This allows one variable starting index and a constant offset for the range.
Array[N*index +: N ] = Vector[index];
reg [M*N:0] Array;
integer index;
always #* begin // Verilog-2001 style sensitivity list
for(index=0; index <= M; index = index + 1) begin
Array[index*N +: N ] = Vector[index];
end
endgenerate
Generate loop assignment
A third approach would be to use a generate block (also added in IEEE1364-2001). A generate blocks for-loop unravels at elaboration. There form you could use Array[N*(index+1) : N*index ] = Vector[index];, provided that index is a genvar:
Or with a generate block
wire [M*N:0] Array; // note 'wire'
generate
genvar g_index; // The 'g_' prefix is suggested coding style to identified genvars
for(g_index=0; g_index <= M; g_index = g_index + 1) begin
assign Array[(g_index+1)*N] : g_index*N] = Vector[g_index];
//assign Array[g_index*N +: N ] = Vector[g_index]; // +: also works
end
endgenerate
SytemVerilog (IEEE1800) added bit streaming which can do the operation in one step Array = {>>{Vector}};, but I am unaware how common it is supported for synthesis. (I typically use array slicing (+:) with SystemVerilog's foreach in an always_comb)
First of all, I had a lot of difficulty phrasing the title of this question. So if you understand the problem I'm facing, and there is a better way to word it and the question has been answered before, I apologise, and please do point out to me how I can resolve this. Anyways, here's the relevant code snippet that I've truncated for clarity:
parameter RAM_DEPTH = 256;
reg ram [0:RAM_DEPTH-1]; //256 deep memory, 1-bit size per location
parameter NUM_INST = 64;
parameter N = 4;
genvar x;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
//instantiate a module here
//connect N bits to input port
//which N bits depends module number x
mod inst (
.in(ram[x*N : x*N + N - 1]) //the error is here
);
end endgenerate
The error is:
error: Array cannot be indexed by a range.
I understand that this is because ram is declared as reg ram [0:RAM_DEPTH-1] instead of reg [0:RAM_DEPTH-1] ram. But is there a way to automate concatenation of RAM bits based on the N parameter, i.e. instead of having to write .in({ram[x*N],ram[x*N+1],ram[x*N+2],ram[x*N+3]}), there's an automated range selection logic that concatenates the bits based on N. You can imagine that if, say, N = 256, I would have to write a very long concatenation operator, and also makes my module less parametric.
In this case, should I just be using reg [0:RAM_DEPTH-1] ram declaration, and re-write my module to support bit updates on a single register array instead?
Thanks.
The easiest solution I found was to do as you suggested and turn reg ram [0:RAM_DEPTH-1] into reg [0:RAM_DEPTH-1] ram. An alternative would be the following:
parameter RAM_DEPTH = 256;
parameter NUM_INST = 64;
parameter N = 4;
reg [RAM_DEPTH-1:0] ram; //256 deep memory, 1-bit size per location
reg [N-1:0] ramwires [NUM_INST-1:0];
genvar x;
integer y, z;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
mod inst (
.in(ramwires[x])
);
end endgenerate
always#(*)
for (y = 0; y<NUM_INST; y = y + 1) begin
for (z=0; z<N; z = z + 1) begin
ramwires[y][z] = ram[y*N+z];
end
end
This converts the 1D array into a 2D array, which is easily passed into the module, while still being parameterizable.