preserving bit widths in enum in system verilog - system-verilog

How do i preserve bit widths in Enum ?
For example in following code :-
typedef enum bit[2:0] {
b1=2'b10,
b2=3'b100
}b;
{// regular stuff module, initial begin etc..
b a1,a2;
a1=b1;
a2=b2;
$display("b=%0d %b",$bits(a1),a1); **// prints 3, 010**
$display("b=%0d %b",$bits(a2),a2); **// prints 3, 100**
}
How can I get to first statement printing
prints 2, 10
I also tried following :-
typedef enum {
w1=2,
w2=3
}w;
w wa1,wa2;
int len,len2;
bit [3:0] bb;
{
bb=a1;
len=w1;
$display("b=%0d %b",$bits(bb[len:0]),wa1);
enter code here
bb=a2; len=w2;
$display("b=%0d %b",$bits(bb[len:0]),wa2);
}
which has compile issue.
Any other technique to preserve bit widths of variables/enums is also welcome.
--------------Edit after original question was posted-----------------
A simpler way to put this question is..
Lets say I have bit[31:0] a;
I need to achieve functionality as follows:-
function bit[] get(bit[31:0] a, int size)
return a[(size-1):0];
thanks,

I don't think you can do what you want in an enum.
When you write typedef enum [2:0] {...} b; you are defining a type called b whose width is 3. All values of this type will (necessarily) have width 3. A good way to think about this might be to consider a module that is going to take a b as an input, e.g.,
module mymod(input b myB, output o);
...
endmodule
How wide should myB be? It needs to be wide enough for mymod to accept any argument of type b. For instance, you would like to be able to pass this module either b1 or b2 and have it work. But the module's input can't be changing its size dynamically as your simulation/hardware runs.
If you just want to have some named values that have independent widths, you might try using localparam, e.g., you can write:
localparam b1 = 2'b10;
localparam b2 = 3'b100;
But you'll still run into a similar issue when you try to assign these to your variables a1 and a2. At that point, it's just a matter of how wide a1 and a2 are.

Well, if you insist in using an enum you can achieve this implicitly:
$display("b=%0d %0b", $clog2(a1+1), a1); **// prints 2, 10**
$display("b=%0d %0b", $clog2(a2+1), a2); **// prints 3, 100**

Related

What is meant by this SystemVerilog typedef enum statement?

typedef enum logic [1:0] {S0, S1, S2} statetype;
Does this statement mean that any variable declared as 'statetype' can only take three values, 2'b00, 2'b01, and 2'b10? If so, what happens if I assign the said variable with the value 2'b11?
The IEEE Std 1800-2017, section 6.19.3 Type checking, states:
Enumerated types are strongly typed; thus, a variable of type enum
cannot be directly assigned a value that lies outside the enumeration
set unless an explicit cast is used or unless the enum variable is a
member of a union. This is a powerful type-checking aid, which
prevents users from accidentally assigning nonexistent values to
variables of an enumerated type. The enumeration values can still be
used as constants in expressions, and the results can be assigned to
any variable of a compatible integral type.
Enumerated variables are type-checked in assignments, arguments, and
relational operators.
What I observe in practice is that some simulators issue a compile warning while others issue a compile error. You can see what happens on multiple simulators on edaplayground (if you sign up for a free account there).
For example, with VCS, the following code:
module tb;
typedef enum logic [1:0] {S0, S1, S2} statetype;
statetype s;
initial begin
s = S0;
$display("n=%s,s=%0d,", s.name(), s);
s = 3;
$display("n=%s,s=%0d,", s.name(), s);
end
endmodule
issues this warning:
Warning-[ENUMASSIGN] Illegal assignment to enum variable
tb.v, 16
tb, "s = 3;"
Only expressions of the enum type can be assigned to an enum variable.
The type int is incompatible with the enum 'statetype'
Expression: 3
Use the static cast operator to convert the expression to enum type.
but, it still runs the simulation and prints:
n=S0,s=0
n=,s=3
I believe the question should be rephrased to say that what is this is happening in our test-bench and how to avoid it. This will gives us more cleaner and bug free code.
efficient code to avoid the confusion:
typedef enum logic [1:0] {S0, S1, S2} statetype;
module top();
statetype st_e;
initial begin
for(int val=0;val<4; val++) begin
// casting for avoid confusion and gotchas
if (!$cast(st_e,val)) begin
$error("Casting not possible -> statetype:%0s and val:%0d",st_e,val);
end else begin
$display("statetype:%0s and val:%0d",st_e,val);
end
end
end
endmodule: top
This code is already there in edaplayground feel free to try it and update it. This could be replace with the sv macro for more efficiency. Please let me know I will provide the example for macros.
Output will be:
# run -all
# statetype:S0 and val:0
# statetype:S1 and val:1
# statetype:S2 and val:2
# ** Error: Casting not possible -> statetype:S2 and val:3
# Time: 0 ns Scope: top File: testbench.sv Line: 14
# exit

