Simulation shows everything and runs slowly; an emulator or a prototype shows little and runs fast, after a build that takes hours. Moving too early wastes the build and loses the visibility that diagnoses wiring bugs in minutes; moving too late means the long tests never run at all. Its one job is the decision: how to compute where a faster platform wins and which NanoSoC tests belong on it.
Total time on a platform is build time plus workload divided by speed. A faster platform has a longer build and a higher speed, so it loses on short workloads and wins on long ones, and the crossover is a number of cycles you can compute. All speeds and build times below are illustrative teaching values, not figures for any product, and the cycle counts are NanoSoC clk_sys-equivalent cycles.
Platform | Speed (illustrative) | Build or compile (illustrative) | What you see |
|---|---|---|---|
RTL simulation | 5,000 cycles/s | 10 min | Every signal, every cycle |
Emulator | 1,000,000 cycles/s | 4 h | Most signals over a captured window; probes change without a rebuild |
FPGA prototype | 12,000,000 cycles/s (clk_sys scaled to 12 MHz) | 8 h | Only the probes chosen before the build, in an on-chip buffer |
Silicon | 96,000,000 cycles/s | A new chip | Pins, registers, whatever debug logic was designed in |
Two NanoSoC workloads show both sides. One full boot is 1,207,768 cycles: simulation takes about 4 minutes after its compile, so no faster platform can beat it once its build is counted. A soak of 1,000,000 DMA jobs at an illustrative 216 cycles per job (seven writes, five reads and the 72-cycle job, about 2.25 us each) is 216 million cycles: 12 hours in simulation, while the run itself takes 3.6 minutes on the emulator and 18 seconds on the prototype. The build is paid once and amortised over every later run, so even one soak finishes sooner in total on the emulator (about 4.1 h) than in simulation (about 12.2 h). The script computes the crossovers and checks that the boot sits below both and the soak above both.
# Break-even workload between simulation and a faster platform.
# Speeds and build times are ILLUSTRATIVE; cycle counts follow the boot flow.
SIM = {"speed": 5_000, "build_s": 600}
EMU = {"speed": 1_000_000, "build_s": 4 * 3600}
FPGA = {"speed": 12_000_000, "build_s": 8 * 3600}
def total_s(p, cycles):
return p["build_s"] + cycles / p["speed"]
def break_even(fast):
# build_s_fast + n/speed_fast == build_s_sim + n/speed_sim, solved for n
return (fast["build_s"] - SIM["build_s"]) / (1 / SIM["speed"] - 1 / fast["speed"])
BOOT = round(12580.917 * 96) # clk_sys-equivalent cycles in one full boot
SOAK = 1_000_000 * 216 # a million DMA jobs at 216 cycles each (illustrative)
be_emu, be_fpga = break_even(EMU), break_even(FPGA)
print(f"break-even: emulator {be_emu / 1e6:.1f} M cycles, prototype {be_fpga / 1e6:.1f} M cycles")
for name, work in (("boot", BOOT), ("soak", SOAK)):
row = [f"{p}: {total_s(v, work) / 3600:.2f} h" for p, v in (("sim", SIM), ("emu", EMU), ("fpga", FPGA))]
print(name, *row)
assert BOOT == 1207768
assert BOOT < be_emu < SOAK and BOOT < be_fpga < SOAK
assert total_s(SIM, BOOT) < total_s(EMU, BOOT) < total_s(FPGA, BOOT) # the boot stays in simulation
assert total_s(EMU, SOAK) < total_s(SIM, SOAK) # even with its build, the emulator wins the soak
assert SOAK / EMU["speed"] < 300 and SOAK / FPGA["speed"] < 30 # the runs themselves take minutes and seconds
# the check can fail: a build ten times longer pushes the emulator break-even beyond the soak
slow_build = dict(EMU, build_s=40 * 3600)
assert break_even(slow_build) > SOAK
print("PASS: boot stays in simulation, a 216 M-cycle soak moves, a 40 h build would not pay")Each test on the plan names its platform with the break-even arithmetic behind it, using speeds measured on this project once they exist.
Short, wiring-level tests stay in simulation: the sweeps, reset order, the first boot. Long and statistical tests move: soaks, long firmware, rare-event hunting, software bring-up.
The prototype is not the first place an integration bug is found: simulation passes the connectivity and boot tests before the platform build is started.
Measure before believing: run the same 100,000-cycle slice on each platform and compute the real cycles per second, because speed depends on design size, probes and I/O bridges. If a prototype run fails and simulation passes the same slice, suspect the platform changes of the next lesson first (replaced clocks, memories, missing power domains) before suspecting the design. Bring any failure back to simulation as soon as a window shows the first wrong cycle.
No, at these illustrative speeds: the boot takes about four minutes in simulation, while the emulator run takes about 1.2 s but only after a 4 h build, and its break-even is about 70 million cycles. It pays only if the build is amortised over far longer tests.