Systemverilog expansion rule - system-verilog

When I review some codes, I found something strange.
It seems that it comes from expansion and operation priority.
(I know that because "sig" is declared with 'signed', $signed is not necessary and '-sig' is correct one, anyway..)
reg signed [9:0] sig;
reg signed [11:0] out;
initial
begin
$monitor ("%0t] sig=%0d, out=%0h", $time, sig, out);
sig = 64;
out = $signed(-sig);
#1
out = -$signed(sig);
#1
sig = -512;
out = $signed(-sig);
#1
out = -$signed(sig);
#1
$finish;
end
Simulation result for above codes is,
0] sig=64, out=-64
2] sig=-512, out=-512
3] sig=-512, out=512
When sig=-512, I expected that 10 bits sig would be expanded to 12bits before negation, but it was expanded after negation.
Therefore negation of -512 was still -512, and after expansion, it had a -512.
I guess "$signed() blocks expansion..Any idea what happens??

First of all, -512 and 512 are identical numbers in 10-bit represenntation. 10 bits can actually only hold signed values from -512 to 511. In this scheme negation of -512 should work weirdly, not mentioned in lrm, at least i was not able to locate anything related. This is probably an undefined behavior.
However, it is logical to assume that in this scheme in order to represent a negated value of '-512' just removing signess is sufficient. It seems that all commercial compilers in eda playground do this. So, a result of the unaray - operator in this case will be unsigned value of 512.
So, in out = $signed(-(-512)) the negation operator returns an unsigned value of 512 and it gets converted to a signed by the system task. Therefore, it gets sign extended in out.
out = -$signed(-512) for the same reason the outermost negation operator returns an unsigned value of 512. No sign extension happens here.
You can again make it signed by enclosing in yet another $signed as out = $signed(-$signed(-512))

Related

Arithmetic right shift on logic (2 dimensional) signal

