@jhlagado/azm 0.2.7 → 0.2.9

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 (253) hide show
  1. package/README.md +239 -76
  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 +55 -227
  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/assemble-program.js +5 -0
  15. package/dist/src/assembly/fixup-emission.js +30 -48
  16. package/dist/src/assembly/import-visibility.d.ts +3 -0
  17. package/dist/src/assembly/import-visibility.js +204 -0
  18. package/dist/src/assembly/program-emission.js +163 -164
  19. package/dist/src/cli/artifact-files.d.ts +15 -0
  20. package/dist/src/cli/artifact-files.js +86 -0
  21. package/dist/src/cli/parse-args.d.ts +6 -5
  22. package/dist/src/cli/parse-args.js +162 -136
  23. package/dist/src/cli/run.js +4 -1
  24. package/dist/src/cli/usage.d.ts +1 -0
  25. package/dist/src/cli/usage.js +33 -0
  26. package/dist/src/cli/write-artifacts.js +18 -91
  27. package/dist/src/core/compile.js +51 -274
  28. package/dist/src/core/conditional-assembly.d.ts +6 -0
  29. package/dist/src/core/conditional-assembly.js +181 -0
  30. package/dist/src/expansion/op-constant-expression.d.ts +3 -0
  31. package/dist/src/expansion/op-constant-expression.js +52 -0
  32. package/dist/src/expansion/op-expand-selected.d.ts +5 -0
  33. package/dist/src/expansion/op-expand-selected.js +143 -0
  34. package/dist/src/expansion/op-expansion.d.ts +5 -53
  35. package/dist/src/expansion/op-expansion.js +85 -815
  36. package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
  37. package/dist/src/expansion/op-instruction-instantiation.js +194 -0
  38. package/dist/src/expansion/op-local-labels.d.ts +8 -0
  39. package/dist/src/expansion/op-local-labels.js +166 -0
  40. package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
  41. package/dist/src/expansion/op-operand-splitting.js +44 -0
  42. package/dist/src/expansion/op-operands.d.ts +53 -0
  43. package/dist/src/expansion/op-operands.js +66 -0
  44. package/dist/src/expansion/op-selection.d.ts +18 -0
  45. package/dist/src/expansion/op-selection.js +172 -0
  46. package/dist/src/index.d.ts +2 -1
  47. package/dist/src/index.js +1 -1
  48. package/dist/src/model/diagnostic.d.ts +4 -0
  49. package/dist/src/model/diagnostic.js +4 -0
  50. package/dist/src/node/source-host.js +40 -13
  51. package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
  52. package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
  53. package/dist/src/outputs/asm80-expressions.d.ts +5 -0
  54. package/dist/src/outputs/asm80-expressions.js +47 -0
  55. package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
  56. package/dist/src/outputs/asm80-instruction-operands.js +38 -0
  57. package/dist/src/outputs/asm80-instructions.d.ts +5 -0
  58. package/dist/src/outputs/asm80-instructions.js +272 -0
  59. package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
  60. package/dist/src/outputs/asm80-ld-operands.js +157 -0
  61. package/dist/src/outputs/asm80-strings.d.ts +4 -0
  62. package/dist/src/outputs/asm80-strings.js +14 -0
  63. package/dist/src/outputs/d8-files.d.ts +10 -0
  64. package/dist/src/outputs/d8-files.js +103 -0
  65. package/dist/src/outputs/d8-helpers.d.ts +21 -0
  66. package/dist/src/outputs/d8-helpers.js +136 -0
  67. package/dist/src/outputs/hex.js +26 -18
  68. package/dist/src/outputs/types.d.ts +16 -10
  69. package/dist/src/outputs/write-asm80.js +72 -597
  70. package/dist/src/outputs/write-d8.js +6 -216
  71. package/dist/src/register-contracts/accept-output.d.ts +2 -0
  72. package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
  73. package/dist/src/register-contracts/analyze-helpers.js +162 -0
  74. package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
  75. package/dist/src/register-contracts/analyze.js +73 -0
  76. package/dist/src/register-contracts/annotate.d.ts +11 -0
  77. package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
  78. package/dist/src/register-contracts/annotations.d.ts +8 -0
  79. package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
  80. package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
  81. package/dist/src/register-contracts/boundaryHints.js +24 -0
  82. package/dist/src/register-contracts/carriers.d.ts +2 -0
  83. package/dist/src/register-contracts/constants.d.ts +4 -0
  84. package/dist/src/register-contracts/constants.js +51 -0
  85. package/dist/src/register-contracts/controlFlow.d.ts +5 -0
  86. package/dist/src/register-contracts/controlFlow.js +55 -0
  87. package/dist/src/register-contracts/fix.d.ts +11 -0
  88. package/dist/src/{register-care → register-contracts}/fix.js +47 -30
  89. package/dist/src/register-contracts/instruction-head.d.ts +2 -0
  90. package/dist/src/register-contracts/instruction-head.js +3 -0
  91. package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
  92. package/dist/src/register-contracts/instruction-operands.js +101 -0
  93. package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
  94. package/dist/src/register-contracts/instruction-predicates.js +44 -0
  95. package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
  96. package/dist/src/register-contracts/interfaceContracts.js +68 -0
  97. package/dist/src/register-contracts/liveness.d.ts +3 -0
  98. package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
  99. package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
  100. package/dist/src/register-contracts/operand-register-name.js +13 -0
  101. package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
  102. package/dist/src/{register-care → register-contracts}/profiles.js +2 -2
  103. package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
  104. package/dist/src/register-contracts/programModel-boundaries.js +64 -0
  105. package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
  106. package/dist/src/register-contracts/programModel-routines.js +144 -0
  107. package/dist/src/register-contracts/programModel.d.ts +3 -0
  108. package/dist/src/register-contracts/programModel.js +14 -0
  109. package/dist/src/register-contracts/report.d.ts +5 -0
  110. package/dist/src/{register-care → register-contracts}/report.js +34 -17
  111. package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
  112. package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
  113. package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
  114. package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
  115. package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
  116. package/dist/src/register-contracts/smartCommentParsing.js +80 -0
  117. package/dist/src/register-contracts/smartComments.d.ts +5 -0
  118. package/dist/src/register-contracts/smartComments.js +92 -0
  119. package/dist/src/register-contracts/summaries.d.ts +12 -0
  120. package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
  121. package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
  122. package/dist/src/register-contracts/summary-boundary.js +40 -0
  123. package/dist/src/register-contracts/summary-contract.d.ts +2 -0
  124. package/dist/src/register-contracts/summary-contract.js +45 -0
  125. package/dist/src/register-contracts/summary-result.d.ts +7 -0
  126. package/dist/src/register-contracts/summary-result.js +122 -0
  127. package/dist/src/register-contracts/summary-state.d.ts +23 -0
  128. package/dist/src/register-contracts/summary-state.js +88 -0
  129. package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
  130. package/dist/src/register-contracts/summary-token-transfer.js +67 -0
  131. package/dist/src/register-contracts/summary.d.ts +3 -0
  132. package/dist/src/register-contracts/summary.js +266 -0
  133. package/dist/src/register-contracts/tooling.d.ts +57 -0
  134. package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
  135. package/dist/src/register-contracts/types.d.ts +188 -0
  136. package/dist/src/semantics/binary-operators.d.ts +2 -0
  137. package/dist/src/semantics/binary-operators.js +15 -0
  138. package/dist/src/semantics/byte-functions.d.ts +2 -0
  139. package/dist/src/semantics/byte-functions.js +7 -0
  140. package/dist/src/semantics/constant-operator-types.d.ts +10 -0
  141. package/dist/src/semantics/constant-operator-types.js +1 -0
  142. package/dist/src/semantics/constant-operators.d.ts +3 -0
  143. package/dist/src/semantics/constant-operators.js +3 -0
  144. package/dist/src/semantics/diagnostics.d.ts +3 -0
  145. package/dist/src/semantics/diagnostics.js +10 -0
  146. package/dist/src/semantics/expression-evaluation.d.ts +11 -19
  147. package/dist/src/semantics/expression-evaluation.js +22 -334
  148. package/dist/src/semantics/layout-evaluation.d.ts +23 -0
  149. package/dist/src/semantics/layout-evaluation.js +202 -0
  150. package/dist/src/semantics/layout-format.d.ts +5 -0
  151. package/dist/src/semantics/layout-format.js +31 -0
  152. package/dist/src/semantics/layout-path.d.ts +24 -0
  153. package/dist/src/semantics/layout-path.js +58 -0
  154. package/dist/src/semantics/unary-operators.d.ts +2 -0
  155. package/dist/src/semantics/unary-operators.js +8 -0
  156. package/dist/src/source/line-comment-scanner.d.ts +1 -0
  157. package/dist/src/source/line-comment-scanner.js +51 -0
  158. package/dist/src/source/logical-lines.d.ts +3 -0
  159. package/dist/src/source/source-span.d.ts +2 -0
  160. package/dist/src/source/strip-line-comment.js +8 -44
  161. package/dist/src/syntax/directive-aliases.js +36 -22
  162. package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
  163. package/dist/src/syntax/expression-tokenizer.js +310 -0
  164. package/dist/src/syntax/parse-directive-statement.d.ts +9 -0
  165. package/dist/src/syntax/parse-directive-statement.js +309 -0
  166. package/dist/src/syntax/parse-expression.d.ts +2 -2
  167. package/dist/src/syntax/parse-expression.js +7 -568
  168. package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
  169. package/dist/src/syntax/parse-layout-declarations.js +189 -0
  170. package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
  171. package/dist/src/syntax/parse-layout-expression.js +175 -0
  172. package/dist/src/syntax/parse-line.js +21 -273
  173. package/dist/src/syntax/parse-token-expression.d.ts +3 -0
  174. package/dist/src/syntax/parse-token-expression.js +133 -0
  175. package/dist/src/tooling/api.js +1 -1
  176. package/dist/src/tooling/case-style.js +47 -30
  177. package/dist/src/z80/effect-groups.d.ts +38 -0
  178. package/dist/src/z80/effect-groups.js +265 -0
  179. package/dist/src/z80/effect-units.d.ts +18 -0
  180. package/dist/src/z80/effect-units.js +165 -0
  181. package/dist/src/z80/effects.d.ts +1 -1
  182. package/dist/src/z80/effects.js +94 -557
  183. package/dist/src/z80/encode-core.d.ts +2 -0
  184. package/dist/src/z80/encode-core.js +42 -0
  185. package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
  186. package/dist/src/z80/encode-ld-helpers.js +172 -0
  187. package/dist/src/z80/encode-ld.d.ts +2 -0
  188. package/dist/src/z80/encode-ld.js +285 -0
  189. package/dist/src/z80/encode.js +190 -542
  190. package/dist/src/z80/ld-support.d.ts +3 -0
  191. package/dist/src/z80/ld-support.js +146 -0
  192. package/dist/src/z80/operand-split-state.d.ts +8 -0
  193. package/dist/src/z80/operand-split-state.js +46 -0
  194. package/dist/src/z80/operand-split.d.ts +1 -0
  195. package/dist/src/z80/operand-split.js +13 -0
  196. package/dist/src/z80/parse-basic.d.ts +4 -0
  197. package/dist/src/z80/parse-basic.js +39 -0
  198. package/dist/src/z80/parse-branch.d.ts +4 -0
  199. package/dist/src/z80/parse-branch.js +218 -0
  200. package/dist/src/z80/parse-conditions.d.ts +6 -0
  201. package/dist/src/z80/parse-conditions.js +10 -0
  202. package/dist/src/z80/parse-exchange.d.ts +2 -0
  203. package/dist/src/z80/parse-exchange.js +30 -0
  204. package/dist/src/z80/parse-instruction.js +224 -1010
  205. package/dist/src/z80/parse-io-control.d.ts +5 -0
  206. package/dist/src/z80/parse-io-control.js +108 -0
  207. package/dist/src/z80/parse-ld.d.ts +2 -0
  208. package/dist/src/z80/parse-ld.js +83 -0
  209. package/dist/src/z80/parse-operands.d.ts +41 -0
  210. package/dist/src/z80/parse-operands.js +259 -0
  211. package/docs/codebase/01-orientation-and-repository-layout.md +192 -0
  212. package/docs/codebase/02-source-loading-and-parsing.md +263 -0
  213. package/docs/codebase/03-assembly-and-z80-emission.md +251 -0
  214. package/docs/codebase/04-ops-and-register-contracts.md +237 -0
  215. package/docs/codebase/05-interfaces-and-output-artifacts.md +253 -0
  216. package/docs/codebase/06-verification-and-maintenance.md +202 -0
  217. package/docs/codebase/appendices/a-directory-file-reference.md +253 -0
  218. package/docs/codebase/appendices/b-compile-flow-reference.md +103 -0
  219. package/docs/codebase/appendices/c-public-surface-reference.md +106 -0
  220. package/docs/codebase/appendices/index.md +16 -0
  221. package/docs/codebase/index.md +46 -0
  222. package/package.json +2 -3
  223. package/dist/src/register-care/accept-output.d.ts +0 -2
  224. package/dist/src/register-care/analyze.js +0 -166
  225. package/dist/src/register-care/annotate.d.ts +0 -11
  226. package/dist/src/register-care/annotations.d.ts +0 -8
  227. package/dist/src/register-care/boundaryHints.d.ts +0 -3
  228. package/dist/src/register-care/boundaryHints.js +0 -80
  229. package/dist/src/register-care/carriers.d.ts +0 -2
  230. package/dist/src/register-care/controlFlow.d.ts +0 -5
  231. package/dist/src/register-care/controlFlow.js +0 -38
  232. package/dist/src/register-care/fix.d.ts +0 -11
  233. package/dist/src/register-care/instruction-shape.d.ts +0 -11
  234. package/dist/src/register-care/instruction-shape.js +0 -129
  235. package/dist/src/register-care/liveness.d.ts +0 -3
  236. package/dist/src/register-care/programModel.d.ts +0 -3
  237. package/dist/src/register-care/programModel.js +0 -266
  238. package/dist/src/register-care/report.d.ts +0 -5
  239. package/dist/src/register-care/routine-summaries.d.ts +0 -6
  240. package/dist/src/register-care/smartComments.d.ts +0 -5
  241. package/dist/src/register-care/smartComments.js +0 -243
  242. package/dist/src/register-care/summaries.d.ts +0 -12
  243. package/dist/src/register-care/summary.d.ts +0 -3
  244. package/dist/src/register-care/summary.js +0 -474
  245. package/dist/src/register-care/tooling.d.ts +0 -43
  246. package/dist/src/register-care/types.d.ts +0 -172
  247. package/docs/reference/cli.md +0 -151
  248. package/docs/reference/tooling-api.md +0 -316
  249. /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
  250. /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
  251. /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
  252. /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
  253. /package/dist/src/{register-care → register-contracts}/types.js +0 -0
