How to simplify compound assignments in yosys - verilog

I am trying to get yosys to synthesize my design to structural verilog for a tool which doesn't understand the syntax {A, B} to specify the concatenation of values A and B.
So for example when yosys generates statements like
assign C = {A,B};
assign {D,E} = F;
the tool chokes. I thought of using the splitnets pass to eliminate multibit wires, but the multibit ports still cause yosys to generate the {} syntax. Even running splitnets -ports leaves some assignments like
assign {A, B} = {C, D}
I was finally able to get these assignments to disappear using an additional run of opt. But this seems to be a very messy way of eliminating the {} construct.
Is there some nicer way to eliminate this construct without splitting all the input ports?

There is no universally applicable way to do that. The {..} operator is part of verilog and thus the verilog back-end uses it when appropriate.
However, in the example you gave all cells in the verilog output have single-bit in- and outputs, so the {..} operator is not needed for assigning cell ports, only for assigning wires to each other.
I've used the following script (executed in your rtl/ directory) as a baseline:
read_verilog aes_128.v table.v round.v
hierarchy -top aes_128
proc; flatten; synth
# opt_clean -purge
write_verilog -noattr -noexpr out.v
This will produce a Verilog file with the following assignments in it that use the {..} operator:
$ grep '{' out.v
assign \a1.S4_0.in = { key[23:0], key[31:24] };
assign { \a1.k0a [31:25], \a1.k0a [23:0] } = { key[127:121], key[119:96] };
assign \a1.v0 = { key[127:121], \a1.k0a [24], key[119:96] };
However, the signals a1.S4_0.in, a1.k0a, and a1.v0 are only present in the design because yosys tries to preserve as many of the original signal names as possible, to make it easier to debug the design.
Un-commenting the opt_clean -purge command will let yosys remove those signals, yielding an output file that does not use the {..} operator:
$ grep -c '{' out.v
0

Related

How to write verilog code if one input has the same value as one output

My output is A,B,C,D and input is x,y,z, from the truth table I just made I found that A has the same value as x, how could I express A when writing a verilog descriptive module?
I know from C = x+y I can write
AND G1(C,x,y);
but what should I do when I don't even need a gate? I can think of 2 ways of writing it, which one makes more sense?
module question1(B,C,x,y);
output B,C,x;
input x,y;
or
module question1(A,B,C,y);
output A,B,C;
input A,y;
Also I want to know if output D has the same value as output C, how could I mention D in the module?
Some tools require some logic between ports. You can use a buf primitive.
module question1(output A,B,C,D, input x,y,z);
buf (A,x);
...
endmodule
Otherwise, you can use a port expression
module question1(output A,B,C,D, input .x(A) ,y,z);
...
endmodule

Passing parameters to a Verilog function

