From 9c024b516bf4dbee83aec13421dcce042fa4c239 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 9 Apr 2026 18:11:00 +0800 Subject: [PATCH] Fix bit manipulation overflow, VCD ID overflow, and corner tile detection 1. Fix integer overflow in bitstream read/write (tile_bits.rs) - `1 << i` defaults to i32, panics in debug when i >= 32 - `write_bits`: changed to `1u64 << i` to match the u64 value type - `read_bits`: changed to `1u64 << i` to match the u64 accumulator - `clear_bits`: changed to `1u8 <<` for the byte mask type - Without this fix, configs wider than 32 bits would panic or corrupt 2. Fix VCD writer signal ID overflow (aegis-sim/src/lib.rs) - `next_id` would wrap past '~' (126) into non-printable/control characters, producing invalid VCD files - Added guard that panics with a clear message when the limit is reached 3. Fix incorrect corner tile detection in nextpnr (aegis.cc) - Used `x == y` / `x != y` to skip corner tiles, which only works for square grids (W == H) - For non-square grids (e.g. 3x5 fabric), this would skip wrong tiles (e.g. tile at (5,0) is a corner but x != y) or fail to skip actual corners (e.g. tile at (0,6) when W=5) - Fixed in all three locations: init_wires, init_bels, init_pips - Now correctly checks all four corners regardless of grid aspect ratio Co-Authored-By: Claude Opus 4.6 --- crates/aegis-ip/src/tile_bits.rs | 6 +++--- crates/aegis-sim/src/lib.rs | 6 +++++- nextpnr-aegis/aegis.cc | 9 ++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/crates/aegis-ip/src/tile_bits.rs b/crates/aegis-ip/src/tile_bits.rs index 8c18b95..1d2bd5e 100644 --- a/crates/aegis-ip/src/tile_bits.rs +++ b/crates/aegis-ip/src/tile_bits.rs @@ -94,7 +94,7 @@ pub fn set_bit(bits: &mut [u8], offset: usize) { /// Clear bits at a given offset and width. pub fn clear_bits(bits: &mut [u8], offset: usize, width: usize) { for i in 0..width { - bits[(offset + i) / 8] &= !(1 << ((offset + i) % 8)); + bits[(offset + i) / 8] &= !(1u8 << ((offset + i) % 8)); } } @@ -102,7 +102,7 @@ pub fn clear_bits(bits: &mut [u8], offset: usize, width: usize) { pub fn write_bits(bits: &mut [u8], offset: usize, value: u64, width: usize) { clear_bits(bits, offset, width); for i in 0..width { - if value & (1 << i) != 0 { + if value & (1u64 << i) != 0 { set_bit(bits, offset + i); } } @@ -115,7 +115,7 @@ pub fn read_bits(bits: &[u8], offset: usize, width: usize) -> u64 { let byte_idx = (offset + i) / 8; let bit_idx = (offset + i) % 8; if byte_idx < bits.len() && bits[byte_idx] & (1 << bit_idx) != 0 { - val |= 1 << i; + val |= 1u64 << i; } } val diff --git a/crates/aegis-sim/src/lib.rs b/crates/aegis-sim/src/lib.rs index d17521c..b95bdf0 100644 --- a/crates/aegis-sim/src/lib.rs +++ b/crates/aegis-sim/src/lib.rs @@ -345,7 +345,11 @@ impl VcdWriter { pub fn add_signal(&mut self, name: &str) -> char { let id = self.next_id; - self.next_id = (self.next_id as u8 + 1) as char; + if id < '~' { + self.next_id = (self.next_id as u8 + 1) as char; + } else { + panic!("VcdWriter: too many signals for single-character VCD IDs"); + } self.buf .push_str(&format!("$var wire 1 {id} {name} $end\n")); self.signals.push((name.to_string(), id)); diff --git a/nextpnr-aegis/aegis.cc b/nextpnr-aegis/aegis.cc index 023a6a5..79cb58f 100644 --- a/nextpnr-aegis/aegis.cc +++ b/nextpnr-aegis/aegis.cc @@ -238,7 +238,7 @@ struct AegisImpl : ViaductAPI { tw.track_w.push_back(ctx->addWire(h.xy_id(x, y, ctx->idf("W%d", t)), ctx->id("ROUTING"), x, y)); } - } else if (x != y) { + } else if (!(x == 0 && y == 0) && !(x == W - 1 && y == 0) && !(x == 0 && y == H - 1) && !(x == W - 1 && y == H - 1)) { // IO tile wires for (int z = 0; z < 2; z++) { tw.pad.push_back(ctx->addWire(h.xy_id(x, y, ctx->idf("PAD%d", z)), @@ -269,7 +269,9 @@ struct AegisImpl : ViaductAPI { for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { if (is_io(x, y)) { - if (x == y) + // Skip corner tiles — they have no IO pads + if ((x == 0 && y == 0) || (x == W - 1 && y == 0) || + (x == 0 && y == H - 1) || (x == W - 1 && y == H - 1)) continue; add_io_bels(x, y); } else { @@ -320,7 +322,8 @@ struct AegisImpl : ViaductAPI { for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { if (is_io(x, y)) { - if (x != y) + if (!((x == 0 && y == 0) || (x == W - 1 && y == 0) || + (x == 0 && y == H - 1) || (x == W - 1 && y == H - 1))) add_io_pips(x, y); } else { add_logic_pips(x, y);