I am trying to do a Shift Right, Arithmetic (keep sign) on the signal in.
When I set the value in[0] to 16'hbb00, I expect in_sign_extend[0] to be 16'hf760 after it is signed right shifted. But, I notice that the actual result I see on in_sign_extend[0] is 16'h0680.
localparam CHANNELS = 8;
localparam AXI_M_DATA_WIDTH = 32;
logic signed [0:CHANNELS-1] [AXI_M_DATA_WIDTH/2-1:0] in;
logic signed [0:CHANNELS-1] [AXI_M_DATA_WIDTH/2-1:0] in_sign_extend;
assign in_sign_extend[0] = (in[0] >>> 3);
I am trying to understand if the in is actually correctly signed. Or am I missing something here.
The part select of a packed array is always unsigned, even when selecting the entire array. Only the variable as a whole reference (in) is signed. You can change your code to
assign in_sign_extend[0] = (signed'(in[0]) >>> 3);
Or you might prefer to use an unpacked array
logic signed [AXI_M_DATA_WIDTH/2-1:0] in[CHANNELS];
logic signed [AXI_M_DATA_WIDTH/2-1:0] in_sign_extend[CHANNELS];
assign in_sign_extend[0] = (in[0] >>> 3);

Long Integer signed Fixed Point to Real convertion SystemVerilog

I need to convert a Long number as Fixed point into a Double rappresentation.
The fixed point math is used into the synthesis process and the Real data type only for validation and simulation.
If I make multiple convertion in chain with multiple datatypes to adjust the format then it is not enough or completely wrong .
In my case with a fixed point mantissa of 44 bit I have 3bit integer+sign bit. Q notation like "sfix_44_48"
As example I am doing this to convert a fixed point integer number into a Real value(getting the number 0.5f ):
logic signed [47:0] fp_number = 48'h0800_0000_0000; // it should be 0.5f
real r_val;
real rr_val;
real rrr_val;
real tmp;
initial
begin
r_val = $itor(fp_number)/(2**44); // doesn't solve the problem.
rr_val = real'{fp_number}/(2**44); // doesn't solve the problem.
$cast(tmp,fp_number>>>44); // doesn't solve the problem
rrr_val = tmp;
end
$itor(...) is limited to 32bit integer part.
As result of above I get zero or NaN, on Modelsim simulation.
No luck during all these convertions.
the SV LRM doesn't seem to have a clear way to do this convertion.
What is the SV workaround to allow simulations to analize data greater than 32bit size easily? please.
C.
You want to use
rr_val = real'(fp_number)/(2.0**44);
Do not use any of the $TtoT functions from Verilog. They have fixed datatype inputs and outputs.
2**44 gets computed as a 32-bit 2-complement value and overflows, giving you 0. You can use 2.0 or real'(2) instead.
thanks to #dave_59 I post this piece of code which show the mess with the convertion.
logic signed [47:0] fp_number = 48'h0800_0000_0000; // it should be 0.5f
logic signed [31:0] fp_number2 = 32'h0800_0000; // it should be 0.5f
real r_val;
real rr_val;
real rrr_val;
real rrrr_val;
initial
begin
$display("48bit fp convertion sfix_44_48");
r_val = real'{fp_number}/(2**44); // doesn't solve the problem (curly braces valid sintax but wrong convertion + wrong convertion on the denominator).
rr_val = real'{fp_number}/(2.0**44); // doesn't solve the problem (curly braces valid sintax but wrong convertion + denominator convertion OK).
rrr_val = real'(fp_number)/(2**44); // doesn't solve the problem (numerator OK + the power operation is not properly converted to a Real number as result).
rrrr_val = real'(fp_number)/(2.0**44); // solve the problem with long integer fixed points convertion (the braces are not curly anymore).
$display("r_val[%08f]",r_val,", rr_val[%08f]",rr_val,", rrr_val[%08f]",rrr_val,", rrrr_val[%08f]",rrrr_val); // it should be 0.5 on the fourth data
$display("32bit fp convertion sfix_28_32");
r_val = real'{fp_number2}/(2**28); // result totally different than previous 48bit operation, doesn't solve the problem (curly braces valid sintax but wrong convertion + wrong convertion on the denominator).
rr_val = real'{fp_number2}/(2.0**28); // doesn't solve the problem (curly braces valid sintax but wrong convertion + denominator convertion OK).
rrr_val = real'(fp_number2)/(2**28); // with a 32bit range it apparently solve the problem (numerator OK + the power operation is OK with this range).
rrrr_val = real'(fp_number2)/(2.0**28); // solve the problem with long integer fixed points convertion (the braces are not curly anymore).
$display("r_val[%08f]",r_val,", rr_val[%08f]",rr_val,", rrr_val[%08f]",rrr_val,", rrrr_val[%08f]",rrrr_val); // it should be 0.5 on the fourth data
end
the only valid convertion at 48bit is the fourth case.
For 32bit the third case is valid and also the fourth case.
First: the classic pow(...) operation must be done with this syntax (2.0**BIT) which will create a Real division and not a integer division using (2**BIT) when a scaling fixed point will be applied.
In this case the operation above is managed as float/double(C style) or real(SystemVerilog)
* Second: the real'() cast operation MUST be used with NO curly braces.
I didn't have a Linting tool to proper check the syntax so I would expect a Warning due to the validity of the operation with the curly braces.
Third: the subdle results are ok if the INTEGER denominator is limited at 32bit operations.
As results shown below:
SIM START.
# 48bit fp convertion sfix_44_48
# ** Error (suppressible): (vsim-8604) ./blocks/sim/test_tb.sv(141): NaN (not a number) resulted from a division operation.
# ** Error (suppressible): (vsim-8630) Infinity results from division operation.
# Time: 0 ps Iteration: 0 Process: /test_tb/#INITIAL#138 File: ./blocks/sim/test_tb.sv Line: 143
# r_val[-1.#IND00], rr_val[0.000000], rrr_val[1.#INF00], rrrr_val[0.500000]
# 32bit fp convertion sfix_28_32
SIM END.
# r_val[0.000000], rr_val[0.000000], rrr_val[0.500000], rrrr_val[0.500000]
The solution is to avoid any not protected casting, like a casting with the braces boundary:
r_val = real'{ byteU,byteH,byteL} / (2.0**44) ; // WRONG
rr_val = real'({byteU,byteH,byteL}) / (2.0**44) ; // CORRECT
If the scaling factor occurs then the operation, generally /, must be done with the same type of operands (real/real).
Unsafe way is (real/long) which leads into a nightmare.

Turn off Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1) for gfortran?

