Skip to content

Commit

Permalink
xc2c_as, xc2c_dis
Browse files Browse the repository at this point in the history
  • Loading branch information
wanda-phi committed Jan 29, 2024
1 parent 362fe69 commit d1c6e8d
Show file tree
Hide file tree
Showing 5 changed files with 497 additions and 5 deletions.
4 changes: 2 additions & 2 deletions prjcombine_xc2c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ name = "prjcombine_xc2c"
edition.workspace = true
version.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bitvec.workspace = true
serde.workspace = true
bincode.workspace = true
zstd.workspace = true
clap.workspace = true
unnamed_entity.workspace = true
prjcombine_types.workspace = true

Expand Down
254 changes: 254 additions & 0 deletions prjcombine_xc2c/src/bin/xc2c_as.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
use std::{
collections::BTreeMap,
error::Error,
fs::{read_to_string, File},
io::Write,
path::{Path, PathBuf},
};

use bitvec::vec::BitVec;
use clap::Parser;
use prjcombine_types::{FbId, FbMcId, IoId, Tile, TileItemKind};
use prjcombine_xc2c::{BitCoord, Database, Device};
use unnamed_entity::EntityId;

struct Bitstream {
fbs: Vec<FbData>,
globals: BTreeMap<String, BitVec>,
}

struct FbData {
imux: BTreeMap<String, BitVec>,
mcs: [BTreeMap<String, BitVec>; 16],
pla_and: [PTermData; 56],
pla_or: [BitVec; 16],
}

struct PTermData {
im_t: BitVec,
im_f: BitVec,
}

fn init_tile(tile: &Tile<BitCoord>) -> BTreeMap<String, BitVec> {
tile.items
.iter()
.map(|(k, v)| (k.clone(), BitVec::repeat(true, v.bits.len())))
.collect()
}

impl Bitstream {
fn new(device: &Device) -> Self {
let fbs = (0..(device.fb_rows as usize * device.fb_cols.len() * 2))
.map(|_| FbData {
imux: init_tile(&device.imux_bits),
mcs: core::array::from_fn(|_| init_tile(&device.mc_bits)),
pla_and: core::array::from_fn(|_| PTermData {
im_t: BitVec::repeat(false, 40),
im_f: BitVec::repeat(false, 40),
}),
pla_or: core::array::from_fn(|_| BitVec::repeat(false, 56)),
})
.collect();
Bitstream {
fbs,
globals: init_tile(&device.global_bits),
}
}

fn to_jed(&self, device: &Device, db: &Database) -> BitVec {
let mut res = BitVec::new();
for (fb, fbd) in self.fbs.iter().enumerate() {
for i in 0..40 {
let n = format!("IM[{i}].MUX");
let val = &fbd.imux[&n];
res.extend(val);
}
for i in 0..56 {
let pt = &fbd.pla_and[i];
for j in 0..40 {
res.push(!pt.im_t[j]);
res.push(!pt.im_f[j]);
}
}
for i in 0..56 {
for j in 0..16 {
res.push(!fbd.pla_or[j][i]);
}
}
for mc in 0..16 {
let iobful = device
.io
.contains_key(&IoId::Mc((FbId::from_idx(fb), FbMcId::from_idx(mc))));
let mcd = &fbd.mcs[mc];
let jed_bits = if !device.has_vref {
&db.jed_mc_bits_small
} else if iobful {
&db.jed_mc_bits_large_iob
} else {
&db.jed_mc_bits_large_buried
};
for (bn, bi) in jed_bits {
res.push(mcd[bn][*bi]);
}
}
}
for (bn, bi) in &device.jed_global_bits {
res.push(self.globals[bn][*bi]);
}
res
}
}

