@jhlagado/azm 0.2.6 → 0.2.8

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 (235) hide show
  1. package/README.md +170 -69
  2. package/dist/src/api-artifacts.d.ts +20 -0
  3. package/dist/src/api-artifacts.js +165 -0
  4. package/dist/src/api-compile.d.ts +8 -2
  5. package/dist/src/api-compile.js +31 -230
  6. package/dist/src/api-register-contracts.d.ts +9 -0
  7. package/dist/src/api-register-contracts.js +77 -0
  8. package/dist/src/api-tooling.d.ts +2 -2
  9. package/dist/src/api-tooling.js +1 -1
  10. package/dist/src/assembly/address-planning.d.ts +1 -2
  11. package/dist/src/assembly/address-planning.js +119 -218
  12. package/dist/src/assembly/address-symbols.d.ts +12 -0
  13. package/dist/src/assembly/address-symbols.js +118 -0
  14. package/dist/src/assembly/fixup-emission.js +30 -48
  15. package/dist/src/assembly/program-emission.js +163 -164
  16. package/dist/src/cli/artifact-files.d.ts +15 -0
  17. package/dist/src/cli/artifact-files.js +86 -0
  18. package/dist/src/cli/parse-args.d.ts +6 -5
  19. package/dist/src/cli/parse-args.js +162 -136
  20. package/dist/src/cli/run.js +4 -1
  21. package/dist/src/cli/usage.d.ts +1 -0
  22. package/dist/src/cli/usage.js +33 -0
  23. package/dist/src/cli/write-artifacts.js +18 -91
  24. package/dist/src/core/compile.js +51 -274
  25. package/dist/src/core/conditional-assembly.d.ts +6 -0
  26. package/dist/src/core/conditional-assembly.js +181 -0
  27. package/dist/src/expansion/op-constant-expression.d.ts +3 -0
  28. package/dist/src/expansion/op-constant-expression.js +52 -0
  29. package/dist/src/expansion/op-expand-selected.d.ts +5 -0
  30. package/dist/src/expansion/op-expand-selected.js +143 -0
  31. package/dist/src/expansion/op-expansion.d.ts +5 -53
  32. package/dist/src/expansion/op-expansion.js +85 -815
  33. package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
  34. package/dist/src/expansion/op-instruction-instantiation.js +194 -0
  35. package/dist/src/expansion/op-local-labels.d.ts +8 -0
  36. package/dist/src/expansion/op-local-labels.js +166 -0
  37. package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
  38. package/dist/src/expansion/op-operand-splitting.js +44 -0
  39. package/dist/src/expansion/op-operands.d.ts +53 -0
  40. package/dist/src/expansion/op-operands.js +66 -0
  41. package/dist/src/expansion/op-selection.d.ts +18 -0
  42. package/dist/src/expansion/op-selection.js +172 -0
  43. package/dist/src/index.d.ts +2 -1
  44. package/dist/src/index.js +1 -1
  45. package/dist/src/model/diagnostic.d.ts +4 -0
  46. package/dist/src/model/diagnostic.js +4 -0
  47. package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
  48. package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
  49. package/dist/src/outputs/asm80-expressions.d.ts +5 -0
  50. package/dist/src/outputs/asm80-expressions.js +47 -0
  51. package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
  52. package/dist/src/outputs/asm80-instruction-operands.js +38 -0
  53. package/dist/src/outputs/asm80-instructions.d.ts +5 -0
  54. package/dist/src/outputs/asm80-instructions.js +272 -0
  55. package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
  56. package/dist/src/outputs/asm80-ld-operands.js +157 -0
  57. package/dist/src/outputs/asm80-strings.d.ts +4 -0
  58. package/dist/src/outputs/asm80-strings.js +14 -0
  59. package/dist/src/outputs/d8-files.d.ts +10 -0
  60. package/dist/src/outputs/d8-files.js +103 -0
  61. package/dist/src/outputs/d8-helpers.d.ts +21 -0
  62. package/dist/src/outputs/d8-helpers.js +136 -0
  63. package/dist/src/outputs/hex.js +26 -18
  64. package/dist/src/outputs/types.d.ts +16 -10
  65. package/dist/src/outputs/write-asm80.js +68 -597
  66. package/dist/src/outputs/write-d8.js +6 -216
  67. package/dist/src/register-contracts/accept-output.d.ts +2 -0
  68. package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
  69. package/dist/src/register-contracts/analyze-helpers.js +162 -0
  70. package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
  71. package/dist/src/register-contracts/analyze.js +73 -0
  72. package/dist/src/register-contracts/annotate.d.ts +11 -0
  73. package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
  74. package/dist/src/register-contracts/annotations.d.ts +8 -0
  75. package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
  76. package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
  77. package/dist/src/register-contracts/boundaryHints.js +24 -0
  78. package/dist/src/register-contracts/carriers.d.ts +2 -0
  79. package/dist/src/register-contracts/constants.d.ts +4 -0
  80. package/dist/src/register-contracts/constants.js +51 -0
  81. package/dist/src/register-contracts/controlFlow.d.ts +5 -0
  82. package/dist/src/register-contracts/controlFlow.js +55 -0
  83. package/dist/src/register-contracts/fix.d.ts +11 -0
  84. package/dist/src/{register-care → register-contracts}/fix.js +47 -30
  85. package/dist/src/register-contracts/instruction-head.d.ts +2 -0
  86. package/dist/src/register-contracts/instruction-head.js +3 -0
  87. package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
  88. package/dist/src/register-contracts/instruction-operands.js +101 -0
  89. package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
  90. package/dist/src/register-contracts/instruction-predicates.js +44 -0
  91. package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
  92. package/dist/src/register-contracts/interfaceContracts.js +68 -0
  93. package/dist/src/register-contracts/liveness.d.ts +3 -0
  94. package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
  95. package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
  96. package/dist/src/register-contracts/operand-register-name.js +13 -0
  97. package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
  98. package/dist/src/{register-care → register-contracts}/profiles.js +13 -2
  99. package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
  100. package/dist/src/register-contracts/programModel-boundaries.js +64 -0
  101. package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
  102. package/dist/src/register-contracts/programModel-routines.js +128 -0
  103. package/dist/src/register-contracts/programModel.d.ts +3 -0
  104. package/dist/src/register-contracts/programModel.js +14 -0
  105. package/dist/src/register-contracts/report.d.ts +5 -0
  106. package/dist/src/{register-care → register-contracts}/report.js +34 -17
  107. package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
  108. package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
  109. package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
  110. package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
  111. package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
  112. package/dist/src/register-contracts/smartCommentParsing.js +80 -0
  113. package/dist/src/register-contracts/smartComments.d.ts +5 -0
  114. package/dist/src/register-contracts/smartComments.js +92 -0
  115. package/dist/src/register-contracts/summaries.d.ts +12 -0
  116. package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
  117. package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
  118. package/dist/src/register-contracts/summary-boundary.js +40 -0
  119. package/dist/src/register-contracts/summary-contract.d.ts +2 -0
  120. package/dist/src/register-contracts/summary-contract.js +45 -0
  121. package/dist/src/register-contracts/summary-result.d.ts +7 -0
  122. package/dist/src/register-contracts/summary-result.js +122 -0
  123. package/dist/src/register-contracts/summary-state.d.ts +23 -0
  124. package/dist/src/register-contracts/summary-state.js +88 -0
  125. package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
  126. package/dist/src/register-contracts/summary-token-transfer.js +67 -0
  127. package/dist/src/register-contracts/summary.d.ts +3 -0
  128. package/dist/src/register-contracts/summary.js +266 -0
  129. package/dist/src/register-contracts/tooling.d.ts +57 -0
  130. package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
  131. package/dist/src/register-contracts/types.d.ts +188 -0
  132. package/dist/src/semantics/binary-operators.d.ts +2 -0
  133. package/dist/src/semantics/binary-operators.js +15 -0
  134. package/dist/src/semantics/byte-functions.d.ts +2 -0
  135. package/dist/src/semantics/byte-functions.js +7 -0
  136. package/dist/src/semantics/constant-operator-types.d.ts +10 -0
  137. package/dist/src/semantics/constant-operator-types.js +1 -0
  138. package/dist/src/semantics/constant-operators.d.ts +3 -0
  139. package/dist/src/semantics/constant-operators.js +3 -0
  140. package/dist/src/semantics/diagnostics.d.ts +3 -0
  141. package/dist/src/semantics/diagnostics.js +10 -0
  142. package/dist/src/semantics/expression-evaluation.d.ts +11 -19
  143. package/dist/src/semantics/expression-evaluation.js +22 -334
  144. package/dist/src/semantics/layout-evaluation.d.ts +23 -0
  145. package/dist/src/semantics/layout-evaluation.js +202 -0
  146. package/dist/src/semantics/layout-format.d.ts +5 -0
  147. package/dist/src/semantics/layout-format.js +31 -0
  148. package/dist/src/semantics/layout-path.d.ts +24 -0
  149. package/dist/src/semantics/layout-path.js +58 -0
  150. package/dist/src/semantics/unary-operators.d.ts +2 -0
  151. package/dist/src/semantics/unary-operators.js +8 -0
  152. package/dist/src/source/line-comment-scanner.d.ts +1 -0
  153. package/dist/src/source/line-comment-scanner.js +51 -0
  154. package/dist/src/source/strip-line-comment.js +8 -44
  155. package/dist/src/syntax/directive-aliases.js +36 -22
  156. package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
  157. package/dist/src/syntax/expression-tokenizer.js +310 -0
  158. package/dist/src/syntax/parse-directive-statement.d.ts +14 -0
  159. package/dist/src/syntax/parse-directive-statement.js +307 -0
  160. package/dist/src/syntax/parse-expression.d.ts +2 -2
  161. package/dist/src/syntax/parse-expression.js +7 -568
  162. package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
  163. package/dist/src/syntax/parse-layout-declarations.js +180 -0
  164. package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
  165. package/dist/src/syntax/parse-layout-expression.js +175 -0
  166. package/dist/src/syntax/parse-line.js +4 -272
  167. package/dist/src/syntax/parse-token-expression.d.ts +3 -0
  168. package/dist/src/syntax/parse-token-expression.js +133 -0
  169. package/dist/src/tooling/case-style.js +47 -30
  170. package/dist/src/z80/effect-groups.d.ts +38 -0
  171. package/dist/src/z80/effect-groups.js +265 -0
  172. package/dist/src/z80/effect-units.d.ts +18 -0
  173. package/dist/src/z80/effect-units.js +165 -0
  174. package/dist/src/z80/effects.d.ts +1 -1
  175. package/dist/src/z80/effects.js +94 -557
  176. package/dist/src/z80/encode-core.d.ts +2 -0
  177. package/dist/src/z80/encode-core.js +42 -0
  178. package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
  179. package/dist/src/z80/encode-ld-helpers.js +172 -0
  180. package/dist/src/z80/encode-ld.d.ts +2 -0
  181. package/dist/src/z80/encode-ld.js +285 -0
  182. package/dist/src/z80/encode.js +190 -542
  183. package/dist/src/z80/ld-support.d.ts +3 -0
  184. package/dist/src/z80/ld-support.js +146 -0
  185. package/dist/src/z80/operand-split-state.d.ts +8 -0
  186. package/dist/src/z80/operand-split-state.js +46 -0
  187. package/dist/src/z80/operand-split.d.ts +1 -0
  188. package/dist/src/z80/operand-split.js +13 -0
  189. package/dist/src/z80/parse-basic.d.ts +4 -0
  190. package/dist/src/z80/parse-basic.js +39 -0
  191. package/dist/src/z80/parse-branch.d.ts +4 -0
  192. package/dist/src/z80/parse-branch.js +218 -0
  193. package/dist/src/z80/parse-conditions.d.ts +6 -0
  194. package/dist/src/z80/parse-conditions.js +10 -0
  195. package/dist/src/z80/parse-exchange.d.ts +2 -0
  196. package/dist/src/z80/parse-exchange.js +30 -0
  197. package/dist/src/z80/parse-instruction.js +224 -1010
  198. package/dist/src/z80/parse-io-control.d.ts +5 -0
  199. package/dist/src/z80/parse-io-control.js +108 -0
  200. package/dist/src/z80/parse-ld.d.ts +2 -0
  201. package/dist/src/z80/parse-ld.js +83 -0
  202. package/dist/src/z80/parse-operands.d.ts +41 -0
  203. package/dist/src/z80/parse-operands.js +259 -0
  204. package/docs/reference/cli.md +42 -35
  205. package/docs/reference/tooling-api.md +20 -16
  206. package/package.json +1 -1
  207. package/dist/src/register-care/accept-output.d.ts +0 -2
  208. package/dist/src/register-care/analyze.js +0 -166
  209. package/dist/src/register-care/annotate.d.ts +0 -11
  210. package/dist/src/register-care/annotations.d.ts +0 -8
  211. package/dist/src/register-care/boundaryHints.d.ts +0 -3
  212. package/dist/src/register-care/boundaryHints.js +0 -80
  213. package/dist/src/register-care/carriers.d.ts +0 -2
  214. package/dist/src/register-care/controlFlow.d.ts +0 -5
  215. package/dist/src/register-care/controlFlow.js +0 -38
  216. package/dist/src/register-care/fix.d.ts +0 -11
  217. package/dist/src/register-care/instruction-shape.d.ts +0 -11
  218. package/dist/src/register-care/instruction-shape.js +0 -129
  219. package/dist/src/register-care/liveness.d.ts +0 -3
  220. package/dist/src/register-care/programModel.d.ts +0 -3
  221. package/dist/src/register-care/programModel.js +0 -266
  222. package/dist/src/register-care/report.d.ts +0 -5
  223. package/dist/src/register-care/routine-summaries.d.ts +0 -6
  224. package/dist/src/register-care/smartComments.d.ts +0 -5
  225. package/dist/src/register-care/smartComments.js +0 -243
  226. package/dist/src/register-care/summaries.d.ts +0 -12
  227. package/dist/src/register-care/summary.d.ts +0 -3
  228. package/dist/src/register-care/summary.js +0 -474
  229. package/dist/src/register-care/tooling.d.ts +0 -43
  230. package/dist/src/register-care/types.d.ts +0 -172
  231. /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
  232. /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
  233. /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
  234. /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
  235. /package/dist/src/{register-care → register-contracts}/types.js +0 -0