I am intentionally casting an array of boolean values to integers but I get this warning:
Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1)
which I don't want. Can I either
(1) Turn off that warning in the Makefile?
or (more favorably)
(2) Explicitly make this cast in the code so that the compiler doesn't need to worry?
The code will looking something like this:
A = (B.eq.0)
where A and B are both size (n,1) integer arrays. B will be filled with integers ranging from 0 to 3. I need to use this type of command again later with something like A = (B.eq.1) and I need A to be an integer array where it is 1 if and only if B is the requested integer, otherwise it should be 0. These should act as boolean values (1 for .true., 0 for .false.), but I am going to be using them in matrix operations and summations where they will be converted to floating point values (when necessary) for division, so logical values are not optimal in this circumstance.
Specifically, I am looking for the fastest, most vectorized version of this command. It is easy to write a wrapper for testing elements, but I want this to be a vectorized operation for efficiency.
I am currently compiling with gfortran, but would like whatever methods are used to also work in ifort as I will be compiling with intel compilers down the road.
update:
Both merge and where work perfectly for the example in question. I will look into performance metrics on these and select the best for vectorization. I am also interested in how this will work with matrices, not just arrays, but that was not my original question so I will post a new one unless someone wants to expand their answer to how this might be adapted for matrices.
I have not found a compiler option to solve (1).
However, the type conversion is pretty simple. The documentation for gfortran specifies that .true. is mapped to 1, and false to 0.
Note that the conversion is not specified by the standard, and different values could be used by other compilers. Specifically, you should not depend on the exact values.
A simple merge will do the trick for scalars and arrays:
program test
integer :: int_sca, int_vec(3)
logical :: log_sca, log_vec(3)
log_sca = .true.
log_vec = [ .true., .false., .true. ]
int_sca = merge( 1, 0, log_sca )
int_vec = merge( 1, 0, log_vec )
print *, int_sca
print *, int_vec
end program
To address your updated question, this is trivial to do with merge:
A = merge(1, 0, B == 0)
This can be performed on scalars and arrays of arbitrary dimensions. For the latter, this can easily be vectorized be the compiler. You should consult the manual of your compiler for that, though.
The where statement in Casey's answer can be extended in the same way.
Since you convert them to floats later on, why not assign them as floats right away? Assuming that A is real, this could look like:
A = merge(1., 0., B == 0)
Another method to compliment #AlexanderVogt is to use the where construct.
program test
implicit none
integer :: int_vec(5)
logical :: log_vec(5)
log_vec = [ .true., .true., .false., .true., .false. ]
where (log_vec)
int_vec = 1
elsewhere
int_vec = 0
end where
print *, log_vec
print *, int_vec
end program test
This will assign 1 to the elements of int_vec that correspond to true elements of log_vec and 0 to the others.
The where construct will work for any rank array.
For this particular example you could avoid the logical all together:
A=1-(3-B)/3
Of course not so good for readability, but it might be ok performance-wise.
Edit, running performance tests this is 2-3 x faster than the where construct, and of course absolutely standards conforming. In fact you can throw in an absolute value and generalize as:
integer,parameter :: h=huge(1)
A=1-(h-abs(B))/h
and still beat the where loop.

concatenation of arrays in system verilog

