From 939860629af7287d6a354f96eb0d247289b9cded Mon Sep 17 00:00:00 2001 From: Wanda Date: Sat, 23 Nov 2024 22:27:36 +0000 Subject: [PATCH] xact_dump: xc3000. --- Cargo.toml | 4 + README.md | 6 + prjcombine_xact_dump/Cargo.toml | 2 + prjcombine_xact_dump/src/extractor.rs | 50 +- prjcombine_xact_dump/src/main.rs | 73 +- prjcombine_xact_dump/src/xc2000.rs | 18 +- prjcombine_xact_dump/src/xc3000.rs | 1383 ++++++++++++++++++++++ prjcombine_xact_dump/src/xc4000.rs | 16 +- prjcombine_xact_dump/src/xc5200.rs | 16 +- prjcombine_xact_geom/Cargo.toml | 2 + prjcombine_xact_geom/src/bin/xagprint.rs | 2 + prjcombine_xact_geom/src/lib.rs | 23 + prjcombine_xact_naming/src/grid.rs | 5 +- prjcombine_xc2000/src/bond.rs | 1 - prjcombine_xc2000/src/expand.rs | 10 + prjcombine_xc2000_xact/src/lib.rs | 4 + prjcombine_xc3000/Cargo.toml | 14 + prjcombine_xc3000/src/bond.rs | 78 ++ prjcombine_xc3000/src/expand.rs | 128 ++ prjcombine_xc3000/src/expanded.rs | 73 ++ prjcombine_xc3000/src/grid.rs | 114 ++ prjcombine_xc3000/src/lib.rs | 4 + prjcombine_xc3000_xact/Cargo.toml | 13 + prjcombine_xc3000_xact/src/lib.rs | 234 ++++ prjcombine_xc4000/src/grid.rs | 4 +- prjcombine_xc4000_rd2db/src/bond.rs | 24 +- prjcombine_xc4000_xact/src/lib.rs | 9 +- prjcombine_xc5200/src/grid.rs | 4 +- prjcombine_xc5200_rd2db/src/bond.rs | 8 +- prjcombine_xc5200_xact/src/lib.rs | 9 +- 30 files changed, 2263 insertions(+), 68 deletions(-) create mode 100644 prjcombine_xact_dump/src/xc3000.rs create mode 100644 prjcombine_xc3000/Cargo.toml create mode 100644 prjcombine_xc3000/src/bond.rs create mode 100644 prjcombine_xc3000/src/expand.rs create mode 100644 prjcombine_xc3000/src/expanded.rs create mode 100644 prjcombine_xc3000/src/grid.rs create mode 100644 prjcombine_xc3000/src/lib.rs create mode 100644 prjcombine_xc3000_xact/Cargo.toml create mode 100644 prjcombine_xc3000_xact/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index e9f2f15e..8bc99035 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "prjcombine_int", "prjcombine_xilinx_naming", "prjcombine_xc2000", + "prjcombine_xc3000", "prjcombine_xc4000", "prjcombine_xc5200", "prjcombine_virtex", @@ -63,6 +64,7 @@ members = [ "prjcombine_ise_hammer", "prjcombine_xact_naming", "prjcombine_xc2000_xact", + "prjcombine_xc3000_xact", "prjcombine_xc4000_xact", "prjcombine_xc5200_xact", "prjcombine_xact_data", @@ -95,6 +97,7 @@ prjcombine_rdgrid = { path = "prjcombine_rdgrid" } prjcombine_rdintb = { path = "prjcombine_rdintb" } prjcombine_rdverify = { path = "prjcombine_rdverify" } prjcombine_xc2000 = { path = "prjcombine_xc2000" } +prjcombine_xc3000 = { path = "prjcombine_xc3000" } prjcombine_xc4000 = { path = "prjcombine_xc4000" } prjcombine_xc4000_naming = { path = "prjcombine_xc4000_naming" } prjcombine_xc4000_rdverify = { path = "prjcombine_xc4000_rdverify" } @@ -140,6 +143,7 @@ prjcombine_hammer = { path = "prjcombine_hammer" } prjcombine_collector = { path = "prjcombine_collector" } prjcombine_xact_naming = { path = "prjcombine_xact_naming" } prjcombine_xc2000_xact = { path = "prjcombine_xc2000_xact" } +prjcombine_xc3000_xact = { path = "prjcombine_xc3000_xact" } prjcombine_xc4000_xact = { path = "prjcombine_xc4000_xact" } prjcombine_xc5200_xact = { path = "prjcombine_xc5200_xact" } prjcombine_xact_geom = { path = "prjcombine_xact_geom" } diff --git a/README.md b/README.md index fbea95db..a9503d96 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ See https://prjunnamed.github.io/prjcombine/ - Xilinx Coolrunner 2 CPLDs: phase 4 in progress - Xilinx FPGAs: + - XC2000, XC2000L: phase 1 complete + - XC3000, XC3100: phase 1 complete + - XC3000A, XC3100A, XC3000L, XC3100L: phase 1 complete + - XC4000, XC4000D: phase 1 complete + - XC4000A: phase 1 complete + - XC4000H: phase 1 complete - XC4000E, XC4000L, Spartan: phase 2 complete - XC4000EX, XC4000XL: phase 2 complete - XC4000XLA: phase 2 complete diff --git a/prjcombine_xact_dump/Cargo.toml b/prjcombine_xact_dump/Cargo.toml index f6621452..1aca2378 100644 --- a/prjcombine_xact_dump/Cargo.toml +++ b/prjcombine_xact_dump/Cargo.toml @@ -11,6 +11,8 @@ unnamed_entity.workspace = true prjcombine_int.workspace = true prjcombine_xc2000.workspace = true prjcombine_xc2000_xact.workspace = true +prjcombine_xc3000.workspace = true +prjcombine_xc3000_xact.workspace = true prjcombine_xc4000.workspace = true prjcombine_xc4000_xact.workspace = true prjcombine_xc5200.workspace = true diff --git a/prjcombine_xact_dump/src/extractor.rs b/prjcombine_xact_dump/src/extractor.rs index ef278f3f..52019553 100644 --- a/prjcombine_xact_dump/src/extractor.rs +++ b/prjcombine_xact_dump/src/extractor.rs @@ -13,7 +13,7 @@ use prjcombine_xact_naming::{ db::{IntPipNaming, NamingDb, NodeNamingId, NodeRawTileId, PipNaming}, grid::ExpandedGridNaming, }; -use unnamed_entity::{entity_id, EntityBitVec, EntityId, EntityPartVec, EntityVec}; +use unnamed_entity::{entity_id, EntityBitVec, EntityId, EntityMap, EntityPartVec, EntityVec}; entity_id! { pub id NetId u32, reserve 1; @@ -119,7 +119,12 @@ impl<'a> Extractor<'a> { used_pips: Default::default(), prims_by_name_a: Default::default(), prims_by_name_i: Default::default(), - bel_pips: ngrid.db.node_namings.ids().map(|_| Default::default()).collect(), + bel_pips: ngrid + .db + .node_namings + .ids() + .map(|_| Default::default()) + .collect(), node_muxes: EntityPartVec::new(), int_pips: EntityPartVec::new(), net_by_tile_override: Default::default(), @@ -491,6 +496,10 @@ impl<'a> Extractor<'a> { } } + pub fn own_pip(&mut self, net_t: NetId, net_f: NetId, nloc: NodeLoc) { + assert_eq!(self.pip_owner.insert((net_t, net_f), nloc), None); + } + pub fn mark_tbuf_pseudo(&mut self, net_t: NetId, net_f: NetId) { assert!(self.nets[net_t].pips_bwd.contains_key(&net_f)); self.tbuf_pseudos.insert((net_t, net_f)); @@ -516,6 +525,9 @@ impl<'a> Extractor<'a> { for (layer, _) in &die[(col, row)].nodes { let nloc = (die.die, col, row, layer); let nnode = &self.ngrid.nodes[&nloc]; + if nnode.coords.is_empty() { + continue; + } let rng = nnode.coords[NodeRawTileId::from_idx(0)].clone(); for x in rng.0 { @@ -664,12 +676,22 @@ impl<'a> Extractor<'a> { if !self.node_muxes.contains_id(node.kind) { self.node_muxes.insert(node.kind, muxes); } else { - assert_eq!(self.node_muxes[node.kind], muxes); + assert_eq!( + self.node_muxes[node.kind], + muxes, + "fail merging node {}", + self.egrid.db.nodes.key(node.kind) + ); } if !self.int_pips.contains_id(nnode.naming) { self.int_pips.insert(nnode.naming, int_pips); } else { - assert_eq!(self.int_pips[nnode.naming], int_pips); + assert_eq!( + self.int_pips[nnode.naming], + int_pips, + "fail merging node naming {}", + self.ngrid.db.node_namings.key(nnode.naming) + ); } } } @@ -715,12 +737,22 @@ impl<'a> Extractor<'a> { impl Finisher { pub fn finish(mut self, db: &mut IntDb, ndb: &mut NamingDb) { - for (naming, _, node_naming) in &mut ndb.node_namings { - node_naming.int_pips = self.int_pips.remove(naming).unwrap(); - node_naming.bel_pips = core::mem::take(&mut self.bel_pips[naming]); + let mut new_node_namings = EntityMap::new(); + for (naming, name, mut node_naming) in core::mem::take(&mut ndb.node_namings) { + if let Some(int_pips) = self.int_pips.remove(naming) { + node_naming.int_pips = int_pips; + node_naming.bel_pips = core::mem::take(&mut self.bel_pips[naming]); + new_node_namings.insert(name, node_naming); + } } - for (kind, _, node) in &mut db.nodes { - node.muxes = self.node_muxes.remove(kind).unwrap(); + ndb.node_namings = new_node_namings; + let mut new_nodes = EntityMap::new(); + for (kind, name, mut node) in core::mem::take(&mut db.nodes) { + if let Some(muxes) = self.node_muxes.remove(kind) { + node.muxes = muxes; + new_nodes.insert(name, node); + } } + db.nodes = new_nodes; } } diff --git a/prjcombine_xact_dump/src/main.rs b/prjcombine_xact_dump/src/main.rs index 7490bed6..d62004db 100644 --- a/prjcombine_xact_dump/src/main.rs +++ b/prjcombine_xact_dump/src/main.rs @@ -13,6 +13,7 @@ use prjcombine_xact_geom::{Bond, Device, DeviceBond, ExpandedNamedDevice, GeomDb mod extractor; mod xc2000; +mod xc3000; mod xc4000; mod xc5200; @@ -62,7 +63,17 @@ fn main() { let (grid, intdb, ndb) = xc2000::dump_grid(&die); (Grid::Xc2000(grid), intdb, ndb) } - PartKind::Xc3000 => todo!(), + PartKind::Xc3000 => { + let (grid, intdb, ndb) = xc3000::dump_grid( + &die, + if args.family == "xc3000a" { + prjcombine_xc3000::grid::GridKind::Xc3000A + } else { + prjcombine_xc3000::grid::GridKind::Xc3000 + }, + ); + (Grid::Xc3000(grid), intdb, ndb) + } PartKind::Xc4000 => { let (grid, intdb, ndb) = xc4000::dump_grid(&die); (Grid::Xc4000(grid), intdb, ndb) @@ -78,16 +89,34 @@ fn main() { btree_map::Entry::Vacant(entry) => { entry.insert(intdb); } - btree_map::Entry::Occupied(entry) => { - assert_eq!(*entry.get(), intdb); + btree_map::Entry::Occupied(mut entry) => { + let cintdb = entry.get_mut(); + assert_eq!(cintdb.wires, intdb.wires); + assert_eq!(cintdb.terms, intdb.terms); + for (_, name, node) in intdb.nodes { + if let Some((_, cnode)) = cintdb.nodes.get(&name) { + assert_eq!(*cnode, node, "mismatch for node {name}"); + } else { + cintdb.nodes.insert(name, node); + } + } } } match db.namings.entry(args.family.clone()) { btree_map::Entry::Vacant(entry) => { entry.insert(ndb); } - btree_map::Entry::Occupied(entry) => { - assert_eq!(*entry.get(), ndb); + btree_map::Entry::Occupied(mut entry) => { + let cndb = entry.get_mut(); + assert_eq!(cndb.tile_widths, ndb.tile_widths); + assert_eq!(cndb.tile_heights, ndb.tile_heights); + for (_, name, node) in ndb.node_namings { + if let Some((_, cnode)) = cndb.node_namings.get(&name) { + assert_eq!(*cnode, node); + } else { + cndb.node_namings.insert(name, node); + } + } } } entry.insert(grid); @@ -134,7 +163,39 @@ fn main() { } Bond::Xc2000(bond) } - PartKind::Xc3000 => todo!(), + PartKind::Xc3000 => { + let ExpandedNamedDevice::Xc3000(ref endev) = endev else { + unreachable!() + }; + let (bond, cfg_io) = xc3000::make_bond(endev, &part.package, &pkg); + let pin_xtl1 = &part.kv["OSCIOB1"][0]; + let pin_xtl2 = &part.kv["OSCIOB2"][0]; + let io_xtl1 = bond.pins[pin_xtl1]; + let io_xtl2 = bond.pins[pin_xtl2]; + assert_eq!( + io_xtl1, + prjcombine_xc3000::bond::BondPin::Io(endev.grid.io_xtl1()) + ); + assert_eq!( + io_xtl2, + prjcombine_xc3000::bond::BondPin::Io(endev.grid.io_xtl2()) + ); + let pad_tclk = &part.kv["TCLKIOB"][0]; + assert_eq!(pad_tclk, endev.get_io_name(endev.grid.io_tclk())); + let pad_bclk = &part.kv["BCLKIOB"][0]; + assert_eq!(pad_bclk, endev.get_io_name(endev.grid.io_xtl2())); + if !cfg_io.is_empty() { + let Grid::Xc3000(ref mut grid) = db.grids[grid] else { + unreachable!() + }; + if grid.cfg_io.is_empty() { + grid.cfg_io = cfg_io; + } else { + assert_eq!(grid.cfg_io, cfg_io); + } + } + Bond::Xc3000(bond) + } PartKind::Xc4000 => { let ExpandedNamedDevice::Xc4000(ref endev) = endev else { unreachable!() diff --git a/prjcombine_xact_dump/src/xc2000.rs b/prjcombine_xact_dump/src/xc2000.rs index 82952dc7..03810c75 100644 --- a/prjcombine_xact_dump/src/xc2000.rs +++ b/prjcombine_xact_dump/src/xc2000.rs @@ -113,7 +113,6 @@ pub fn make_intdb() -> IntDb { for name in ["GCLK", "ACLK", "IOCLK.B", "IOCLK.T", "IOCLK.L", "IOCLK.R"] { db.wires.insert(name.into(), WireKind::ClkOut(0)); } - db.wires.insert("ACLK".into(), WireKind::ClkOut(0)); for name in [ "IMUX.CLB.A", @@ -263,6 +262,19 @@ pub fn make_intdb() -> IntDb { db.nodes.insert(name.into(), node); } + for name in ["BIDIH", "BIDIV"] { + db.nodes.insert( + name.into(), + NodeKind { + tiles: Default::default(), + muxes: Default::default(), + iris: Default::default(), + intfs: Default::default(), + bels: Default::default(), + }, + ); + } + db } @@ -463,7 +475,7 @@ pub fn dump_grid(die: &Die) -> (Grid, IntDb, NamingDb) { } } - // horizontal single and double + // horizontal singles let mut queue = vec![]; for col in die.cols() { let mut x = endev.col_x[col].end; @@ -504,7 +516,7 @@ pub fn dump_grid(die: &Die) -> (Grid, IntDb, NamingDb) { } } } - // vertical single and double + // vertical singles for row in die.rows() { let mut y = endev.row_y[row].start; if row == grid.row_bio() { diff --git a/prjcombine_xact_dump/src/xc3000.rs b/prjcombine_xact_dump/src/xc3000.rs new file mode 100644 index 00000000..23929faf --- /dev/null +++ b/prjcombine_xact_dump/src/xc3000.rs @@ -0,0 +1,1383 @@ +use std::collections::{BTreeMap, BTreeSet}; + +use enum_map::EnumMap; +use prjcombine_int::{ + db::{BelInfo, BelPin, Dir, IntDb, NodeKind, NodeTileId, PinDir, TermInfo, TermKind, WireKind}, + grid::{DieId, LayerId}, +}; +use prjcombine_xact_data::die::Die; +use prjcombine_xact_naming::db::{NamingDb, NodeNaming}; +use prjcombine_xc3000::{ + bond::{Bond, BondPin, CfgPin}, + grid::{Grid, GridKind, IoCoord, SharedCfgPin}, +}; +use prjcombine_xc3000_xact::{name_device, ExpandedNamedDevice}; +use unnamed_entity::{EntityId, EntityVec}; + +use crate::extractor::{Extractor, NetBinding}; + +fn bel_from_pins(db: &IntDb, pins: &[(&str, impl AsRef)]) -> BelInfo { + let mut bel = BelInfo::default(); + for &(name, ref wire) in pins { + let wire = wire.as_ref(); + bel.pins.insert( + name.into(), + BelPin { + wires: BTreeSet::from_iter([(NodeTileId::from_idx(0), db.get_wire(wire))]), + dir: if wire.starts_with("IMUX") { + PinDir::Input + } else { + PinDir::Output + }, + is_intf_in: false, + }, + ); + } + bel +} + +pub fn make_intdb() -> IntDb { + let mut db = IntDb::default(); + let mut main_terms = EnumMap::from_fn(|dir| TermKind { + dir, + wires: Default::default(), + }); + + for (name, stub) in [ + ("SINGLE.H0", true), + ("SINGLE.H1", false), + ("SINGLE.H2", true), + ("SINGLE.H3", false), + ("SINGLE.H4", true), + ("SINGLE.H.B0", true), + ("SINGLE.H.B1", false), + ("SINGLE.H.B2", true), + ("SINGLE.H.B3", false), + ("SINGLE.H.B4", true), + ("SINGLE.H.T0", true), + ("SINGLE.H.T1", false), + ("SINGLE.H.T2", true), + ("SINGLE.H.T3", false), + ("SINGLE.H.T4", true), + ] { + let w0 = db.wires.insert(name.into(), WireKind::PipOut).0; + let w1 = db + .wires + .insert(format!("{name}.E"), WireKind::PipBranch(Dir::W)) + .0; + main_terms[Dir::W].wires.insert(w1, TermInfo::PassFar(w0)); + if stub { + db.wires.insert(format!("{name}.STUB"), WireKind::PipOut); + } + } + + for (name, stub) in [ + ("SINGLE.V0", true), + ("SINGLE.V1", false), + ("SINGLE.V2", true), + ("SINGLE.V3", false), + ("SINGLE.V4", false), + ("SINGLE.V.L0", false), + ("SINGLE.V.L1", false), + ("SINGLE.V.L2", true), + ("SINGLE.V.L3", false), + ("SINGLE.V.L4", true), + ("SINGLE.V.R0", false), + ("SINGLE.V.R1", false), + ("SINGLE.V.R2", true), + ("SINGLE.V.R3", false), + ("SINGLE.V.R4", true), + ] { + let w0 = db.wires.insert(name.into(), WireKind::PipOut).0; + let w1 = db + .wires + .insert(format!("{name}.S"), WireKind::PipBranch(Dir::N)) + .0; + main_terms[Dir::N].wires.insert(w1, TermInfo::PassFar(w0)); + if stub { + db.wires.insert(format!("{name}.STUB"), WireKind::PipOut); + db.wires.insert(format!("{name}.S.STUB"), WireKind::PipOut); + } + } + + for name in [ + "LONG.H0", + "LONG.H1", + "LONG.IO.B0", + "LONG.IO.B1", + "LONG.IO.T0", + "LONG.IO.T1", + ] { + let w = db + .wires + .insert(name.into(), WireKind::MultiBranch(Dir::W)) + .0; + main_terms[Dir::W].wires.insert(w, TermInfo::PassFar(w)); + } + for name in [ + "LONG.V0", + "LONG.V1", + "LONG.IO.L0", + "LONG.IO.L1", + "LONG.IO.R0", + "LONG.IO.R1", + "GCLK.V", + "ACLK.V", + ] { + let w = db + .wires + .insert(name.into(), WireKind::MultiBranch(Dir::S)) + .0; + main_terms[Dir::S].wires.insert(w, TermInfo::PassFar(w)); + } + + for name in [ + "GCLK", "ACLK", "IOCLK.B0", "IOCLK.B1", "IOCLK.T0", "IOCLK.T1", "IOCLK.L0", "IOCLK.L1", + "IOCLK.R0", "IOCLK.R1", + ] { + db.wires.insert(name.into(), WireKind::ClkOut(0)); + } + + for name in [ + "IMUX.CLB.A", + "IMUX.CLB.B", + "IMUX.CLB.C", + "IMUX.CLB.D", + "IMUX.CLB.E", + "IMUX.CLB.DI", + "IMUX.CLB.EC", + "IMUX.CLB.RD", + "IMUX.CLB.K", + "IMUX.BIOB0.O", + "IMUX.BIOB0.T", + "IMUX.BIOB0.IK", + "IMUX.BIOB0.OK", + "IMUX.BIOB1.O", + "IMUX.BIOB1.T", + "IMUX.BIOB1.IK", + "IMUX.BIOB1.OK", + "IMUX.TIOB0.O", + "IMUX.TIOB0.T", + "IMUX.TIOB0.IK", + "IMUX.TIOB0.OK", + "IMUX.TIOB1.O", + "IMUX.TIOB1.T", + "IMUX.TIOB1.IK", + "IMUX.TIOB1.OK", + "IMUX.LIOB0.O", + "IMUX.LIOB0.T", + "IMUX.LIOB0.IK", + "IMUX.LIOB0.OK", + "IMUX.LIOB1.O", + "IMUX.LIOB1.T", + "IMUX.LIOB1.IK", + "IMUX.LIOB1.OK", + "IMUX.RIOB0.O", + "IMUX.RIOB0.T", + "IMUX.RIOB0.IK", + "IMUX.RIOB0.OK", + "IMUX.RIOB1.O", + "IMUX.RIOB1.T", + "IMUX.RIOB1.IK", + "IMUX.RIOB1.OK", + "IMUX.TBUF0.I", + "IMUX.TBUF0.T", + "IMUX.TBUF1.I", + "IMUX.TBUF1.T", + "IMUX.TBUF2.I", + "IMUX.TBUF2.T", + "IMUX.TBUF3.I", + "IMUX.TBUF3.T", + "IMUX.BUFG", + "IMUX.IOCLK0", + "IMUX.IOCLK1", + ] { + db.wires.insert(name.into(), WireKind::MuxOut); + } + + for (name, dirs) in [ + ("OUT.CLB.X", &[Dir::W, Dir::E][..]), + ("OUT.CLB.Y", &[Dir::E, Dir::S][..]), + ("OUT.BIOB0.I", &[][..]), + ("OUT.BIOB0.Q", &[][..]), + ("OUT.BIOB1.I", &[Dir::E][..]), + ("OUT.BIOB1.Q", &[Dir::E][..]), + ("OUT.TIOB0.I", &[][..]), + ("OUT.TIOB0.Q", &[][..]), + ("OUT.TIOB1.I", &[Dir::E][..]), + ("OUT.TIOB1.Q", &[Dir::E][..]), + ("OUT.LIOB0.I", &[][..]), + ("OUT.LIOB0.Q", &[][..]), + ("OUT.LIOB1.I", &[Dir::S][..]), + ("OUT.LIOB1.Q", &[Dir::S][..]), + ("OUT.RIOB0.I", &[][..]), + ("OUT.RIOB0.Q", &[][..]), + ("OUT.RIOB1.I", &[Dir::S][..]), + ("OUT.RIOB1.Q", &[Dir::S][..]), + ("OUT.CLKIOB", &[][..]), + ("OUT.OSC", &[][..]), + ] { + let w = db.wires.insert(name.into(), WireKind::LogicOut).0; + for &dir in dirs { + let wo = db + .wires + .insert(format!("{name}.{dir}"), WireKind::Branch(!dir)) + .0; + main_terms[!dir].wires.insert(wo, TermInfo::PassFar(w)); + + if name == "OUT.CLB.X" && dir == Dir::E { + let wos = db + .wires + .insert(format!("{name}.{dir}S"), WireKind::Branch(Dir::N)) + .0; + main_terms[Dir::N].wires.insert(wos, TermInfo::PassFar(wo)); + } + } + } + + let mut llh_w = main_terms[Dir::W].clone(); + let mut llh_e = main_terms[Dir::E].clone(); + let mut llv_s = main_terms[Dir::S].clone(); + let mut llv_n = main_terms[Dir::N].clone(); + let mut llvs_s = main_terms[Dir::S].clone(); + let mut llvs_n = main_terms[Dir::N].clone(); + + for term in [&mut llh_w, &mut llh_e] { + term.wires.remove(db.get_wire("LONG.IO.B0")); + term.wires.remove(db.get_wire("LONG.IO.T0")); + } + for term in [&mut llv_s, &mut llv_n, &mut llvs_n, &mut llvs_s] { + term.wires.remove(db.get_wire("LONG.IO.L0")); + term.wires.remove(db.get_wire("LONG.IO.R0")); + } + for term in [&mut llv_s, &mut llv_n] { + term.wires.remove(db.get_wire("LONG.V0")); + term.wires.remove(db.get_wire("LONG.V1")); + } + + for (dir, term) in main_terms { + db.terms.insert(format!("MAIN.{dir}"), term); + } + db.terms.insert("LLH.W".into(), llh_w); + db.terms.insert("LLH.E".into(), llh_e); + db.terms.insert("LLV.S".into(), llv_s); + db.terms.insert("LLV.N".into(), llv_n); + db.terms.insert("LLV.S.S".into(), llvs_s); + db.terms.insert("LLV.S.N".into(), llvs_n); + + for name in [ + "CLB", "CLB.L", "CLB.R", "CLB.B", "CLB.BL", "CLB.BR", "CLB.T", "CLB.TL", "CLB.TR", + ] { + let mut node = NodeKind { + tiles: EntityVec::from_iter([()]), + muxes: Default::default(), + iris: Default::default(), + intfs: Default::default(), + bels: Default::default(), + }; + node.bels.insert( + "CLB".into(), + bel_from_pins( + &db, + &[ + ("A", "IMUX.CLB.A"), + ("B", "IMUX.CLB.B"), + ("C", "IMUX.CLB.C"), + ("D", "IMUX.CLB.D"), + ("E", "IMUX.CLB.E"), + ("DI", "IMUX.CLB.DI"), + ("EC", "IMUX.CLB.EC"), + ("RD", "IMUX.CLB.RD"), + ("K", "IMUX.CLB.K"), + ("X", "OUT.CLB.X"), + ("Y", "OUT.CLB.Y"), + ], + ), + ); + + if name.starts_with("CLB.B") || name.starts_with("CLB.T") { + let bt = if name.starts_with("CLB.B") { 'B' } else { 'T' }; + for i in 0..2 { + node.bels.insert( + format!("{bt}IOB{i}"), + bel_from_pins( + &db, + &[ + ("O", format!("IMUX.{bt}IOB{i}.O")), + ("T", format!("IMUX.{bt}IOB{i}.T")), + ("IK", format!("IMUX.{bt}IOB{i}.IK")), + ("OK", format!("IMUX.{bt}IOB{i}.OK")), + ("I", format!("OUT.{bt}IOB{i}.I")), + ("Q", format!("OUT.{bt}IOB{i}.Q")), + ], + ), + ); + } + } + + if name.ends_with('L') || name.ends_with('R') { + let lr = if name.ends_with('L') { 'L' } else { 'R' }; + for i in 0..2 { + node.bels.insert( + format!("{lr}IOB{i}"), + bel_from_pins( + &db, + &[ + ("O", format!("IMUX.{lr}IOB{i}.O")), + ("T", format!("IMUX.{lr}IOB{i}.T")), + ("IK", format!("IMUX.{lr}IOB{i}.IK")), + ("OK", format!("IMUX.{lr}IOB{i}.OK")), + ("I", format!("OUT.{lr}IOB{i}.I")), + ("Q", format!("OUT.{lr}IOB{i}.Q")), + ], + ), + ); + } + } + + for i in 0..4 { + if i >= 2 && !name.ends_with('R') { + continue; + } + node.bels.insert( + format!("TBUF{i}"), + bel_from_pins( + &db, + &[ + ("I", format!("IMUX.TBUF{i}.I")), + ("T", format!("IMUX.TBUF{i}.T")), + ("O", format!("LONG.H{}", i % 2)), + ], + ), + ); + } + if name.ends_with('L') || name.ends_with('R') { + for i in 0..2 { + node.bels.insert( + format!("PULLUP.TBUF{i}"), + bel_from_pins(&db, &[("O", format!("LONG.H{}", i % 2))]), + ); + } + } + + if name == "CLB.TL" || name == "CLB.BR" { + node.bels + .insert("CLKIOB".into(), bel_from_pins(&db, &[("I", "OUT.CLKIOB")])); + node.bels.insert( + "BUFG".into(), + bel_from_pins( + &db, + &[ + ("I", "IMUX.BUFG"), + ("O", if name == "CLB.TL" { "GCLK" } else { "ACLK" }), + ], + ), + ); + } + if name == "CLB.BR" { + node.bels + .insert("OSC".into(), bel_from_pins(&db, &[("O", "OUT.OSC")])); + } + + for subkind in 0..4 { + if subkind == 3 && name != "CLB.R" { + continue; + } + db.nodes.insert(format!("{name}.{subkind}"), node.clone()); + if matches!(name, "CLB.BL" | "CLB.BR" | "CLB.TL") { + db.nodes.insert(format!("{name}S.{subkind}"), node.clone()); + } + } + } + for name in [ + "LLH.B", "LLH.T", "LLV.LS", "LLV.RS", "LLV.L", "LLV.R", "LLV", + ] { + let node = NodeKind { + tiles: EntityVec::from_iter([(); 2]), + muxes: Default::default(), + iris: Default::default(), + intfs: Default::default(), + bels: Default::default(), + }; + db.nodes.insert(name.into(), node); + } + + db +} + +pub fn make_grid(die: &Die, kind: GridKind) -> Grid { + let pd_clb = die + .primdefs + .iter() + .find(|(_, pd)| pd.name == "xcle") + .unwrap() + .0; + let mut clb_x = BTreeSet::new(); + let mut clb_y = BTreeSet::new(); + for prim in die.prims.values() { + if prim.primdef != pd_clb { + continue; + } + clb_x.insert(prim.pins.first().unwrap().x); + clb_y.insert(prim.pins.first().unwrap().y); + } + Grid { + kind, + columns: clb_x.len(), + rows: clb_y.len(), + is_small: clb_x.len() == 8, + cfg_io: Default::default(), + } +} + +pub fn dump_grid(die: &Die, kind: GridKind) -> (Grid, IntDb, NamingDb) { + let grid = make_grid(die, kind); + let mut intdb = make_intdb(); + let mut ndb = NamingDb::default(); + for name in intdb.nodes.keys() { + ndb.node_namings.insert(name.clone(), NodeNaming::default()); + if name.starts_with("CLB") && !name.contains("L.") && !name.contains("R.") { + ndb.node_namings + .insert(format!("{name}.L1"), NodeNaming::default()); + if !name.starts_with("CLB.B") && !name.starts_with("CLB.T") { + ndb.node_namings + .insert(format!("{name}.L1.B1"), NodeNaming::default()); + } + } + if name.starts_with("CLB") && !name.starts_with("CLB.B") && !name.starts_with("CLB.T") { + ndb.node_namings + .insert(format!("{name}.B1"), NodeNaming::default()); + } + } + let bd_c20 = die + .boxdefs + .iter() + .find(|(_, bd)| bd.name == "cross20") + .unwrap() + .0; + let mut c20_x = BTreeSet::new(); + let mut c20_y = BTreeSet::new(); + for boxx in die.boxes.values() { + if boxx.boxdef != bd_c20 { + continue; + } + c20_x.insert(usize::from(boxx.bx)); + c20_y.insert(usize::from(boxx.by)); + } + let c20_x = Vec::from_iter(c20_x); + let c20_y = Vec::from_iter(c20_y); + assert_eq!(c20_x.len(), grid.columns - 1); + assert_eq!(c20_y.len(), grid.rows - 1); + ndb.tile_widths.insert("L".into(), c20_x[0] - 1); + ndb.tile_widths.insert("C".into(), c20_x[1] - c20_x[0]); + ndb.tile_widths.insert( + "R".into(), + die.matrix.as_ref().unwrap().dim().0 - (c20_x[grid.columns - 2] - 1), + ); + ndb.tile_heights.insert("B".into(), c20_y[0] + 2); + ndb.tile_heights.insert("C".into(), c20_y[1] - c20_y[0]); + ndb.tile_heights.insert( + "T".into(), + die.matrix.as_ref().unwrap().dim().1 - (c20_y[grid.rows - 2] + 2), + ); + let edev = grid.expand_grid(&intdb); + let endev = name_device(&edev, &ndb); + + let mut extractor = Extractor::new(die, &edev.egrid, &endev.ngrid); + + let die = edev.egrid.die(DieId::from_idx(0)); + for col in die.cols() { + for row in die.rows() { + for (layer, node) in &die[(col, row)].nodes { + let nloc = (die.die, col, row, layer); + let node_kind = &intdb.nodes[node.kind]; + let nnode = &endev.ngrid.nodes[&nloc]; + for (bel, key, bel_info) in &node_kind.bels { + match &key[..] { + "CLB" | "OSC" | "CLKIOB" | "BUFG" => { + let mut prim = extractor.grab_prim_a(&nnode.bels[bel][0]); + for pin in bel_info.pins.keys() { + extractor.net_bel_int(prim.get_pin(pin), nloc, bel, pin); + } + } + "BIOB0" | "BIOB1" | "TIOB0" | "TIOB1" | "LIOB0" | "LIOB1" | "RIOB0" + | "RIOB1" => { + let mut prim = extractor.grab_prim_i(&nnode.bels[bel][0]); + for pin in bel_info.pins.keys() { + extractor.net_bel_int(prim.get_pin(pin), nloc, bel, pin); + } + } + "TBUF0" | "TBUF1" | "TBUF2" | "TBUF3" => { + let mut prim = extractor.grab_prim_a(&nnode.bels[bel][0]); + for pin in ["I", "T"] { + extractor.net_bel_int(prim.get_pin(pin), nloc, bel, pin); + } + let o = prim.get_pin("O"); + extractor.net_bel(o, nloc, bel, "O"); + let (line, pip) = extractor.consume_one_fwd(o, nloc); + extractor.net_bel_int(line, nloc, bel, "O"); + extractor.bel_pip(nnode.naming, bel, "O", pip); + + let net_i = extractor.get_bel_int_net(nloc, bel, "I"); + let net_o = extractor.get_bel_int_net(nloc, bel, "O"); + let src_nets = + Vec::from_iter(extractor.nets[net_i].pips_bwd.keys().copied()); + for net in src_nets { + extractor.mark_tbuf_pseudo(net_o, net); + } + } + "PULLUP.TBUF0" | "PULLUP.TBUF1" => { + let mut prim = extractor.grab_prim_a(&nnode.bels[bel][0]); + let o = prim.get_pin("O"); + extractor.net_bel(o, nloc, bel, "O"); + let (line, pip) = extractor.consume_one_fwd(o, nloc); + extractor.net_bel_int(line, nloc, bel, "O"); + extractor.bel_pip(nnode.naming, bel, "O", pip); + } + _ => panic!("umm bel {key}?"), + } + } + } + } + } + extractor.junk_prim_names.extend( + ["VCC", "GND", "M0RT", "M1RD", "DPGM", "RST", "PWRDN", "CCLK"] + .into_iter() + .map(|x| x.to_string()), + ); + + // long verticals + GCLK + for col in die.cols() { + let mut queue = vec![]; + for row in [grid.row_bio() + 1, grid.row_tio() - 1] { + let by = endev.row_y[row].start; + let ty = endev.row_y[row].end; + let mut nets = vec![]; + for x in endev.col_x[col].clone() { + let net_b = extractor.matrix_nets[(x, by)].net_b; + let net_t = extractor.matrix_nets[(x, ty)].net_b; + if net_b != net_t { + continue; + } + let Some(net) = net_b else { continue }; + if extractor.nets[net].binding != NetBinding::None { + continue; + } + nets.push(net); + } + let wires = if col == grid.col_lio() { + &[ + "IOCLK.L0", + "IOCLK.L1", + "LONG.IO.L0", + "LONG.IO.L1", + "LONG.V0", + "LONG.V1", + "ACLK.V", + "GCLK.V", + ][..] + } else if col == grid.col_rio() { + &[ + "GCLK.V", + "LONG.V0", + "LONG.V1", + "ACLK.V", + "LONG.IO.R1", + "LONG.IO.R0", + "IOCLK.R1", + "IOCLK.R0", + ][..] + } else { + &["GCLK.V", "LONG.V0", "LONG.V1", "ACLK.V"][..] + }; + assert_eq!(nets.len(), wires.len()); + for (net, wire) in nets.into_iter().zip(wires.iter().copied()) { + let wire = intdb.get_wire(wire); + queue.push((net, (die.die, (col, row), wire))); + } + } + for (net, wire) in queue { + extractor.net_int(net, wire); + } + } + // long horizontals + for row in die.rows() { + let mut queue = vec![]; + for col in [grid.col_lio() + 1, grid.col_rio() - 1] { + let lx = endev.col_x[col].start; + let rx = endev.col_x[col].end; + let mut nets = vec![]; + for y in endev.row_y[row].clone() { + let net_l = extractor.matrix_nets[(lx, y)].net_l; + let net_r = extractor.matrix_nets[(rx, y)].net_l; + if net_l != net_r { + continue; + } + let Some(net) = net_l else { continue }; + if extractor.nets[net].binding != NetBinding::None { + continue; + } + nets.push(net); + } + let wires = if row == grid.row_bio() { + &["IOCLK.B0", "IOCLK.B1", "LONG.IO.B0", "LONG.IO.B1"][..] + } else if row == grid.row_tio() { + &["LONG.IO.T1", "LONG.IO.T0", "IOCLK.T1", "IOCLK.T0"][..] + } else { + &[][..] + }; + assert_eq!(nets.len(), wires.len()); + for (net, wire) in nets.into_iter().zip(wires.iter().copied()) { + let wire = intdb.get_wire(wire); + queue.push((net, (die.die, (col, row), wire))); + } + } + for (net, wire) in queue { + extractor.net_int(net, wire); + } + } + + // assign LL splitters to their proper tiles + let mut queue = vec![]; + for (net_t, net_info) in &extractor.nets { + let NetBinding::Int(rwt) = net_info.binding else { + continue; + }; + for &net_f in net_info.pips_bwd.keys() { + let NetBinding::Int(rwf) = extractor.nets[net_f].binding else { + continue; + }; + if rwt.2 != rwf.2 { + continue; + } + if rwt.1 .0 == rwf.1 .0 { + assert_ne!(rwt.1 .1, rwf.1 .1); + // LLV + let col = rwt.1 .0; + let row = grid.row_mid(); + let layer = edev + .egrid + .find_node_layer(die.die, (col, row), |node| node.starts_with("LLV")) + .unwrap(); + queue.push((net_t, net_f, (die.die, col, row, layer))) + } else { + assert_eq!(rwt.1 .1, rwf.1 .1); + // LLH + let col = grid.col_mid(); + let row = rwt.1 .1; + let layer = edev + .egrid + .find_node_layer(die.die, (col, row), |node| node.starts_with("LLH")) + .unwrap(); + queue.push((net_t, net_f, (die.die, col, row, layer))) + } + } + } + for (net_t, net_f, nloc) in queue { + extractor.own_pip(net_t, net_f, nloc); + } + + // horizontal singles + let mut queue = vec![]; + for col in die.cols() { + let mut x = endev.col_x[col].end; + if col == grid.col_rio() { + x = endev.col_x[col].start + 8; + } + for row in die.rows() { + let mut nets = vec![]; + for y in endev.row_y[row].clone() { + let Some(net) = extractor.matrix_nets[(x, y)].net_l else { + continue; + }; + if extractor.nets[net].binding != NetBinding::None { + continue; + } + nets.push(net); + } + let wires = if row == grid.row_bio() { + &[ + "SINGLE.H.B4", + "SINGLE.H.B3", + "SINGLE.H.B2", + "SINGLE.H.B1", + "SINGLE.H.B0", + "SINGLE.H4", + "SINGLE.H3", + "SINGLE.H2", + "SINGLE.H1", + "SINGLE.H0", + ][..] + } else if row == grid.row_tio() { + &[ + "SINGLE.H.T4", + "SINGLE.H.T3", + "SINGLE.H.T2", + "SINGLE.H.T1", + "SINGLE.H.T0", + ][..] + } else { + &[ + "SINGLE.H4", + "SINGLE.H3", + "SINGLE.H2", + "SINGLE.H1", + "SINGLE.H0", + ][..] + }; + assert_eq!(nets.len(), wires.len()); + for (net, wire) in nets.into_iter().zip(wires.iter().copied()) { + let wire = intdb.get_wire(wire); + queue.push((net, (die.die, (col, row), wire))); + } + } + } + // vertical singles + for row in die.rows() { + let mut y = endev.row_y[row].start; + if row == grid.row_bio() { + y = endev.row_y[row + 1].start - 8; + } + for col in die.cols() { + let mut nets = vec![]; + for x in endev.col_x[col].clone() { + let Some(net) = extractor.matrix_nets[(x, y)].net_b else { + continue; + }; + if extractor.nets[net].binding != NetBinding::None { + continue; + } + nets.push(net); + } + let wires = if col == grid.col_lio() { + &[ + "SINGLE.V.L0", + "SINGLE.V.L1", + "SINGLE.V.L2", + "SINGLE.V.L3", + "SINGLE.V.L4", + ][..] + } else if col == grid.col_rio() { + &[ + "SINGLE.V0", + "SINGLE.V1", + "SINGLE.V2", + "SINGLE.V3", + "SINGLE.V4", + "SINGLE.V.R0", + "SINGLE.V.R1", + "SINGLE.V.R2", + "SINGLE.V.R3", + "SINGLE.V.R4", + ][..] + } else { + &[ + "SINGLE.V0", + "SINGLE.V1", + "SINGLE.V2", + "SINGLE.V3", + "SINGLE.V4", + ][..] + }; + assert_eq!(nets.len(), wires.len()); + for (net, wire) in nets.into_iter().zip(wires.iter().copied()) { + let wire = intdb.get_wire(wire); + queue.push((net, (die.die, (col, row), wire))); + } + } + } + for (net, wire) in queue { + extractor.net_int(net, wire); + } + + // find single stubs + for x in 0..extractor.matrix.dim().0 { + for y in 0..extractor.matrix.dim().1 { + let cv = extractor.matrix[(x, y)] & 0xff; + if cv == 0x28 { + // vertical joiner + let net_u = extractor.matrix_nets[(x, y + 1)].net_b.unwrap(); + let net_d = extractor.matrix_nets[(x, y)].net_b.unwrap(); + if let NetBinding::Int(rw) = extractor.nets[net_u].binding { + if rw.1 .1 == grid.row_bio() { + if extractor.nets[net_d].binding == NetBinding::None { + let sw = + intdb.get_wire(&format!("{wn}.STUB", wn = intdb.wires.key(rw.2))); + extractor.net_int(net_d, (rw.0, rw.1, sw)); + } + } else { + if extractor.nets[net_d].binding == NetBinding::None { + let sw = + intdb.get_wire(&format!("{wn}.S.STUB", wn = intdb.wires.key(rw.2))); + extractor.net_int(net_d, (rw.0, (rw.1 .0, rw.1 .1 - 1), sw)); + } + } + } + } else if cv == 0x68 { + // horizontal joiner + let net_r = extractor.matrix_nets[(x + 1, y)].net_l.unwrap(); + let net_l = extractor.matrix_nets[(x, y)].net_l.unwrap(); + if let NetBinding::Int(rw) = extractor.nets[net_r].binding { + if extractor.nets[net_l].binding == NetBinding::None { + let sw = intdb.get_wire(&format!("{wn}.STUB", wn = intdb.wires.key(rw.2))); + extractor.net_int(net_l, (rw.0, rw.1, sw)); + } + } + } + } + } + + let xlut = endev.col_x.map_values(|x| x.end); + let ylut = endev.row_y.map_values(|y| y.end); + for (box_id, boxx) in &extractor.die.boxes { + let col = xlut.binary_search(&usize::from(boxx.bx)).unwrap_err(); + let row = ylut.binary_search(&usize::from(boxx.by)).unwrap_err(); + extractor.own_box(box_id, (die.die, col, row, LayerId::from_idx(0))); + } + + // find IMUX.IOCLK + let mut queue = vec![]; + for (net, net_info) in &extractor.nets { + if net_info.binding != NetBinding::None { + continue; + } + assert_eq!(net_info.pips_fwd.len(), 1); + let (&net_t, &pip) = net_info.pips_fwd.iter().next().unwrap(); + let NetBinding::Int(rw) = extractor.nets[net_t].binding else { + unreachable!() + }; + let wn = intdb.wires.key(rw.2); + assert!(wn.starts_with("IOCLK")); + let nwn = if wn.ends_with('1') { + "IMUX.IOCLK1" + } else { + "IMUX.IOCLK0" + }; + let col = xlut.binary_search(&pip.0).unwrap_err(); + let row = ylut.binary_search(&pip.1).unwrap_err(); + assert!(col == grid.col_lio() || col == grid.col_rio()); + assert!(row == grid.row_bio() || row == grid.row_tio()); + queue.push((net, (die.die, (col, row), intdb.get_wire(nwn)))); + } + for (net, wire) in queue { + extractor.net_int(net, wire); + } + + for (wire, name, &kind) in &intdb.wires { + if !name.starts_with("IMUX") { + continue; + } + if kind != WireKind::MuxOut { + continue; + } + for col in die.cols() { + for row in die.rows() { + let rw = edev + .egrid + .resolve_wire((die.die, (col, row), wire)) + .unwrap(); + if extractor.int_nets.contains_key(&rw) { + extractor.own_mux(rw, (die.die, col, row, LayerId::from_idx(0))); + } + } + } + } + + let finisher = extractor.finish(); + finisher.finish(&mut intdb, &mut ndb); + (grid, intdb, ndb) +} + +pub fn make_bond( + endev: &ExpandedNamedDevice, + name: &str, + pkg: &BTreeMap, +) -> (Bond, BTreeMap) { + let io_lookup: BTreeMap<_, _> = endev + .edev + .get_bonded_ios() + .into_iter() + .map(|io| (endev.get_io_name(io), io)) + .collect(); + let mut bond = Bond { + pins: Default::default(), + }; + for (pin, pad) in pkg { + let io = io_lookup[&**pad]; + bond.pins.insert(pin.to_ascii_uppercase(), BondPin::Io(io)); + } + + let (pwrdwn, m1, m0, prog, done, cclk, gnd, vcc) = match name { + "pc44" => ( + "P7", + "P16", + "P17", + "P27", + "P28", + "P40", + &["P1", "P23"][..], + &["P12", "P34"][..], + ), + "pc68" => ( + "P10", + "P25", + "P26", + "P44", + "P45", + "P60", + &["P1", "P35"][..], + &["P18", "P52"][..], + ), + "pc84" if endev.grid.columns < 14 => ( + "P12", + "P31", + "P32", + "P54", + "P55", + "P74", + &["P1", "P43"][..], + &["P22", "P64"][..], + ), + "pc84" if endev.grid.columns >= 14 => ( + "P12", + "P31", + "P32", + "P54", + "P55", + "P74", + &["P1", "P21", "P43", "P65"][..], + &["P2", "P22", "P42", "P64"][..], + ), + + "pq100" => ( + "P29", + "P52", + "P54", + "P78", + "P80", + "P2", + &["P4", "P16", "P28", "P53", "P66", "P77"][..], + &["P3", "P27", "P41", "P55", "P79", "P91"][..], + ), + "pq160" => ( + "P159", + "P40", + "P42", + "P78", + "P80", + "P121", + &["P19", "P41", "P61", "P77", "P101", "P123", "P139", "P158"][..], + &["P20", "P43", "P60", "P79", "P100", "P122", "P140", "P157"][..], + ), + "pq208" if endev.grid.columns == 16 => ( + "P3", + "P48", + "P50", + "P102", + "P107", + "P153", + &["P2", "P25", "P49", "P79", "P101", "P131", "P160", "P182"][..], + &["P26", "P55", "P78", "P106", "P130", "P154", "P183", "P205"][..], + ), + "pq208" if endev.grid.columns == 22 => ( + "P1", + "P50", + "P52", + "P105", + "P107", + "P156", + &["P26", "P51", "P79", "P104", "P131", "P158", "P182", "P208"][..], + &["P27", "P53", "P78", "P106", "P130", "P157", "P183", "P207"][..], + ), + + "vq64" => ( + "P17", + "P31", + "P32", + "P48", + "P49", + "P64", + &["P8", "P41"][..], + &["P24", "P56"][..], + ), + "tq100" | "vq100" => ( + "P26", + "P49", + "P51", + "P75", + "P77", + "P99", + &["P1", "P13", "P25", "P50", "P63", "P74"][..], + &["P24", "P38", "P52", "P76", "P88", "P100"][..], + ), + "tq144" => ( + "P1", + "P36", + "P38", + "P71", + "P73", + "P108", + &["P18", "P37", "P55", "P70", "P91", "P110", "P126", "P144"][..], + &["P19", "P39", "P54", "P72", "P90", "P109", "P127", "P143"][..], + ), + "tq176" => ( + "P1", + "P45", + "P47", + "P87", + "P89", + "P132", + &["P22", "P46", "P67", "P86", "P111", "P134", "P154", "P176"][..], + &["P23", "P48", "P66", "P88", "P110", "P133", "P155", "P175"][..], + ), + + "cb100" | "cq100" => ( + "P14", + "P37", + "P39", + "P63", + "P65", + "P87", + &["P1", "P13", "P38", "P51", "P62", "P89"][..], + &["P12", "P26", "P40", "P64", "P76", "P88"][..], + ), + "cb164" | "cq164" => ( + "P20", + "P62", + "P64", + "P101", + "P103", + "P145", + &["P19", "P41", "P63", "P83", "P100", "P124", "P147", "P164"][..], + &["P1", "P18", "P42", "P65", "P82", "P102", "P123", "P146"][..], + ), + + "pg84" => ( + "B2", + "J2", + "L1", + "K10", + "J10", + "A11", + &["C6", "J6"][..], + &["F3", "F9"][..], + ), + "pg132" | "pp132" => ( + "A1", + "B13", + "A14", + "P14", + "N13", + "P1", + &["C4", "C7", "C11", "H12", "L12", "M7", "L3", "H3"][..], + &["C8", "D12", "G12", "M11", "M8", "M4", "G3", "D3"][..], + ), + "pp175" | "pg175" => ( + "B2", + "B14", + "B15", + "R15", + "R14", + "R2", + &["D8", "C14", "J14", "N14", "N8", "N3", "J3", "C3"][..], + &["D9", "D14", "H14", "P14", "N9", "P3", "H3", "D3"][..], + ), + "pg223" => ( + "B2", + "C16", + "B17", + "U17", + "V17", + "U2", + &["D9", "D15", "K15", "R16", "R9", "R3", "K4", "D4"][..], + &["D10", "D16", "J15", "R15", "R10", "R4", "J4", "D3"][..], + ), + + _ => panic!("ummm {name}?"), + }; + assert_eq!( + bond.pins + .insert(pwrdwn.into(), BondPin::Cfg(CfgPin::PwrdwnB)), + None + ); + assert_eq!(bond.pins.insert(m0.into(), BondPin::Cfg(CfgPin::M0)), None); + assert_eq!(bond.pins.insert(m1.into(), BondPin::Cfg(CfgPin::M1)), None); + assert_eq!( + bond.pins.insert(prog.into(), BondPin::Cfg(CfgPin::ProgB)), + None + ); + assert_eq!( + bond.pins.insert(done.into(), BondPin::Cfg(CfgPin::Done)), + None + ); + assert_eq!( + bond.pins.insert(cclk.into(), BondPin::Cfg(CfgPin::Cclk)), + None + ); + for &pin in gnd { + assert_eq!(bond.pins.insert(pin.into(), BondPin::Gnd), None); + } + for &pin in vcc { + assert_eq!(bond.pins.insert(pin.into(), BondPin::Vcc), None); + } + + let len1d = match name { + "pc44" => Some(44), + "pc68" => Some(68), + "pc84" => Some(84), + "vq64" => Some(64), + "vq100" | "tq100" => Some(100), + "tq144" => Some(144), + "tq176" => Some(176), + "pq100" => Some(100), + "pq160" => Some(160), + "pq208" => Some(208), + "cb100" | "cq100" => Some(100), + "cb164" | "cq164" => Some(164), + _ => None, + }; + if let Some(len1d) = len1d { + for i in 1..=len1d { + bond.pins.entry(format!("P{i}")).or_insert(BondPin::Nc); + } + assert_eq!(bond.pins.len(), len1d); + } + + match name { + "pg84" => { + for a in ["A", "B", "K", "L"] { + for i in 1..=11 { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["C", "D", "E", "F", "G", "H", "J"] { + for i in (1..=2).chain(10..=11) { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["C", "J"] { + for i in 5..=7 { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["E", "F", "G"] { + for i in [3, 9] { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + assert_eq!(bond.pins.len(), 84); + } + "pg132" | "pp132" => { + for a in ["A", "B", "C", "M", "N", "P"] { + for i in 1..=14 { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["D", "E", "F", "G", "H", "J", "K", "L"] { + for i in (1..=3).chain(12..=14) { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + + assert_eq!(bond.pins.len(), 132); + } + "pp175" | "pg175" => { + for i in 2..=16 { + bond.pins.entry(format!("A{i}")).or_insert(BondPin::Nc); + } + for a in ["B", "C", "D", "N", "P", "R", "T"] { + for i in 1..=16 { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["E", "F", "G", "H", "J", "K", "L", "M"] { + for i in (1..=3).chain(14..=16) { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + assert_eq!(bond.pins.len(), 175); + } + "pg223" => { + for i in 2..=18 { + bond.pins.entry(format!("A{i}")).or_insert(BondPin::Nc); + } + for a in ["B", "C", "D", "R", "T", "U", "V"] { + for i in 1..=18 { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + for a in ["E", "F", "G", "H", "J", "K", "L", "M", "N", "P"] { + for i in (1..=4).chain(15..=18) { + bond.pins.entry(format!("{a}{i}")).or_insert(BondPin::Nc); + } + } + assert_eq!(bond.pins.len(), 223); + } + _ => (), + } + + let mut cfg_io = BTreeMap::new(); + if name == "pc68" { + for (pin, fun) in [ + ("P2", SharedCfgPin::Addr(13)), + ("P3", SharedCfgPin::Addr(6)), + ("P4", SharedCfgPin::Addr(12)), + ("P5", SharedCfgPin::Addr(7)), + ("P6", SharedCfgPin::Addr(11)), + ("P7", SharedCfgPin::Addr(8)), + ("P8", SharedCfgPin::Addr(10)), + ("P9", SharedCfgPin::Addr(9)), + ("P27", SharedCfgPin::M2), + ("P28", SharedCfgPin::Hdc), + ("P30", SharedCfgPin::Ldc), + ("P34", SharedCfgPin::InitB), + ("P46", SharedCfgPin::Data(7)), + ("P48", SharedCfgPin::Data(6)), + ("P49", SharedCfgPin::Data(5)), + ("P50", SharedCfgPin::Cs0B), + ("P51", SharedCfgPin::Data(4)), + ("P53", SharedCfgPin::Data(3)), + ("P54", SharedCfgPin::Cs1B), + ("P55", SharedCfgPin::Data(2)), + ("P56", SharedCfgPin::Data(1)), + ("P57", SharedCfgPin::RclkB), + ("P58", SharedCfgPin::Data(0)), + ("P59", SharedCfgPin::Dout), + ("P61", SharedCfgPin::Addr(0)), + ("P62", SharedCfgPin::Addr(1)), + ("P63", SharedCfgPin::Addr(2)), + ("P64", SharedCfgPin::Addr(3)), + ("P65", SharedCfgPin::Addr(15)), + ("P66", SharedCfgPin::Addr(4)), + ("P67", SharedCfgPin::Addr(14)), + ("P68", SharedCfgPin::Addr(5)), + ] { + let BondPin::Io(io) = bond.pins[pin] else { + unreachable!() + }; + cfg_io.insert(fun, io); + } + } else if name == "pc84" && endev.grid.columns < 14 { + for (pin, fun) in [ + ("P2", SharedCfgPin::Addr(13)), + ("P3", SharedCfgPin::Addr(6)), + ("P4", SharedCfgPin::Addr(12)), + ("P5", SharedCfgPin::Addr(7)), + ("P8", SharedCfgPin::Addr(11)), + ("P9", SharedCfgPin::Addr(8)), + ("P10", SharedCfgPin::Addr(10)), + ("P11", SharedCfgPin::Addr(9)), + ("P33", SharedCfgPin::M2), + ("P34", SharedCfgPin::Hdc), + ("P36", SharedCfgPin::Ldc), + ("P42", SharedCfgPin::InitB), + ("P56", SharedCfgPin::Data(7)), + ("P58", SharedCfgPin::Data(6)), + ("P60", SharedCfgPin::Data(5)), + ("P61", SharedCfgPin::Cs0B), + ("P62", SharedCfgPin::Data(4)), + ("P65", SharedCfgPin::Data(3)), + ("P66", SharedCfgPin::Cs1B), + ("P67", SharedCfgPin::Data(2)), + ("P70", SharedCfgPin::Data(1)), + ("P71", SharedCfgPin::RclkB), + ("P72", SharedCfgPin::Data(0)), + ("P73", SharedCfgPin::Dout), + ("P75", SharedCfgPin::Addr(0)), + ("P76", SharedCfgPin::Addr(1)), + ("P77", SharedCfgPin::Addr(2)), + ("P78", SharedCfgPin::Addr(3)), + ("P81", SharedCfgPin::Addr(15)), + ("P82", SharedCfgPin::Addr(4)), + ("P83", SharedCfgPin::Addr(14)), + ("P84", SharedCfgPin::Addr(5)), + ] { + let BondPin::Io(io) = bond.pins[pin] else { + unreachable!() + }; + cfg_io.insert(fun, io); + } + } else if name == "pg132" { + for (pin, fun) in [ + ("G2", SharedCfgPin::Addr(13)), + ("G1", SharedCfgPin::Addr(6)), + ("F2", SharedCfgPin::Addr(12)), + ("E1", SharedCfgPin::Addr(7)), + ("D1", SharedCfgPin::Addr(11)), + ("D2", SharedCfgPin::Addr(8)), + ("B1", SharedCfgPin::Addr(10)), + ("C2", SharedCfgPin::Addr(9)), + ("C13", SharedCfgPin::M2), + ("B14", SharedCfgPin::Hdc), + ("D14", SharedCfgPin::Ldc), + ("G14", SharedCfgPin::InitB), + ("M12", SharedCfgPin::Data(7)), + ("N11", SharedCfgPin::Data(6)), + ("M9", SharedCfgPin::Data(5)), + ("N9", SharedCfgPin::Cs0B), + ("N8", SharedCfgPin::Data(4)), + ("N7", SharedCfgPin::Data(3)), + ("P6", SharedCfgPin::Cs1B), + ("M6", SharedCfgPin::Data(2)), + ("M5", SharedCfgPin::Data(1)), + ("N4", SharedCfgPin::RclkB), + ("N2", SharedCfgPin::Data(0)), + ("M3", SharedCfgPin::Dout), + ("M2", SharedCfgPin::Addr(0)), + ("N1", SharedCfgPin::Addr(1)), + ("L2", SharedCfgPin::Addr(2)), + ("L1", SharedCfgPin::Addr(3)), + ("K1", SharedCfgPin::Addr(15)), + ("J2", SharedCfgPin::Addr(4)), + ("H1", SharedCfgPin::Addr(14)), + ("H2", SharedCfgPin::Addr(5)), + ] { + let BondPin::Io(io) = bond.pins[pin] else { + unreachable!() + }; + cfg_io.insert(fun, io); + } + } else if name == "pq160" { + for (pin, fun) in [ + ("P141", SharedCfgPin::Addr(13)), + ("P142", SharedCfgPin::Addr(6)), + ("P147", SharedCfgPin::Addr(12)), + ("P148", SharedCfgPin::Addr(7)), + ("P151", SharedCfgPin::Addr(11)), + ("P152", SharedCfgPin::Addr(8)), + ("P155", SharedCfgPin::Addr(10)), + ("P156", SharedCfgPin::Addr(9)), + ("P44", SharedCfgPin::M2), + ("P45", SharedCfgPin::Hdc), + ("P49", SharedCfgPin::Ldc), + ("P59", SharedCfgPin::InitB), + ("P81", SharedCfgPin::Data(7)), + ("P86", SharedCfgPin::Data(6)), + ("P92", SharedCfgPin::Data(5)), + ("P93", SharedCfgPin::Cs0B), + ("P98", SharedCfgPin::Data(4)), + ("P102", SharedCfgPin::Data(3)), + ("P103", SharedCfgPin::Cs1B), + ("P108", SharedCfgPin::Data(2)), + ("P114", SharedCfgPin::Data(1)), + ("P115", SharedCfgPin::RclkB), + ("P119", SharedCfgPin::Data(0)), + ("P120", SharedCfgPin::Dout), + ("P124", SharedCfgPin::Addr(0)), + ("P125", SharedCfgPin::Addr(1)), + ("P128", SharedCfgPin::Addr(2)), + ("P129", SharedCfgPin::Addr(3)), + ("P132", SharedCfgPin::Addr(15)), + ("P133", SharedCfgPin::Addr(4)), + ("P136", SharedCfgPin::Addr(14)), + ("P137", SharedCfgPin::Addr(5)), + ] { + let BondPin::Io(io) = bond.pins[pin] else { + unreachable!() + }; + cfg_io.insert(fun, io); + } + } + + (bond, cfg_io) +} diff --git a/prjcombine_xact_dump/src/xc4000.rs b/prjcombine_xact_dump/src/xc4000.rs index 4516539a..62a545de 100644 --- a/prjcombine_xact_dump/src/xc4000.rs +++ b/prjcombine_xact_dump/src/xc4000.rs @@ -2145,10 +2145,10 @@ pub fn make_bond( ("P60", SharedCfgPin::Cs0B), ("P61", SharedCfgPin::Data(4)), ("P65", SharedCfgPin::Data(3)), - ("P66", SharedCfgPin::RsB), + ("P66", SharedCfgPin::Cs1B), ("P67", SharedCfgPin::Data(2)), ("P69", SharedCfgPin::Data(1)), - ("P70", SharedCfgPin::BusyB), + ("P70", SharedCfgPin::RclkB), ("P71", SharedCfgPin::Data(0)), ("P72", SharedCfgPin::Dout), ("P77", SharedCfgPin::Addr(0)), @@ -2185,10 +2185,10 @@ pub fn make_bond( ("P95", SharedCfgPin::Cs0B), ("P98", SharedCfgPin::Data(4)), ("P102", SharedCfgPin::Data(3)), - ("P103", SharedCfgPin::RsB), + ("P103", SharedCfgPin::Cs1B), ("P106", SharedCfgPin::Data(2)), ("P113", SharedCfgPin::Data(1)), - ("P114", SharedCfgPin::BusyB), + ("P114", SharedCfgPin::RclkB), ("P117", SharedCfgPin::Data(0)), ("P118", SharedCfgPin::Dout), ("P123", SharedCfgPin::Addr(0)), @@ -2225,10 +2225,10 @@ pub fn make_bond( ("P123", SharedCfgPin::Cs0B), ("P128", SharedCfgPin::Data(4)), ("P132", SharedCfgPin::Data(3)), - ("P133", SharedCfgPin::RsB), + ("P133", SharedCfgPin::Cs1B), ("P138", SharedCfgPin::Data(2)), ("P147", SharedCfgPin::Data(1)), - ("P148", SharedCfgPin::BusyB), + ("P148", SharedCfgPin::RclkB), ("P151", SharedCfgPin::Data(0)), ("P152", SharedCfgPin::Dout), ("P161", SharedCfgPin::Addr(0)), @@ -2265,10 +2265,10 @@ pub fn make_bond( ("P142", SharedCfgPin::Cs0B), ("P148", SharedCfgPin::Data(4)), ("P152", SharedCfgPin::Data(3)), - ("P153", SharedCfgPin::RsB), + ("P153", SharedCfgPin::Cs1B), ("P159", SharedCfgPin::Data(2)), ("P173", SharedCfgPin::Data(1)), - ("P174", SharedCfgPin::BusyB), + ("P174", SharedCfgPin::RclkB), ("P177", SharedCfgPin::Data(0)), ("P178", SharedCfgPin::Dout), ("P183", SharedCfgPin::Addr(0)), diff --git a/prjcombine_xact_dump/src/xc5200.rs b/prjcombine_xact_dump/src/xc5200.rs index af890f24..d22a2371 100644 --- a/prjcombine_xact_dump/src/xc5200.rs +++ b/prjcombine_xact_dump/src/xc5200.rs @@ -1515,10 +1515,10 @@ pub fn make_bond( ("P60", SharedCfgPin::Cs0B), ("P61", SharedCfgPin::Data(4)), ("P65", SharedCfgPin::Data(3)), - ("P66", SharedCfgPin::RsB), + ("P66", SharedCfgPin::Cs1B), ("P67", SharedCfgPin::Data(2)), ("P69", SharedCfgPin::Data(1)), - ("P70", SharedCfgPin::BusyB), + ("P70", SharedCfgPin::RclkB), ("P71", SharedCfgPin::Data(0)), ("P72", SharedCfgPin::Dout), ("P75", SharedCfgPin::Tdo), @@ -1557,10 +1557,10 @@ pub fn make_bond( ("P95", SharedCfgPin::Cs0B), ("P98", SharedCfgPin::Data(4)), ("P102", SharedCfgPin::Data(3)), - ("P103", SharedCfgPin::RsB), + ("P103", SharedCfgPin::Cs1B), ("P106", SharedCfgPin::Data(2)), ("P113", SharedCfgPin::Data(1)), - ("P114", SharedCfgPin::BusyB), + ("P114", SharedCfgPin::RclkB), ("P117", SharedCfgPin::Data(0)), ("P118", SharedCfgPin::Dout), ("P121", SharedCfgPin::Tdo), @@ -1599,10 +1599,10 @@ pub fn make_bond( ("P123", SharedCfgPin::Cs0B), ("P128", SharedCfgPin::Data(4)), ("P132", SharedCfgPin::Data(3)), - ("P133", SharedCfgPin::RsB), + ("P133", SharedCfgPin::Cs1B), ("P138", SharedCfgPin::Data(2)), ("P147", SharedCfgPin::Data(1)), - ("P148", SharedCfgPin::BusyB), + ("P148", SharedCfgPin::RclkB), ("P151", SharedCfgPin::Data(0)), ("P152", SharedCfgPin::Dout), ("P159", SharedCfgPin::Tdo), @@ -1641,10 +1641,10 @@ pub fn make_bond( ("P142", SharedCfgPin::Cs0B), ("P148", SharedCfgPin::Data(4)), ("P152", SharedCfgPin::Data(3)), - ("P153", SharedCfgPin::RsB), + ("P153", SharedCfgPin::Cs1B), ("P159", SharedCfgPin::Data(2)), ("P173", SharedCfgPin::Data(1)), - ("P174", SharedCfgPin::BusyB), + ("P174", SharedCfgPin::RclkB), ("P177", SharedCfgPin::Data(0)), ("P178", SharedCfgPin::Dout), ("P181", SharedCfgPin::Tdo), diff --git a/prjcombine_xact_geom/Cargo.toml b/prjcombine_xact_geom/Cargo.toml index 7b9b390f..ad7ace2e 100644 --- a/prjcombine_xact_geom/Cargo.toml +++ b/prjcombine_xact_geom/Cargo.toml @@ -13,6 +13,8 @@ prjcombine_int.workspace = true prjcombine_virtex_bitstream.workspace = true prjcombine_xc2000.workspace = true prjcombine_xc2000_xact.workspace = true +prjcombine_xc3000.workspace = true +prjcombine_xc3000_xact.workspace = true prjcombine_xc4000.workspace = true prjcombine_xc4000_xact.workspace = true prjcombine_xc5200.workspace = true diff --git a/prjcombine_xact_geom/src/bin/xagprint.rs b/prjcombine_xact_geom/src/bin/xagprint.rs index be42e8bd..8d64c25a 100644 --- a/prjcombine_xact_geom/src/bin/xagprint.rs +++ b/prjcombine_xact_geom/src/bin/xagprint.rs @@ -41,6 +41,7 @@ fn main() -> Result<(), Box> { if args.grids { match grid { Grid::Xc2000(g) => print!("{}", g), + Grid::Xc3000(g) => print!("{}", g), Grid::Xc4000(g) => print!("{}", g), Grid::Xc5200(g) => print!("{}", g), } @@ -61,6 +62,7 @@ fn main() -> Result<(), Box> { if args.pkgs { match bond { Bond::Xc2000(bond) => print!("{}", bond), + Bond::Xc3000(bond) => print!("{}", bond), Bond::Xc4000(bond) => print!("{}", bond), Bond::Xc5200(bond) => print!("{}", bond), } diff --git a/prjcombine_xact_geom/src/lib.rs b/prjcombine_xact_geom/src/lib.rs index 35c2f022..515c4479 100644 --- a/prjcombine_xact_geom/src/lib.rs +++ b/prjcombine_xact_geom/src/lib.rs @@ -14,6 +14,7 @@ entity_id! { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Grid { Xc2000(prjcombine_xc2000::grid::Grid), + Xc3000(prjcombine_xc3000::grid::Grid), Xc4000(prjcombine_xc4000::grid::Grid), Xc5200(prjcombine_xc5200::grid::Grid), } @@ -34,12 +35,14 @@ pub struct Device { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Bond { Xc2000(prjcombine_xc2000::bond::Bond), + Xc3000(prjcombine_xc3000::bond::Bond), Xc4000(prjcombine_xc4000::bond::Bond), Xc5200(prjcombine_xc5200::bond::Bond), } pub enum ExpandedBond<'a> { Xc2000(prjcombine_xc2000::bond::ExpandedBond<'a>), + Xc3000(prjcombine_xc3000::bond::ExpandedBond<'a>), Xc4000(prjcombine_xc4000::bond::ExpandedBond<'a>), Xc5200(prjcombine_xc5200::bond::ExpandedBond<'a>), } @@ -48,6 +51,7 @@ impl Bond { pub fn expand(&self) -> ExpandedBond { match self { Bond::Xc2000(bond) => ExpandedBond::Xc2000(bond.expand()), + Bond::Xc3000(bond) => ExpandedBond::Xc3000(bond.expand()), Bond::Xc4000(bond) => ExpandedBond::Xc4000(bond.expand()), Bond::Xc5200(bond) => ExpandedBond::Xc5200(bond.expand()), } @@ -65,6 +69,7 @@ pub struct GeomDb { pub enum ExpandedDevice<'a> { Xc2000(prjcombine_xc2000::expanded::ExpandedDevice<'a>), + Xc3000(prjcombine_xc3000::expanded::ExpandedDevice<'a>), Xc4000(prjcombine_xc4000::expanded::ExpandedDevice<'a>), Xc5200(prjcombine_xc5200::expanded::ExpandedDevice<'a>), } @@ -73,6 +78,7 @@ impl<'a> ExpandedDevice<'a> { pub fn egrid(&self) -> &ExpandedGrid<'a> { match self { ExpandedDevice::Xc2000(edev) => &edev.egrid, + ExpandedDevice::Xc3000(edev) => &edev.egrid, ExpandedDevice::Xc4000(edev) => &edev.egrid, ExpandedDevice::Xc5200(edev) => &edev.egrid, } @@ -81,6 +87,7 @@ impl<'a> ExpandedDevice<'a> { pub fn bs_geom(&self) -> &BitstreamGeom { match self { ExpandedDevice::Xc2000(_edev) => todo!(), + ExpandedDevice::Xc3000(_edev) => todo!(), ExpandedDevice::Xc4000(edev) => &edev.bs_geom, ExpandedDevice::Xc5200(edev) => &edev.bs_geom, } @@ -89,6 +96,7 @@ impl<'a> ExpandedDevice<'a> { pub enum ExpandedNamedDevice<'a> { Xc2000(prjcombine_xc2000_xact::ExpandedNamedDevice<'a>), + Xc3000(prjcombine_xc3000_xact::ExpandedNamedDevice<'a>), Xc4000(prjcombine_xc4000_xact::ExpandedNamedDevice<'a>), Xc5200(prjcombine_xc5200_xact::ExpandedNamedDevice<'a>), } @@ -97,6 +105,7 @@ impl<'a> ExpandedNamedDevice<'a> { pub fn ngrid(&self) -> &ExpandedGridNaming<'a> { match self { ExpandedNamedDevice::Xc2000(endev) => &endev.ngrid, + ExpandedNamedDevice::Xc3000(endev) => &endev.ngrid, ExpandedNamedDevice::Xc4000(endev) => &endev.ngrid, ExpandedNamedDevice::Xc5200(endev) => &endev.ngrid, } @@ -125,6 +134,13 @@ impl GeomDb { let intdb = &self.ints["xc2000"]; ExpandedDevice::Xc2000(grid.expand_grid(intdb)) } + Grid::Xc3000(grid) => { + let intdb = &self.ints[match grid.kind { + prjcombine_xc3000::grid::GridKind::Xc3000 => "xc3000", + prjcombine_xc3000::grid::GridKind::Xc3000A => "xc3000a", + }]; + ExpandedDevice::Xc3000(grid.expand_grid(intdb)) + } Grid::Xc4000(grid) => { let intdb = &self.ints[match grid.kind { prjcombine_xc4000::grid::GridKind::Xc4000 => "xc4000", @@ -151,6 +167,13 @@ impl GeomDb { let ndb = &self.namings["xc2000"]; ExpandedNamedDevice::Xc2000(prjcombine_xc2000_xact::name_device(edev, ndb)) } + ExpandedDevice::Xc3000(edev) => { + let ndb = &self.namings[match edev.grid.kind { + prjcombine_xc3000::grid::GridKind::Xc3000 => "xc3000", + prjcombine_xc3000::grid::GridKind::Xc3000A => "xc3000a", + }]; + ExpandedNamedDevice::Xc3000(prjcombine_xc3000_xact::name_device(edev, ndb)) + } ExpandedDevice::Xc4000(edev) => { let ndb = &self.namings[match edev.grid.kind { prjcombine_xc4000::grid::GridKind::Xc4000 => "xc4000", diff --git a/prjcombine_xact_naming/src/grid.rs b/prjcombine_xact_naming/src/grid.rs index d3804fc1..5181ae32 100644 --- a/prjcombine_xact_naming/src/grid.rs +++ b/prjcombine_xact_naming/src/grid.rs @@ -1,4 +1,7 @@ -use std::{collections::{hash_map, HashMap}, ops::Range}; +use std::{ + collections::{hash_map, HashMap}, + ops::Range, +}; use prjcombine_int::{ db::BelId, diff --git a/prjcombine_xc2000/src/bond.rs b/prjcombine_xc2000/src/bond.rs index f97c589b..7440cb98 100644 --- a/prjcombine_xc2000/src/bond.rs +++ b/prjcombine_xc2000/src/bond.rs @@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize}; use crate::grid::IoCoord; - #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum CfgPin { Cclk, diff --git a/prjcombine_xc2000/src/expand.rs b/prjcombine_xc2000/src/expand.rs index 33ff1cd4..99994265 100644 --- a/prjcombine_xc2000/src/expand.rs +++ b/prjcombine_xc2000/src/expand.rs @@ -52,6 +52,16 @@ impl Grid { } } } + for row in grid.rows() { + for &col in &self.cols_bidi { + grid.add_xnode((col, row), "BIDIH", &[]); + } + } + for col in grid.cols() { + for &row in &self.rows_bidi { + grid.add_xnode((col, row), "BIDIV", &[]); + } + } for col in grid.cols() { for row in grid.rows() { grid[(col, row)].clkroot = (ColId::from_idx(0), RowId::from_idx(0)); diff --git a/prjcombine_xc2000_xact/src/lib.rs b/prjcombine_xc2000_xact/src/lib.rs index 41b73439..10143a69 100644 --- a/prjcombine_xc2000_xact/src/lib.rs +++ b/prjcombine_xc2000_xact/src/lib.rs @@ -65,6 +65,10 @@ pub fn name_device<'a>(edev: &'a ExpandedDevice<'a>, ndb: &'a NamingDb) -> Expan for (layer, node) in &die[(col, row)].nodes { let nloc = (die.die, col, row, layer); let kind = egrid.db.nodes.key(node.kind); + if kind.starts_with("BIDI") { + ngrid.name_node(nloc, kind, []); + continue; + } let mut naming = &kind[..]; if col == grid.col_lio() && row == grid.row_bio() + 1 { naming = "CLB.B1L"; diff --git a/prjcombine_xc3000/Cargo.toml b/prjcombine_xc3000/Cargo.toml new file mode 100644 index 00000000..0951ef98 --- /dev/null +++ b/prjcombine_xc3000/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "prjcombine_xc3000" +edition.workspace = true +version.workspace = true + +[dependencies] +itertools.workspace = true +unnamed_entity.workspace = true +prjcombine_int.workspace = true +prjcombine_virtex_bitstream.workspace = true +serde.workspace = true + +[lints] +workspace = true diff --git a/prjcombine_xc3000/src/bond.rs b/prjcombine_xc3000/src/bond.rs new file mode 100644 index 00000000..7440cb98 --- /dev/null +++ b/prjcombine_xc3000/src/bond.rs @@ -0,0 +1,78 @@ +use std::{collections::BTreeMap, fmt::Display}; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; + +use crate::grid::IoCoord; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum CfgPin { + Cclk, + Done, + ProgB, + PwrdwnB, + M0, + M1, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum BondPin { + Io(IoCoord), + Gnd, + Vcc, + Nc, + Cfg(CfgPin), +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct Bond { + pub pins: BTreeMap, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ExpandedBond<'a> { + pub bond: &'a Bond, + pub ios: BTreeMap, +} + +impl Bond { + pub fn expand(&self) -> ExpandedBond { + let mut ios = BTreeMap::new(); + for (name, pad) in &self.pins { + if let BondPin::Io(io) = *pad { + ios.insert(io, name.clone()); + } + } + ExpandedBond { bond: self, ios } + } +} + +fn pad_sort_key(name: &str) -> (usize, &str, u32) { + let pos = name.find(|x: char| x.is_ascii_digit()).unwrap(); + (pos, &name[..pos], name[pos..].parse().unwrap()) +} + +impl Display for Bond { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "\tPINS:")?; + for (pin, pad) in self.pins.iter().sorted_by_key(|(k, _)| pad_sort_key(k)) { + write!(f, "\t\t{pin:4}: ")?; + match pad { + BondPin::Io(io) => { + write!(f, "IOB_X{x}Y{y}B{b}", x = io.col, y = io.row, b = io.iob)? + } + BondPin::Gnd => write!(f, "GND")?, + BondPin::Vcc => write!(f, "VCC")?, + BondPin::Nc => write!(f, "NC")?, + BondPin::Cfg(CfgPin::Cclk) => write!(f, "CCLK")?, + BondPin::Cfg(CfgPin::Done) => write!(f, "DONE")?, + BondPin::Cfg(CfgPin::ProgB) => write!(f, "PROG_B")?, + BondPin::Cfg(CfgPin::M0) => write!(f, "M0")?, + BondPin::Cfg(CfgPin::M1) => write!(f, "M1")?, + BondPin::Cfg(CfgPin::PwrdwnB) => write!(f, "PWRDWN_B")?, + } + writeln!(f)?; + } + Ok(()) + } +} diff --git a/prjcombine_xc3000/src/expand.rs b/prjcombine_xc3000/src/expand.rs new file mode 100644 index 00000000..718bdc92 --- /dev/null +++ b/prjcombine_xc3000/src/expand.rs @@ -0,0 +1,128 @@ +use prjcombine_int::{ + db::IntDb, + grid::{ColId, ExpandedGrid, RowId}, +}; +use unnamed_entity::EntityId; + +use crate::{expanded::ExpandedDevice, grid::Grid}; + +impl Grid { + pub fn expand_grid<'a>(&'a self, db: &'a IntDb) -> ExpandedDevice<'a> { + let mut egrid = ExpandedGrid::new(db); + let (_, mut grid) = egrid.add_die(self.columns, self.rows); + let s = if self.is_small { "S" } else { "" }; + + for col in grid.cols() { + for row in grid.rows() { + let mut subkind = (row.to_idx() + 2 * (self.columns - 1 - col.to_idx())) % 3; + if subkind == 1 && col == self.col_rio() && row == self.row_tio() - 1 { + // fuck me with the rustiest fork you can find + subkind = 3; + } + if col == self.col_lio() { + if row == self.row_bio() { + grid.add_xnode( + (col, row), + &format!("CLB.BL{s}.{subkind}"), + &[(col, row), (col + 1, row), (col, row + 1)], + ); + } else if row == self.row_tio() { + grid.add_xnode( + (col, row), + &format!("CLB.TL{s}.{subkind}"), + &[(col, row), (col + 1, row), (col, row - 1)], + ); + } else { + grid.add_xnode( + (col, row), + &format!("CLB.L.{subkind}"), + &[(col, row), (col + 1, row), (col, row - 1), (col, row + 1)], + ); + } + } else if col == self.col_rio() { + if row == self.row_bio() { + grid.add_xnode( + (col, row), + &format!("CLB.BR{s}.{subkind}"), + &[(col, row), (col, row + 1)], + ); + } else if row == self.row_tio() { + grid.add_xnode( + (col, row), + &format!("CLB.TR.{subkind}"), + &[(col, row), (col, row - 1)], + ); + } else { + grid.add_xnode( + (col, row), + &format!("CLB.R.{subkind}"), + &[(col, row), (col, row - 1), (col, row + 1)], + ); + } + } else { + if row == self.row_bio() { + grid.add_xnode( + (col, row), + &format!("CLB.B.{subkind}"), + &[(col, row), (col + 1, row), (col, row + 1)], + ); + } else if row == self.row_tio() { + grid.add_xnode( + (col, row), + &format!("CLB.T.{subkind}"), + &[(col, row), (col + 1, row), (col, row - 1)], + ); + } else { + grid.add_xnode( + (col, row), + &format!("CLB.{subkind}"), + &[(col, row), (col + 1, row), (col, row - 1), (col, row + 1)], + ); + } + } + } + } + { + let col = self.col_mid(); + let row = self.row_bio(); + grid.fill_term_pair((col - 1, row), (col, row), "LLH.E", "LLH.W"); + grid.add_xnode((col, row), "LLH.B", &[(col - 1, row), (col, row)]); + let row = self.row_tio(); + grid.fill_term_pair((col - 1, row), (col, row), "LLH.E", "LLH.W"); + grid.add_xnode((col, row), "LLH.T", &[(col - 1, row), (col, row)]); + } + if self.is_small { + let row = self.row_mid(); + let col = self.col_lio(); + grid.fill_term_pair((col, row - 1), (col, row), "LLV.S.N", "LLV.S.S"); + grid.add_xnode((col, row), "LLV.LS", &[(col, row - 1), (col, row)]); + let col = self.col_rio(); + grid.fill_term_pair((col, row - 1), (col, row), "LLV.S.N", "LLV.S.S"); + grid.add_xnode((col, row), "LLV.RS", &[(col, row - 1), (col, row)]); + } else { + let row = self.row_mid(); + for col in grid.cols() { + let kind = if col == self.col_lio() { + "LLV.L" + } else if col == self.col_rio() { + "LLV.R" + } else { + "LLV" + }; + grid.fill_term_pair((col, row - 1), (col, row), "LLV.N", "LLV.S"); + grid.add_xnode((col, row), kind, &[(col, row - 1), (col, row)]); + } + } + for col in grid.cols() { + for row in grid.rows() { + grid[(col, row)].clkroot = (ColId::from_idx(0), RowId::from_idx(0)); + } + } + + grid.fill_main_passes(); + + egrid.finish(); + + ExpandedDevice { grid: self, egrid } + } +} diff --git a/prjcombine_xc3000/src/expanded.rs b/prjcombine_xc3000/src/expanded.rs new file mode 100644 index 00000000..f435625e --- /dev/null +++ b/prjcombine_xc3000/src/expanded.rs @@ -0,0 +1,73 @@ +use prjcombine_int::grid::{DieId, ExpandedGrid}; +use unnamed_entity::EntityId; + +use crate::grid::{Grid, IoCoord, TileIobId}; + +pub struct ExpandedDevice<'a> { + pub grid: &'a Grid, + pub egrid: ExpandedGrid<'a>, +} + +impl ExpandedDevice<'_> { + pub fn get_bonded_ios(&self) -> Vec { + let mut res = vec![]; + let die = self.egrid.die(DieId::from_idx(0)); + for col in die.cols() { + for iob in [0, 1] { + res.push(IoCoord { + col, + row: self.grid.row_tio(), + iob: TileIobId::from_idx(iob), + }); + } + } + for row in die.rows().rev() { + if row == self.grid.row_bio() || row == self.grid.row_tio() { + for iob in [2, 3] { + res.push(IoCoord { + col: self.grid.col_rio(), + row, + iob: TileIobId::from_idx(iob), + }); + } + } else { + for iob in [0, 1] { + res.push(IoCoord { + col: self.grid.col_rio(), + row, + iob: TileIobId::from_idx(iob), + }); + } + } + } + for col in die.cols().rev() { + for iob in [1, 0] { + res.push(IoCoord { + col, + row: self.grid.row_bio(), + iob: TileIobId::from_idx(iob), + }); + } + } + for row in die.rows() { + if row == self.grid.row_bio() || row == self.grid.row_tio() { + for iob in [3, 2] { + res.push(IoCoord { + col: self.grid.col_lio(), + row, + iob: TileIobId::from_idx(iob), + }); + } + } else { + for iob in [1, 0] { + res.push(IoCoord { + col: self.grid.col_lio(), + row, + iob: TileIobId::from_idx(iob), + }); + } + } + } + res + } +} diff --git a/prjcombine_xc3000/src/grid.rs b/prjcombine_xc3000/src/grid.rs new file mode 100644 index 00000000..21e72e0b --- /dev/null +++ b/prjcombine_xc3000/src/grid.rs @@ -0,0 +1,114 @@ +use std::{collections::BTreeMap, fmt::Display}; + +use prjcombine_int::grid::{ColId, RowId}; +use serde::{Deserialize, Serialize}; +use unnamed_entity::{entity_id, EntityId}; + +entity_id! { + pub id TileIobId u8; +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum GridKind { + Xc3000, + Xc3000A, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] +pub struct IoCoord { + pub col: ColId, + pub row: RowId, + pub iob: TileIobId, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum SharedCfgPin { + Addr(u8), + Data(u8), + Ldc, + Hdc, + RclkB, + Dout, + M2, + InitB, + Cs0B, + Cs1B, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct Grid { + pub kind: GridKind, + pub columns: usize, + pub rows: usize, + pub is_small: bool, + pub cfg_io: BTreeMap, +} + +impl Grid { + pub fn col_lio(&self) -> ColId { + ColId::from_idx(0) + } + + pub fn col_rio(&self) -> ColId { + ColId::from_idx(self.columns - 1) + } + + pub fn col_mid(&self) -> ColId { + ColId::from_idx(self.columns / 2) + } + + pub fn row_bio(&self) -> RowId { + RowId::from_idx(0) + } + + pub fn row_tio(&self) -> RowId { + RowId::from_idx(self.rows - 1) + } + + pub fn row_mid(&self) -> RowId { + RowId::from_idx(self.rows / 2) + } + + pub fn io_xtl1(&self) -> IoCoord { + IoCoord { + col: self.col_rio(), + row: self.row_bio(), + iob: TileIobId::from_idx(1), + } + } + + pub fn io_xtl2(&self) -> IoCoord { + IoCoord { + col: self.col_rio(), + row: self.row_bio(), + iob: TileIobId::from_idx(2), + } + } + + pub fn io_tclk(&self) -> IoCoord { + IoCoord { + col: self.col_lio(), + row: self.row_tio(), + iob: TileIobId::from_idx(2), + } + } +} + +impl Display for Grid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "\tKIND: {:?}", self.kind)?; + writeln!(f, "\tDIMS: {c}×{r}", c = self.columns, r = self.rows)?; + writeln!(f, "\tSMALL: {}", self.is_small)?; + writeln!(f, "\tCFG PINS:")?; + for (k, v) in &self.cfg_io { + writeln!( + f, + "\t\t{k:?}: IOB_X{x}Y{y}B{b}", + x = v.col, + y = v.row, + b = v.iob + )?; + } + Ok(()) + } +} diff --git a/prjcombine_xc3000/src/lib.rs b/prjcombine_xc3000/src/lib.rs new file mode 100644 index 00000000..0cb40a12 --- /dev/null +++ b/prjcombine_xc3000/src/lib.rs @@ -0,0 +1,4 @@ +pub mod bond; +mod expand; +pub mod expanded; +pub mod grid; diff --git a/prjcombine_xc3000_xact/Cargo.toml b/prjcombine_xc3000_xact/Cargo.toml new file mode 100644 index 00000000..ba8fc9fe --- /dev/null +++ b/prjcombine_xc3000_xact/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "prjcombine_xc3000_xact" +edition.workspace = true +version.workspace = true + +[dependencies] +unnamed_entity.workspace = true +prjcombine_int.workspace = true +prjcombine_xact_naming.workspace = true +prjcombine_xc3000.workspace = true + +[lints] +workspace = true diff --git a/prjcombine_xc3000_xact/src/lib.rs b/prjcombine_xc3000_xact/src/lib.rs new file mode 100644 index 00000000..05bc31cd --- /dev/null +++ b/prjcombine_xc3000_xact/src/lib.rs @@ -0,0 +1,234 @@ +use std::ops::Range; + +use prjcombine_int::{ + db::BelId, + grid::{ColId, DieId, LayerId, RowId}, +}; +use prjcombine_xact_naming::{db::NamingDb, grid::ExpandedGridNaming}; +use prjcombine_xc3000::{ + expanded::ExpandedDevice, + grid::{Grid, IoCoord}, +}; +use unnamed_entity::{EntityId, EntityVec}; + +pub struct ExpandedNamedDevice<'a> { + pub edev: &'a ExpandedDevice<'a>, + pub ngrid: ExpandedGridNaming<'a>, + pub grid: &'a Grid, + pub col_x: EntityVec>, + pub row_y: EntityVec>, +} + +impl<'a> ExpandedNamedDevice<'a> { + pub fn get_io_name(&'a self, coord: IoCoord) -> &'a str { + let die = self.edev.egrid.die(DieId::from_idx(0)); + let nnode = &self.ngrid.nodes[&(die.die, coord.col, coord.row, LayerId::from_idx(0))]; + let bel = BelId::from_idx(1 + coord.iob.to_idx()); + &nnode.bels[bel][0] + } +} + +fn name_a( + grid: &Grid, + prefix: &str, + suffix: &str, + col: ColId, + row: RowId, + dx: i32, + dy: i32, +) -> String { + let cidx = col.to_idx(); + let ridx = grid.rows - row.to_idx() - 1; + let cidx = u32::try_from(cidx).unwrap().checked_add_signed(dx).unwrap(); + let ridx = u32::try_from(ridx).unwrap().checked_add_signed(dy).unwrap(); + let r = char::from_u32(u32::from('A') + ridx).unwrap(); + let c = char::from_u32(u32::from('A') + cidx).unwrap(); + format!("{prefix}{r}{c}{suffix}") +} + +pub fn name_device<'a>(edev: &'a ExpandedDevice<'a>, ndb: &'a NamingDb) -> ExpandedNamedDevice<'a> { + let egrid = &edev.egrid; + let grid = edev.grid; + let mut ngrid = ExpandedGridNaming::new(ndb, egrid); + + let mut col_x = EntityVec::new(); + let mut row_y = EntityVec::new(); + let mut x = 0; + for col in egrid.die(DieId::from_idx(0)).cols() { + let ox = x; + x += if col == grid.col_lio() { + ndb.tile_widths["L"] + } else if col == grid.col_rio() { + ndb.tile_widths["R"] + } else { + ndb.tile_widths["C"] + }; + col_x.push(ox..x); + } + let mut y = 0; + for row in egrid.die(DieId::from_idx(0)).rows() { + let oy = y; + y += if row == grid.row_bio() { + ndb.tile_heights["B"] + } else if row == grid.row_tio() { + ndb.tile_heights["T"] + } else { + ndb.tile_heights["C"] + }; + row_y.push(oy..y); + } + for die in egrid.dies() { + for col in die.cols() { + for row in die.rows() { + for (layer, node) in &die[(col, row)].nodes { + let nloc = (die.die, col, row, layer); + let kind = egrid.db.nodes.key(node.kind); + let mut naming = kind.to_string(); + if col == grid.col_lio() + 1 { + naming += ".L1"; + } + if row == grid.row_bio() + 1 { + naming += ".B1"; + } + if kind.starts_with("CLB") { + let nnode = ngrid.name_node( + nloc, + &naming, + [(col_x[col].clone(), row_y[row].clone())], + ); + + if col != grid.col_lio() { + nnode + .coords + .push((col_x[col - 1].clone(), row_y[row].clone())); + } + if col != grid.col_rio() { + nnode + .coords + .push((col_x[col + 1].clone(), row_y[row].clone())); + } + if row != grid.row_bio() { + nnode + .coords + .push((col_x[col].clone(), row_y[row - 1].clone())); + } + if row != grid.row_tio() { + nnode + .coords + .push((col_x[col].clone(), row_y[row + 1].clone())); + } + + nnode.add_bel(0, vec![name_a(grid, "", "", col, row, 0, 0)]); + + let tidx = if kind.starts_with("CLB.B") { + let p0 = 1 + + grid.columns * 2 + + grid.rows * 2 + + (grid.col_rio().to_idx() - col.to_idx()) * 2; + let p1 = p0 + 1; + nnode.add_bel(1, vec![format!("PAD{p1}")]); + nnode.add_bel(2, vec![format!("PAD{p0}")]); + if kind.starts_with("CLB.BL") { + let p2 = p0 + 2; + let p3 = p0 + 3; + nnode.add_bel(3, vec![format!("PAD{p3}")]); + nnode.add_bel(4, vec![format!("PAD{p2}")]); + 5 + } else if kind.starts_with("CLB.BR") { + let p2 = p0 - 2; + let p3 = p0 - 1; + nnode.add_bel(3, vec![format!("PAD{p2}")]); + nnode.add_bel(4, vec![format!("PAD{p3}")]); + 5 + } else { + 3 + } + } else if kind.starts_with("CLB.T") { + let p0 = 1 + col.to_idx() * 2; + let p1 = p0 + 1; + nnode.add_bel(1, vec![format!("PAD{p0}")]); + nnode.add_bel(2, vec![format!("PAD{p1}")]); + if kind.starts_with("CLB.TL") { + let p0 = grid.columns * 4 + grid.rows * 4 - 1; + let p1 = p0 + 1; + nnode.add_bel(3, vec![format!("PAD{p1}")]); + nnode.add_bel(4, vec![format!("PAD{p0}")]); + 5 + } else if kind.starts_with("CLB.TR") { + let p2 = p0 + 2; + let p3 = p0 + 3; + nnode.add_bel(3, vec![format!("PAD{p2}")]); + nnode.add_bel(4, vec![format!("PAD{p3}")]); + 5 + } else { + 3 + } + } else if kind.starts_with("CLB.L") { + let p0 = 1 + grid.columns * 4 + grid.rows * 2 + row.to_idx() * 2; + let p1 = p0 + 1; + nnode.add_bel(1, vec![format!("PAD{p1}")]); + nnode.add_bel(2, vec![format!("PAD{p0}")]); + 3 + } else if kind.starts_with("CLB.R") { + let p0 = + 1 + grid.columns * 2 + (grid.row_tio().to_idx() - row.to_idx()) * 2; + let p1 = p0 + 1; + nnode.add_bel(1, vec![format!("PAD{p0}")]); + nnode.add_bel(2, vec![format!("PAD{p1}")]); + 3 + } else { + 1 + }; + + let suf2 = if row == grid.row_tio() { ".1" } else { ".2" }; + nnode.add_bel(tidx, vec![name_a(grid, "TBUF.", ".1", col, row, 0, 1)]); + nnode.add_bel(tidx + 1, vec![name_a(grid, "TBUF.", suf2, col, row, 0, 0)]); + if col == grid.col_rio() { + nnode.add_bel( + tidx + 2, + vec![name_a(grid, "TBUF.", ".1", col, row, 1, 1)], + ); + nnode.add_bel( + tidx + 3, + vec![name_a(grid, "TBUF.", suf2, col, row, 1, 0)], + ); + nnode + .add_bel(tidx + 4, vec![name_a(grid, "PU.", ".1", col, row, 1, 1)]); + nnode + .add_bel(tidx + 5, vec![name_a(grid, "PU.", suf2, col, row, 1, 0)]); + } else if col == grid.col_lio() { + nnode + .add_bel(tidx + 2, vec![name_a(grid, "PU.", ".1", col, row, 0, 1)]); + nnode + .add_bel(tidx + 3, vec![name_a(grid, "PU.", suf2, col, row, 0, 0)]); + } + + if kind.starts_with("CLB.TL") { + nnode.add_bel(9, vec!["TCLKIN".into()]); + nnode.add_bel(10, vec!["GCLK".into()]); + } + if kind.starts_with("CLB.BR") { + nnode.add_bel(11, vec!["BCLKIN".into()]); + nnode.add_bel(12, vec!["ACLK".into()]); + nnode.add_bel(13, vec!["OSC".into()]); + } + } else if kind.starts_with("LLH") { + ngrid.name_node(nloc, kind, [(col_x[col].clone(), row_y[row].clone())]); + } else if kind.starts_with("LLV") { + ngrid.name_node(nloc, kind, [(col_x[col].clone(), row_y[row - 1].clone())]); + } else { + panic!("ummmm {kind}?"); + } + } + } + } + } + + ExpandedNamedDevice { + edev, + ngrid, + grid, + col_x, + row_y, + } +} diff --git a/prjcombine_xc4000/src/grid.rs b/prjcombine_xc4000/src/grid.rs index 10f41b25..375e6908 100644 --- a/prjcombine_xc4000/src/grid.rs +++ b/prjcombine_xc4000/src/grid.rs @@ -54,9 +54,9 @@ pub enum SharedCfgPin { Hdc, InitB, Cs0B, - RsB, + Cs1B, Dout, - BusyB, + RclkB, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] diff --git a/prjcombine_xc4000_rd2db/src/bond.rs b/prjcombine_xc4000_rd2db/src/bond.rs index 632d8579..c9c71d4b 100644 --- a/prjcombine_xc4000_rd2db/src/bond.rs +++ b/prjcombine_xc4000_rd2db/src/bond.rs @@ -84,10 +84,10 @@ pub fn make_bond( ("P60", SharedCfgPin::Cs0B), ("P61", SharedCfgPin::Data(4)), ("P65", SharedCfgPin::Data(3)), - ("P66", SharedCfgPin::RsB), + ("P66", SharedCfgPin::Cs1B), ("P67", SharedCfgPin::Data(2)), ("P69", SharedCfgPin::Data(1)), - ("P70", SharedCfgPin::BusyB), + ("P70", SharedCfgPin::RclkB), ("P71", SharedCfgPin::Data(0)), ("P72", SharedCfgPin::Dout), ("P77", SharedCfgPin::Addr(0)), @@ -111,10 +111,10 @@ pub fn make_bond( ("P58", SharedCfgPin::Cs0B), ("P61", SharedCfgPin::Data(4)), ("P65", SharedCfgPin::Data(3)), - ("P66", SharedCfgPin::RsB), + ("P66", SharedCfgPin::Cs1B), ("P68", SharedCfgPin::Data(2)), ("P70", SharedCfgPin::Data(1)), - ("P71", SharedCfgPin::BusyB), + ("P71", SharedCfgPin::RclkB), ("P72", SharedCfgPin::Data(0)), ("P73", SharedCfgPin::Dout), ("P78", SharedCfgPin::Addr(0)), @@ -165,10 +165,10 @@ pub fn make_bond( ("P95", SharedCfgPin::Cs0B), ("P98", SharedCfgPin::Data(4)), ("P102", SharedCfgPin::Data(3)), - ("P103", SharedCfgPin::RsB), + ("P103", SharedCfgPin::Cs1B), ("P106", SharedCfgPin::Data(2)), ("P113", SharedCfgPin::Data(1)), - ("P114", SharedCfgPin::BusyB), + ("P114", SharedCfgPin::RclkB), ("P117", SharedCfgPin::Data(0)), ("P118", SharedCfgPin::Dout), ("P123", SharedCfgPin::Addr(0)), @@ -206,10 +206,10 @@ pub fn make_bond( ("P142", SharedCfgPin::Cs0B), ("P148", SharedCfgPin::Data(4)), ("P152", SharedCfgPin::Data(3)), - ("P153", SharedCfgPin::RsB), + ("P153", SharedCfgPin::Cs1B), ("P159", SharedCfgPin::Data(2)), ("P173", SharedCfgPin::Data(1)), - ("P174", SharedCfgPin::BusyB), + ("P174", SharedCfgPin::RclkB), ("P177", SharedCfgPin::Data(0)), ("P178", SharedCfgPin::Dout), ("P183", SharedCfgPin::Addr(0)), @@ -247,10 +247,10 @@ pub fn make_bond( ("Y2", SharedCfgPin::Cs0B), ("T1", SharedCfgPin::Data(4)), ("T3", SharedCfgPin::Data(3)), - ("R1", SharedCfgPin::RsB), + ("R1", SharedCfgPin::Cs1B), ("L2", SharedCfgPin::Data(2)), ("G4", SharedCfgPin::Data(1)), - ("F2", SharedCfgPin::BusyB), + ("F2", SharedCfgPin::RclkB), ("C2", SharedCfgPin::Data(0)), ("D3", SharedCfgPin::Dout), ("B3", SharedCfgPin::Addr(0)), @@ -281,8 +281,8 @@ pub fn make_bond( if matches!( io, SharedCfgPin::Addr(0 | 1 | 3..) - | SharedCfgPin::RsB - | SharedCfgPin::BusyB + | SharedCfgPin::Cs1B + | SharedCfgPin::RclkB | SharedCfgPin::Cs0B ) && endev.grid.kind == GridKind::SpartanXl { diff --git a/prjcombine_xc4000_xact/src/lib.rs b/prjcombine_xc4000_xact/src/lib.rs index 7daaecfe..3bb771c6 100644 --- a/prjcombine_xc4000_xact/src/lib.rs +++ b/prjcombine_xc4000_xact/src/lib.rs @@ -4,10 +4,7 @@ use prjcombine_int::{ db::BelId, grid::{ColId, DieId, LayerId, RowId}, }; -use prjcombine_xact_naming::{ - db::NamingDb, - grid::ExpandedGridNaming, -}; +use prjcombine_xact_naming::{db::NamingDb, grid::ExpandedGridNaming}; use prjcombine_xc4000::{ expanded::ExpandedDevice, grid::{Grid, GridKind, IoCoord}, @@ -33,7 +30,7 @@ impl<'a> ExpandedNamedDevice<'a> { } } -pub fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { +fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { let cidx = if col < grid.col_mid() { col.to_idx() } else { @@ -55,7 +52,7 @@ pub fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) - } } -pub fn name_b(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { +fn name_b(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { let cidx = col.to_idx(); let ridx = if row < grid.row_mid() && prefix == "TIE_" && grid.kind == GridKind::Xc4000H { grid.rows - row.to_idx() diff --git a/prjcombine_xc5200/src/grid.rs b/prjcombine_xc5200/src/grid.rs index 7ad5f39e..b4407310 100644 --- a/prjcombine_xc5200/src/grid.rs +++ b/prjcombine_xc5200/src/grid.rs @@ -30,9 +30,9 @@ pub enum SharedCfgPin { Hdc, InitB, Cs0B, - RsB, + Cs1B, Dout, - BusyB, + RclkB, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] diff --git a/prjcombine_xc5200_rd2db/src/bond.rs b/prjcombine_xc5200_rd2db/src/bond.rs index 81b0d729..d7f21ce0 100644 --- a/prjcombine_xc5200_rd2db/src/bond.rs +++ b/prjcombine_xc5200_rd2db/src/bond.rs @@ -359,10 +359,10 @@ pub fn make_bond( ("P60", SharedCfgPin::Cs0B), ("P61", SharedCfgPin::Data(4)), ("P65", SharedCfgPin::Data(3)), - ("P66", SharedCfgPin::RsB), + ("P66", SharedCfgPin::Cs1B), ("P67", SharedCfgPin::Data(2)), ("P69", SharedCfgPin::Data(1)), - ("P70", SharedCfgPin::BusyB), + ("P70", SharedCfgPin::RclkB), ("P71", SharedCfgPin::Data(0)), ("P72", SharedCfgPin::Dout), ("P75", SharedCfgPin::Tdo), @@ -401,10 +401,10 @@ pub fn make_bond( ("P95", SharedCfgPin::Cs0B), ("P98", SharedCfgPin::Data(4)), ("P102", SharedCfgPin::Data(3)), - ("P103", SharedCfgPin::RsB), + ("P103", SharedCfgPin::Cs1B), ("P106", SharedCfgPin::Data(2)), ("P113", SharedCfgPin::Data(1)), - ("P114", SharedCfgPin::BusyB), + ("P114", SharedCfgPin::RclkB), ("P117", SharedCfgPin::Data(0)), ("P118", SharedCfgPin::Dout), ("P121", SharedCfgPin::Tdo), diff --git a/prjcombine_xc5200_xact/src/lib.rs b/prjcombine_xc5200_xact/src/lib.rs index cd0a928d..8a632cef 100644 --- a/prjcombine_xc5200_xact/src/lib.rs +++ b/prjcombine_xc5200_xact/src/lib.rs @@ -4,10 +4,7 @@ use prjcombine_int::{ db::BelId, grid::{ColId, DieId, LayerId, RowId}, }; -use prjcombine_xact_naming::{ - db::NamingDb, - grid::ExpandedGridNaming, -}; +use prjcombine_xact_naming::{db::NamingDb, grid::ExpandedGridNaming}; use prjcombine_xc5200::{ expanded::ExpandedDevice, grid::{Grid, IoCoord}, @@ -33,7 +30,7 @@ impl<'a> ExpandedNamedDevice<'a> { } } -pub fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { +fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { let cidx = if col < grid.col_mid() { col.to_idx() } else { @@ -51,7 +48,7 @@ pub fn name_a(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) - format!("{prefix}{r}{c}{suffix}") } -pub fn name_b(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { +fn name_b(grid: &Grid, prefix: &str, suffix: &str, col: ColId, row: RowId) -> String { let cidx = col.to_idx(); let ridx = grid.rows - row.to_idx() - 1; format!("{prefix}R{ridx}C{cidx}{suffix}")