code wiki / _hdl_build / nx_gate_energy_test.nx

nx_gate_energy_test.nx

buildroot/runtime/_hdl_build/nx_gate_energy_test.nx

9767 B211 linesdepth 6pulls 6 transitivereach 0 importersview sourcekind gate/prooftopic gate
docsdependenciesstructsconstsfunctions

about

nx_gate_energy_test.nx -- the EFFICIENCY leg of the triangle, measured BITS-UP from the silicon we built, not borrowed from an OS. This is the PORTABLE layer: it runs identically on ANY hardware because it owes nothing to the host (no RAPL, no /sys, no privilege) -- the energy is a property of the GATE DESIGN. THE GOOD TRIANGLE (operator's framing): SPEED = critical-path gate DEPTH (signals ripple through the carry chain) SIZE/AREA = gate COUNT (how much silicon the design occupies) EFFICIENCY = switching ACTIVITY = gate-output TOGGLES per op. Dynamic energy in real silicon is ~ (toggles * C * V^2): every gate output that flips charges/discharges a capacitance and burns joules. Counting toggles is exactly how chip designers estimate dynamic power. CAPABILITY = 1:1 CORRECTNESS (the sum is right for every vector). CITATIONS (Cardinal #4 -- real sources): the dynamic-power law P = a*C*V^2*f and switching-activity-based estimation are textbook -- Weste & Harris, "CMOS VLSI Design" 4e; Najm, "A Survey of Power Estimation Techniques in VLSI Circuits," IEEE Trans. VLSI Systems, 1994. Ripple-carry critical-path ~2W gate delays is standard (Weste & Harris, adder chapter). The energy/time/memory tradeoff this triangle measures is empirically grounded in Pereira et al., "Energy Efficiency across Programming Languages," ACM SLE 2017 (the benchmarks-game-based study). We build a REAL ripple-carry adder out of PRIMITIVE 1-bit gates (XOR/AND/OR), simulate it on consecutive input vectors, and count how many gate outputs flip. Key physical truth this proves: ENERGY IS DATA-DEPENDENT. The same correct adder burns more on random inputs (carries propagate, ~half the bits flip) than on small increments (short carries, few flips). That is WHY a garden sensor must MEASURE its real workload's energy, not assume it -- the companion real-hardware probe (nx_energy_probe) reads the node's actual power sensor and calibrates THIS toggle count into joules for whatever silicon it landed on. Known answer: correctness holds for all vectors AND random-workload toggles > increment-workload toggles (data-dependent energy). exit 0.

dependencies 1 imports · 0 importers

nx_nxgate_sim.nx nx_gate_energy_test.nx

imports: nx_nxgate_sim.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main ge_build ge_set ge_cin ge_cout ge_base ge_axb ge_base ↻ ge_anet ge_bnet ge_aab ge_base ↻ ge_sum ge_base ↻ ge_axbc ge_base ↻ ge_cout ↻ _emit ge_depth ge_sum ↻ ge_cout ↻ ge_run_workload ge_rng ge_set_inputs ge_anet ↻ ge_bnet ↻ nx_gsim_run nx_gsim_kind_supported nx_gsim_eval_cell ge_read_sum ge_sum ↻ ge_toggles ge_snapshot

structs

none

consts

37const GE_W: i64 = 8 // adder width (small + clear; the structure scales)
38const GE_N: i64 = 256 // vectors per workload

functions

44func ge_anet(i: i64) -> i64 { return 1 + i }
45func ge_bnet(i: i64) -> i64 { return 1 + GE_W + i }
46func ge_base() -> i64 { return 1 + 2 * GE_W }
47func ge_axb(i: i64) -> i64 { return ge_base() + 5 * i + 0 }
called by 1: ge_build calls 1: ge_base
48func ge_sum(i: i64) -> i64 { return ge_base() + 5 * i + 1 }
called by 3: ge_buildge_read_sumge_depth calls 1: ge_base
49func ge_aab(i: i64) -> i64 { return ge_base() + 5 * i + 2 }
called by 1: ge_build calls 1: ge_base
50func ge_axbc(i: i64) -> i64 { return ge_base() + 5 * i + 3 }
called by 1: ge_build calls 1: ge_base
51func ge_cout(i: i64) -> i64 { return ge_base() + 5 * i + 4 }
called by 3: ge_cinge_buildge_depth calls 1: ge_base
52func ge_cin(i: i64) -> i64 { if i == 0 { return 0 } return ge_cout(i - 1) }
called by 1: ge_build calls 1: ge_cout
54func ge_set(cells: *NxGsimCell, idx: i64, kind: i64, fo: i64, f0: i64, f1: i64, f2: i64, val: i64) -> i64
called by 1: ge_build
67func ge_build(cells: *NxGsimCell) -> i64
83func ge_set_inputs(g: *NxGsim, a: i64, b: i64) -> i64
called by 1: ge_run_workload calls 2: ge_anetge_bnet
92func ge_read_sum(g: *NxGsim) -> i64
called by 1: ge_run_workload calls 1: ge_sum
101func ge_depth(g: *NxGsim, cells: *NxGsimCell, ncells: i64) -> i64
called by 1: main calls 2: ge_sumge_cout
124func ge_snapshot(g: *NxGsim, cells: *NxGsimCell, ncells: i64, snap: *i64) -> i64
called by 1: ge_run_workload
130func ge_toggles(g: *NxGsim, cells: *NxGsimCell, ncells: i64, prev: *i64) -> i64
called by 1: ge_run_workload
137func ge_rng(s: i64) -> i64 { return s * 6364136223846793005 + 1442695040888963407 }
called by 1: ge_run_workload
141func ge_run_workload(g: *NxGsim, cells: *NxGsimCell, ncells: i64, mode: i64, n: i64, mask: i64, prev: *i64) -> i64
162func _emit(name: *u8, v: i64) -> i64
called by 1: main
172func main() -> i64