I wrote a code for concatenation as below:
module p2;
int n[1:2][1:3] = {2{{3{1}}}};
initial
begin
$display("val:%d",n[2][1]);
end
endmodule
It is showing errors.
Please explain?
Unpacked arrays require a '{} format. See IEEE Std 1800-2012 § 5.11 (or search for '{ in the LRM for many examples).
Therefore update your assignment to:
int n[1:2][1:3] = '{2{'{3{1}}}};
int n[1:2][1:3] = {2{{3{1}}}};
Just looking at {3{1}} this is a 96 bit number 3 integers concatenated together.
It is likely that {3{1'b1}} was intended.
The main issue looks to be the the left hand side is an unpacked array, and the left hand side is a packed array.
{ 2 { {3{1'b1}} } } => 6'b111_111
What is required is [[3'b111],[3'b111]],
From IEEE std 1800-2009 the array assignments section will be of interest here
10.9.1 Array assignment patterns
Concatenation braces are used to construct and deconstruct simple bit vectors.
A similar syntax is used to support the construction and deconstruction of arrays. The expressions shall match element for element, and the braces shall match the array dimensions. Each expression item shall be evaluated in the context of an
assignment to the type of the corresponding element in the array. In other words, the following examples are not required to cause size warnings:
bit unpackedbits [1:0] = '{1,1}; // no size warning required as
// bit can be set to 1
int unpackedints [1:0] = '{1'b1, 1'b1}; // no size warning required as
// int can be set to 1’b1
A syntax resembling replications (see 11.4.12.1) can be used in array assignment patterns as well. Each replication shall represent an entire single dimension.
unpackedbits = '{2 {y}} ; // same as '{y, y}
int n[1:2][1:3] = '{2{'{3{y}}}}; // same as '{'{y,y,y},'{y,y,y}}

Perl booleans, negation (and how to explain it)?

I'm new here. After reading through how to ask and format, I hope this will be an OK question. I'm not very skilled in perl, but it is the programming language what I known most.
I trying apply Perl to real life but I didn't get an great understanding - especially not from my wife. I tell her that:
if she didn't bring to me 3 beers in the evening, that means I got zero (or nothing) beers.
As you probably guessed, without much success. :(
Now factually. From perlop:
Unary "!" performs logical negation, that is, "not".
Languages, what have boolean types (what can have only two "values") is OK:
if it is not the one value -> must be the another one.
so naturally:
!true -> false
!false -> true
But perl doesn't have boolean variables - have only a truth system, whrere everything is not 0, '0' undef, '' is TRUE. Problem comes, when applying logical negation to an not logical value e.g. numbers.
E.g. If some number IS NOT 3, thats mean it IS ZERO or empty, instead of the real life meaning, where if something is NOT 3, mean it can be anything but 3 (e.g. zero too).
So the next code:
use 5.014;
use Strictures;
my $not_3beers = !3;
say defined($not_3beers) ? "defined, value>$not_3beers<" : "undefined";
say $not_3beers ? "TRUE" : "FALSE";
my $not_4beers = !4;
printf qq{What is not 3 nor 4 mean: They're same value: %d!\n}, $not_3beers if( $not_3beers == $not_4beers );
say qq(What is not 3 nor 4 mean: #{[ $not_3beers ? "some bears" : "no bears" ]}!) if( $not_3beers eq $not_4beers );
say ' $not_3beers>', $not_3beers, "<";
say '-$not_3beers>', -$not_3beers, "<";
say '+$not_3beers>', -$not_3beers, "<";
prints:
defined, value><
FALSE
What is not 3 nor 4 mean: They're same value: 0!
What is not 3 nor 4 mean: no bears!
$not_3beers><
-$not_3beers>0<
+$not_3beers>0<
Moreover:
perl -E 'say !!4'
what is not not 4 IS 1, instead of 4!
The above statements with wife are "false" (mean 0) :), but really trying teach my son Perl and he, after a while, asked my wife: why, if something is not 3 mean it is 0 ? .
So the questions are:
how to explain this to my son
why perl has this design, so why !0 is everytime 1
Is here something "behind" what requires than !0 is not any random number, but 0.
as I already said, I don't know well other languages - in every language is !3 == 0?
I think you are focussing to much on negation and too little on what Perl booleans mean.
Historical/Implementation Perspective
What is truth? The detection of a higher voltage that x Volts.
On a higher abstraction level: If this bit here is set.
The abstraction of a sequence of bits can be considered an integer. Is this integer false? Yes, if no bit is set, i.e. the integer is zero.
A hardware-oriented language will likely use this definition of truth, e.g. C, and all C descendants incl Perl.
The negation of 0 could be bitwise negation—all bits are flipped to 1—, or we just set the last bit to 1. The results would usually be decoded as integers -1 and 1 respectively, but the latter is more energy efficient.
Pragmatic Perspective
It is convenient to think of all numbers but zero as true when we deal with counts:
my $wordcount = ...;
if ($wordcount) {
say "We found $wordcount words";
} else {
say "There were no words";
}
or
say "The array is empty" unless #array; # notice scalar context
A pragmatic language like Perl will likely consider zero to be false.
Mathematical Perspective
There is no reason for any number to be false, every number is a well-defined entity. Truth or falseness emerges solely through predicates, expressions which can be true or false. Only this truth value can be negated. E.g.
¬(x ≤ y) where x = 2, y = 3
is false. Many languages which have a strong foundation in maths won't consider anything false but a special false value. In Lisps, '() or nil is usually false, but 0 will usually be true. That is, a value is only true if it is not nil!
In such mathematical languages, !3 == 0 is likely a type error.
Re: Beers
Beers are good. Any number of beers are good, as long as you have one:
my $beers = ...;
if (not $beers) {
say "Another one!";
} else {
say "Aaah, this is good.";
}
Boolification of a beer-counting variable just tells us if you have any beers. Consider !! to be a boolification operator:
my $enough_beer = !! $beers;
The boolification doesn't concern itself with the exact amount. But maybe any number ≥ 3 is good. Then:
my $enough_beer = ($beers >= 3);
The negation is not enough beer:
my $not_enough_beer = not($beers >= 3);
or
my $not_enough_beer = not $beers;
fetch_beer() if $not_enough_beer;
Sets
A Perl scalar does not symbolize a whole universe of things. Especially, not 3 is not the set of all entities that are not three. Is the expression 3 a truthy value? Yes. Therefore, not 3 is a falsey value.
The suggested behaviour of 4 == not 3 to be true is likely undesirable: 4 and “all things that are not three” are not equal, the four is just one of many things that are not three. We should write it correctly:
4 != 3 # four is not equal to three
or
not( 4 == 3 ) # the same
It might help to think of ! and not as logical-negation-of, but not as except.
How to teach
It might be worth introducing mathematical predicates: expressions which can be true or false. If we only ever “create” truthness by explicit tests, e.g. length($str) > 0, then your issues don't arise. We can name the results: my $predicate = (1 < 2), but we can decide to never print them out, instead: print $predicate ? "True" : "False". This sidesteps the problem of considering special representations of true or false.
Considering values to be true/false directly would then only be a shortcut, e.g. foo if $x can considered to be a shortcut for
foo if defined $x and length($x) > 0 and $x != 0;
Perl is all about shortcuts.
Teaching these shortcuts, and the various contexts of perl and where they turn up (numeric/string/boolean operators) could be helpful.
List Context
Even-sized List Context
Scalar Context
Numeric Context
String Context
Boolean Context
Void Context
as I already said, I don't know well other languages - in every language is !3 == 0?
Yes. In C (and thus C++), it's the same.
void main() {
int i = 3;
int n = !i;
int nn = !n;
printf("!3=%i ; !!3=%i\n", n, nn);
}
Prints (see http://codepad.org/vOkOWcbU )
!3=0 ; !!3=1
how to explain this to my son
Very simple. !3 means "opposite of some non-false value, which is of course false". This is called "context" - in a Boolean context imposed by negation operator, "3" is NOT a number, it's a statement of true/false.
The result is also not a "zero" but merely something that's convenient Perl representation of false - which turns into a zero if used in a numeric context (but an empty string if used in a string context - see the difference between 0 + !3 and !3 . "a")
The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed. (perldoc perldata)
why perl has this design, so why !0 is everytime 1
See above. Among other likely reasons (though I don't know if that was Larry's main reason), C has the same logic and Perl took a lot of its syntax and ideas from C.
For a VERY good underlying technical detail, see the answers here: " What do Perl functions that return Boolean actually return " and here: " Why does Perl use the empty string to represent the boolean false value? "
Is here something "behind" what requires than !0 is not any random number, but 0.
Nothing aside from simplicity of implementation. It's easier to produce a "1" than a random number.
if you're asking a different question of "why is it 1 instead of the original # that was negated to get 0", the answer to that is simple - by the time Perl interpreter gets to negate that zero, it no longer knows/remembers that zero was a result of "!3" as opposed to some other expression that resulted in a value of zero/false.
If you want to test that a number is not 3, then use this:
my_variable != 3;
Using the syntax !3, since ! is a boolean operator, first converts 3 into a boolean (even though perl may not have an official boolean type, it still works this way), which, since it is non-zero, means it gets converted to the equivalent of true. Then, !true yields false, which, when converted back to an integer context, gives 0. Continuing with that logic shows how !!3 converts 3 to true, which then is inverted to false, inverted again back to true, and if this value is used in an integer context, gets converted to 1. This is true of most modern programming languages (although maybe not some of the more logic-centered ones), although the exact syntax may vary some depending on the language...
Logically negating a false value requires some value be chosen to represent the resulting true value. "1" is as good a choice as any. I would say it is not important which value is returned (or conversely, it is important that you not rely on any particular true value being returned).