@@ -1,7 +1,26 @@
1
- import { evaluateExpression, } from '../semantics/expression-evaluation.js';
2
1
  import { instructionSize } from '../assembly/fixup-emission.js';
2
+ import { evaluateLoweredConstant, formatExpression, formatLoweredNumber, } from './asm80-expressions.js';
3
+ import { formatInstruction } from './asm80-instructions.js';
4
+ import { stringDirectiveBytes } from './asm80-strings.js';
3
5
  const asm80Header = '; AZM lowered ASM80 output';
4
- const silentSpan = { sourceName: '', line: 0, column: 0 };
6
+ const FORMATTERS = {
7
+ org: formatOrg,
8
+ equ: formatEqu,
9
+ comment: formatComment,
10
+ label: formatLabel,
11
+ db: formatDbItem,
12
+ dw: formatDwItem,
13
+ ds: formatDsItem,
14
+ align: formatAlignItem,
15
+ 'string-data': formatStringDataItem,
16
+ instruction: formatInstructionItem,
17
+ enum: formatIgnoredItem,
18
+ type: formatIgnoredItem,
19
+ 'type-alias': formatIgnoredItem,
20
+ end: formatIgnoredItem,
21
+ binfrom: formatIgnoredItem,
22
+ binto: formatIgnoredItem,
23
+ };
5
24
  export class UnsupportedAsm80LoweringError extends Error {
6
25
  item;
7
26
  constructor(message, item) {
@@ -12,6 +31,10 @@ export class UnsupportedAsm80LoweringError extends Error {
12
31
  }
13
32
  export function writeAsm80(items, symbols, opts = {}) {
14
33
  void opts;
34
+ const importedItem = items.find((item) => item.span.sourceRelation === 'import');
35
+ if (importedItem !== undefined) {
36
+ throw new UnsupportedAsm80LoweringError('lowered .z80 output does not yet support .import source units', importedItem);
37
+ }
15
38
  const evalContext = {
16
39
  constants: collectConstants(symbols),
17
40
  symbols: collectSymbolValues(symbols),
@@ -72,52 +95,54 @@ function collectLayouts(items) {
72
95
  return layouts;
73
96
  }
74
97
  function formatItem(item, evalContext, state) {
75
- switch (item.kind) {
76
- case 'org': {
77
- const expression = formatExpression(item.expression, evalContext, 'word');
78
- const address = evaluateLoweredConstant(item.expression, evalContext);
79
- if (expression === undefined || address === undefined) {
80
- return undefined;
81
- }
82
- state.address = address;
83
- state.emittedOrg = true;
84
- return { text: `ORG ${expression}`, size: 0 };
85
- }
86
- case 'equ': {
87
- const expression = formatExpression(item.expression, evalContext, 'auto');
88
- return expression === undefined
89
- ? undefined
90
- : withImplicitOrg(state, `${item.name} EQU ${expression}`, 0);
91
- }
92
- case 'comment':
93
- return {
94
- text: item.origin === 'user' ? `; ${item.text}` : `; AZM: ${item.text}`,
95
- size: 0,
96
- };
97
- case 'label':
98
- return withImplicitOrg(state, `${item.name}:`, 0);
99
- case 'db':
100
- return formatDb(item.values, evalContext, state);
101
- case 'dw':
102
- return formatDw(item.values, evalContext, state);
103
- case 'ds':
104
- return formatDs(item.size, item.fill, evalContext, state);
105
- case 'align':
106
- return formatAlign(item.alignment, evalContext, state);
107
- case 'string-data':
108
- return formatStringData(item.directive, item.value, state);
109
- case 'instruction':
110
- return withImplicitOrg(state, formatInstruction(item.instruction, evalContext)?.text, instructionSize(item.instruction));
111
- case 'enum':
112
- case 'type':
113
- case 'type-alias':
114
- case 'end':
115
- case 'binfrom':
116
- case 'binto':
117
- return { text: '', size: 0 };
118
- default:
119
- return undefined;
98
+ const formatter = FORMATTERS[item.kind];
99
+ return formatter(item, evalContext, state);
100
+ }
101
+ function formatOrg(item, evalContext, state) {
102
+ const expression = formatExpression(item.expression, evalContext, 'word');
103
+ const address = evaluateLoweredConstant(item.expression, evalContext);
104
+ if (expression === undefined || address === undefined) {
105
+ return undefined;
120
106
  }
107
+ state.address = address;
108
+ state.emittedOrg = true;
109
+ return { text: `ORG ${expression}`, size: 0 };
110
+ }
111
+ function formatEqu(item, evalContext, state) {
112
+ const expression = formatExpression(item.expression, evalContext, 'auto');
113
+ return expression === undefined
114
+ ? undefined
115
+ : withImplicitOrg(state, `${item.name} EQU ${expression}`, 0);
116
+ }
117
+ function formatComment(item) {
118
+ return {
119
+ text: item.origin === 'user' ? `; ${item.text}` : `; AZM: ${item.text}`,
120
+ size: 0,
121
+ };
122
+ }
123
+ function formatLabel(item, _evalContext, state) {
124
+ return withImplicitOrg(state, `${item.name}:`, 0);
125
+ }
126
+ function formatDbItem(item, evalContext, state) {
127
+ return formatDb(item.values, evalContext, state);
128
+ }
129
+ function formatDwItem(item, evalContext, state) {
130
+ return formatDw(item.values, evalContext, state);
131
+ }
132
+ function formatDsItem(item, evalContext, state) {
133
+ return formatDs(item.size, item.fill, evalContext, state);
134
+ }
135
+ function formatAlignItem(item, evalContext, state) {
136
+ return formatAlign(item.alignment, evalContext, state);
137
+ }
138
+ function formatStringDataItem(item, _evalContext, state) {
139
+ return formatStringData(item.directive, item.value, state);
140
+ }
141
+ function formatInstructionItem(item, evalContext, state) {
142
+ return withImplicitOrg(state, formatInstruction(item.instruction, evalContext)?.text, instructionSize(item.instruction));
143
+ }
144
+ function formatIgnoredItem() {
145
+ return { text: '', size: 0 };
121
146
  }
122
147
  function formatDb(values, evalContext, state) {
123
148
  const parts = [];
@@ -182,265 +207,6 @@ function formatStringData(directive, value, state) {
182
207
  }
183
208
  return withImplicitOrg(state, `DB ${bytes.map((byte) => formatLoweredNumber(byte, 'byte')).join(', ')}`, bytes.length);
184
209
  }
185
- function formatInstruction(instruction, evalContext) {
186
- const size = instructionSize(instruction);
187
- void size;
188
- switch (instruction.mnemonic) {
189
- case 'ld-a-imm': {
190
- const expression = formatExpression(instruction.expression, evalContext, 'byte');
191
- if (expression === undefined) {
192
- return undefined;
193
- }
194
- return {
195
- text: `ld a, ${expression}`,
196
- };
197
- }
198
- case 'ld':
199
- return formatLd(instruction.target, instruction.source, evalContext);
200
- case 'nop':
201
- return { text: 'nop' };
202
- case 'ret':
203
- return { text: 'ret' };
204
- case 'di':
205
- case 'ei':
206
- case 'scf':
207
- case 'ccf':
208
- case 'cpl':
209
- case 'daa':
210
- case 'exx':
211
- case 'halt':
212
- case 'rlca':
213
- case 'rrca':
214
- case 'rla':
215
- case 'rra':
216
- case 'neg':
217
- case 'rrd':
218
- case 'rld':
219
- case 'ldi':
220
- case 'ldir':
221
- case 'ldd':
222
- case 'lddr':
223
- case 'cpi':
224
- case 'cpir':
225
- case 'cpd':
226
- case 'cpdr':
227
- case 'ini':
228
- case 'inir':
229
- case 'ind':
230
- case 'indr':
231
- case 'outi':
232
- case 'otir':
233
- case 'outd':
234
- case 'otdr':
235
- case 'reti':
236
- case 'retn':
237
- return { text: instruction.mnemonic };
238
- case 'im':
239
- return { text: `im ${formatLoweredNumber(instruction.mode, 'byte')}` };
240
- case 'rst':
241
- return { text: `rst ${formatLoweredNumber(instruction.vector, 'byte')}` };
242
- case 'add':
243
- if ('target' in instruction) {
244
- return formatReg16Alu('add', instruction.target, instruction.source);
245
- }
246
- return formatAlu('add', instruction.source, evalContext);
247
- case 'adc':
248
- case 'sbc':
249
- if ('target' in instruction) {
250
- return formatReg16Alu(instruction.mnemonic, instruction.target, instruction.source);
251
- }
252
- return formatAlu(instruction.mnemonic, instruction.source, evalContext);
253
- case 'sub':
254
- case 'and':
255
- case 'or':
256
- case 'xor':
257
- case 'cp':
258
- return formatAlu(instruction.mnemonic, instruction.source, evalContext);
259
- case 'bit':
260
- case 'res':
261
- case 'set':
262
- return formatBitOp(instruction, evalContext);
263
- case 'rlc':
264
- case 'rrc':
265
- case 'rl':
266
- case 'rr':
267
- case 'sla':
268
- case 'sra':
269
- case 'sll':
270
- case 'sls':
271
- case 'srl':
272
- return formatRotateShift(instruction, evalContext);
273
- case 'in':
274
- return formatIn(instruction, evalContext);
275
- case 'out':
276
- return formatOut(instruction, evalContext);
277
- case 'inc':
278
- case 'dec':
279
- return formatIncDec(instruction, evalContext);
280
- case 'ex':
281
- return formatEx(instruction.form);
282
- case 'jp':
283
- return formatBranch('jp', instruction.expression, evalContext);
284
- case 'jp-cc':
285
- return formatBranch(`jp ${instruction.condition},`, instruction.expression, evalContext);
286
- case 'jp-indirect':
287
- return { text: `jp (${instruction.register})` };
288
- case 'jr':
289
- return formatBranch('jr', instruction.expression, evalContext);
290
- case 'jr-cc':
291
- return formatBranch(`jr ${instruction.condition},`, instruction.expression, evalContext);
292
- case 'call':
293
- return formatBranch('call', instruction.expression, evalContext);
294
- case 'call-cc':
295
- return formatBranch(`call ${instruction.condition},`, instruction.expression, evalContext);
296
- case 'djnz':
297
- return formatBranch('djnz', instruction.expression, evalContext);
298
- case 'push':
299
- case 'pop':
300
- return { text: `${instruction.mnemonic} ${instruction.register}` };
301
- case 'ret-cc':
302
- return { text: `ret ${instruction.condition}` };
303
- default:
304
- return undefined;
305
- }
306
- }
307
- function formatAlu(mnemonic, source, evalContext) {
308
- const operand = formatAluOperand(source, evalContext);
309
- if (operand === undefined) {
310
- return undefined;
311
- }
312
- if (mnemonic === 'add' || mnemonic === 'adc' || mnemonic === 'sbc') {
313
- return { text: `${mnemonic} a, ${operand}` };
314
- }
315
- if (mnemonic === 'xor' && source.kind === 'reg8' && source.register === 'a') {
316
- return { text: 'xor a' };
317
- }
318
- return { text: `${mnemonic} ${operand}` };
319
- }
320
- function formatAluOperand(source, evalContext) {
321
- if (source.kind === 'reg8' || source.kind === 'reg-half-index') {
322
- return source.register;
323
- }
324
- if (source.kind === 'reg-indirect' && source.register === 'hl') {
325
- return '(HL)';
326
- }
327
- if (source.kind === 'imm') {
328
- return formatExpression(source.expression, evalContext, 'byte');
329
- }
330
- return undefined;
331
- }
332
- function formatReg16Alu(mnemonic, target, source) {
333
- const targetText = formatReg16PairOperand(target);
334
- const sourceText = formatReg16PairOperand(source);
335
- return targetText === undefined || sourceText === undefined
336
- ? undefined
337
- : { text: `${mnemonic} ${targetText}, ${sourceText}` };
338
- }
339
- function formatReg16PairOperand(operand) {
340
- if (operand.kind === 'reg16') {
341
- return operand.register;
342
- }
343
- if (operand.kind === 'reg-index16') {
344
- return operand.register;
345
- }
346
- return undefined;
347
- }
348
- function formatEx(form) {
349
- switch (form) {
350
- case 'af-af':
351
- return { text: "ex af, af'" };
352
- case 'de-hl':
353
- return { text: 'ex de, hl' };
354
- case 'sp-hl':
355
- return { text: 'ex (sp), hl' };
356
- case 'sp-ix':
357
- return { text: 'ex (SP), ix' };
358
- case 'sp-iy':
359
- return { text: 'ex (SP), iy' };
360
- }
361
- }
362
- function formatLd(target, source, evalContext) {
363
- if (target.kind === 'reg8' && source.kind === 'imm') {
364
- return formatLdText(target.register, formatExpression(source.expression, evalContext, 'byte'));
365
- }
366
- if (target.kind === 'reg8' && source.kind === 'reg8') {
367
- return { text: `ld ${target.register}, ${source.register}` };
368
- }
369
- if (target.kind === 'reg8' && source.kind === 'reg-half-index') {
370
- return { text: `ld ${target.register}, ${source.register}` };
371
- }
372
- if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'special8') {
373
- return { text: `ld a, ${source.register}` };
374
- }
375
- if (target.kind === 'special8' && source.kind === 'reg8' && source.register === 'a') {
376
- return { text: `ld ${target.register}, a` };
377
- }
378
- if (target.kind === 'reg-index16' && source.kind === 'imm') {
379
- return formatLdText(target.register, formatExpression(source.expression, evalContext, 'word'));
380
- }
381
- if (target.kind === 'reg16' && source.kind === 'imm') {
382
- return formatLdText(target.register, formatExpression(source.expression, evalContext, 'word'));
383
- }
384
- if (target.kind === 'reg16' && source.kind === 'mem-abs') {
385
- return formatLdText(target.register, formatParenthesizedExpression(source.expression, evalContext, 'auto'));
386
- }
387
- if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'reg-indirect') {
388
- return { text: `ld a, (${source.register})` };
389
- }
390
- if (target.kind === 'reg-indirect' &&
391
- (target.register === 'bc' || target.register === 'de') &&
392
- source.kind === 'reg8' &&
393
- source.register === 'a') {
394
- return { text: `ld (${target.register}), a` };
395
- }
396
- if (target.kind === 'reg8' && source.kind === 'reg-indirect' && source.register === 'hl') {
397
- return { text: `ld ${target.register}, (hl)` };
398
- }
399
- if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'reg8') {
400
- return { text: `ld (hl), ${source.register}` };
401
- }
402
- if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'imm') {
403
- const value = formatExpression(source.expression, evalContext, 'byte');
404
- return value === undefined ? undefined : { text: `ld (hl), ${value}` };
405
- }
406
- if (target.kind === 'reg8' && source.kind === 'indexed') {
407
- const memory = formatIndexedMemory(source.register, source.displacement, evalContext);
408
- return memory === undefined ? undefined : { text: `ld ${target.register}, ${memory}` };
409
- }
410
- if (target.kind === 'indexed' && source.kind === 'reg8') {
411
- const memory = formatIndexedMemory(target.register, target.displacement, evalContext);
412
- return memory === undefined ? undefined : { text: `ld ${memory}, ${source.register}` };
413
- }
414
- if (target.kind === 'reg8' && source.kind === 'mem-abs') {
415
- return formatLdText(target.register, formatParenthesizedExpression(source.expression, evalContext, 'auto'));
416
- }
417
- if (target.kind === 'mem-abs' && source.kind === 'reg8') {
418
- const targetText = formatParenthesizedExpression(target.expression, evalContext, 'auto');
419
- return targetText === undefined
420
- ? undefined
421
- : { text: `ld ${targetText}, ${source.register}` };
422
- }
423
- if (target.kind === 'mem-abs' && source.kind === 'reg16') {
424
- const targetText = formatParenthesizedExpression(target.expression, evalContext, 'auto');
425
- return targetText === undefined
426
- ? undefined
427
- : { text: `ld ${targetText}, ${source.register}` };
428
- }
429
- if (target.kind === 'mem-abs' && source.kind === 'reg-index16') {
430
- const targetText = formatParenthesizedExpression(target.expression, evalContext, 'auto');
431
- return targetText === undefined
432
- ? undefined
433
- : { text: `ld ${targetText}, ${source.register}` };
434
- }
435
- return undefined;
436
- }
437
- function formatLdText(target, source) {
438
- return source === undefined ? undefined : { text: `ld ${target}, ${source}` };
439
- }
440
- function formatParenthesizedExpression(expression, evalContext, width) {
441
- const formatted = formatExpression(expression, evalContext, width);
442
- return formatted === undefined ? undefined : `(${formatted})`;
443
- }
444
210
  function withImplicitOrg(state, text, size) {
445
211
  if (text === undefined) {
446
212
  return undefined;
@@ -451,297 +217,6 @@ function withImplicitOrg(state, text, size) {
451
217
  state.emittedOrg = true;
452
218
  return { text: `ORG $00\n${text}`, size };
453
219
  }
454
- function formatBranch(mnemonic, expression, evalContext) {
455
- const target = formatExpression(expression, evalContext, 'word');
456
- return target === undefined ? undefined : { text: `${mnemonic} ${target}` };
457
- }
458
- function formatExpression(expression, evalContext, width) {
459
- const value = evaluateLoweredConstant(expression, evalContext);
460
- if (value !== undefined) {
461
- return formatLoweredNumber(value, width);
462
- }
463
- if (expression.kind === 'symbol') {
464
- return expression.name;
465
- }
466
- if (expression.kind === 'type-size') {
467
- const value = evaluateLoweredConstant(expression, evalContext);
468
- return value === undefined ? expression.typeExpr.name : formatLoweredNumber(value, width);
469
- }
470
- if (expression.kind === 'current-location') {
471
- return '$';
472
- }
473
- if (expression.kind === 'unary') {
474
- const inner = formatExpression(expression.expression, evalContext, width);
475
- if (inner === undefined) {
476
- return undefined;
477
- }
478
- switch (expression.operator) {
479
- case '+':
480
- return inner;
481
- case '-':
482
- return `-${inner}`;
483
- case '~': {
484
- const value = evaluateLoweredConstant(expression, evalContext);
485
- return value === undefined ? undefined : formatLoweredNumber(value, width);
486
- }
487
- }
488
- }
489
- if (expression.kind === 'binary') {
490
- const left = formatExpression(expression.left, evalContext, width);
491
- const right = formatExpression(expression.right, evalContext, width);
492
- if (left === undefined || right === undefined) {
493
- return undefined;
494
- }
495
- return `${left}${expression.operator}${right}`;
496
- }
497
- return undefined;
498
- }
499
- function evaluateLoweredConstant(expression, evalContext) {
500
- switch (expression.kind) {
501
- case 'number':
502
- return expression.value;
503
- case 'symbol':
504
- return evalContext.constants.get(expression.name);
505
- case 'type-size': {
506
- const constant = evalContext.constants.get(expression.typeExpr.name);
507
- if (constant !== undefined) {
508
- return constant;
509
- }
510
- return evaluateExpression(expression, {}, new Map(), silentSpan, [], {
511
- currentLocation: 0,
512
- layouts: evalContext.layouts,
513
- reportUnknown: false,
514
- });
515
- }
516
- case 'offset':
517
- case 'sizeof':
518
- return evaluateExpression(expression, {}, new Map(), silentSpan, [], {
519
- currentLocation: 0,
520
- layouts: evalContext.layouts,
521
- reportUnknown: false,
522
- });
523
- case 'byte-function': {
524
- const value = evaluateLoweredResolvedConstant(expression.expression, evalContext);
525
- if (value === undefined) {
526
- return undefined;
527
- }
528
- return expression.function === 'LSB' ? value & 0xff : (value >> 8) & 0xff;
529
- }
530
- case 'unary': {
531
- const value = evaluateLoweredConstant(expression.expression, evalContext);
532
- if (value === undefined) {
533
- return undefined;
534
- }
535
- switch (expression.operator) {
536
- case '+':
537
- return value;
538
- case '-':
539
- return -value;
540
- case '~':
541
- return ~value;
542
- }
543
- break;
544
- }
545
- case 'binary': {
546
- const left = evaluateLoweredConstant(expression.left, evalContext);
547
- const right = evaluateLoweredConstant(expression.right, evalContext);
548
- if (left === undefined || right === undefined) {
549
- return undefined;
550
- }
551
- switch (expression.operator) {
552
- case '+':
553
- return left + right;
554
- case '-':
555
- return left - right;
556
- case '*':
557
- return left * right;
558
- case '/':
559
- return right === 0 ? undefined : Math.trunc(left / right);
560
- case '%':
561
- return right === 0 ? undefined : left % right;
562
- case '&':
563
- return left & right;
564
- case '^':
565
- return left ^ right;
566
- case '|':
567
- return left | right;
568
- case '<<':
569
- return left << right;
570
- case '>>':
571
- return left >> right;
572
- }
573
- break;
574
- }
575
- default:
576
- return undefined;
577
- }
578
- }
579
- function evaluateLoweredResolvedConstant(expression, evalContext) {
580
- switch (expression.kind) {
581
- case 'symbol':
582
- return evalContext.symbols.get(expression.name);
583
- case 'unary': {
584
- const value = evaluateLoweredResolvedConstant(expression.expression, evalContext);
585
- if (value === undefined) {
586
- return undefined;
587
- }
588
- switch (expression.operator) {
589
- case '+':
590
- return value;
591
- case '-':
592
- return -value;
593
- case '~':
594
- return ~value;
595
- }
596
- break;
597
- }
598
- case 'binary': {
599
- const left = evaluateLoweredResolvedConstant(expression.left, evalContext);
600
- const right = evaluateLoweredResolvedConstant(expression.right, evalContext);
601
- if (left === undefined || right === undefined) {
602
- return undefined;
603
- }
604
- switch (expression.operator) {
605
- case '+':
606
- return left + right;
607
- case '-':
608
- return left - right;
609
- case '*':
610
- return left * right;
611
- case '/':
612
- return right === 0 ? undefined : Math.trunc(left / right);
613
- case '%':
614
- return right === 0 ? undefined : left % right;
615
- case '&':
616
- return left & right;
617
- case '^':
618
- return left ^ right;
619
- case '|':
620
- return left | right;
621
- case '<<':
622
- return left << right;
623
- case '>>':
624
- return left >> right;
625
- }
626
- break;
627
- }
628
- case 'byte-function': {
629
- const value = evaluateLoweredResolvedConstant(expression.expression, evalContext);
630
- if (value === undefined) {
631
- return undefined;
632
- }
633
- return expression.function === 'LSB' ? value & 0xff : (value >> 8) & 0xff;
634
- }
635
- default:
636
- return evaluateLoweredConstant(expression, evalContext);
637
- }
638
- }
639
- function formatLoweredNumber(value, width) {
640
- const normalized = value < 0 ? 0x10000 + (value & 0xffff) : value;
641
- const digits = normalized.toString(16).toUpperCase();
642
- const minWidth = width === 'word' || (width === 'auto' && normalized > 0xff) ? 4 : 2;
643
- return `$${digits.padStart(minWidth, '0')}`;
644
- }
645
- function formatRotateShift(instruction, evalContext) {
646
- const operand = formatBitOperand(instruction.operand, evalContext);
647
- if (operand === undefined) {
648
- return undefined;
649
- }
650
- const parts = [operand];
651
- if (instruction.destination) {
652
- parts.push(instruction.destination.register);
653
- }
654
- return { text: `${instruction.mnemonic} ${parts.join(', ')}` };
655
- }
656
- function formatBitOp(instruction, evalContext) {
657
- const bit = formatLoweredNumber(instruction.bit, 'byte');
658
- const operand = formatBitOperand(instruction.operand, evalContext);
659
- if (operand === undefined) {
660
- return undefined;
661
- }
662
- const parts = [bit, operand];
663
- if (instruction.destination) {
664
- parts.push(instruction.destination.register);
665
- }
666
- return { text: `${instruction.mnemonic} ${parts.join(', ')}` };
667
- }
668
- function formatBitOperand(operand, evalContext) {
669
- if (operand.kind === 'reg8') {
670
- return operand.register;
671
- }
672
- if (operand.kind === 'reg-indirect' && operand.register === 'hl') {
673
- return '(HL)';
674
- }
675
- if (operand.kind === 'indexed') {
676
- return formatIndexedMemory(operand.register, operand.displacement, evalContext);
677
- }
678
- return undefined;
679
- }
680
- function formatIndexedMemory(register, displacement, evalContext) {
681
- const value = evaluateLoweredConstant(displacement, evalContext);
682
- if (value === undefined) {
683
- return undefined;
684
- }
685
- const magnitude = formatLoweredNumber(Math.abs(value), 'byte');
686
- if (value === 0) {
687
- return `(${register}+$00)`;
688
- }
689
- if (value > 0) {
690
- return `(${register}+${magnitude})`;
691
- }
692
- return `(${register}-${magnitude})`;
693
- }
694
- function formatIn(instruction, evalContext) {
695
- const port = formatPort(instruction.port, evalContext);
696
- if (port === undefined) {
697
- return undefined;
698
- }
699
- const target = instruction.target?.register ?? 'a';
700
- return { text: `in ${target}, ${port}` };
701
- }
702
- function formatOut(instruction, evalContext) {
703
- const port = formatPort(instruction.port, evalContext);
704
- if (port === undefined) {
705
- return undefined;
706
- }
707
- const source = instruction.source.kind === 'zero' ? '0' : instruction.source.register;
708
- return { text: `out ${port}, ${source}` };
709
- }
710
- function formatPort(port, evalContext) {
711
- if (port.kind === 'c') {
712
- return '(c)';
713
- }
714
- const expression = formatExpression(port.expression, evalContext, 'byte');
715
- return expression === undefined ? undefined : `(${expression})`;
716
- }
717
- function formatIncDec(instruction, evalContext) {
718
- const operand = instruction.operand;
719
- if (operand.kind === 'reg8' || operand.kind === 'reg16') {
720
- return { text: `${instruction.mnemonic} ${operand.register}` };
721
- }
722
- if (operand.kind === 'reg-indirect' && operand.register === 'hl') {
723
- return { text: `${instruction.mnemonic} (HL)` };
724
- }
725
- if (operand.kind === 'indexed') {
726
- const memory = formatIndexedMemory(operand.register, operand.displacement, evalContext);
727
- return memory === undefined ? undefined : { text: `${instruction.mnemonic} ${memory}` };
728
- }
729
- return undefined;
730
- }
731
- function stringDirectiveBytes(directive, value) {
732
- const bytes = [...value].map((char) => char.codePointAt(0) ?? 0);
733
- switch (directive) {
734
- case 'cstr':
735
- return [...bytes, 0];
736
- case 'pstr':
737
- return [bytes.length & 0xff, ...bytes];
738
- case 'istr':
739
- if (bytes.length === 0) {
740
- return [];
741
- }
742
- return bytes.map((byte, index) => (index === bytes.length - 1 ? byte | 0x80 : byte));
743
- }
744
- }
745
220
  function describeItem(item) {
746
221
  if (item.kind === 'instruction') {
747
222
  return `instruction "${item.instruction.mnemonic}"`;