I'm currently implementing a PRNG in SystemVerilog using an LFSR as described here. The width should be variable using a parameter. I reach a construct of:
module PRNG
#(
parameter WIDTH = 32,
parameter SEED = 1
)
(
input clk,
input update,
output reg [WIDTH-1:0] prng
);
reg [WIDTH-1:0] lastRng = WIDTH'(SEED);
always_comb begin
var tap;
case (WIDTH)
default: tap = 0;
3: tap = lastRng[2] ^~ lastRng[1];
[...]
168: tap = lastRng[167] ^~ lastRng[165] ^~ lastRng[152] ^~ lastRng[150];
endcase
if (update) begin
prng = {lastRng[WIDTH-2:0], tap};
end else begin
prng = lastRng;
end
end
always_ff #(posedge clk) begin
lastRng <= prng;
end
endmodule
Now, while simulating this module using Verilator it complains of selection indices out of range for every case > WIDTH-1, even though (I think that) these cases should clearly be optimized out, since WIDTH is a constant:
Selection index out of range: 167:167 outside 31:0
Is there a simple way around this error, without eg. bit shifting logic just to index the nth bit?
To do this, you need to use a generate.
Try this
Move the case statement block outside of the always_comb (you can't use generate in an always block, someone correct me if that does not stand for always_comb
Change the tap = statements to be assign tap =.
(optional) Surround the case block with generate/endgenerate. This isn't required but you might find it helps readability.
You need to restructure your block so you don't have out-of-bound references. In simulation, the compiler is not required to optimize your procedural code based on constant values, so it needs to be legal. Moving the case statement outside the always block changes it from procedural to elaboration based (same for if and for-loop statements.
logic tap;// same as var tap, but better to show the implicit data type
case (WIDTH)
default: assign tap = 0;
3: assign tap = lastRng[2] ^~ lastRng[1];
[...]
168: assign tap = lastRng[167] ^~ lastRng[165] ^~ lastRng[152] ^~ lastRng[150];
endcase
always_comb
if (update)
prng = {lastRng[WIDTH-2:0], tap};
else
prng = lastRng;
Related
I do have a problem understanding how always_ff works in a way of creating a mesh of logic gates.
What do I mean ? When I use always_comb like here :
module gray_koder_dekoder(i_data, i_oper, o_code);
parameter LEN = 4;
input logic [LEN-1:0] i_data;
input logic i_oper;
output logic [LEN-1:0] o_code;
int i;
always_comb
begin
o_code = '0;
i = LEN-1;
if (i_oper == 1'b1) // 1'b1 - operacja
begin // kodowania
o_code = i_data ^ (i_data >> 1);
end
else // dla kazdej innej wartosci
begin // realizuj dokodowanie
o_code = i_data;
for (i=LEN-1; i>0; i=i-1)
begin
o_code[i-1] = o_code[i]
^ i_data[i-1];
end
end
end
endmodule
So how do I see it.
At the beggining the program sees that output is 0000,
now if the i_oper is equal 1 so the input is 1 then it checks changes the o_code to i_data ^ (i_data >> 1) so now the program want's to do combination of logic gates for this operation but if the i_oper is equal 0 then the program makes another set of logic gates to get different o_code.
So the always_comb gives the final result for every bite in the i_data that results in o_code.
So my teacher said that always_comb is "blocking" but always_ff is not "blocking" I don't get it ...
So the always_ff doesn't give the final result of logic gates for the input to get a specific output ?
Another example of always_comb :
module gray_dekoder (i_gray, o_data);
parameter LEN = 4;
input logic [LEN-1:0] i_gray;
output logic [LEN-1:0] o_data;
always_comb
begin
o_data = i_gray;
for (int i=LEN-1; i>0; i=i-1)
o_data[i-1] = o_data[i] ^ i_gray[i-1];
end
endmodule
So at the beggining the program sees that the output is 0000 so it will make a set of logic combination to have 0 at the end. Then he sees loop for that modifies the output so the program checks every bit of the input like bit nr 3 then nr 2 then nr 1 etc. and creates for every input specific output so now the output is not 0000 anymore but set of instructions that modifies the output made from loop "for"
so the always comb gives a final result from the analizing the whole code from top to bottom of "always_comb" and creates a set of instructions/set of logic gates that helps it. Because always_comb overwrites the previous instructions like 0000 it was a basic instruction but then was overwrited by the loop "for"
But maybe I think wrongly because if instruction doesn't overwrite the 0000 instruction like here :
module replace(i_a, i_b, o_replaced, o_error);
parameter BITS = 4;
input logic signed [BITS-1:0] i_a, i_b;
output logic signed [BITS-1:0] o_replaced;
output logic o_error;
int i;
always_comb
begin
o_replaced = '0;
if(i_b < 0 || i_b > BITS)
begin
o_error = 1;
o_replaced = 'x;
end
else
begin
i = i_b;
o_replaced = i_a;
o_replaced[i-1] = 1;
o_error = 0;
end
end
endmodule
I have here 0000 output that isn't overwrited for "else" So I don't know what happens then.
I think of always_comb as an "final result" that gives a set of instructions how to create logic gates. But the final result is at the end, so if something changes then the beggining result doesn't matter "overwrited" but with if loop it doesn't work with my mind set.
So always_ff I heard that it doesn't give a final result that it can stop at any point not like in always_comb that the program analysis from top to bottom.
Verilog is designed to represent behavior of hardware and it is not a regular programming language. It operates different semantics.
At a very top glance, hardware consists of combinational logic and flops (and latches). From the other point of view hardware is a set of parallel functions which are synchronized across design by clocks. This means that at a clock edge a lot of hardware devices start working in parallel and they should produce results by the next clock edge. Those results could be used by other functions at the next clock cycle.
Roughly, combinational logic defines a function, flops provide synchronization.
In verilog all those devices are described with always blocks. TUse of edges, e.g., #(posedge clk) provides synchronization points and usually defines flops in the code. A simple function and a flop look like the following.
// combinational logic
always #* // you can use always_comb instead
val = in1 & in2; // a combinational function
// flop
always #(posedge clk) // you can use always_ff instead
out <= val; // synchronization
So, in the example val is calculated by the combinational function and its synchronous out is made available to other functions to be used by a flop. You can see progression of clocks and results in a waveform.
So, this is what always_ff is doing, just providing synchronization and expressing flops for synthesis.
In general, always, always_comb, always_ff and always_latch are identical. The last three are system verilog blocks and just provide additional hints to the compiler which can run additional checks on them. I intentionally used just always blocks in my example to show that. There are some other conditions which need to be programmed to cleanly express the intention. So, your assertion about different working of always_ff has no base. It works the same as other always blocks.
What I think confuses you, is use of blocking (=) and non-blocking (<=) assignments. It does not matter for synthesis which one you use, but it matters for simulation. The difference is described and numerous documents and examples. To understand it properly you need to look into verilog simulation scheduling semantics.
But the rule of thumb is that you should use non-blocking assignments (<=) in flops and use blocking (=) in combinational logic. In flops '<=' allows simulating real behavior of flops. Remember that hardware is a massively-parallel evaluation engine. Consider the following example:
always_ff #(posedge clk) begin
out1 <= in1;
out2 <= out1;
end
The above example defines at least two flops working at posedge clk. out1 and out2 must be synchronized at this clock. It means, the flops have to catch values which existed before the edge and present them after the edge. So, for out1 the value existed before the edge is in1, evaluated by a combinational logic. What would be the value of out2? Which value existed before the edge? Apparently, the value of the out1 before it gets changed to the new value of in1.
clk ___|---|___|---|___
in1 0
out1 x 0 << new value of in1
out2 x << old value of ou1
.
in1 1 .
out1 . 1 << new value of in1
out2 . 0 << old value of ou1
So, after evaluation of the block, the at the first edge the value of out2 will be 'x' (previous value of out1), at the second clock edge it will finally get value of 'in1' as it existed at the previous clock cycle.
I hope it would make your understanding a bit better.
My question emphases the amend of the struct's element!
struct packed {
logic word;
logic [31:0] test;
} a;
logic [32:0] a_input;
logic a_ff;
always_latch begin
if (enable) begin
a = a_input; // map the bus `a_input` to the struct `a`
a.test = a.test[1:0]; // change the `test` child
end
end
enable and a_input are flip-flops on the same clock (then can reach the latch at different moment in physical hardware)
a is the modified comb/latch version of a_input
Vivado doesn't synthetize this as a latch.
I want to change only the a.test, a_input isn't a struct then I can't use a_input.test. Then that code describes well what I want to do.
How can I get a latch?
Edit: I can use a mix of always_comb, always_ff and assign.
struct packed {
logic word;
logic [31:0] test;
} a, a_comb;
logic [32:0] a_input;
logic a_ff;
always_ff #(posedge clk)
if (enable) begin
a_ff <= a_comb;
end
always_comb begin
a_comb = a_input; // map the bus `a_input` to the struct `a_comb`
a_comb.test = a_comb.test[1:0]; // change the `test` child
end
assign a = (enable)? a_comb: a_ff;
I'd like to avoid these extra lines and temporary logics, it should be possible using a simple always_latch.
Edit #2:
I really want to amend only the test element of my struct, and let all the other element being assigned from a_input.
If it was a FF, it'd do:
always_ff #(posedge clk)
if (enable) begin
a <= a_input; // map the bus `a_input` to the struct `a`
a.test <= a.test[1:0]; // change the `test` child
end
end
I want to convert that logic to a latch instead of FF.
First make sure a simple latch will synthesize as a latch. If it doesn't, then that a separate problem and you will need to figure out; check your synthesizer version and target device.
always_latch
if (enable)
a <= a_input;
I'm not sure why your latch does not work. Latches should be kept simple to prevent unintended complex feedback. Your code looks simple enough as the only thing it is doing beyond a basic D-latch is mask some bits.
Assuming the basic latch synthesizes correctly, you can do combinational logic before or after the latch. Ex:
always_comb begin
a_comb = a_input;
a_comb.test = a_comb.test[1:0];
end
always_latch
if (enable)
a <= a_comb;
or:
always_latch
if (enable)
a_lat <= a_input;
always_comb begin
a = a_lat;
a.test = a.test[1:0];
end
If you are only masking bits, you should be able to use:
always_latch
if (enable)
a <= a_input & 32'h100000003;
If the above three doesn't work, but a simple latch does work properly, then it might be optimization related. In this case make sure a_input and enable are FF and are functionally toggleable (ie not optimized away due do something else upstream). Also check how a is begin used down stream.
I tried this code in vivado, it able to synthesize it to LDCE latch .
module latch (
input logic a_input,enable,
output logic a
);
always_latch if(enable) a = a_input;
endmodule
A latch is effectively a level sensitive register rather than edge sensitive. The driver of enable isn't shown, so that may be getting driven to 0 by Vivado. A quick example, if you are trying to make a latch the following would should do it.
always#(enable) begin
a = enable ? a_input : a;
end
Generally, we tend to want to avoid latches, but if you are dead set on making one, you can start by getting rid of the posedge clk from the sensitivity list and changing it to *. That would mean that on any change of the signals, you would get a re-evaluation of the block. The fact that enable would control loading of the a_ff term while high, and then hold the value while low, should be seen as a latch provided that enable is driven from some source and not optimized to a constant 0 state because it is a undriven signal.
Is it possible to evaluate statements in an always block when any bit in a bus is toggled(posedge)? e.g. If I have:
input [1:0] a;
always#([what to do here?]) begin
[statements]
end
I have tried
always#(posedge a)
and also
always#(posedge a[1:0])
but simulation shows only on posedge of a[0] are the statements evaluated.
I am not able to use "," or "or" because the width is determined by a parameter.
Thank you in advance!
You need to generate a process for each bit
event ev;
for (genvar ii =0;ii<$bits(a);ii++) begin
always #(posedge a[ii] ) ->>ev;
end
always #ev ...
I wrote a 32-bit LFSR based on the taps from [1]. I want to ask if the following description is right for the 32-bit LFSR with the taps 32,22,2 and 1.
module lfsr (
input logic clk_i,
input logic rst_i,
output logic [31:0] rand_o
);
logic[31:0] lfsr_value;
assign rand_o = lfsr_value;
always_ff #(posedge clk_i, negedge rst_i) begin
if(~rst_i) begin
lfsr_value <= '0;
end else begin
lfsr_value[31:1] <= lfsr_value[30:0];
lfsr_value[0] <= ~(lfsr_value[31] ^ lfsr_value[21] ^ lfsr_value[1] ^ lfsr_value[0]);
end
end
endmodule
[1] http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
Looks Ok. you could also use an XOR, instead of an XNOR, as long as you reset to something else (the XOR version locks up at all 0's, the XNOR at all 1's).
For many apps the pseudo-random output is the single bit you shift out (31 in your case), rather than the entire register. It's also (more?) common to shift right, and put the XOR data in the top bit, and use the bit 0 output as your PR data.
Your code is specifically SystemVerilog, and not Verilog, so I've removed the Verilog tag.
I have a bunch of signals like this:
logic [7:0] in0;
logic [7:0] in1;
logic [7:0] in2;
logic [7:0] in3;
That I want to assign to an array:
logic [7:0] in_array [4];
assign in_array[0] = in0;
assign in_array[1] = in1;
assign in_array[2] = in2;
assign in_array[3] = in3;
Easy enough, but if instead of 4 items I have 128 this gets annoying. I am sure there is a combination of defines and generates that can do this in a loop. Something like:
`define IN(x) inx
genvar i;
generate
for(i = 0; i<4; i++) begin
assign in_array[i] = `IN(i);
end
endgenerate
The above code doesn't work, but I think that I have done something like this before.
Simplifying that code is something that cannot be done in SystemVerilog. You can reduce you typing by creating a macro like below (note the double backticks ``), but you will still need to manually write each index. Macros are are resolved before generate loops and the input variable to the macro is treated as a literal.
// short named macro for reduced typing
// Note: using short named macro is typically a bad practice,
// but will be removed latter with an undef
`define A(idx) assign array_in[idx] = out``idx
//This works
`A(0);
`A(1);
`A(2);
`A(3);
// doesn't work. For example # gidx==0 will eval to 'assign array_in[0] = outgidx;'.
// There is not outgidx
genvar gidx;
generate
for(gidx=0; gidx<4; gidx++) begin
`A(gidx);
end
endgenerate
`undef A // prevent macro from from being used latter on
If it is just a small number of entries, it is best to do it manually. If it is large number of entries, then you need to consider a way to generate the for you, such as embedded coded.
There are also various embedded code (such as Perl's EP3, Ruby's eRuby/ruby_it, Python's prepro, etc.) that can generate the desired code. Pick your preference. You will need to per-process these files before giving to the compiler. Example with EP3 generating 400 assignments:
#perl_begin
foreach my $idx (0..400) {
printf "assign array_in[%0d] = out%0d;", $idx, $idx;
}
#perl_end
Use `` to separate text from argument.
`define IN(x) in``x
But there is another issue with the variable i not being declared at the time when the macro is evaluated. Thus the whole generate loop just connects to ini, because i is just another letter. Because of this macros cannot be assigned by dynamically allocated values.
The environment of your module already has to connect explicitly to each input assign in0 = out0; ... assign in127 = out127. So the simplest solution would be to have in_array as your modules input and let the environment connect to it assign array_in[0] = out0.
Something like this:
module parent_module();
/*some other stuff that has outputs out0, out1 etc.*/
logic [7:0] array_in[4];
assign array_in[0] = out0;
assign array_in[1] = out1;
assign array_in[2] = out2;
assign array_in[3] = out3;
my_module(.array_in(array_in));
endmodule