fn set_tile_item(data: &mut BTreeMap<String, BitVec>, tile: &Tile<BitCoord>, item: &str) {
if let Some((name, val)) = item.split_once('=') {
let item = &tile.items[name];
let val = match &item.kind {
TileItemKind::Enum { values } => values[val].clone(),
TileItemKind::BitVec { invert } => {
assert_eq!(val.len(), item.bits.len());
val.chars()
.rev()
.map(|x| match x {
'0' => *invert,
'1' => !*invert,
_ => unreachable!(),
})
.collect()
}
};
data.insert(name.to_string(), val);
} else {
let (name, val) = if let Some(name) = item.strip_prefix('!') {
(name, false)
} else {
(item, true)
};
let item = &tile.items[name];
match &item.kind {
TileItemKind::Enum { .. } => unreachable!(),
TileItemKind::BitVec { invert } => {
assert_eq!(item.bits.len(), 1);
data.insert(name.to_string(), BitVec::repeat(val ^ *invert, 1));
}
}
}
}

#[derive(Parser)]
struct Args {
db: PathBuf,
src: PathBuf,
jed: PathBuf,
}

fn write_jed(fname: impl AsRef<Path>, dev: &str, bits: &BitVec) -> Result<(), Box<dyn Error>> {
let mut f = File::create(fname)?;
writeln!(f, "\x02QF{n}*", n = bits.len())?;
writeln!(f, "F0*")?;
writeln!(f, "N DEVICE {dev}*")?;
for (i, c) in bits.chunks(80).enumerate() {
write!(f, "L{ii:06} ", ii = i * 80)?;
for bit in c {
write!(f, "{x}", x = u32::from(*bit))?;
}
writeln!(f, "*")?;
}
writeln!(f, "\x030000")?;
Ok(())
}

pub fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let src = read_to_string(args.src)?;
let mut lines = src.lines();
let mut dev = None;
for mut line in &mut lines {
if let Some(pos) = line.find('#') {
line = &line[..pos];
}
line = line.trim();
if line.is_empty() {
continue;
}
let (pref, suf) = line.split_once(':').unwrap();
let suf = suf.trim();
assert_eq!(pref, "DEVICE");
dev = Some(suf);
break;
}
let dev = dev.unwrap();
let db = Database::from_file(args.db)?;
let mut part = None;
for p in &db.parts {
if p.name == dev {
part = Some(p);
break;
}
}
let Some(part) = part else {
eprintln!("Unknown device {dev}");
return Ok(());
};
let device = &db.devices[part.device];
let mut bs = Bitstream::new(device);
for mut line in lines {
if let Some(pos) = line.find('#') {
line = &line[..pos];
}
line = line.trim();
if line.is_empty() {
continue;
}
let (pref, suf) = line.split_once(':').unwrap();
let pref: Vec<_> = pref.split_ascii_whitespace().collect();
let suf: Vec<_> = suf.trim().split_ascii_whitespace().collect();
match pref[..] {
["GLOBAL"] => {
for item in suf {
set_tile_item(&mut bs.globals, &device.global_bits, item);
}
}
["FB", fb] => {
let fb: usize = fb.parse()?;
for item in suf {
set_tile_item(&mut bs.fbs[fb].imux, &device.imux_bits, item);
}
}
["MC", fb, mc] => {
let fb: usize = fb.parse()?;
let mc: usize = mc.parse()?;
for item in suf {
set_tile_item(&mut bs.fbs[fb].mcs[mc], &device.mc_bits, item);
}
}
["PT", fb, pt] => {
let fb: usize = fb.parse()?;
let pt: usize = pt.parse()?;
let pt = &mut bs.fbs[fb].pla_and[pt];
for item in suf {
if let Some(idx) = item.strip_prefix('!') {
let idx = idx.parse()?;
pt.im_f.set(idx, true);
} else {
let idx = item.parse()?;
pt.im_t.set(idx, true);
}
}
}
["ST", fb, mc] => {
let fb: usize = fb.parse()?;
let mc: usize = mc.parse()?;
for item in suf {
let idx = item.parse()?;
bs.fbs[fb].pla_or[mc].set(idx, true);
}
}

_ => panic!("weird line {line}"),
}
}
let fuses = bs.to_jed(device, &db);
write_jed(args.jed, dev, &fuses)?;

Ok(())
}
Loading

0 comments on commit d1c6e8d

Please sign in to comment.