@vessel-dsp/compiler 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +118 -2
  2. package/dist/bake.d.ts +38 -0
  3. package/dist/bake.d.ts.map +1 -0
  4. package/dist/bake.js +101 -0
  5. package/dist/bake.js.map +1 -0
  6. package/dist/bbd-clock.d.ts +171 -0
  7. package/dist/bbd-clock.d.ts.map +1 -0
  8. package/dist/bbd-clock.js +1750 -0
  9. package/dist/bbd-clock.js.map +1 -0
  10. package/dist/block-row.d.ts +51 -0
  11. package/dist/block-row.d.ts.map +1 -0
  12. package/dist/block-row.js +17 -0
  13. package/dist/block-row.js.map +1 -0
  14. package/dist/bypass.d.ts +3 -0
  15. package/dist/bypass.d.ts.map +1 -0
  16. package/dist/bypass.js +228 -0
  17. package/dist/bypass.js.map +1 -0
  18. package/dist/compile.d.ts +24 -0
  19. package/dist/compile.d.ts.map +1 -0
  20. package/dist/compile.js +348 -0
  21. package/dist/compile.js.map +1 -0
  22. package/dist/converter-scale.d.ts +14 -0
  23. package/dist/converter-scale.d.ts.map +1 -0
  24. package/dist/converter-scale.js +133 -0
  25. package/dist/converter-scale.js.map +1 -0
  26. package/dist/couple.d.ts +28 -0
  27. package/dist/couple.d.ts.map +1 -0
  28. package/dist/couple.js +567 -0
  29. package/dist/couple.js.map +1 -0
  30. package/dist/dangling-active-terminal.d.ts +47 -0
  31. package/dist/dangling-active-terminal.d.ts.map +1 -0
  32. package/dist/dangling-active-terminal.js +542 -0
  33. package/dist/dangling-active-terminal.js.map +1 -0
  34. package/dist/declared-program.d.ts +23 -0
  35. package/dist/declared-program.d.ts.map +1 -0
  36. package/dist/declared-program.js +387 -0
  37. package/dist/declared-program.js.map +1 -0
  38. package/dist/denomination.d.ts +48 -0
  39. package/dist/denomination.d.ts.map +1 -0
  40. package/dist/denomination.js +27 -0
  41. package/dist/denomination.js.map +1 -0
  42. package/dist/device-laws.d.ts +237 -0
  43. package/dist/device-laws.d.ts.map +1 -0
  44. package/dist/device-laws.js +3513 -0
  45. package/dist/device-laws.js.map +1 -0
  46. package/dist/diagnostics.d.ts +13 -0
  47. package/dist/diagnostics.d.ts.map +1 -0
  48. package/dist/diagnostics.js +19 -0
  49. package/dist/diagnostics.js.map +1 -0
  50. package/dist/emit.d.ts +8 -0
  51. package/dist/emit.d.ts.map +1 -0
  52. package/dist/emit.js +43 -0
  53. package/dist/emit.js.map +1 -0
  54. package/dist/errors.d.ts +22 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/errors.js +39 -0
  57. package/dist/errors.js.map +1 -0
  58. package/dist/firmware-class.d.ts +69 -0
  59. package/dist/firmware-class.d.ts.map +1 -0
  60. package/dist/firmware-class.js +20 -0
  61. package/dist/firmware-class.js.map +1 -0
  62. package/dist/fixtures/circuits.d.ts +1742 -0
  63. package/dist/fixtures/circuits.d.ts.map +1 -0
  64. package/dist/fixtures/circuits.js +13896 -0
  65. package/dist/fixtures/circuits.js.map +1 -0
  66. package/dist/fixtures/expected.d.ts +261 -0
  67. package/dist/fixtures/expected.d.ts.map +1 -0
  68. package/dist/fixtures/expected.js +315 -0
  69. package/dist/fixtures/expected.js.map +1 -0
  70. package/dist/fixtures/index.d.ts +4 -0
  71. package/dist/fixtures/index.d.ts.map +1 -0
  72. package/dist/fixtures/index.js +8 -0
  73. package/dist/fixtures/index.js.map +1 -0
  74. package/dist/fixtures/registry.d.ts +52 -0
  75. package/dist/fixtures/registry.d.ts.map +1 -0
  76. package/dist/fixtures/registry.js +341 -0
  77. package/dist/fixtures/registry.js.map +1 -0
  78. package/dist/generic-tube-fit.d.ts +12 -0
  79. package/dist/generic-tube-fit.d.ts.map +1 -0
  80. package/dist/generic-tube-fit.js +45 -0
  81. package/dist/generic-tube-fit.js.map +1 -0
  82. package/dist/grounded-clock-supply.d.ts +13 -0
  83. package/dist/grounded-clock-supply.d.ts.map +1 -0
  84. package/dist/grounded-clock-supply.js +45 -0
  85. package/dist/grounded-clock-supply.js.map +1 -0
  86. package/dist/identify.d.ts +50 -0
  87. package/dist/identify.d.ts.map +1 -0
  88. package/dist/identify.js +319 -0
  89. package/dist/identify.js.map +1 -0
  90. package/dist/index.d.ts +10 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +19 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/inert-controls.d.ts +15 -0
  95. package/dist/inert-controls.d.ts.map +1 -0
  96. package/dist/inert-controls.js +266 -0
  97. package/dist/inert-controls.js.map +1 -0
  98. package/dist/latch-seed.d.ts +53 -0
  99. package/dist/latch-seed.d.ts.map +1 -0
  100. package/dist/latch-seed.js +257 -0
  101. package/dist/latch-seed.js.map +1 -0
  102. package/dist/link.d.ts +7 -0
  103. package/dist/link.d.ts.map +1 -0
  104. package/dist/link.js +270 -0
  105. package/dist/link.js.map +1 -0
  106. package/dist/lower.d.ts +79 -0
  107. package/dist/lower.d.ts.map +1 -0
  108. package/dist/lower.js +1855 -0
  109. package/dist/lower.js.map +1 -0
  110. package/dist/netlist.d.ts +79 -0
  111. package/dist/netlist.d.ts.map +1 -0
  112. package/dist/netlist.js +4746 -0
  113. package/dist/netlist.js.map +1 -0
  114. package/dist/non-executable-clock-drivers.d.ts +8 -0
  115. package/dist/non-executable-clock-drivers.d.ts.map +1 -0
  116. package/dist/non-executable-clock-drivers.js +33 -0
  117. package/dist/non-executable-clock-drivers.js.map +1 -0
  118. package/dist/open-category.d.ts +98 -0
  119. package/dist/open-category.d.ts.map +1 -0
  120. package/dist/open-category.js +111 -0
  121. package/dist/open-category.js.map +1 -0
  122. package/dist/over-driven-node.d.ts +33 -0
  123. package/dist/over-driven-node.d.ts.map +1 -0
  124. package/dist/over-driven-node.js +188 -0
  125. package/dist/over-driven-node.js.map +1 -0
  126. package/dist/part-catalog.d.ts +15 -0
  127. package/dist/part-catalog.d.ts.map +1 -0
  128. package/dist/part-catalog.js +6712 -0
  129. package/dist/part-catalog.js.map +1 -0
  130. package/dist/part-number.d.ts +32 -0
  131. package/dist/part-number.d.ts.map +1 -0
  132. package/dist/part-number.js +80 -0
  133. package/dist/part-number.js.map +1 -0
  134. package/dist/partition.d.ts +7 -0
  135. package/dist/partition.d.ts.map +1 -0
  136. package/dist/partition.js +242 -0
  137. package/dist/partition.js.map +1 -0
  138. package/dist/port-full-scale.d.ts +70 -0
  139. package/dist/port-full-scale.d.ts.map +1 -0
  140. package/dist/port-full-scale.js +235 -0
  141. package/dist/port-full-scale.js.map +1 -0
  142. package/dist/pot-orientation.d.ts +114 -0
  143. package/dist/pot-orientation.d.ts.map +1 -0
  144. package/dist/pot-orientation.js +551 -0
  145. package/dist/pot-orientation.js.map +1 -0
  146. package/dist/power-domain-control.d.ts +40 -0
  147. package/dist/power-domain-control.d.ts.map +1 -0
  148. package/dist/power-domain-control.js +142 -0
  149. package/dist/power-domain-control.js.map +1 -0
  150. package/dist/proxy-declaration.d.ts +121 -0
  151. package/dist/proxy-declaration.d.ts.map +1 -0
  152. package/dist/proxy-declaration.js +50 -0
  153. package/dist/proxy-declaration.js.map +1 -0
  154. package/dist/registry.d.ts +323 -0
  155. package/dist/registry.d.ts.map +1 -0
  156. package/dist/registry.js +192 -0
  157. package/dist/registry.js.map +1 -0
  158. package/dist/sparse-schedule.d.ts +65 -0
  159. package/dist/sparse-schedule.d.ts.map +1 -0
  160. package/dist/sparse-schedule.js +421 -0
  161. package/dist/sparse-schedule.js.map +1 -0
  162. package/dist/speaker-load.d.ts +38 -0
  163. package/dist/speaker-load.d.ts.map +1 -0
  164. package/dist/speaker-load.js +97 -0
  165. package/dist/speaker-load.js.map +1 -0
  166. package/dist/stage-coverage.d.ts +21 -0
  167. package/dist/stage-coverage.d.ts.map +1 -0
  168. package/dist/stage-coverage.js +124 -0
  169. package/dist/stage-coverage.js.map +1 -0
  170. package/dist/stamp-partition.d.ts +314 -0
  171. package/dist/stamp-partition.d.ts.map +1 -0
  172. package/dist/stamp-partition.js +472 -0
  173. package/dist/stamp-partition.js.map +1 -0
  174. package/dist/supply-reference.d.ts +19 -0
  175. package/dist/supply-reference.d.ts.map +1 -0
  176. package/dist/supply-reference.js +66 -0
  177. package/dist/supply-reference.js.map +1 -0
  178. package/dist/supply-short.d.ts +32 -0
  179. package/dist/supply-short.d.ts.map +1 -0
  180. package/dist/supply-short.js +118 -0
  181. package/dist/supply-short.js.map +1 -0
  182. package/dist/supply-stamps.d.ts +51 -0
  183. package/dist/supply-stamps.d.ts.map +1 -0
  184. package/dist/supply-stamps.js +363 -0
  185. package/dist/supply-stamps.js.map +1 -0
  186. package/dist/terminal-role.d.ts +109 -0
  187. package/dist/terminal-role.d.ts.map +1 -0
  188. package/dist/terminal-role.js +46 -0
  189. package/dist/terminal-role.js.map +1 -0
  190. package/dist/terminal-roles.d.ts +59 -0
  191. package/dist/terminal-roles.d.ts.map +1 -0
  192. package/dist/terminal-roles.js +92 -0
  193. package/dist/terminal-roles.js.map +1 -0
  194. package/dist/transformer.d.ts +181 -0
  195. package/dist/transformer.d.ts.map +1 -0
  196. package/dist/transformer.js +476 -0
  197. package/dist/transformer.js.map +1 -0
  198. package/dist/types.d.ts +3157 -0
  199. package/dist/types.d.ts.map +1 -0
  200. package/dist/types.js +11 -0
  201. package/dist/types.js.map +1 -0
  202. package/dist/unbounded-operating-point.d.ts +35 -0
  203. package/dist/unbounded-operating-point.d.ts.map +1 -0
  204. package/dist/unbounded-operating-point.js +181 -0
  205. package/dist/unbounded-operating-point.js.map +1 -0
  206. package/dist/unexecuted-region.d.ts +3 -0
  207. package/dist/unexecuted-region.d.ts.map +1 -0
  208. package/dist/unexecuted-region.js +122 -0
  209. package/dist/unexecuted-region.js.map +1 -0
  210. package/dist/unimplemented-control-role.d.ts +3 -0
  211. package/dist/unimplemented-control-role.d.ts.map +1 -0
  212. package/dist/unimplemented-control-role.js +61 -0
  213. package/dist/unimplemented-control-role.js.map +1 -0
  214. package/dist/unreachable-output.d.ts +3 -0
  215. package/dist/unreachable-output.d.ts.map +1 -0
  216. package/dist/unreachable-output.js +97 -0
  217. package/dist/unreachable-output.js.map +1 -0
  218. package/dist/unreadable-terminal-role.d.ts +67 -0
  219. package/dist/unreadable-terminal-role.d.ts.map +1 -0
  220. package/dist/unreadable-terminal-role.js +409 -0
  221. package/dist/unreadable-terminal-role.js.map +1 -0
  222. package/dist/unverified-pinout.d.ts +27 -0
  223. package/dist/unverified-pinout.d.ts.map +1 -0
  224. package/dist/unverified-pinout.js +121 -0
  225. package/dist/unverified-pinout.js.map +1 -0
  226. package/package.json +75 -5
