@jhlagado/azm 0.2.7 → 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 +2 -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
@@ -0,0 +1,272 @@
1
+ import { formatExpression, formatLoweredNumber, } from './asm80-expressions.js';
2
+ import { formatBitOp, formatIndexedMemory, formatLd, formatRotateShift, } from './asm80-instruction-operands.js';
3
+ const ZERO_OPERAND_MNEMONICS = new Set([
4
+ 'nop',
5
+ 'ret',
6
+ 'di',
7
+ 'ei',
8
+ 'scf',
9
+ 'ccf',
10
+ 'cpl',
11
+ 'daa',
12
+ 'exx',
13
+ 'halt',
14
+ 'rlca',
15
+ 'rrca',
16
+ 'rla',
17
+ 'rra',
18
+ 'neg',
19
+ 'rrd',
20
+ 'rld',
21
+ 'ldi',
22
+ 'ldir',
23
+ 'ldd',
24
+ 'lddr',
25
+ 'cpi',
26
+ 'cpir',
27
+ 'cpd',
28
+ 'cpdr',
29
+ 'ini',
30
+ 'inir',
31
+ 'ind',
32
+ 'indr',
33
+ 'outi',
34
+ 'otir',
35
+ 'outd',
36
+ 'otdr',
37
+ 'reti',
38
+ 'retn',
39
+ ]);
40
+ const BIT_MNEMONICS = new Set(['bit', 'res', 'set']);
41
+ const ROTATE_SHIFT_MNEMONICS = new Set([
42
+ 'rlc',
43
+ 'rrc',
44
+ 'rl',
45
+ 'rr',
46
+ 'sla',
47
+ 'sra',
48
+ 'sll',
49
+ 'sls',
50
+ 'srl',
51
+ ]);
52
+ const TARGETED_ALU_MNEMONICS = new Set(['add', 'adc', 'sbc']);
53
+ const ACCUMULATOR_ALU_MNEMONICS = new Set([
54
+ 'add',
55
+ 'adc',
56
+ 'sbc',
57
+ 'sub',
58
+ 'and',
59
+ 'or',
60
+ 'xor',
61
+ 'cp',
62
+ ]);
63
+ export function formatInstruction(instruction, evalContext) {
64
+ if (ZERO_OPERAND_MNEMONICS.has(instruction.mnemonic)) {
65
+ return { text: instruction.mnemonic };
66
+ }
67
+ return (formatLoadOrImmediateInstruction(instruction, evalContext) ??
68
+ formatAluInstruction(instruction, evalContext) ??
69
+ formatBitRotateInstruction(instruction, evalContext) ??
70
+ formatIoInstruction(instruction, evalContext) ??
71
+ formatSingleOperandInstruction(instruction, evalContext) ??
72
+ formatBranchStackReturnInstruction(instruction, evalContext));
73
+ }
74
+ function formatLoadOrImmediateInstruction(instruction, evalContext) {
75
+ switch (instruction.mnemonic) {
76
+ case 'ld-a-imm': {
77
+ const expression = formatExpression(instruction.expression, evalContext, 'byte');
78
+ if (expression === undefined) {
79
+ return undefined;
80
+ }
81
+ return {
82
+ text: `ld a, ${expression}`,
83
+ };
84
+ }
85
+ case 'ld':
86
+ return formatLd(instruction.target, instruction.source, evalContext);
87
+ case 'im':
88
+ return { text: `im ${formatLoweredNumber(instruction.mode, 'byte')}` };
89
+ case 'rst':
90
+ return { text: `rst ${formatLoweredNumber(instruction.vector, 'byte')}` };
91
+ default:
92
+ return undefined;
93
+ }
94
+ }
95
+ function formatAluInstruction(instruction, evalContext) {
96
+ if (isTargetedAluInstruction(instruction)) {
97
+ return formatReg16Alu(instruction.mnemonic, instruction.target, instruction.source);
98
+ }
99
+ if (isAccumulatorAluInstruction(instruction)) {
100
+ return formatAlu(instruction.mnemonic, instruction.source, evalContext);
101
+ }
102
+ return undefined;
103
+ }
104
+ function isTargetedAluInstruction(instruction) {
105
+ return TARGETED_ALU_MNEMONICS.has(instruction.mnemonic) && 'target' in instruction;
106
+ }
107
+ function isAccumulatorAluInstruction(instruction) {
108
+ return ACCUMULATOR_ALU_MNEMONICS.has(instruction.mnemonic) && 'source' in instruction;
109
+ }
110
+ function formatBitRotateInstruction(instruction, evalContext) {
111
+ if (BIT_MNEMONICS.has(instruction.mnemonic)) {
112
+ return formatBitOp(instruction, evalContext);
113
+ }
114
+ if (ROTATE_SHIFT_MNEMONICS.has(instruction.mnemonic)) {
115
+ return formatRotateShift(instruction, evalContext);
116
+ }
117
+ return undefined;
118
+ }
119
+ function formatIoInstruction(instruction, evalContext) {
120
+ switch (instruction.mnemonic) {
121
+ case 'in':
122
+ return formatIn(instruction, evalContext);
123
+ case 'out':
124
+ return formatOut(instruction, evalContext);
125
+ default:
126
+ return undefined;
127
+ }
128
+ }
129
+ function formatSingleOperandInstruction(instruction, evalContext) {
130
+ switch (instruction.mnemonic) {
131
+ case 'inc':
132
+ case 'dec':
133
+ return formatIncDec(instruction, evalContext);
134
+ case 'ex':
135
+ return formatEx(instruction.form);
136
+ default:
137
+ return undefined;
138
+ }
139
+ }
140
+ function formatBranchStackReturnInstruction(instruction, evalContext) {
141
+ return (formatBranchInstruction(instruction, evalContext) ??
142
+ formatStackOrReturnInstruction(instruction));
143
+ }
144
+ function formatBranchInstruction(instruction, evalContext) {
145
+ switch (instruction.mnemonic) {
146
+ case 'jp':
147
+ return formatBranch('jp', instruction.expression, evalContext);
148
+ case 'jp-cc':
149
+ return formatBranch(`jp ${instruction.condition},`, instruction.expression, evalContext);
150
+ case 'jp-indirect':
151
+ return { text: `jp (${instruction.register})` };
152
+ case 'jr':
153
+ return formatBranch('jr', instruction.expression, evalContext);
154
+ case 'jr-cc':
155
+ return formatBranch(`jr ${instruction.condition},`, instruction.expression, evalContext);
156
+ case 'call':
157
+ return formatBranch('call', instruction.expression, evalContext);
158
+ case 'call-cc':
159
+ return formatBranch(`call ${instruction.condition},`, instruction.expression, evalContext);
160
+ case 'djnz':
161
+ return formatBranch('djnz', instruction.expression, evalContext);
162
+ default:
163
+ return undefined;
164
+ }
165
+ }
166
+ function formatStackOrReturnInstruction(instruction) {
167
+ switch (instruction.mnemonic) {
168
+ case 'push':
169
+ case 'pop':
170
+ return { text: `${instruction.mnemonic} ${instruction.register}` };
171
+ case 'ret-cc':
172
+ return { text: `ret ${instruction.condition}` };
173
+ default:
174
+ return undefined;
175
+ }
176
+ }
177
+ function formatAlu(mnemonic, source, evalContext) {
178
+ const operand = formatAluOperand(source, evalContext);
179
+ if (operand === undefined) {
180
+ return undefined;
181
+ }
182
+ if (mnemonic === 'add' || mnemonic === 'adc' || mnemonic === 'sbc') {
183
+ return { text: `${mnemonic} a, ${operand}` };
184
+ }
185
+ if (mnemonic === 'xor' && source.kind === 'reg8' && source.register === 'a') {
186
+ return { text: 'xor a' };
187
+ }
188
+ return { text: `${mnemonic} ${operand}` };
189
+ }
190
+ function formatAluOperand(source, evalContext) {
191
+ if (source.kind === 'reg8' || source.kind === 'reg-half-index') {
192
+ return source.register;
193
+ }
194
+ if (source.kind === 'reg-indirect' && source.register === 'hl') {
195
+ return '(HL)';
196
+ }
197
+ if (source.kind === 'imm') {
198
+ return formatExpression(source.expression, evalContext, 'byte');
199
+ }
200
+ return undefined;
201
+ }
202
+ function formatReg16Alu(mnemonic, target, source) {
203
+ const targetText = formatReg16PairOperand(target);
204
+ const sourceText = formatReg16PairOperand(source);
205
+ return targetText === undefined || sourceText === undefined
206
+ ? undefined
207
+ : { text: `${mnemonic} ${targetText}, ${sourceText}` };
208
+ }
209
+ function formatReg16PairOperand(operand) {
210
+ if (operand.kind === 'reg16') {
211
+ return operand.register;
212
+ }
213
+ if (operand.kind === 'reg-index16') {
214
+ return operand.register;
215
+ }
216
+ return undefined;
217
+ }
218
+ function formatEx(form) {
219
+ switch (form) {
220
+ case 'af-af':
221
+ return { text: "ex af, af'" };
222
+ case 'de-hl':
223
+ return { text: 'ex de, hl' };
224
+ case 'sp-hl':
225
+ return { text: 'ex (sp), hl' };
226
+ case 'sp-ix':
227
+ return { text: 'ex (SP), ix' };
228
+ case 'sp-iy':
229
+ return { text: 'ex (SP), iy' };
230
+ }
231
+ }
232
+ function formatBranch(mnemonic, expression, evalContext) {
233
+ const target = formatExpression(expression, evalContext, 'word');
234
+ return target === undefined ? undefined : { text: `${mnemonic} ${target}` };
235
+ }
236
+ function formatIn(instruction, evalContext) {
237
+ const port = formatPort(instruction.port, evalContext);
238
+ if (port === undefined) {
239
+ return undefined;
240
+ }
241
+ const target = instruction.target?.register ?? 'a';
242
+ return { text: `in ${target}, ${port}` };
243
+ }
244
+ function formatOut(instruction, evalContext) {
245
+ const port = formatPort(instruction.port, evalContext);
246
+ if (port === undefined) {
247
+ return undefined;
248
+ }
249
+ const source = instruction.source.kind === 'zero' ? '0' : instruction.source.register;
250
+ return { text: `out ${port}, ${source}` };
251
+ }
252
+ function formatPort(port, evalContext) {
253
+ if (port.kind === 'c') {
254
+ return '(c)';
255
+ }
256
+ const expression = formatExpression(port.expression, evalContext, 'byte');
257
+ return expression === undefined ? undefined : `(${expression})`;
258
+ }
259
+ function formatIncDec(instruction, evalContext) {
260
+ const operand = instruction.operand;
261
+ if (operand.kind === 'reg8' || operand.kind === 'reg16') {
262
+ return { text: `${instruction.mnemonic} ${operand.register}` };
263
+ }
264
+ if (operand.kind === 'reg-indirect' && operand.register === 'hl') {
265
+ return { text: `${instruction.mnemonic} (HL)` };
266
+ }
267
+ if (operand.kind === 'indexed') {
268
+ const memory = formatIndexedMemory(operand.register, operand.displacement, evalContext);
269
+ return memory === undefined ? undefined : { text: `${instruction.mnemonic} ${memory}` };
270
+ }
271
+ return undefined;
272
+ }
@@ -0,0 +1,10 @@
1
+ import type { Expression } from '../model/expression.js';
2
+ import type { Z80IndexRegister16, Z80Instruction } from '../z80/instruction.js';
3
+ import { type LoweredEvalContext } from './asm80-expressions.js';
4
+ export type LdOperand = Extract<Z80Instruction, {
5
+ readonly mnemonic: 'ld';
6
+ }>['target'];
7
+ export declare function formatLd(target: LdOperand, source: LdOperand, evalContext: LoweredEvalContext): {
8
+ readonly text: string;
9
+ } | undefined;
10
+ export declare function formatIndexedMemory(register: Z80IndexRegister16, displacement: Expression, evalContext: LoweredEvalContext): string | undefined;
@@ -0,0 +1,157 @@
1
+ import { evaluateLoweredConstant, formatExpression, formatLoweredNumber, } from './asm80-expressions.js';
2
+ export function formatLd(target, source, evalContext) {
3
+ return (formatLdRegisterForm(target, source) ??
4
+ formatLdImmediateOrAbsoluteLoad(target, source, evalContext) ??
5
+ formatLdIndirectForm(target, source, evalContext) ??
6
+ formatLdAbsoluteStore(target, source, evalContext));
7
+ }
8
+ export function formatIndexedMemory(register, displacement, evalContext) {
9
+ const value = evaluateLoweredConstant(displacement, evalContext);
10
+ if (value === undefined) {
11
+ return undefined;
12
+ }
13
+ const magnitude = formatLoweredNumber(Math.abs(value), 'byte');
14
+ if (value === 0) {
15
+ return `(${register}+$00)`;
16
+ }
17
+ if (value > 0) {
18
+ return `(${register}+${magnitude})`;
19
+ }
20
+ return `(${register}-${magnitude})`;
21
+ }
22
+ function formatLdRegisterForm(target, source) {
23
+ return (formatLdReg8FromReg8(target, source) ??
24
+ formatLdReg8FromHalfIndex(target, source) ??
25
+ formatLdAFromSpecial8(target, source) ??
26
+ formatLdSpecial8FromA(target, source));
27
+ }
28
+ function formatLdReg8FromReg8(target, source) {
29
+ if (target.kind === 'reg8' && source.kind === 'reg8') {
30
+ return { text: `ld ${target.register}, ${source.register}` };
31
+ }
32
+ return undefined;
33
+ }
34
+ function formatLdReg8FromHalfIndex(target, source) {
35
+ if (target.kind === 'reg8' && source.kind === 'reg-half-index') {
36
+ return { text: `ld ${target.register}, ${source.register}` };
37
+ }
38
+ return undefined;
39
+ }
40
+ function formatLdAFromSpecial8(target, source) {
41
+ if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'special8') {
42
+ return { text: `ld a, ${source.register}` };
43
+ }
44
+ return undefined;
45
+ }
46
+ function formatLdSpecial8FromA(target, source) {
47
+ if (target.kind === 'special8' && source.kind === 'reg8' && source.register === 'a') {
48
+ return { text: `ld ${target.register}, a` };
49
+ }
50
+ return undefined;
51
+ }
52
+ function formatLdImmediateOrAbsoluteLoad(target, source, evalContext) {
53
+ return (formatLdReg8Immediate(target, source, evalContext) ??
54
+ formatLdReg16Immediate(target, source, evalContext) ??
55
+ formatLdIndex16Immediate(target, source, evalContext) ??
56
+ formatLdReg16AbsoluteLoad(target, source, evalContext) ??
57
+ formatLdReg8AbsoluteLoad(target, source, evalContext));
58
+ }
59
+ function formatLdReg8Immediate(target, source, evalContext) {
60
+ if (target.kind === 'reg8' && source.kind === 'imm') {
61
+ return formatLdText(target.register, formatExpression(source.expression, evalContext, 'byte'));
62
+ }
63
+ return undefined;
64
+ }
65
+ function formatLdReg16Immediate(target, source, evalContext) {
66
+ if (target.kind === 'reg16' && source.kind === 'imm') {
67
+ return formatLdText(target.register, formatExpression(source.expression, evalContext, 'word'));
68
+ }
69
+ return undefined;
70
+ }
71
+ function formatLdIndex16Immediate(target, source, evalContext) {
72
+ if (target.kind === 'reg-index16' && source.kind === 'imm') {
73
+ return formatLdText(target.register, formatExpression(source.expression, evalContext, 'word'));
74
+ }
75
+ return undefined;
76
+ }
77
+ function formatLdReg16AbsoluteLoad(target, source, evalContext) {
78
+ if (target.kind === 'reg16' && source.kind === 'mem-abs') {
79
+ return formatLdText(target.register, formatParenthesizedExpression(source.expression, evalContext, 'auto'));
80
+ }
81
+ return undefined;
82
+ }
83
+ function formatLdReg8AbsoluteLoad(target, source, evalContext) {
84
+ if (target.kind === 'reg8' && source.kind === 'mem-abs') {
85
+ return formatLdText(target.register, formatParenthesizedExpression(source.expression, evalContext, 'auto'));
86
+ }
87
+ return undefined;
88
+ }
89
+ function formatLdIndirectForm(target, source, evalContext) {
90
+ return (formatLdRegisterIndirect(target, source, evalContext) ??
91
+ formatLdIndexed(target, source, evalContext));
92
+ }
93
+ function formatLdRegisterIndirect(target, source, evalContext) {
94
+ return (formatLdAFromRegisterIndirect(target, source) ??
95
+ formatLdAStoreToBcDeIndirect(target, source) ??
96
+ formatLdFromHlIndirect(target, source) ??
97
+ formatLdToHlIndirect(target, source, evalContext));
98
+ }
99
+ function formatLdAFromRegisterIndirect(target, source) {
100
+ if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'reg-indirect') {
101
+ return { text: `ld a, (${source.register})` };
102
+ }
103
+ return undefined;
104
+ }
105
+ function formatLdAStoreToBcDeIndirect(target, source) {
106
+ if (target.kind === 'reg-indirect' && isBcDeIndirectAStore(target.register, source)) {
107
+ return { text: `ld (${target.register}), a` };
108
+ }
109
+ return undefined;
110
+ }
111
+ function formatLdFromHlIndirect(target, source) {
112
+ if (target.kind === 'reg8' && source.kind === 'reg-indirect' && source.register === 'hl') {
113
+ return { text: `ld ${target.register}, (hl)` };
114
+ }
115
+ return undefined;
116
+ }
117
+ function formatLdToHlIndirect(target, source, evalContext) {
118
+ if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'reg8') {
119
+ return { text: `ld (hl), ${source.register}` };
120
+ }
121
+ if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'imm') {
122
+ const value = formatExpression(source.expression, evalContext, 'byte');
123
+ return value === undefined ? undefined : { text: `ld (hl), ${value}` };
124
+ }
125
+ return undefined;
126
+ }
127
+ function formatLdIndexed(target, source, evalContext) {
128
+ if (target.kind === 'reg8' && source.kind === 'indexed') {
129
+ const memory = formatIndexedMemory(source.register, source.displacement, evalContext);
130
+ return memory === undefined ? undefined : { text: `ld ${target.register}, ${memory}` };
131
+ }
132
+ if (target.kind === 'indexed' && source.kind === 'reg8') {
133
+ const memory = formatIndexedMemory(target.register, target.displacement, evalContext);
134
+ return memory === undefined ? undefined : { text: `ld ${memory}, ${source.register}` };
135
+ }
136
+ return undefined;
137
+ }
138
+ function isBcDeIndirectAStore(register, source) {
139
+ return (register === 'bc' || register === 'de') && source.kind === 'reg8' && source.register === 'a';
140
+ }
141
+ function formatLdAbsoluteStore(target, source, evalContext) {
142
+ if (target.kind !== 'mem-abs') {
143
+ return undefined;
144
+ }
145
+ if (source.kind !== 'reg8' && source.kind !== 'reg16' && source.kind !== 'reg-index16') {
146
+ return undefined;
147
+ }
148
+ const targetText = formatParenthesizedExpression(target.expression, evalContext, 'auto');
149
+ return targetText === undefined ? undefined : { text: `ld ${targetText}, ${source.register}` };
150
+ }
151
+ function formatLdText(target, source) {
152
+ return source === undefined ? undefined : { text: `ld ${target}, ${source}` };
153
+ }
154
+ function formatParenthesizedExpression(expression, evalContext, width) {
155
+ const formatted = formatExpression(expression, evalContext, width);
156
+ return formatted === undefined ? undefined : `(${formatted})`;
157
+ }
@@ -0,0 +1,4 @@
1
+ import type { SourceItem } from '../model/source-item.js';
2
+ export declare function stringDirectiveBytes(directive: Extract<SourceItem, {
3
+ readonly kind: 'string-data';
4
+ }>['directive'], value: string): number[];
@@ -0,0 +1,14 @@
1
+ export function stringDirectiveBytes(directive, value) {
2
+ const bytes = [...value].map((char) => char.codePointAt(0) ?? 0);
3
+ switch (directive) {
4
+ case 'cstr':
5
+ return [...bytes, 0];
6
+ case 'pstr':
7
+ return [bytes.length & 0xff, ...bytes];
8
+ case 'istr':
9
+ if (bytes.length === 0) {
10
+ return [];
11
+ }
12
+ return bytes.map((byte, index) => (index === bytes.length - 1 ? byte | 0x80 : byte));
13
+ }
14
+ }
@@ -0,0 +1,10 @@
1
+ import type { D8mFileEntry, D8mSymbol, EmittedSourceSegment } from './types.js';
2
+ type AddressRange = {
3
+ start: number;
4
+ end: number;
5
+ };
6
+ export declare function buildD8mFiles(symbols: readonly D8mSymbol[], sourceSegments: readonly EmittedSourceSegment[], segments: readonly AddressRange[], fileList: readonly string[]): {
7
+ files: Record<string, D8mFileEntry>;
8
+ sortedSymbols: D8mSymbol[];
9
+ };
10
+ export {};
@@ -0,0 +1,103 @@
1
+ import { compareFileSymbol, compareSegment, compareSymbol, rangesOverlap, } from './d8-helpers.js';
2
+ function hasOverlappingSourceSegment(sourceSegmentsByFile, file, range) {
3
+ return (sourceSegmentsByFile.get(file) ?? []).some((segment) => rangesOverlap({ start: segment.start, end: segment.end }, range));
4
+ }
5
+ function sourceSegmentsByFile(sourceSegments) {
6
+ const byFile = new Map();
7
+ for (const segment of sourceSegments) {
8
+ const segments = byFile.get(segment.file);
9
+ if (segments) {
10
+ segments.push(segment);
11
+ }
12
+ else {
13
+ byFile.set(segment.file, [segment]);
14
+ }
15
+ }
16
+ return byFile;
17
+ }
18
+ function symbolRangesByFile(symbols) {
19
+ const byFile = new Map();
20
+ for (const symbol of symbols) {
21
+ if (symbol.kind === 'constant' || symbol.file === undefined)
22
+ continue;
23
+ if (symbol.address === undefined)
24
+ continue;
25
+ const size = symbol.size !== undefined && symbol.size > 0 ? symbol.size : 1;
26
+ const ranges = byFile.get(symbol.file) ?? [];
27
+ ranges.push({ start: symbol.address, end: Math.min(0x10000, symbol.address + size) });
28
+ byFile.set(symbol.file, ranges);
29
+ }
30
+ return byFile;
31
+ }
32
+ function ensureEntry(entries, file) {
33
+ let entry = entries.get(file);
34
+ if (!entry) {
35
+ entry = { symbols: [], segments: [] };
36
+ entries.set(file, entry);
37
+ }
38
+ return entry;
39
+ }
40
+ function addFileSymbols(entries, symbols) {
41
+ const sortedSymbols = [...symbols].sort(compareSymbol);
42
+ for (const symbol of sortedSymbols) {
43
+ const entry = ensureEntry(entries, symbol.file ?? '');
44
+ const symbolWithoutFile = { ...symbol };
45
+ delete symbolWithoutFile.file;
46
+ entry.symbols.push(symbolWithoutFile);
47
+ }
48
+ return sortedSymbols;
49
+ }
50
+ function addSourceSegments(entries, sourceSegments) {
51
+ for (const segment of sourceSegments) {
52
+ ensureEntry(entries, segment.file).segments.push({
53
+ start: segment.start,
54
+ end: segment.end,
55
+ line: segment.line,
56
+ lstLine: segment.line,
57
+ kind: segment.kind,
58
+ confidence: segment.confidence,
59
+ });
60
+ }
61
+ }
62
+ function addFallbackSegments(entries, segments, symbols, sourceSegments, fileList) {
63
+ const sourceByFile = sourceSegmentsByFile(sourceSegments);
64
+ const rangesByFile = symbolRangesByFile(symbols);
65
+ for (const segment of segments) {
66
+ const targetFiles = [...rangesByFile.entries()]
67
+ .filter(([, ranges]) => ranges.some((range) => rangesOverlap(range, segment)))
68
+ .map(([file]) => file)
69
+ .sort((a, b) => a.localeCompare(b));
70
+ const targets = targetFiles.length > 0 ? targetFiles : [fileList[0] ?? ''];
71
+ for (const target of targets) {
72
+ if (hasOverlappingSourceSegment(sourceByFile, target, segment))
73
+ continue;
74
+ ensureEntry(entries, target).segments.push({
75
+ start: segment.start,
76
+ end: segment.end,
77
+ lstLine: 1,
78
+ kind: 'unknown',
79
+ confidence: 'low',
80
+ });
81
+ }
82
+ }
83
+ }
84
+ export function buildD8mFiles(symbols, sourceSegments, segments, fileList) {
85
+ const entries = new Map();
86
+ const sortedSymbols = addFileSymbols(entries, symbols);
87
+ addSourceSegments(entries, sourceSegments);
88
+ addFallbackSegments(entries, segments, sortedSymbols, sourceSegments, fileList);
89
+ for (const entry of entries.values()) {
90
+ entry.symbols.sort(compareFileSymbol);
91
+ entry.segments.sort(compareSegment);
92
+ }
93
+ const files = Object.fromEntries([...entries.entries()]
94
+ .sort(([a], [b]) => a.localeCompare(b))
95
+ .map(([path, fileEntry]) => [
96
+ path,
97
+ {
98
+ ...(fileEntry.segments.length > 0 ? { segments: fileEntry.segments } : {}),
99
+ ...(fileEntry.symbols.length > 0 ? { symbols: fileEntry.symbols } : {}),
100
+ },
101
+ ]));
102
+ return { files, sortedSymbols };
103
+ }
@@ -0,0 +1,21 @@
1
+ import type { D8mFileSymbol, D8mSegment, D8mSymbol, EmittedSourceSegment, SymbolEntry, WriteD8mOptions } from './types.js';
2
+ export declare function toD8mSymbol(symbol: SymbolEntry, rootDir?: string): D8mSymbol;
3
+ export declare function compareSymbol(a: D8mSymbol, b: D8mSymbol): number;
4
+ export declare function compareFileSymbol(a: D8mFileSymbol, b: D8mFileSymbol): number;
5
+ export declare function compareSegment(a: D8mSegment, b: D8mSegment): number;
6
+ export declare function rangesOverlap(a: {
7
+ start: number;
8
+ end: number;
9
+ }, b: {
10
+ start: number;
11
+ end: number;
12
+ }): boolean;
13
+ export declare function normalizeInputs(inputs: NonNullable<WriteD8mOptions['inputs']>, rootDir?: string): {
14
+ entry?: string;
15
+ hex?: string;
16
+ bin?: string;
17
+ } | undefined;
18
+ export declare function normalizeSourceSegments(sourceSegments: readonly EmittedSourceSegment[], writtenSegments: readonly {
19
+ readonly start: number;
20
+ readonly end: number;
21
+ }[], rootDir?: string): EmittedSourceSegment[];