Sign of expression in Verilog - verilog

Here is a small bit of Verilog code. I would expect it to return three identical results, all 8-bit representations of -1.
module trivial;
reg we;
reg [7:0] c;
initial
begin
c = 8'd3;
we = 1'b1;
$display ("res(we) = %d", (we ? (-$signed(c)) / 8'sd2 : 8'd0));
$display ("res(1) = %d", (1'b1 ? (-$signed(c)) / 8'sd2 : 8'd0));
$display ("res = %d", (-$signed(c)) / 8'sd2);
end
endmodule
Briefly, the version of the standard I have (1364-2001) says in section 4.1.5 that division rounds towards zero, so -3/2=-1. It also says in section 4.5 that operator sign only depends on the operands (edit: but only for "self determined expressions"; turns out it's necessary to read the part of the standard on signs together with the part on widths). So the sub-expression with the division should presumably be unaffected by the context it is used in, and similarly for the sub-expression involving $signed. So the results should all be the same?
Three different simulators disagree with me. And only two of them agree with each other. The apparent cause is that unsigned division is used instead of the signed division that I would expect. (-3=253, and 253/2=126.5)
Can someone please tell me if any of the simulators are right and why? (see below) I clearly must be missing something, but what please? Many thanks. edit: see above for what I was missing. I now think there is a bug in Icarus and the other two simulators are right
NB: the unused value in the ternary choice does not seem to make any difference, whether signed or unsigned. edit: this is incorrect, perhaps I forgot to save the modified test before retrying with signed numbers
Altera edition of Modelsim:
$ vsim work.trivial -do 'run -all'
Reading C:/altera/12.1/modelsim_ase/tcl/vsim/pref.tcl
# 10.1b
# vsim -do {run -all} work.trivial
# Loading work.trivial
# run -all
# res(we) = 126
# res(1) = 126
# res = -1
GPL Cver
GPLCVER_2.12a of 05/16/07 (Cygwin32).
Copyright (c) 1991-2007 Pragmatic C Software Corp.
All Rights reserved. Licensed under the GNU General Public License (GPL).
See the 'COPYING' file for details. NO WARRANTY provided.
Today is Mon Jan 21 18:49:05 2013.
Compiling source file "trivial.v"
Highest level modules:
trivial
res(we) = 126
res(1) = 126
res = -1
Icarus Verilog 0.9.6
$ iverilog.exe trivial.v && vvp a.out
res(we) = 126
res(1) = -1
res = -1

NCSIM gives:
res(we) = 126
res(1) = 126
res = -1
But if all inputs to the mux are signed I get:
$display ("res(we) = %d", (we ? (-$signed(c)) / 8'sd2 : 8'sd0)); //last argument now signed
$display ("res(1) = %d", (1'b1 ? (-$signed(c)) / 8'sd2 : 8'sd0));
$display ("res = %d", (-$signed(c)) / 8'sd2);
res(we) = -1
res(1) = -1
res = -1
Remembering if we do any arithmetic with an unsigned number the arithmetic is done as unsigned, the same happens when using bit selects:
reg signed [7:0] c;
c = c[7:0] + 7'sd1; //<-- this is unsigned
In the example the mux is part of a single line expression, I assume this is logically flattened for optimisation and therefore the signed/unsigned of all arguments is taken into consideration.

Related

verilog ; can't use "string" type in $display

I'm using a recent master branch build of icarus verilog.
Should I expect the following to run?
module string_display ();
//reg [10:0][7:0] x = "initial";
string x = "initial";
always #* begin
$display ("x = %s",x);
end
initial begin
// Assign new string
x = "aaaaa";
#1
// Assign new string
x = "bbbb";
#1
#1 $finish;
end
endmodule
The above gives
internal error: 18vvp_fun_anyedge_sa: recv_string(initial) not implemented
vvp: vvp_net.cc:2972: virtual void vvp_net_fun_t::recv_string(vvp_net_ptr_t, const string&, vvp_context_t): Assertion `0' failed.
However, if I define 'x' as a reg by uncommenting the line above then it works as expected ...
x = aaaaa
x = bbbb
The error message tells you exactly what's wrong: "not implemented". That means it recognizes what you want to do, but it has not been implemented yet.
No, you should not expect Icarus Verilog to support the string keyword, which was introduced in the IEEE Std 1800 for SystemVerilog.
According to the Icarus website:
The compiler proper is intended to parse and elaborate design
descriptions written to the IEEE standard IEEE Std 1364-2005. This is
a fairly large and complex standard, so it will take some time to fill
all the dark alleys of the standard, but that's the goal.
There is no mention of IEEE Std 1800.
You can look at the extensions.txt file from the github site, which states:
Icarus Verilog supports certain extensions to the baseline IEEE1364
standard. Some of these are picked from extended variants of the
language, such as SystemVerilog, ...
But, there is no mention of string there.
I tried your code with the -g2012 option on edaplayground, but I get the same error. You could try it on your version.
I just tried something similar, and it worked for me:
module testit;
integer code;
string str;
string word_0;
string word_1;
string word_2;
string word_3;
string word_4;
integer file;
initial begin
//file = $fopenr(" ../../testcase/testcase_4x4.txt");
str = "this is a test... 1, 2, 3";
code = $sscanf(str, "%s %s %s %s %s",
word_0, word_1, word_2, word_3, word_4);
$display("Number of words: %0d", code);
$display("words[0]:(%-0s)", word_0);
$display("words[1]:(%-0s)", word_1);
$display("words[2]:(%-0s)", word_2);
$display("words[3]:(%-0s)", word_3);
$display("words[4]:(%-0s)", word_4);
end
endmodule
Icarus Verilog Run Command:
iverilog -g2012 .\testit.sv
vvp -i a.out
Output:
Number of words: 5
words[0]:(this)
words[1]:(is)
words[2]:(a)
words[3]:(test...)
words[4]:(1,)
Icarus Verilog Version:
PS> iverilog -v
Icarus Verilog version 11.0 (devel) (s20150603-612-ga9388a89)

Shifter output is always 0 when using concatenation and case

I have the following code:
module shifter(
input[7:0] in,
input[1:0] amt,
output logic[7:0] out
);
always_comb case(amt)
2'h0: out = in;
2'h1: out = {{in[6:0]}, 0};
2'h2: out = {{in[5:0]}, 0, 0};
2'h3: out = {{in[4:0]}, 0, 0, 0};
default: out = in;
endcase
endmodule
It describes a simple shifter which takes in the amount of shifts through the amt input. The problem is that no matter what the value of amt is (except 0), out is always 0 as seen on this waveform from a test:
Am I concatenating wrong? Examples I've seen online are similar to this, however.
Try constraining the size of the 0 to 1'b0 in 2'h1: out = {{in[6:0]}, 0};. What happens is that you are assigning a concatenation of in[6:0] and 32-bit (default width) 0, so only LSBs of the 0 goes to the out.
Also, default is redundant since you've described all the possible cases for amt.
The code you wrote is illegal according to the IEEE 1800-2017 LRM section 11.4.12 Concatenation operators:
Unsized constant numbers shall not be allowed in concatenations. This
is because the size of each operand in the concatenation is needed to
calculate the complete size of the concatenation
The tool you are using has a bug and did not catch this error, which is very difficult to find on your own.

How to do explicit resize?

Is there a way to do explict resize to LEN of an expression?
The reason I want this, is to make the code explicitly describe the intention, and also to avoid the warnings for implicit resize that some tools generate.
The code below works in some tools, but fails in other:
localparam EXPR = 12;
localparam LEN = 7;
assign res = LEN'(EXPR);
Based on reading the Verilog-2001 standard, it looks like lengty by LEN'... can only be used for literals, e.g. 7'd12, and not for general expressions.
So, is there a way to do explicit resize of general expressions in Verilog-2001?
The syntax you are looking for is already in SystemVerilog. You need to make sure you turn it on or use the proper .sv file extension so your tools recognize it.
assign res = LEN'(EXPR);
However, there is no way to dynamically calculate the length of a type - it needs to be a constant expression.
But you can dynamically apply a mask that truncates your value to desired length
assign res = EXPR & ((64'b10<<LEN)-1);
How about
localparam LEN = 7;
localparam [LEN-1:0] EXPR = 12;
assign res = EXPR;
or if you need to use EXPR for some other purpose
localparam LEN = 7;
localparam [LEN-1:0] EXPR7 = 12;
localparam EXPR = 12;
assign res = EXPR7
System Verilog has a $bits() system call. It returns the number of bits required for an expression. Thus:
wire [11:0] res;
$bits(res) // <= will return 12
You have to check if you simulator/compiler supports it. Also I don't know if you can use it as:
$bits(res)'d7
The only thing I should warn off is not to sacrifice your code readability to suppress superfluous warnings. Good readability prevents more errors than anything else.
I have a [systemverilog] macro I use for resizing:
// Drive a signal with a constant, automatically resize constant to signal value
`define assign_const(SIGNAL,VALUE) assign SIGNAL = ($bits(SIGNAL))'(VALUE)
The ($bits(SIGNAL))'(VALUE) is the critical part. It uses $bits to determine the signal length and recasts the value accordingly.

GBZ80 - ADC instructions fail test

I've been running Blarggs CPU tests through my Gameboy emulator, and the op r,r test shows that my ADC instruction is not working properly, but that ADD is. My understanding is that the only difference between the two is adding the existing carry flag to the second operand before addition. As such, my ADC code is the following:
void Emu::add8To8Carry(BYTE &a, BYTE b) //4 cycles - 1 byte
{
if((Flags >> FLAG_CARRY) & 1)
b++;
FLAGCLEAR_N;
halfCarryAdd8_8(a, b); //generates H flag based on addition
carryAdd8_8(a, b); //generates C flag appropriately
a+=b;
if(a == 0)
FLAGSET_Z;
else
FLAGCLEAR_Z;
}
I entered the following into a test ROM:
06 FE 3E 01 88
Which leaves A with the value 0 (Flags = B0) when the carry flag is set, and FF (Flags = 00) when it is not. This is how it should work, as far as my understanding goes. However, it still fails the test.
From my research, I believe that flags are affected in an identical manner to ADD. Literally the only change in my code from the working ADD instruction is the addition of the flag check/potential increment in the first two lines, which my test code seems to prove works.
Am I missing something? Perhaps there's a peculiarity with flag states between ADD/ADC? As a side note, SUB instructions also pass, but SBC fails in the same way.
Thanks
The problem is that b is an 8 bit value. If b is 0xff and carry is set then adding 1 to b will set it to 0 and won't generate carry if added with a >= 1. You get similar problems with the half carry flag if the lower nybble is 0xf.
This might be fixed if you call halfCarryAdd8_8(a, b + 1); and carryAdd8_8(a, b + 1); when carry is set. However, I suspect that those routines also take byte operands so you may have to make changes to them internally. Perhaps by adding the carry as a separate argument so that you can do tmp = a + b + carry; without overflow of b. But I can only speculate without the source to those functions.
On a somewhat related note, there's a fairly simple way to check for carry over all the bits:
int sum = a + b;
int no_carry_sum = a ^ b;
int carry_into = sum ^ no_carry_sum;
int half_carry = carry_into & 0x10;
int carry = carry_info & 0x100;
How does that work? Consider that bitwise "xor" gives the expected result of each bit if there is no carry going in to that bit: 0 ^ 0 == 0, 1 ^ 0 == 0 ^ 1 == 1 and 1 ^ 1 == 0. By xoring sum with no_carry_sum we get the bits where the sum differs from the bit-by-bit addition. sum is only different whenever there is a carry into a particular bit position. Thus both the half carry and carry bits can be obtained with almost no overhead.

Generate instance with different string parameters in verilog

When I was config pll_reconfig module in Quartus II, the generate for statement in design have to specify different string parameter (filenames) to different instances.
I have tried these code:
genvar i;
generate
for (i=0; i<2; i=i+1) begin:u
rom #($sformatf("mif%d.mif",i)) U(
//signals connected.
);
end
endgenerate
It is said that the code is not synthesizable.
How can I specify variable string parameter in generate for block?
I had a similar problem but on a system that did not support $sformatf. My solution is a little dirty but may help others:
genvar i;
generate
for (i=0; i<10; i=i+1)
begin
mymodule #(.NAME("NAME0" + i) instance(.RESET(mreset) ... );
end
endgenerate
This works, I believe, by treating the string "NAME0" as a number (a 40-bit number). By adding i, you just increase the value by i and the result is the last ASCII char changes. Luckily '0' + i gives you '1', '2', '3' etc
The obvious flaw is this only works for 0-9, however there is a simple extension using divide and modulo arithmatic:
mymodule #(.NAME("NAME00" + (256 * (i / 10)) + (i % 10) ) ) ...
As a side note, I ran into issues using string concatenation {"NAME", i} because Verilog was treating i as 32-bit value so the string ends up as:
NAME 1
due to the extra 'unwanted' 24 bits which equate to 3 null characters

Resources