package/dist/link.js ADDED
@@ -0,0 +1,270 @@
1
+ // Stage 6: order the blocks and assemble the program.
2
+ //
3
+ // Execution order comes from the partition dependency graph: a macro model whose
4
+ // parameters are set by an analog region must run after it. Topological, and a cycle
5
+ // is an error rather than an arbitrary tie-break.
6
+ //
7
+ // **`order` is what executes, and it is not every block.** A block that cannot reach the
8
+ // output is left out of it, which is the build order's "do not execute an operator that
9
+ // cannot reach the output" -- see `executionOrder`. The blocks themselves all stay in the
10
+ // program.
11
+ //
12
+ // The program carries its controls -- including each one's taper -- because taper is
13
+ // emitted rather than evaluated at compile time. It deliberately carries **no sample
14
+ // rate**: a program is valid at any rate and is given one at initialization.
15
+ import { StageRefusal } from "./errors.js";
16
+ import { portFullScaleVolts } from "./port-full-scale.js";
17
+ import { stageCoverage } from "./stage-coverage.js";
18
+ import { supplyReference } from "./supply-reference.js";
19
+ export class LinkError extends StageRefusal {
20
+ constructor(message) {
21
+ super("link", null, message);
22
+ }
23
+ }
24
+ export function link(blocks, partitioning, controls, ports,
25
+ // Defaulted, because "the source declares no port impedance" is the state of almost every
26
+ // document -- zero corpus input jacks declare one -- so a caller with nothing to say says nothing.
27
+ portImpedanceOhms = {
28
+ input: null,
29
+ output: null,
30
+ },
31
+ // Likewise defaulted, and likewise a stage-1 read: `V0dBFS` is a declaration on the port's own
32
+ // jack, which only stage 1 can see.
33
+ portDeclaredFullScaleVolts = {
34
+ input: null,
35
+ output: null,
36
+ }, bypass = { declared: "none" }) {
37
+ const order = executionOrder(blocks, partitioning);
38
+ const live = new Set(order);
39
+ const executed = blocks.filter((block) => live.has(block.id));
40
+ return {
41
+ formatVersion: 6,
42
+ // Read off `order`'s blocks, not `blocks` -- see `requiredOperators`'s own comment for
43
+ // why a pruned block's operator is not "required to execute a program" at all. The
44
+ // same exclusion applies to `requiredModels` and to `costPredictors`, for the same
45
+ // reason: a block that never runs cannot be a cost this program's execution needs to be
46
+ // admitted against, and cannot be an algorithm a runtime needs to gain to execute it.
47
+ requiredOperators: requiredOperators(executed),
48
+ requiredModels: requiredModels(executed),
49
+ costPredictors: costPredictors(executed, order.length),
50
+ blocks,
51
+ order,
52
+ controls,
53
+ ports,
54
+ // From `blocks`, not `executed`, and the difference is deliberate: the three fields
55
+ // above describe what executing this program costs and needs, so a pruned block cannot
56
+ // contribute to them. Which terminal the circuit calls ground is a property of the
57
+ // circuit as declared -- a positive-ground fuzz whose supply island happens not to
58
+ // reach the output port is still a positive-ground fuzz, and a chain sharing one
59
+ // physical supply has to know that.
60
+ supplyReference: supplyReference(blocks),
61
+ // From `blocks` and `ports` together: the bound is a property of the rails feeding the
62
+ // circuit and of which node the port landed on, both of which are already decided by
63
+ // the time this runs.
64
+ portFullScaleVolts: portFullScaleVolts(blocks, ports),
65
+ // **The port's declared 0 dBFS reference, kept apart from the derived ceiling above.**
66
+ //
67
+ // They are different quantities and folding them together is a level error, measured
68
+ // rather than argued: a pedal's derived output is its 9 V supply -- the largest voltage
69
+ // that node can reach -- while a declared input `V0dBFS` is 0.1 to 1 V, the voltage that
70
+ // *means* full scale. Substituting one for the other made 4,994 of the 13,806 ordered
71
+ // pedal-to-pedal seams scale by a median of 9x (+19 dB) and up to 240x (+47.6 dB), by
72
+ // dividing a ceiling by a reference.
73
+ //
74
+ // So a consumer picks the one its question needs. A render converting into a +/-1 file
75
+ // wants the reference where a source states one and the ceiling otherwise -- either is a
76
+ // valid conversion. `chainScaleFactor` compares two ports and needs like with like, so it
77
+ // still reads `portFullScaleVolts`; moving it to reference-to-reference would start
78
+ // scaling 850 seams at a median of +9.5 dB and belongs in its own change with its own
79
+ // listening pass.
80
+ portReferenceVolts: portDeclaredFullScaleVolts,
81
+ stageCoverage: stageCoverage(blocks, ports),
82
+ // A port property, decided in stage 1 where the jack's own declaration is readable.
83
+ portImpedanceOhms,
84
+ bypass,
85
+ };
86
+ }
87
+ /**
88
+ * The rate-independent cost facts the executed blocks can honestly declare — see
89
+ * `CostPredictors`'s own doc for what this deliberately omits and why.
90
+ */
91
+ function costPredictors(executed, executedBlockCount) {
92
+ let stateCount = 0;
93
+ const solvedBlocks = [];
94
+ const macroBlocks = [];
95
+ for (const block of executed) {
96
+ if (block.kind === "macro" || block.kind === "composed") {
97
+ // Declared, not priced -- see `CostPredictors.macroBlocks`. Its absence is what let
98
+ // a macro's per-sample work cost zero at the admission gate. A composed block
99
+ // prices at its `modelId` exactly like the macro it replaces (board-p3 row 4,
100
+ // first slice): equal budget while the bit-identical gate holds; op-level
101
+ // costing follows with the catalog migration.
102
+ macroBlocks.push({ blockId: block.id, modelId: block.modelId });
103
+ continue;
104
+ }
105
+ stateCount += block.stateCount;
106
+ solvedBlocks.push({
107
+ blockId: block.id,
108
+ unknownCount: block.nodeCount + block.auxCount,
109
+ linear: block.linear,
110
+ });
111
+ }
112
+ return { executedBlockCount, stateCount, solvedBlocks, macroBlocks };
113
+ }
114
+ /**
115
+ * The blocks to execute, in dependency order: those that can reach the output.
116
+ *
117
+ * **Why any block cannot.** Stage 4 groups devices into regions by shared non-ground node,
118
+ * so two analog regions share nothing but ground — they are separate subcircuits, not
119
+ * halves of one system. The runtime solves each independently and takes its output sample
120
+ * from the block owning the output jack. A region owning neither the output nor an edge into
121
+ * something that does therefore has its entire solution discarded, every sample. Measured
122
+ * across the corpus: 141 of 191 regions own neither port, and 84% of the nodes solved per
123
+ * sample are thrown away. `boss-ds-1` is the extreme, and is exactly why it is both the
124
+ * slowest packet and a silent one.
125
+ *
126
+ * **Why the dependency graph is needed rather than the port fields alone.** A macro model's
127
+ * parameters can be set by an analog region it shares a node with — a BBD's delay time comes
128
+ * from its clock network — so a region with no port of its own can still be load-bearing.
129
+ * Reachability computed from `inputNode`/`outputNode` alone would delete the input shell and
130
+ * the clock network of the `hybridDelayPedal` fixture, which is a silent wrong answer rather
131
+ * than a slow one. Hence the traversal: if a live block depends on a producer, the producer
132
+ * is live too.
133
+ *
134
+ * **Why a macro block is seeded live unconditionally**, which is the conservative half of
135
+ * this rule and the reason it is safe to land before the operator format is finished. The
136
+ * `macro` variant carries no `inputNode` or `outputNode` at all, so the compiler cannot show
137
+ * that a macro fails to reach the output — the ports that would answer do not exist. The two
138
+ * errors are not symmetric: keeping a dead block costs solve time that shows up in a
139
+ * measurement, while dropping a live one is audio that is quietly missing a stage. So an
140
+ * unprovable case stays.
141
+ *
142
+ * **Why `order` and not `blocks`.** Pruning the block list would delete the structural
143
+ * record `report-compiler-fidelity.ts` reads — the compiler's own correctness gate while
144
+ * stamps exist — turning a scheduling change into a fidelity regression, and would also
145
+ * discard the circuit a later step still has to eliminate or factor. Leaving the blocks and
146
+ * shortening the execution list is the whole of the change the runtime needs: it already
147
+ * iterates `order`.
148
+ *
149
+ * The cycle refusal is deliberately computed over *every* block, before this filter: a
150
+ * cyclic dependency is a compiler defect whether or not the blocks in it are audible.
151
+ */
152
+ function executionOrder(blocks, partitioning) {
153
+ const live = blocksReachingOutput(blocks, partitioning);
154
+ return topologicalOrder(blocks, partitioning).filter((id) => live.has(id));
155
+ }
156
+ function blocksReachingOutput(blocks, partitioning) {
157
+ const live = new Set();
158
+ const pending = [];
159
+ for (const block of blocks) {
160
+ // A composed block stays live like a macro: its readers are stamps, so its
161
+ // reachability is as unprovable as a macro's, and the error asymmetry is
162
+ // the same -- a kept dead block costs time, a dropped live one loses audio.
163
+ if (block.kind === "macro" ||
164
+ block.kind === "composed" ||
165
+ block.outputNode !== null) {
166
+ live.add(block.id);
167
+ pending.push(block.id);
168
+ }
169
+ }
170
+ while (pending.length > 0) {
171
+ const id = pending.pop();
172
+ for (const producer of partitioning.dependencies[id] ?? []) {
173
+ if (!live.has(producer)) {
174
+ live.add(producer);
175
+ pending.push(producer);
176
+ }
177
+ }
178
+ }
179
+ return live;
180
+ }
181
+ /**
182
+ * The operators the *executed* blocks actually use, sorted and deduplicated.
183
+ *
184
+ * Read off the stamps rather than assumed from the device kinds, because the two are not
185
+ * the same list: a pot lowers to two `controlled-conductance` stamps, a jack's engage
186
+ * contact to a `conductance`, and a device whose law is `open` stamps nothing at all. What
187
+ * a runtime must implement is what is in the program, not what was in the document.
188
+ *
189
+ * **Callers pass only the live blocks (`order`'s), not every retained one.** `Program`'s own
190
+ * doc comment calls this "every operator this program needs a runtime to implement... to
191
+ * execute a program," and a block `executionOrder` prunes never executes under any runtime --
192
+ * so its operators cannot be needed to execute the program regardless of what a consumer
193
+ * implements. Declaring them anyway is not safe conservatism either: the console/ROM
194
+ * principle's refusal exists to prevent *silence*, and a pruned block is silent (never runs)
195
+ * under every runtime already, so requiring its operator cannot prevent silence and can only
196
+ * cause a constrained second runtime (e.g. ESP32, implementing a subset) to refuse a pedal it
197
+ * could actually play. Measured on the corpus before this changed: 4 of 52 compiling packets
198
+ * (`boss-ds-1`, `analog-man-prince-of-tone` -- both zero live blocks -- plus `boss-od-3` and
199
+ * `boss-sd-1`, each carrying a `selector` only in a region that never reaches the output) had
200
+ * exactly this gap. A consumer that wants every retained block's operators regardless of
201
+ * liveness (a fidelity/structural tool, say) can compute it itself from `Program.blocks`,
202
+ * which still carries every block -- only this declared, "must implement" set narrows.
203
+ *
204
+ * Sorted so the declaration is a function of the set and not of stamp order — otherwise two
205
+ * identical circuits drawn in a different order would emit different bytes and different
206
+ * digests.
207
+ */
208
+ function requiredOperators(blocks) {
209
+ const kinds = new Set();
210
+ for (const block of blocks) {
211
+ if (block.kind !== "mna") {
212
+ continue;
213
+ }
214
+ for (const stamp of block.stamps) {
215
+ kinds.add(stamp.kind);
216
+ }
217
+ }
218
+ return [...kinds].sort();
219
+ }
220
+ /**
221
+ * The DSP algorithms the executed macro blocks name — `requiredOperators`'s counterpart for
222
+ * the half of the instruction set that is not a stamp. See `Program.requiredModels` for why
223
+ * this is a second set rather than more entries in the first.
224
+ *
225
+ * Live blocks only and sorted, for the two reasons `requiredOperators` records: a pruned
226
+ * block cannot be an algorithm a runtime needs to gain, and an unsorted declaration would
227
+ * make the emitted bytes a function of block order rather than of the set.
228
+ *
229
+ * **No validation here, deliberately.** This compiler cannot know which algorithms the
230
+ * runtime that will execute the program implements, and inventing an allowlist here would
231
+ * either duplicate one runtime's list into a portable artifact or refuse a program a second,
232
+ * richer runtime could play. Declaring truthfully is the whole contribution; refusing is the
233
+ * runtime's job, by name, at load.
234
+ */
235
+ function requiredModels(blocks) {
236
+ const models = new Set();
237
+ for (const block of blocks) {
238
+ if (block.kind !== "macro" && block.kind !== "composed") {
239
+ continue;
240
+ }
241
+ // A composition whose ops came from the source needs no algorithm from the runtime:
242
+ // it brought its own. Declaring its chip's part number here would make every
243
+ // reprogrammable pedal refuse at load on a name no runtime could ever register,
244
+ // which is the opposite of what this set is for.
245
+ if (block.kind === "composed" && block.modelSource === "declared") {
246
+ continue;
247
+ }
248
+ models.add(block.modelId);
249
+ }
250
+ return [...models].sort();
251
+ }
252
+ function topologicalOrder(blocks, partitioning) {
253
+ const ids = blocks.map((block) => block.id);
254
+ const remaining = new Set(ids);
255
+ const ordered = [];
256
+ while (remaining.size > 0) {
257
+ const ready = [...remaining].filter((id) => (partitioning.dependencies[id] ?? []).every((dependency) => !remaining.has(dependency)));
258
+ if (ready.length === 0) {
259
+ throw new LinkError(`cyclic region dependencies among ${[...remaining].join(", ")}`);
260
+ }
261
+ // Stable: preserve the order blocks were produced in.
262
+ ready.sort((a, b) => ids.indexOf(a) - ids.indexOf(b));
263
+ for (const id of ready) {
264
+ ordered.push(id);
265
+ remaining.delete(id);
266
+ }
267
+ }
268
+ return ordered;
269
+ }
270
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import { type BistableLatch } from "./latch-seed";
2
+ export { stampNeedsNewton } from "./stamp-partition";
3
+ import type { Block, Device, LawedNetlist, NodeId, OperatingPointSeed, Partitioning, Region, Stamp } from "./types";
4
+ export { opampInvertingInputNodes, opampInputDistances, opampOutputAcDistances, opampOutputDistances, potTerminals, quietDistances, } from "./pot-orientation";
5
+ export { LoweringError } from "./errors";
6
+ export { stampControl } from "./stamp-partition";
7
+ export declare function lowerRegion(region: Region, lawed: LawedNetlist, inputNode: number, outputNode: number,
8
+ /**
9
+ * Computed once by `lower` rather than per region: the rule is a pairwise scan over
10
+ * transistors, and `boss-ds-1` lowers 82 regions from one netlist.
11
+ */
12
+ latchSeeds?: readonly OperatingPointSeed[], latches?: readonly BistableLatch[],
13
+ /**
14
+ * Computed once by `lower`, for the same reason `latchSeeds` is: the graph a pot's
15
+ * orientation reads (`quietDistances`) does not change between `boss-ds-1`'s 82 regions
16
+ * either. Empty by default so a direct call site not passing one gets today's
17
+ * declaration-order behaviour for every pot -- never a wrong answer, only an unresolved one.
18
+ */
19
+ quietDistance?: ReadonlyMap<NodeId, number>,
20
+ /**
21
+ * The narrower, scoped fallback `potTerminals` only consults when `quietDistance` leaves a
22
+ * pot fully unreachable -- see `opampInputDistances`. Empty by default for the same reason
23
+ * `quietDistance` is: an unresolved pot, never a wrong one.
24
+ */
25
+ opampInputDistance?: ReadonlyMap<NodeId, number>,
26
+ /**
27
+ * Companion of `opampInputDistance` for the negative-feedback gain-stage tie in
28
+ * `potTerminals`: a pot that the input-distance evidence cannot break reads which end
29
+ * sits on an op-amp's declared output instead. Empty by default for the same reason.
30
+ */
31
+ opampOutputDistance?: ReadonlyMap<NodeId, number>,
32
+ /**
33
+ * Nodes that are a declared op-amp inverting input, and the AC (DC + capacitors) distance to
34
+ * an op-amp's declared output: the two signals `potTerminals` reads for the one finite-tie
35
+ * shape the DC maps cannot break -- a non-inverting gain pot whose wiper sits on the
36
+ * inverting input. Empty by default for the same reason as the other maps.
37
+ */
38
+ invertingInputNodes?: ReadonlySet<NodeId>, acOutputDistance?: ReadonlyMap<NodeId, number>): Block;
39
+ /**
40
+ * A block's row index for a source `NodeId`, or `null` when the node is not one of this
41
+ * block's own.
42
+ *
43
+ * The forward direction of `Block.nodeIds`. `null` rather than a throw because the two
44
+ * callers that need it are asking a question whose honest answer can be "not this block":
45
+ * `couple.ts` locating a macro's port node, and a report matching a declared source net
46
+ * against whichever region owns it.
47
+ */
48
+ export declare function blockNodeIndex(block: Extract<Block, {
49
+ readonly kind: "mna";
50
+ }>, node: NodeId): number | null;
51
+ /**
52
+ * A stamp read back in the document's node ids rather than its block's rows.
53
+ *
54
+ * The inverse of what `lowerRegion` did on the way out, for consumers that have to state a
55
+ * stamp's topology in the terms the source authored -- a report naming the net a device
56
+ * sits on, or an assertion written against a fixture's declared node numbers.
57
+ */
58
+ export declare function stampInSourceNodes(block: Extract<Block, {
59
+ readonly kind: "mna";
60
+ }>, stamp: Stamp): Stamp;
61
+ export declare function lower(partitioning: Partitioning, lawed: LawedNetlist): readonly Block[];
62
+ /**
63
+ * Slots a reactive element's companion model needs: the voltage across it and the current
64
+ * through it, which is what a trapezoidal companion carries between samples.
65
+ *
66
+ * The program declares state in slots and each stamp declares the offset its own state
67
+ * begins at, so both are the same unit and no executor has to know a hidden convention.
68
+ */
69
+ export declare const STATE_SLOTS_PER_REACTIVE_ELEMENT = 2;
70
+ /**
71
+ * Which rung decided an optocoupler's wiring, so a warning can name the devices that reached the
72
+ * weaker ones without restating either test.
73
+ *
74
+ * The alternative -- a predicate in the warning module that mirrors this vocabulary -- is how a
75
+ * silent switch mis-wiring was introduced in this compiler once already: the mirror drifted from
76
+ * the resolver and the warning went quiet about the case it existed for.
77
+ */
78
+ export declare function optocouplerBinding(device: Device): "declared" | "named" | "declaration-order";
79
+ //# sourceMappingURL=lower.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lower.d.ts","sourceRoot":"","sources":["../src/lower.ts"],"names":[],"mappings":"AAqBA,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EACX,KAAK,EACL,MAAM,EACN,YAAY,EACZ,MAAM,EACN,kBAAkB,EAClB,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,SAAS,CAAC;AAkBjB,OAAO,EACN,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,wBAAgB,WAAW,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM;AAClB;;;GAGG;AACH,UAAU,GAAE,SAAS,kBAAkB,EAAO,EAC9C,OAAO,GAAE,SAAS,aAAa,EAAO;AACtC;;;;;GAKG;AACH,aAAa,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa;AACtD;;;;GAIG;AACH,kBAAkB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa;AAC3D;;;;GAIG;AACH,mBAAmB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa;AAC5D;;;;;GAKG;AACH,mBAAmB,GAAE,WAAW,CAAC,MAAM,CAAa,EACpD,gBAAgB,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GACvD,KAAK,CAmtCP;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,EAC/C,IAAI,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAGf;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,EAC/C,KAAK,EAAE,KAAK,GACV,KAAK,CAEP;AAGD,wBAAgB,KAAK,CACpB,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,YAAY,GACjB,SAAS,KAAK,EAAE,CAwBlB;AA2TD;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAqYlD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,GACZ,UAAU,GAAG,OAAO,GAAG,mBAAmB,CAK5C"}