Way to have a function like urandom_range(); which will return unique values?

I want to have a urandom_range(); which will not repeat a value once its picked in a simulation ? If it has exhausted its supply of 'available' numbers, then perhaps it can repeat .
Is there any keyword in systemverilog which will help quickly to get around this ?
Not a SV expert here so an example would really help! Thanks
randc does exactly this. (cyclic randomization)
class A;
randc bit[7:0] m;
endclass
Each time you call randomize() on the same object, it will not repeat value for m until all possible values have been given.
Simulators have limits on how large the cyclic value can be, but the standard requires a minimum of 8-bits. If you have a larger value, then you can use the inside operator.
class A;
rand bit[23:0] r;
bit [23:0] list[$];
constraint c { !(r inside {list}); }
function void post_randomize();
list.push_back(r);
endfunction
endclass
If you really expect to cycle through the list, it might be simpler to build the list first, and then shuffle through the list.
bit [7:0] list[20];
for(int i=0;i<20;i++) list[i] = i+10; // range 10-29
list.shuffle();
// cycle through list[0] ... list[29]
list.shuffle();
// cycle through list[0] ... list[29]
You can declare a variable with randc identifier. This is called 'cyclical random' and will ensure exactly what you are requiring.
Note: This requires a license that supports randomization and random variables. Most commercial simulators do provide this but at a higher cost. If you are constrained by this and need to only use the system calls - $urandom or $urandom_range, I would implement something like a queue that tracks all the values returned.
function automatic void find_unique_num();
int c;
int vals[$];
bit found;
do begin
c = $urandom_range(10, 1);
foreach(vals[i])
if (c == vals[i]) found = 1;
end
while (!found);
vals.push_back(c);
return c
endfunction

Decode name of packed struct member based on bit position

I have a register map which is generated with a script. The output of the module is one huge packed struct. This is normally not a problem, but when I lint my code I get warnings like this:
*W,UNCONO (./module_name.v,158):: 'reg[1415]' is not connected.
So I can see that one of my register bits isn't getting used, which is bad, but which one is it? How do I map the bit position in the packed struct back to the named struct member?
To clarify I am looking for a function of some sort that will take a bit position as input and returns the struct member name as an output.
In a packed struct, the bits are numbered right to left, 0 to N-1. So, if you have
typedef struct packed {
logic sign;
logic [7:0] exponent;
logic [22:0] mantissa;
} Float32;
Float32 F;
then
assert (F.sign === F[31]);
assert (F.exponent === F[30:23]);
assert (F.mantissa === F[22:0]);

Pack individual signal into an array

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

How do I make use of multipliers to generate a simple adder?

I'm trying to synthesize an Altera circuit using as few logic elements as possible. Also, embedded multipliers do not count against logic elements, so I should be using them. So far the circuit looks correct in terms of functionality. However, the following module uses a large amount of logic elements. It uses 24 logic elements and I'm not sure why since it should be using 8 + a couple of combinational gates for the case block.
I suspect the adder but I'm not 100% sure. If my suspicion is correct however, is it possible to use multipliers as a simple adder?
module alu #(parameter N = 8)
(
output logic [N-1:0] alu_res,
input [N-1:0] a,
input [N-1:0] b,
input [1:0] op,
input clk
);
wire [7:0] dataa, datab;
wire [15:0] result;
// instantiate embedded 8-bit signed multiplier
mult mult8bit (.*);
// assign multiplier operands
assign dataa = a;
assign datab = b;
always_comb
unique case (op)
// LW
2'b00: alu_res = 8'b0;
// ADD
2'b01: alu_res = a + b;
// MUL
2'b10: alu_res = result[2*N-2:N-1]; // a is a fraction
// MOV
2'b11: alu_res = a;
endcase
endmodule
Your case statement will generate a 4 input mux with op as the select which uses a minimum of 2 logic cells. However since your assigning an 8-bit variable in the case block you will require 2 logic elements for each bit of the output. Therefore total logic elements is 8*2 for the large mux and 8 for the adder giving you 24 as the total.
I'm doing this project too so I won't give too much away about how to optimise this. However what I will tell you is that both the mux's and the adder can be implemented using multipliers, 8 at most. With that said I don't think this architecture is optimal for a multiplier implementation.