package/README.md CHANGED
@@ -4,10 +4,12 @@ AZM is the Z80 assembler used by the Debug80 toolchain. It assembles `.asm`
4
4
  and `.z80` source into Intel HEX, flat binary and Debug80 map artifacts for
5
5
  hardware, emulators and Debug80.
6
6
 
7
- This README is the condensed manual. The full AZM book is on the Debug80
8
- documentation site:
7
+ This README is the condensed manual. The Debug80 website contains the detailed
8
+ AZM manual and broader Debug80 documentation:
9
9
 
10
- [AZM Assembler Manual](https://jhlagado.github.io/debug80-docs/azm-book/book4/)
10
+ - [Debug80 documentation](https://debug80.com/)
11
+ - [AZM Book 0 — Assembler Manual](https://debug80.com/azm-book/book0/)
12
+ - [AZM Book 4](https://jhlagado.github.io/debug80-docs/azm-book/book4/)
11
13
 
12
14
  ## Install
13
15
 
@@ -43,13 +45,13 @@ azm start.asm
43
45
  ```
44
46
 
45
47
  `.org` means origin. It sets the assembly address for the bytes that follow.
46
- `@Start:` is an address label and also a public routine entry for register-care
48
+ `@Start:` is an address label and also a public routine entry for register contracts
47
49
  analysis. The Z80 instructions assemble at `$0100`.
48
50
 
49
51
  ## Source Style
50
52
 
51
53
  AZM source is built from labels, declarations, directives, Z80 instructions,
52
- data definitions, layout declarations, register-care comments and optional
54
+ data definitions, layout declarations, register contract comments and optional
53
55
  inline `op` definitions.
54
56
 
55
57
  Canonical AZM directives are lowercase and dotted:
@@ -89,16 +91,102 @@ Colour .enum Red, Green, Blue
89
91
  SpriteArray .typealias Sprite[16]
90
92
  ```
91
93
 
92
- Constants often use upper case with underscores. Labels and routine names are
93
- clearer in PascalCase or camelCase:
94
+ ### Style Guide
95
+
96
+ AZM is stricter than many older Z80 assemblers. It accepts compatibility aliases
97
+ so existing source can be assembled, but source that you control should use the
98
+ canonical syntax below. These rules are intended to make AZM source predictable
99
+ for people and coding agents.
100
+
101
+ Use lowercase dotted directives, not legacy aliases:
94
102
 
95
103
  ```asm
96
- SCREEN_WIDTH .equ 32
104
+ .org 0x4000
105
+ .include "../shared/constants.asm"
97
106
 
98
- DrawSprite:
99
- ret
107
+ MOVE_PERIOD .equ 128
108
+
109
+ Message:
110
+ .db "READY",0
111
+
112
+ StatePtr:
113
+ .dw 0
114
+
115
+ Buffer:
116
+ .ds 32
100
117
  ```
101
118
 
119
+ Use `@Name:` for callable routine entries. The `@` marks a register contracts
120
+ routine boundary; call sites still write the symbol name without `@`:
121
+
122
+ ```asm
123
+ ;! in A
124
+ ;! out A
125
+ ;! clobbers BC
126
+ @MxMask:
127
+ LD C,A
128
+ OR A
129
+ LD A,0x80
130
+ JR Z,MxMaskDone
131
+ MxMaskLp:
132
+ SRL A
133
+ DJNZ MxMaskLp
134
+ MxMaskDone:
135
+ RET
136
+ ```
137
+
138
+ Use plain labels for data and internal branch targets. Plain labels are global,
139
+ so give branch labels names that stay unique across the whole include tree.
140
+ Prefer descriptive labels such as `MxMaskLoop`, `MxMaskDone`, `SpawnFailed` and
141
+ `HeldDirRateSet` rather than generic names such as `Loop` or `Done`.
142
+
143
+ Use uppercase with underscores for constants, following the usual C-style
144
+ convention. Group related constants with clear prefixes:
145
+
146
+ ```asm
147
+ PORT_DIGITS .equ 0x01
148
+ PORT_LCD_DATA .equ 0x84
149
+
150
+ API_SCAN_KEYS .equ 16
151
+ KEY_LEFT .equ 0x11
152
+ KEY_RIGHT .equ 0x10
153
+
154
+ COLOR_RED .equ 0x01
155
+ COLOR_GREEN .equ 0x02
156
+ COLOR_YELLOW .equ COLOR_RED + COLOR_GREEN
157
+ ```
158
+
159
+ Use PascalCase for routine entries, branch labels, data labels, type names and
160
+ enum names. Use lower camel case for fields and enum members when that makes
161
+ layout expressions easier to read. The assembler enforces uniqueness, not style,
162
+ but symbols are case-sensitive: `ColorRed`, `COLOR_RED` and `colorRed` are
163
+ different names.
164
+
165
+ Put declaration names on the left and do not use a colon for constants, enums,
166
+ types or type aliases:
167
+
168
+ ```asm
169
+ MOVE_PERIOD .equ 128
170
+ Colour .enum Red, Green, Blue
171
+ SpriteArray .typealias Sprite[16]
172
+
173
+ Sprite .type
174
+ x .field byte
175
+ y .field byte
176
+ tile .field byte
177
+ flags .field byte
178
+ .endtype
179
+ ```
180
+
181
+ Use a colon only for address labels. `COUNT .equ 8` declares a constant;
182
+ `Count:` declares an address label. Do not write `COUNT: .equ 8` in canonical
183
+ AZM.
184
+
185
+ Use indentation to make columns easy to scan. Put labels at the left margin,
186
+ indent instructions and standalone directives, and align operands enough to keep
187
+ dense assembly readable. Exact tab width is less important than keeping one
188
+ source file internally consistent.
189
+
102
190
  ## Literals
103
191
 
104
192
  AZM accepts the usual Z80 numeric forms:
@@ -247,9 +335,9 @@ azm -I include -I vendor program.asm
247
335
  Included source contributes labels, constants, enums, types, ops and routines to
248
336
  the same assembly.
249
337
 
250
- ## Register Care
338
+ ## Register Contracts
251
339
 
252
- Register care checks whether subroutines preserve the register values that their
340
+ Register contracts check whether subroutines preserve the register values that their
253
341
  callers still need. It is designed to catch register collisions, a common source
254
342
  of assembly bugs.
255
343
 
@@ -272,7 +360,7 @@ name:
272
360
  call CheckTile
273
361
  ```
274
362
 
275
- AZMDoc register-care comments use `;!` and may record inputs, outputs,
363
+ AZMDoc register contract comments use `;!` and may record inputs, outputs,
276
364
  clobbered registers and preserved registers. `clobbers B` means the routine may
277
365
  change `B`. `preserves B` means the value that enters in `B` is still present
278
366
  when the routine returns.
@@ -280,13 +368,24 @@ when the routine returns.
280
368
  Run the analysis with:
281
369
 
282
370
  ```sh
283
- azm --rc audit --reg-report program.asm
371
+ azm --rc audit program.asm
372
+ azm --rc warn program.asm
284
373
  azm --rc error --interface monitor.asmi program.asm
374
+ azm --rc strict program.asm
285
375
  ```
286
376
 
287
- The main modes are `audit`, `warn`, `error` and `strict`. AZM can also emit
288
- register-care reports and `.asmi` interface files for externally assembled
289
- routines.
377
+ The main modes are `audit`, `warn`, `error` and `strict`. Use `audit` for a
378
+ non-blocking check, `warn` for visible diagnostics with a successful compile,
379
+ `error` to fail on proven caller/callee register conflicts, and `strict` to fail
380
+ on any register contracts issue AZM cannot prove safe, including unknown call
381
+ boundaries and unbalanced or unknown stack effects.
382
+
383
+ The normal register contracts interface is compiler diagnostics plus source
384
+ contracts. Use `--contracts` or `--fix` when you want AZM to update compact
385
+ AZMDoc contract comments in source. Use `.asmi` files for externally assembled
386
+ routines or monitor/system APIs. Text report files are available with
387
+ `--reg-report`, but they are an explicit debug/export option and are not part of
388
+ the normal workflow.
290
389
 
291
390
  ## Ops and Aliases
292
391
 
@@ -316,7 +415,7 @@ azm [options] <entry.asm|entry.z80>
316
415
  ```
317
416
 
318
417
  The entry file is the final argument. Source entries use `.asm` or `.z80`.
319
- External register-care interfaces use `.asmi` and are loaded with
418
+ External register contract interfaces use `.asmi` and are loaded with
320
419
  `--interface`.
321
420
 
322
421
  Basic use writes the default artifact set next to the source file:
@@ -364,38 +463,40 @@ Generate ASM80-compatible lowered source:
364
463
  azm --asm80 program.asm
365
464
  ```
366
465
 
367
- Run register-care analysis:
466
+ Run register contracts analysis:
368
467
 
369
468
  ```sh
370
- azm --rc audit --reg-report program.asm
469
+ azm --rc audit program.asm
470
+ azm --rc warn program.asm
371
471
  azm --rc error --interface monitor.asmi program.asm
472
+ azm --rc strict program.asm
372
473
  azm --contracts --rc audit program.asm
373
474
  ```
374
475
 
375
476
  The main switches are:
376
477
 
377
- | Option | Meaning |
378
- | --------------------------------------------- | ------------------------------------------------------------- |
379
- | `-o, --output <file>` | Primary output path. The extension matches `--type`. |
380
- | `-t, --type <hex\|bin>` | Primary output type. Default: `hex`. |
381
- | `--nobin` | Skip `.bin` output. |
382
- | `--nohex` | Skip `.hex` output. |
383
- | `--nod8m` | Skip `.d8.json` output. |
384
- | `--asm80` | Write lowered assembler source as `.z80`. |
385
- | `--source-root <dir>` | Emit project-relative source paths in `.d8.json`. |
386
- | `--case-style <mode>` | Lint mnemonic, register and op-head case style. |
387
- | `--rc, --register-care <mode>` | Register-care mode: `off`, `audit`, `warn`, `error`, `strict`. |
388
- | `--reg-report, --emit-register-report` | Write `.regcare.txt`. |
389
- | `--reg-interface, --emit-register-interface` | Write inferred `.asmi` interface metadata. |
390
- | `--contracts, --annotate-register-contracts` | Update AZMDoc contract comments in source. |
391
- | `--fix` | Apply conservative register-care source fixes. |
392
- | `--accept-out <routine:carrier>` | Promote an inferred output candidate while annotating. |
393
- | `--interface <file>` | Load external register-care contracts from `.asmi`. |
394
- | `--reg-profile, --register-profile <profile>` | Register-care profile. Currently `mon3`. |
395
- | `--aliases <file>` | Load project directive alias JSON. |
396
- | `-I, --include <dir>` | Add an include search path. |
397
- | `-V, --version` | Print package version. |
398
- | `-h, --help` | Print CLI help. |
478
+ | Option | Meaning |
479
+ | --------------------------------------------- | ------------------------------------------------------------------- |
480
+ | `-o, --output <file>` | Primary output path. The extension matches `--type`. |
481
+ | `-t, --type <hex\|bin>` | Primary output type. Default: `hex`. |
482
+ | `--nobin` | Skip `.bin` output. |
483
+ | `--nohex` | Skip `.hex` output. |
484
+ | `--nod8m` | Skip `.d8.json` output. |
485
+ | `--asm80` | Write lowered assembler source as `.z80`. |
486
+ | `--source-root <dir>` | Emit project-relative source paths in `.d8.json`. |
487
+ | `--case-style <mode>` | Lint mnemonic, register and op-head case style. |
488
+ | `--rc, --register-contracts <mode>` | Register contracts mode: `off`, `audit`, `warn`, `error`, `strict`. |
489
+ | `--reg-report, --emit-register-report` | Opt-in debug report: write `.regcontracts.txt`. |
490
+ | `--reg-interface, --emit-register-interface` | Write inferred `.asmi` interface metadata. |
491
+ | `--contracts, --annotate-register-contracts` | Update AZMDoc contract comments in source. |
492
+ | `--fix` | Apply conservative register contract source fixes. |
493
+ | `--accept-out <routine:carrier>` | Promote an inferred output candidate while annotating. |
494
+ | `--interface <file>` | Load external register contracts from `.asmi`. |
495
+ | `--reg-profile, --register-profile <profile>` | Register contracts profile. Currently `mon3`. |
496
+ | `--aliases <file>` | Load project directive alias JSON. |
497
+ | `-I, --include <dir>` | Add an include search path. |
498
+ | `-V, --version` | Print package version. |
499
+ | `-h, --help` | Print CLI help. |
399
500
 
400
501
  See [docs/reference/cli.md](docs/reference/cli.md) for the complete option
401
502
  reference.
@@ -405,14 +506,14 @@ reference.
405
506
  By default, AZM writes the requested primary output plus useful side artifacts
406
507
  using the same base path.
407
508
 
408
- | Extension | Contents |
409
- | -------------- | --------------------------------------------- |
410
- | `.hex` | Intel HEX |
411
- | `.bin` | flat binary |
412
- | `.d8.json` | Debug80 map |
413
- | `.z80` | ASM80-compatible lowered source when enabled |
414
- | `.regcare.txt` | register-care report when enabled |
415
- | `.asmi` | register-care interface when enabled |
509
+ | Extension | Contents |
510
+ | ------------------- | -------------------------------------------- |
511
+ | `.hex` | Intel HEX |
512
+ | `.bin` | flat binary |
513
+ | `.d8.json` | Debug80 map |
514
+ | `.z80` | ASM80-compatible lowered source when enabled |
515
+ | `.regcontracts.txt` | opt-in register contracts debug report |
516
+ | `.asmi` | register contracts interface when enabled |
416
517
 
417
518
  ## Programmatic API
418
519
 
@@ -430,13 +531,13 @@ npm install @jhlagado/azm
430
531
  ```
431
532
 
432
533
  Use `@jhlagado/azm/tooling` when an editor, linter or debugger integration
433
- needs parsing, diagnostics, symbols, semantic checks or register-care facts in
534
+ needs parsing, diagnostics, symbols, semantic checks or register contract facts in
434
535
  memory:
435
536
 
436
537
  ```ts
437
538
  import {
438
539
  analyzeProgram,
439
- analyzeRegisterCareForTools,
540
+ analyzeRegisterContractsForTools,
440
541
  loadProgram,
441
542
  } from '@jhlagado/azm/tooling';
442
543
 
@@ -451,13 +552,13 @@ if (loaded.loadedProgram) {
451
552
  requireMain: false,
452
553
  });
453
554
 
454
- const registerCare = analyzeRegisterCareForTools(loaded.loadedProgram, {
555
+ const registerContracts = analyzeRegisterContractsForTools(loaded.loadedProgram, {
455
556
  mode: 'audit',
456
- registerCareProfile: 'mon3',
557
+ registerContractsProfile: 'mon3',
457
558
  });
458
559
 
459
560
  console.log(analysis.diagnostics);
460
- console.log(registerCare.candidateDiagnostics);
561
+ console.log(registerContracts.candidateDiagnostics);
461
562
  }
462
563
  ```
463
564
 
@@ -483,8 +584,8 @@ const result = await compile(
483
584
  hex: '/abs/path/to/project/build/main.hex',
484
585
  bin: '/abs/path/to/project/build/main.bin',
485
586
  },
486
- registerCare: 'audit',
487
- registerCareInterfaces: ['/abs/path/to/monitor.asmi'],
587
+ registerContracts: 'audit',
588
+ registerContractsInterfaces: ['/abs/path/to/monitor.asmi'],
488
589
  },
489
590
  { formats: defaultFormatWriters },
490
591
  );
@@ -501,20 +602,20 @@ write those artifacts to disk.
501
602
 
502
603
  Common programmatic options include:
503
604
 
504
- | Option | Use |
505
- | ---------------------------- | --------------------------------------------------------- |
506
- | `includeDirs` | Include search paths, like repeated `-I`. |
507
- | `directiveAliasFiles` | Project directive alias JSON files. |
508
- | `sourceRoot` | Stable project-relative paths in Debug80 maps. |
509
- | `d8mInputs` | Intended artifact paths recorded in Debug80 map metadata. |
510
- | `outputType` | Primary output type, `hex` or `bin`. |
511
- | `emitBin`, `emitHex`, `emitD8m` | Select in-memory artifact kinds. |
512
- | `emitAsm80` | Request lowered `.z80` artifact. |
513
- | `registerCare` | Register-care mode. |
514
- | `registerCareInterfaces` | External `.asmi` contract files. |
605
+ | Option | Use |
606
+ | ------------------------------- | --------------------------------------------------------- |
607
+ | `includeDirs` | Include search paths, like repeated `-I`. |
608
+ | `directiveAliasFiles` | Project directive alias JSON files. |
609
+ | `sourceRoot` | Stable project-relative paths in Debug80 maps. |
610
+ | `d8mInputs` | Intended artifact paths recorded in Debug80 map metadata. |
611
+ | `outputType` | Primary output type, `hex` or `bin`. |
612
+ | `emitBin`, `emitHex`, `emitD8m` | Select in-memory artifact kinds. |
613
+ | `emitAsm80` | Request lowered `.z80` artifact. |
614
+ | `registerContracts` | Register contracts mode. |
615
+ | `registerContractsInterfaces` | External `.asmi` contract files. |
515
616
 
516
617
  Public tooling types include `Diagnostic`, `LoadedProgram`,
517
- `AnalyzeProgramResult`, `LoadProgramResult`, `RegisterCareCandidateDiagnostic`
618
+ `AnalyzeProgramResult`, `LoadProgramResult`, `RegisterContractsCandidateDiagnostic`
518
619
  and the Debug80 map artifact types `D8mArtifact`, `D8mJson` and `D8mSymbol`.
519
620
 
520
621
  See [docs/reference/tooling-api.md](docs/reference/tooling-api.md) for current
@@ -0,0 +1,20 @@
1
+ import type { Diagnostic } from './model/diagnostic.js';
2
+ import type { SourceItem } from './model/source-item.js';
3
+ import type { Artifact, EmittedByteMap, FormatWriters } from './outputs/types.js';
4
+ import type { CompileNextFunctionOptions } from './api-compile.js';
5
+ interface EmitAssemblyArtifactsOptions {
6
+ readonly entryFile: string;
7
+ readonly options: CompileNextFunctionOptions;
8
+ readonly formats: FormatWriters;
9
+ readonly program: readonly SourceItem[];
10
+ readonly bytes: Uint8Array;
11
+ readonly origin: number;
12
+ readonly sourceSegments: EmittedByteMap['sourceSegments'];
13
+ readonly initializedAddresses: readonly number[];
14
+ readonly symbols: Readonly<Record<string, number>>;
15
+ }
16
+ export declare function emitAssemblyArtifacts(input: EmitAssemblyArtifactsOptions): Promise<{
17
+ readonly artifacts: readonly Artifact[];
18
+ readonly diagnostics: readonly Diagnostic[];
19
+ }>;
20
+ export {};
@@ -0,0 +1,165 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { dirname, normalize } from 'node:path';
3
+ import { UnsupportedAsm80LoweringError } from './outputs/write-asm80.js';
4
+ let cachedPackageVersion;
5
+ export async function emitAssemblyArtifacts(input) {
6
+ const artifacts = [];
7
+ const diagnostics = [];
8
+ const map = assembledImageToMap(input.bytes, input.origin, input.sourceSegments);
9
+ const hexMap = assembledInitializedImageToMap(input.bytes, input.origin, input.initializedAddresses);
10
+ const sidecarMap = assembledInitializedImageToMap(input.bytes, input.origin, input.initializedAddresses, input.sourceSegments);
11
+ const symbols = collectSymbolEntries(input.program, input.symbols);
12
+ const emit = compileArtifactDefaults(input.options);
13
+ const d8Root = input.options.sourceRoot ?? dirname(input.entryFile);
14
+ if (emit.emitBin) {
15
+ artifacts.push(input.formats.writeBin(map, symbols));
16
+ }
17
+ if (emit.emitHex) {
18
+ artifacts.push(input.formats.writeHex(hexMap, symbols));
19
+ }
20
+ if (emit.emitD8m) {
21
+ artifacts.push(input.formats.writeD8m(sidecarMap, symbols, await buildD8mOptions(input.entryFile, d8Root, input.options, symbols)));
22
+ }
23
+ if (emit.emitAsm80 && input.formats.writeAsm80 !== undefined) {
24
+ try {
25
+ artifacts.push(input.formats.writeAsm80(input.program, symbols));
26
+ }
27
+ catch (error) {
28
+ if (error instanceof UnsupportedAsm80LoweringError) {
29
+ diagnostics.push({
30
+ severity: 'error',
31
+ code: 'AZMN_ASM80',
32
+ message: error.message,
33
+ sourceName: error.item.span.sourceName,
34
+ line: error.item.span.line,
35
+ column: error.item.span.column,
36
+ });
37
+ }
38
+ else {
39
+ throw error;
40
+ }
41
+ }
42
+ }
43
+ return { artifacts, diagnostics };
44
+ }
45
+ function compileArtifactDefaults(options) {
46
+ const anyPrimary = [options.emitBin, options.emitHex, options.emitD8m].some((value) => value !== undefined);
47
+ const emitBin = anyPrimary ? (options.emitBin ?? false) : true;
48
+ const emitHex = anyPrimary ? (options.emitHex ?? false) : true;
49
+ const emitD8m = anyPrimary ? (options.emitD8m ?? false) : true;
50
+ const emitAsm80 = options.emitAsm80 ?? false;
51
+ return { emitBin, emitHex, emitD8m, emitAsm80 };
52
+ }
53
+ function assembledImageToMap(bytes, origin, sourceSegments = []) {
54
+ const map = new Map();
55
+ for (let offset = 0; offset < bytes.length; offset += 1) {
56
+ map.set(origin + offset, bytes[offset] ?? 0);
57
+ }
58
+ const writtenRange = {
59
+ start: origin,
60
+ end: origin + bytes.length,
61
+ };
62
+ return { bytes: map, writtenRange, sourceSegments };
63
+ }
64
+ function assembledInitializedImageToMap(bytes, origin, initializedAddresses, sourceSegments = []) {
65
+ const map = new Map();
66
+ for (const address of initializedAddresses) {
67
+ const offset = address - origin;
68
+ if (offset >= 0 && offset < bytes.length) {
69
+ map.set(address, bytes[offset] ?? 0);
70
+ }
71
+ }
72
+ return { bytes: map, sourceSegments };
73
+ }
74
+ function collectSymbolEntries(items, resolvedSymbols) {
75
+ const map = new Map();
76
+ for (const item of items) {
77
+ appendSymbolEntry(map, item, resolvedSymbols);
78
+ }
79
+ return [...map.values()];
80
+ }
81
+ function appendSymbolEntry(map, item, resolvedSymbols) {
82
+ if (item.kind === 'equ') {
83
+ const value = resolvedSymbols[item.name];
84
+ if (value !== undefined) {
85
+ map.set(item.name, {
86
+ kind: 'constant',
87
+ name: item.name,
88
+ value,
89
+ file: item.span.sourceName,
90
+ line: item.span.line,
91
+ scope: 'global',
92
+ });
93
+ }
94
+ return;
95
+ }
96
+ if (item.kind === 'label') {
97
+ const address = resolvedSymbols[item.name];
98
+ if (address !== undefined) {
99
+ map.set(item.name, {
100
+ kind: 'label',
101
+ name: item.name,
102
+ address,
103
+ file: item.span.sourceName,
104
+ line: item.span.line,
105
+ scope: 'global',
106
+ });
107
+ }
108
+ return;
109
+ }
110
+ if (item.kind === 'enum') {
111
+ for (const member of item.members) {
112
+ const fullName = `${item.name}.${member}`;
113
+ const value = resolvedSymbols[fullName];
114
+ if (value !== undefined) {
115
+ map.set(fullName, {
116
+ kind: 'constant',
117
+ name: fullName,
118
+ value,
119
+ file: item.span.sourceName,
120
+ line: item.span.line,
121
+ scope: 'global',
122
+ });
123
+ }
124
+ }
125
+ }
126
+ }
127
+ async function buildD8mOptions(entryFile, d8Root, options, symbols) {
128
+ const main = symbols.find((symbol) => symbol.kind === 'label' && symbol.name.toLowerCase() === 'main');
129
+ return {
130
+ rootDir: normalize(d8Root),
131
+ packageVersion: await readPackageVersion(),
132
+ inputs: {
133
+ entry: entryFile,
134
+ ...(options.d8mInputs?.hex !== undefined ? { hex: options.d8mInputs.hex } : {}),
135
+ ...(options.d8mInputs?.bin !== undefined ? { bin: options.d8mInputs.bin } : {}),
136
+ },
137
+ ...(main !== undefined ? { entrySymbol: main.name } : {}),
138
+ ...(main !== undefined ? { entryAddress: main.kind === 'constant' ? main.value : main.address } : {}),
139
+ };
140
+ }
141
+ async function readPackageVersion() {
142
+ if (cachedPackageVersion !== undefined) {
143
+ return cachedPackageVersion;
144
+ }
145
+ const packageJsonCandidates = [
146
+ new URL('../package.json', import.meta.url),
147
+ new URL('../../package.json', import.meta.url),
148
+ new URL('../../../package.json', import.meta.url),
149
+ ];
150
+ for (const candidate of packageJsonCandidates) {
151
+ try {
152
+ const raw = await readFile(candidate, 'utf8');
153
+ const json = JSON.parse(raw);
154
+ if (json.version !== undefined) {
155
+ cachedPackageVersion = json.version;
156
+ return cachedPackageVersion;
157
+ }
158
+ }
159
+ catch {
160
+ // Continue searching candidates.
161
+ }
162
+ }
163
+ cachedPackageVersion = '0.0.0';
164
+ return cachedPackageVersion;
165
+ }
@@ -3,7 +3,7 @@ import { writeHex } from './outputs/write-hex.js';
3
3
  import type { AddressRange, Artifact, D8mArtifact, D8mFileEntry, D8mFileSymbol, D8mGenerator, D8mJson, D8mSegment, D8mSymbol, EmittedByteMap, FormatWriters, SymbolEntry, WriteD8mOptions } from './outputs/types.js';
4
4
  import type { Diagnostic } from './model/diagnostic.js';
5
5
  import type { CaseStyleMode } from './tooling/case-style.js';
6
- import type { RegisterCareMode } from './register-care/types.js';
6
+ import type { RegisterContractsMode } from './register-contracts/types.js';
7
7
  export { writeHex, defaultFormatWriters };
8
8
  export type { AddressRange, Artifact, D8mArtifact, D8mFileEntry, D8mFileSymbol, D8mGenerator, D8mJson, D8mSegment, D8mSymbol, EmittedByteMap, FormatWriters, SymbolEntry, WriteD8mOptions, };
9
9
  export type CompileDependencies = CompileNextDependencies;
@@ -27,13 +27,19 @@ export interface CompileNextFunctionOptions {
27
27
  readonly emitHex?: boolean;
28
28
  readonly emitD8m?: boolean;
29
29
  readonly emitAsm80?: boolean;
30
- readonly registerCare?: RegisterCareMode;
30
+ readonly registerContracts?: RegisterContractsMode;
31
+ /** @deprecated Use registerContracts. */
32
+ readonly registerCare?: RegisterContractsMode;
31
33
  readonly emitRegisterReport?: boolean;
32
34
  readonly emitRegisterInterface?: boolean;
33
35
  readonly emitRegisterAnnotations?: boolean;
34
36
  readonly fixRegisterContracts?: boolean;
35
37
  readonly acceptRegisterOutputCandidates?: string[];
38
+ readonly registerContractsProfile?: 'mon3';
39
+ /** @deprecated Use registerContractsProfile. */
36
40
  readonly registerCareProfile?: 'mon3';
41
+ readonly registerContractsInterfaces?: string[];
42
+ /** @deprecated Use registerContractsInterfaces. */
37
43
  readonly registerCareInterfaces?: string[];
38
44
  readonly skipAssembly?: boolean;
39
45
  }