I want to pass a parameter to a function and use it as a parameter (e.g. to select bits) but I don't know how to tell the function that this input is a constant.
For example, if I wanted to do this:
assign foo = bar[MY_PARAM:0];
I want to write my_function so that I could do this:
assign foo = my_function(bar, MY_PARAM);
In my case I need to do a little more that just select bits but not too much, and I'll want it to work for inputs of different bit widths.
If I just wanted to select a bit I could use the function below and I'd hope for a solution of similar form but I can't work out the syntax:
function my_function;
input [3:0] data, my_bit;
begin
my_function = data[my_bit];
end
endfunction
As per Silicon1602's answer, the code I'd need for this would be:
virtual class myClass#(parameter LOCAL_PARAM);
static function [LOCAL_PARAM:0] my_function;
input [LOCAL_PARAM:0] data;
begin
my_function = data[LOCAL_PARAM:0];
end
endfunction
endclass
assign foo = myClass#(MY_PARAM)::my_function(bar);
At first I forgot about the [LOCAL_PARAM] part and was just getting 1-bit back.
The SystemVerilog LRM has a section on your particular case: 13.8 Parameterized tasks and functions. It says:
SystemVerilog provides a way to create parameterized tasks and functions, also known as parameterized subroutines. [...] The way to implement parameterized subroutines is through the use of static methods in parameterized classes (see 8.10 and 8.25).
In your case, you should declare your function like this:
virtual class myClass#(parameter MY_PARAM);
static function my_function;
input [MY_PARAM-1:0] data, my_bit;
begin
my_function = data[my_bit];
end
endfunction
endclass
You could then call your function like this:
assign my_function_output = myClass#(MY_PARAM)::my_function(data, my_bit);
Please note that you may declare multiple functions in your abstract class. So, if you have a whole bunch of functions which all depend on a parameter in the same way, you could all declare them in the same class.
Some additional information on the virtual and static keyword in the aforementioned context:
Section 8.10 of the LRM talks about static methods.
A static method is subject to all the class scoping and access rules, but behaves like a regular subroutine that can be called outside the class, even with no class instantiation. A static method has no access to non-static members (class properties or methods), but it can directly access static class properties or call static methods of the same class.
By using the virtual keyword for the class declaration, you show the compiler that this is an abstract class (see Section 8.21 in the LRM). Creating an object of a virtual class causes a compilation error. This enforces strict static usage of the method.
Since the question was also tagged as 'verilog', a similar trick could be played in a simple verilog. You can use parameterized modules to achieve the same effect. For example:
module util#(
parameter int W = 10)();
function funct;
input [W-1:0] inp;
funct = inp;
endfunction
endmodule
module top(out, in);
parameter W = 8;
output wire [W-1:0] out;
input wire [W-1:0] in;
util#(W) u1(); // inst util module with a parameter
assign out = u1.funct(in); // call the function
initial #1 $finish;
endmodule
By default, all functions declared within a module are static.
You can use macro expansion to achieve this. I wanted a function that would check different test stimulus. The simulation arrays of 'bus' signals (or multi-bit values) and this was my 'parameter'.
`define MY_FUNCTION(LOCAL_PARAM) \
function my_function_``LOCAL_PARAM``; \
input [LOCAL_PARAM:0] data, my_bit; \
begin \
my_function_``LOCAL_PARAM`` = data[my_bit]; \
end \
endfunction \
Later...
`MY_FUNCTION(10)
my_function_10 (data_ten, my_bit); // Really my_bit is size $clog of LOCAL_PARAM.
Like Serge's answer, this works with Verilog (2001). Also, you can use tasks and then the entire module net is available. The macro call is equivalent the module instantiation with a parameter. It is basically like the elaboration phase.
Probably the module solution has more valid syntax and constructs. However, a macro of a function can achieve a similar result for simulation and could be suitable for some synthesis cases.

Why is "gen_srl16" used in a standard "SRL16E" instantiation?

