You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
t27c silicon: wire bitstream_reuse.t27 -- blocked by the no-growth rule for hand-written code #8295
specs/verified/bitstream_reuse.t27 (PR #8291) decides when t27c silicon may load a bitstream it built before. That skips about 27 s of yosys, nextpnr and fasm2frames per run on die A, and later lets an agent with no toolchain load a sealed bitstream.
Wiring it needs I/O that t27 cannot express yet:
read and hash files: the gen-verilog output, the --top files, the chipdb, the nextpnr binary;
run yosys -V and git rev-parse;
read and write ~/.cache/t27/bitstreams/<key>/.
The glue is 32 lines of Rust (service.rs +28, main.rs +4), written and built locally. Since the owner's rule of 2026-10-09, hand-written code in any language but t27 may not grow (own-language), and no label lifts that. So the glue is not landed.
Ways forward (the owner's call):
In the same PR, port at least 32 lines of existing hand Rust from bootstrap/src to .t27, so the net change is 0 or less.
a second t27c silicon run of an unchanged spec prints a bitstream REUSED stage instead of yosys and nextpnr
the own-language check passes on the PR that wires it
Boundary
specs/verified/bitstream_reuse.t27
User Scenarios
Given a verified spec that declares bitstream reuse via specs/verified/bitstream_reuse.t27, When t27c silicon runs a second time with unchanged inputs (gen-verilog output, --top files, chipdb, nextpnr binary, yosys version, git revision), Then the command prints a bitstream REUSED stage and skips yosys, nextpnr, and fasm2frames.
Given the own-language rule (no net growth of hand-written Rust), When the wiring for bitstream reuse is submitted in a PR, Then the PR must either port at least 32 lines of existing bootstrap/src Rust to .t27 or depend on t27 gaining file/process/hash I/O (tracked in epic: self-host t27c -- rewrite the compiler from Rust into t27 #5980) so the glue is generated.
Requirements
FR-001: The second t27c silicon run of an unchanged spec MUST print a bitstream REUSED stage instead of invoking yosys and nextpnr.
FR-002: The PR that wires specs/verified/bitstream_reuse.t27 MUST pass the own-language check (net change ≤ 0 lines of hand-written Rust).
FR-003: Bitstream reuse key derivation MUST incorporate hashes of gen-verilog output, --top files, chipdb, nextpnr binary, yosys -V output, and git rev-parse output.
FR-004: The implementation MUST read and write ~/.cache/t27/bitstreams/<key>/ for cached bitstreams.
The 32-line glue, built and compiled locally against master 1ab051f. Apply with git apply once the way forward is chosen:
diff --git a/bootstrap/src/main.rs b/bootstrap/src/main.rs
index 1bf18d68d..0ba14acaf 100644
--- a/bootstrap/src/main.rs+++ b/bootstrap/src/main.rs@@ -117,6 +117,10 @@ mod silicon_queue;
#[path = "../gen/rust/verified/bench_agent.rs"]
#[allow(dead_code, unused_parens, unused_mut, unused_assignments, unused_variables, non_snake_case, non_upper_case_globals, clippy::all)]
mod bench_agent;
+// specs/verified/bitstream_reuse.t27 (#8095): when `t27c silicon` loads a bitstream it built before.+#[path = "../gen/rust/verified/bitstream_reuse.rs"]+#[allow(dead_code, unused_parens, unused_mut, unused_assignments, unused_variables, non_snake_case, non_upper_case_globals, clippy::all)]+mod bitstream_reuse;
mod phi_f64_literals;
mod weight_bram;
mod bitnet_pipeline;
diff --git a/bootstrap/src/service.rs b/bootstrap/src/service.rs
index bc5887859..beada1e3f 100644
--- a/bootstrap/src/service.rs+++ b/bootstrap/src/service.rs@@ -4246,6 +4246,25 @@ pub fn run_silicon(
let mut derived_chain: Option<u32> = None;
let mut seen_sites: Vec<u32> = Vec::new();
+ // #8095: load a bitstream built before from the same inputs by the same tools (specs/verified/bitstream_reuse.t27).+ use crate::bitstream_reuse as br;+ let bit_path = tmp.join(format!("{stem}.bit"));+ let tools = [chipdb.clone(), pnr.clone(), xr.join("utils/fasm2frames.py"), PathBuf::from(run(Command::new("which").arg("xc7frames2bit")).1.trim())];+ let xdc_in = tops.last().map(|t| Path::new(t).with_extension("xdc")).filter(|p| p.exists());+ let mut key_in = format!("{}|{}|{pnr_seed:?}|{}|{}", run(Command::new("yosys").arg("-V")).1.trim(), run(Command::new("git").arg("-C").arg(&db).args(["rev-parse", "HEAD"])).1.trim(), br::BIT_RECIPE, env!("CARGO_PKG_VERSION"));+ for f in sources.iter().map(PathBuf::from).chain(xdc_in).chain(tools) { key_in += &format!("|{}", crate::sha256_hex(&std::fs::read(&f).unwrap_or_default())); }+ let cache = PathBuf::from(std::env::var_os("HOME").unwrap_or_default()).join(".cache/t27/bitstreams").join(crate::sha256_hex(key_in.as_bytes()));+ let (cached_bit, cached_chain) = (std::fs::read(cache.join("design.bit")).ok(), std::fs::read_to_string(cache.join("chain")).ok());+ let intact = cached_bit.as_deref().map(crate::sha256_hex) == std::fs::read_to_string(cache.join("bit.sha256")).ok();+ let decision = br::bit_decision(std::env::var_os("T27_SILICON_REBUILD").is_some(), cached_bit.is_some(), cached_chain.is_some(), intact);+ 'build: {+ if decision == br::BIT_REUSE {+ std::fs::write(&bit_path, cached_bit.as_deref().unwrap_or_default())?;+ derived_chain = cached_chain.and_then(|c| c.trim().parse().ok());+ let note = format!("same inputs, same tools: {} (T27_SILICON_REBUILD=1 rebuilds)", cache.display());+ stages.push(Stage { name: "bitstream REUSED", secs: 0.0, code: Some(0), artefact: file_len(&bit_path), note });+ break 'build;+ }
for attempt in 0..6u32 {
let t = Instant::now();
let chparam = match chain_override {
@@ -4609,7 +4628,6 @@ pub fn run_silicon(
});
// ---- bitstream, ONLY from non-empty frames ----
- let bit_path = tmp.join(format!("{stem}.bit"));
let frames_ok = file_len(&frames_path).map(|(_, n)| n > 0).unwrap_or(false);
let t = Instant::now();
let c = if frames_ok {
@@ -4634,12 +4652,21 @@ pub fn run_silicon(
"SKIPPED: empty frames would still yield a 9.7 MB .bit (T169)".into()
},
});
+ }
let build_ok = print_table(&stages);
if !build_ok {
println!("FAIL -- the build did not complete. Nothing was loaded.");
std::process::exit(1);
}
+ if br::may_store(decision, build_ok, stages.iter().any(|s| s.name == "BSCAN chain == site" && s.ok())) {+ let bit = std::fs::read(&bit_path)?;+ std::fs::create_dir_all(&cache)?;+ std::fs::write(cache.join("design.bit"), &bit)?;+ std::fs::write(cache.join("chain"), derived_chain.map(|c| c.to_string()).unwrap_or_default())?;+ std::fs::write(cache.join("bit.sha256"), crate::sha256_hex(&bit))?; // last: a torn entry reads CORRUPT+ println!(" bitstream stored for reuse: {}", cache.display());+ }
if skip_hardware {
println!("PASS (build only) -- rerun without --skip-hardware to load and read.");
Activity
gHashTag commentedon Oct 9, 2026
The 32-line glue, built and compiled locally against master 1ab051f. Apply with
git applyonce the way forward is chosen:t27c silicon reuses its bitstream; math_compare's Pell code moves to …
Pay for the bitstream-reuse glue by deleting a ported script, not mat…
Merge origin/master into claude/bitstream-reuse-wire (Closes #8295)
bitstream reuse: the venv in the key, and every 10th hit is audited (C…
t27c silicon reuses its bitstream; a ported script pays for the glue (C…
t27b: the node scans of lower.rs move to specs/tri/t27b/ast_scan.t27 (C…