@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
@@ -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) {
@@ -72,52 +91,54 @@ function collectLayouts(items) {
72
91
  return layouts;
73
92
  }
74
93
  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;
94
+ const formatter = FORMATTERS[item.kind];
95
+ return formatter(item, evalContext, state);
96
+ }
97
+ function formatOrg(item, evalContext, state) {
98
+ const expression = formatExpression(item.expression, evalContext, 'word');
99
+ const address = evaluateLoweredConstant(item.expression, evalContext);
100
+ if (expression === undefined || address === undefined) {
101
+ return undefined;
120
102
  }
103
+ state.address = address;
104
+ state.emittedOrg = true;
105
+ return { text: `ORG ${expression}`, size: 0 };
106
+ }
107
+ function formatEqu(item, evalContext, state) {
108
+ const expression = formatExpression(item.expression, evalContext, 'auto');
109
+ return expression === undefined
110
+ ? undefined
111
+ : withImplicitOrg(state, `${item.name} EQU ${expression}`, 0);
112
+ }
113
+ function formatComment(item) {
114
+ return {
115
+ text: item.origin === 'user' ? `; ${item.text}` : `; AZM: ${item.text}`,
116
+ size: 0,
117
+ };
118
+ }
119
+ function formatLabel(item, _evalContext, state) {
120
+ return withImplicitOrg(state, `${item.name}:`, 0);
121
+ }
122
+ function formatDbItem(item, evalContext, state) {
123
+ return formatDb(item.values, evalContext, state);
124
+ }
125
+ function formatDwItem(item, evalContext, state) {
126
+ return formatDw(item.values, evalContext, state);
127
+ }
128
+ function formatDsItem(item, evalContext, state) {
129
+ return formatDs(item.size, item.fill, evalContext, state);
130
+ }
131
+ function formatAlignItem(item, evalContext, state) {
132
+ return formatAlign(item.alignment, evalContext, state);
133
+ }
134
+ function formatStringDataItem(item, _evalContext, state) {
135
+ return formatStringData(item.directive, item.value, state);
136
+ }
137
+ function formatInstructionItem(item, evalContext, state) {
138
+ return withImplicitOrg(state, formatInstruction(item.instruction, evalContext)?.text, instructionSize(item.instruction));
139
+ }
140
+ function formatIgnoredItem() {
141
+ return { text: '', size: 0 };
121
142
  }
122
143
  function formatDb(values, evalContext, state) {
123
144
  const parts = [];
@@ -182,265 +203,6 @@ function formatStringData(directive, value, state) {
182
203
  }
183
204
  return withImplicitOrg(state, `DB ${bytes.map((byte) => formatLoweredNumber(byte, 'byte')).join(', ')}`, bytes.length);
184
205
  }
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
206
  function withImplicitOrg(state, text, size) {
445
207
  if (text === undefined) {
446
208
  return undefined;
@@ -451,297 +213,6 @@ function withImplicitOrg(state, text, size) {
451
213
  state.emittedOrg = true;
452
214
  return { text: `ORG $00\n${text}`, size };
453
215
  }
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
216
  function describeItem(item) {
746
217
  if (item.kind === 'instruction') {
747
218
  return `instruction "${item.instruction.mnemonic}"`;