I've got this code snip. It's a standard instantiation, but why is gen_srl16 used? I always thought SRL16E srl16e (... should be enough.
genvar i;
generate
for (i=0;i<WIDTH;i=i+1)
begin :
gen_srl16
SRL16E srl16e(
.Q(dataout[i]),
.A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
.CE(write),.CLK(clk),.D(datain[i])); // CE -clock enable
end
endgenerate
In this situation gen_srl16 is just a name of a generate for-loop. It has nothing to do with submodule instantiation.
Following Verilog spec (IEEE Std 1800-2012, ch. 27.4):
Generate blocks in loop generate constructs can be named or unnamed (...) If the generate block is named, it is a declaration of an array of generate block instances. The index values in this array are the values assumed by the genvar during elaboration. This can be a sparse array because the genvar values do not have to form a contiguous range of integers. The array is considered to be declared even if the loop generate scheme resulted in no instances of the generate block.

Verilog bitwise or ("|") monadic

I've seen Verilog code where the bitwise or operator ("|") is used monadic. What's the purpose?
For example
| address[15:14]==0
or
|address[15:14]? io_din : ramrd
Cann't we omit the "|" in these cases?
In this case it acts as a reduction operator, for example:
|4'b1000 => 1'b1 (OR)
&4'b1000 => 1'b0 (AND)
^4'b1000 => 1'b1 (XOR)
|4'b0000 => 1'b0
&4'b1111 => 1'b1
^4'b1111 => 1'b0
ORing the entire bus to a 1 bit value, or applying an AND/XOR to the entire bus.
This is referred to as a 'unary' operator as it only take a right hand argument. They are covered in Section 11.4.9 of SystemVerilog IEEE1800-2012.
|address[15:14]? io_din : ramrd
is the shortcut for writing
(address[15] | address[14]) ? io_din : ramrd
i.e bitwise ORing of all bits of the bus together to generate a 1bit value.
In this case it will evaluate as HIGH if either(or both) bit 15 OR bit 14 is HIGH.
similarly you can write other bitwise operators
&address[15:14]? io_din : ramrd // ANDing
^address[15:14]? io_din : ramrd // XORing
In the examples provided, the code with | is functionally equivalent to the same coded with the | omitted. Three possible reason to have and keep the | for the provided code are:
It gives guidance to the synthesizer: first OR the address bits then compare to 0, instead of comparing each address bit to 0 then ANDing the results. It is the same functional result with different gate configurations.
It following a coding style or formatting style requirement.
It just read better (visually/structurally appealing) because there is a |address[15:14]==1 on a near by line of code to |address[15:14]==0. (Reminder: |address[15:14]==1 is not the same as address[15:14]==1)
On the specific question of whether the '|' can be omitted in these cases:
Whether |address[15:14] and address[15:14] are identical depends on the context (in general, they aren't, because unknowns are handled differently). Your first example compared to 0, and it's true that the | can be dropped in this particular case, but it wouldn't be true if you compared to anything other than 0.
Your second example is trickier. The LRM doesn't appear to specify how the first expression in a ternary is evaluated. I know of 2 sims that evaluate it as a reduction-OR, so the | can be dropped in those cases. However, if a sim instead evaluates it in the same way as an if (ie if(address[15:14])) then the | is required.
Synthesis is simpler, of course, since the synthesiser doesn't have to worry about unknowns.

Verilog net to reg assignment

I have an input port from_LS(511:0). This is declared as wire in my module. I am assigning this to a set of 32 registers ilb(0:31), each of which are 1 nits long. I was trying to use the for loop to do this.
integer i;
genvar j;
initial
begin
count1 = 0;
count2=0;
flush_ctrl=0;
buffer_bit=0;
a=(hmic_ctrl[1]) + (hmic_ctrl[2]*2) + (hmic_ctrl[3]*4);
//assigning data from LS to ilb
for (i=0;i<=31;i=i+1)
ilb[i]=from_LS[511-(16*i) : 511-(16*(i-1))];
ilb[0]= from_LS[511:496];
ilb[1]= from_LS[495:480];
ilb[2]= from_LS[479:464];
ilb[3]= from_LS[463:448];
ilb[4]= from_LS[447:432];
ilb[5]= from_LS[431:416];
ilb[6]= from_LS[415:400];
ilb[7]= from_LS[399:384];
ilb[8]= from_LS[383:368];
ilb[9]= from_LS[367:352];
ilb[10]= from_LS[351:336];
ilb[11]= from_LS[335:320];
ilb[12]= from_LS[319:304];
ilb[13]= from_LS[303:288];
ilb[14]= from_LS[287:272];
ilb[15]= from_LS[271:256];
ilb[16]= from_LS[255:240];
ilb[17]= from_LS[239:224];
ilb[18]= from_LS[223:208];
ilb[19]= from_LS[207:192];
ilb[20]= from_LS[191:176];
ilb[21]= from_LS[175:160];
ilb[22]= from_LS[159:144];
ilb[23]= from_LS[143:128];
ilb[24]= from_LS[127:112];
ilb[25]= from_LS[111:96];
ilb[26]= from_LS[95:80];
ilb[27]= from_LS[79:64];
ilb[28]= from_LS[63:48];
ilb[29]= from_LS[47:32];
ilb[30]= from_LS[31:16];
ilb[31]= from_LS[15:0];
pctr(
.clk(clk),
.reset(0),
.offset(branch_ctrl[13:1]),
.mux_select(branch_ctrl[0]),
.pc1(pc)
);
end
I was getting the error that I should not use a variable index. The error is :
# ** Error: C:/Modeltech_pe_edu_10.0/examples/COMP ARC/inst_line_buf.v(55): Range must be bounded by constant expressions.
So i wrote down the following:
ilb[0]= from_LS[511:496];
ilb[1]= from_LS[495:480];
ilb[2]= from_LS[479:464];
....
ilb[31]= from_LS[15:0];
But i guess there must be a better way to do this. Could anyone tell me how?
The orginal verilog doesnt allow this kind of expression as it wanted to assure that the width is always right (it is, but in earlier times compilers werent as good :-).
Verilog 2001 offers some solution with +: you can specify the width
e.g. from_LS[ 511-(16*i) +:16 ] in your loop.
EDIT: Another solution would be to put another loop inside, which copies 16 bits bit by bit.
You should include more code (at least up to the always block containing that loop for the sensitivity list) and the exact error you're getting.
Does it work if you change integer i to genvar i and wrap the for in generate and endgenerate?

Resources