Skip to content

Commit ab677a2

Browse files
committed
Fix incorrect negative integer literals (#186)
1 parent 6fb5ee9 commit ab677a2

File tree

8 files changed

+219
-11
lines changed

8 files changed

+219
-11
lines changed

src/codegen/system_verilog.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,13 @@ fn display_constant(typ: &ConcreteType, cst: &Value) -> impl Display {
433433
Value::Integer(v) => {
434434
if bounds.from < &IBig::from(0) {
435435
if v < &IBig::from(0) {
436-
write!(f, "-{bitwidth}'sd{}", -v)
436+
let mut higher_pow2 = ibig::ubig!(0);
437+
higher_pow2.set_bit(bitwidth as usize);
438+
let unsigned_equivalent = IBig::from(higher_pow2) + v;
439+
let unsigned_equivalent: UBig =
440+
UBig::try_from(unsigned_equivalent).unwrap();
441+
assert!(unsigned_equivalent.bit((bitwidth - 1) as usize), "Sign bit must be \"true\", of course, because it's negative.");
442+
write!(f, "{bitwidth}'sh{unsigned_equivalent:x} /* {v} */")
437443
} else {
438444
write!(f, "{bitwidth}'sd{v}")
439445
}

src/typing/concrete_type.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,13 @@ impl IntBounds<&'_ IBig> {
337337
pub fn bitwidth(self) -> u64 {
338338
assert!(!self.is_empty(), "{self}");
339339
let min = self.from;
340-
let max = self.to - IBig::from(1);
341340
if min < &IBig::from(0) {
342341
let min_abs: UBig = UBig::try_from(-min).unwrap() - 1;
343342

344343
let bits_for_min = min_abs.bit_len();
345344

346-
let bits_for_max = if max > IBig::from(0) {
347-
let max = UBig::try_from(max).unwrap();
345+
let bits_for_max = if *self.to > IBig::from(0) {
346+
let max: UBig = UBig::try_from(self.to).unwrap() - 1;
348347

349348
max.bit_len()
350349
} else {
@@ -353,7 +352,7 @@ impl IntBounds<&'_ IBig> {
353352

354353
(usize::max(bits_for_min, bits_for_max) + 1) as u64
355354
} else {
356-
let max = UBig::try_from(max).unwrap();
355+
let max: UBig = UBig::try_from(self.to).unwrap() - 1;
357356

358357
max.bit_len() as u64
359358
}
@@ -429,16 +428,41 @@ mod tests {
429428
#[test]
430429
#[rustfmt::skip]
431430
fn test_bound_to_bits() {
431+
for unsigned_bitwidth in 0..5 {
432+
let to = IBig::from(2_i64.pow(unsigned_bitwidth));
433+
assert_eq!(IntBounds{from: &IBig::from(0), to: &to}.bitwidth(), unsigned_bitwidth as u64);
434+
assert_eq!(IntBounds{from: &IBig::from(0), to: &(&to+1)}.bitwidth(), (unsigned_bitwidth+1) as u64);
435+
}
436+
for signed_bitwidth in 1..5 {
437+
let from = -IBig::from(2_i64.pow(signed_bitwidth - 1));
438+
let to = IBig::from(2_i64.pow(signed_bitwidth - 1));
439+
assert_eq!(IntBounds{from: &from, to: &to}.bitwidth(), signed_bitwidth as u64);
440+
assert_eq!(IntBounds{from: &(&from-1), to: &to}.bitwidth(), (signed_bitwidth+1) as u64);
441+
assert_eq!(IntBounds{from: &from, to: &(&to+1)}.bitwidth(), (signed_bitwidth+1) as u64);
442+
}
443+
// Try one-sided negative numbers
444+
assert_eq!(IntBounds{from: &IBig::from(-1), to: &IBig::from(0)}.bitwidth(), 1);
445+
assert_eq!(IntBounds{from: &IBig::from(-2), to: &IBig::from(0)}.bitwidth(), 2);
446+
assert_eq!(IntBounds{from: &IBig::from(-3), to: &IBig::from(0)}.bitwidth(), 3);
447+
assert_eq!(IntBounds{from: &IBig::from(-4), to: &IBig::from(0)}.bitwidth(), 3);
448+
assert_eq!(IntBounds{from: &IBig::from(-5), to: &IBig::from(0)}.bitwidth(), 4);
449+
assert_eq!(IntBounds{from: &IBig::from(-6), to: &IBig::from(0)}.bitwidth(), 4);
450+
assert_eq!(IntBounds{from: &IBig::from(-7), to: &IBig::from(0)}.bitwidth(), 4);
451+
assert_eq!(IntBounds{from: &IBig::from(-8), to: &IBig::from(0)}.bitwidth(), 4);
452+
453+
assert_eq!(IntBounds{from: &IBig::from(0), to: &IBig::from(1)}.bitwidth(), 0); // Zero sized wires are now possible
454+
assert_eq!(IntBounds{from: &IBig::from(0), to: &IBig::from(256)}.bitwidth(), 8);
455+
assert_eq!(IntBounds{from: &IBig::from(20), to: &IBig::from(257)}.bitwidth(), 9);
456+
assert_eq!(IntBounds{from: &IBig::from(-256), to: &IBig::from(256)}.bitwidth(), 9);
432457
assert_eq!(IntBounds{from: &IBig::from(-1), to: &IBig::from(1)}.bitwidth(), 1);
433458
assert_eq!(IntBounds{from: &IBig::from(-2), to: &IBig::from(1)}.bitwidth(), 2);
459+
assert_eq!(IntBounds{from: &IBig::from(-2), to: &IBig::from(2)}.bitwidth(), 2);
460+
assert_eq!(IntBounds{from: &IBig::from(-3), to: &IBig::from(2)}.bitwidth(), 3);
461+
assert_eq!(IntBounds{from: &IBig::from(-2), to: &IBig::from(3)}.bitwidth(), 3);
434462
assert_eq!(IntBounds{from: &IBig::from(-1), to: &IBig::from(2)}.bitwidth(), 2);
435463
assert_eq!(IntBounds{from: &IBig::from(-2), to: &IBig::from(3)}.bitwidth(), 3);
436464
assert_eq!(IntBounds{from: &IBig::from(2), to: &IBig::from(9)}.bitwidth(), 4);
437465
assert_eq!(IntBounds{from: &IBig::from(-1000), to: &IBig::from(1)}.bitwidth(), 11);
438466
assert_eq!(IntBounds{from: &IBig::from(-2000), to: &IBig::from(-999)}.bitwidth(), 12);
439-
assert_eq!(IntBounds{from: &IBig::from(-256), to: &IBig::from(256)}.bitwidth(), 9);
440-
assert_eq!(IntBounds{from: &IBig::from(0), to: &IBig::from(256)}.bitwidth(), 8);
441-
assert_eq!(IntBounds{from: &IBig::from(20), to: &IBig::from(257)}.bitwidth(), 9);
442-
assert_eq!(IntBounds{from: &IBig::from(0), to: &IBig::from(1)}.bitwidth(), 0); // Zero sized wires are now possible
443467
}
444468
}

test.sus

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,3 +1852,9 @@ module IntNarrowToZero {
18521852
int x = IntNarrow#(FROM: 0, TO: 1)(5)
18531853
int y = IntNarrow#(FROM: -3, TO: 6)(0)
18541854
}
1855+
1856+
module NegativeIntLiterals {
1857+
for int I in -10..10 {
1858+
int j = I
1859+
}
1860+
}

test.sus_codegen.sv

Lines changed: 126 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test.sus_errors.txt

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/signed_integers/run.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
cargo run signed_int_tests.sus -o codegen.sv --top AllTests
1+
set -e
22

3+
cargo run signed_int_tests.sus -o codegen.sv --top AllTests
34

5+
vivado -mode batch -source sim.tcl

tests/signed_integers/signed_int_tests.sus

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,24 @@ module TestSpecificModulos {
181181
assert_eq#(ID: "Modulo specific case")(l_wide, r_wide, found_wide, 5 mod 6)
182182
}
183183

184+
module TestNegate#(int FROM, int TO) {
185+
for int V in FROM..TO {
186+
int v = V
187+
int found = -v
188+
gen int EXPECTED = -V
189+
190+
assert_eq#(ID: "- narrow")(v, v, found, EXPECTED)
191+
192+
int found_from_zero = 0-v
193+
assert_eq#(ID: "0-narrow")(v, v, found_from_zero, EXPECTED)
194+
195+
int#(FROM, TO) v_wide = v
196+
197+
int found_wide = -v_wide
198+
assert_eq#(ID: "- wide ")(v_wide, v_wide, found_wide, EXPECTED)
199+
}
200+
}
201+
184202
module AllTests {
185203
TestAdd#(FROM_L: -8, TO_L: 7, FROM_R: -8, TO_R: 7) add_both_signed
186204
TestAdd#(FROM_L: -8, TO_L: 7, FROM_R: 0, TO_R: 7) add_l_signed
@@ -216,5 +234,16 @@ module AllTests {
216234
TestShr#(FROM_L: -8, TO_L: 7, FROM_R: 0, TO_R: 7) shr_l_signed
217235
TestShr#(FROM_L: 0, TO_L: 7, FROM_R: 0, TO_R: 7) shr_unsigned
218236

237+
TestNegate#(FROM: 0, TO: 6) neg_unsigned6
238+
TestNegate#(FROM: 0, TO: 7) neg_unsigned7
239+
TestNegate#(FROM: 0, TO: 8) neg_unsigned8
240+
TestNegate#(FROM: 0, TO: 9) neg_unsigned9
241+
TestNegate#(FROM: -8, TO: 7) neg_signed
242+
243+
int vvv1 = -1
244+
int vvv2 = -2
245+
int vvv3 = -3
246+
int vvv4 = -4
247+
219248
TestSpecificModulos test_specific_modulos
220249
}

tests/signed_integers/sim.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Simulate with Vivado
22

3-
create_project test_signed_ints /tmp/test_signed_ints -part xc7vx485tffg1157-1
3+
create_project test_signed_ints /tmp/test_signed_ints -part xc7vx485tffg1157-1 -force
44

55
add_files harness.sv
66
add_files codegen.sv

0 commit comments

Comments
 (0)