@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.
- package/README.md +170 -69
- package/dist/src/api-artifacts.d.ts +20 -0
- package/dist/src/api-artifacts.js +165 -0
- package/dist/src/api-compile.d.ts +8 -2
- package/dist/src/api-compile.js +31 -230
- package/dist/src/api-register-contracts.d.ts +9 -0
- package/dist/src/api-register-contracts.js +77 -0
- package/dist/src/api-tooling.d.ts +2 -2
- package/dist/src/api-tooling.js +1 -1
- package/dist/src/assembly/address-planning.d.ts +1 -2
- package/dist/src/assembly/address-planning.js +119 -218
- package/dist/src/assembly/address-symbols.d.ts +12 -0
- package/dist/src/assembly/address-symbols.js +118 -0
- package/dist/src/assembly/fixup-emission.js +30 -48
- package/dist/src/assembly/program-emission.js +163 -164
- package/dist/src/cli/artifact-files.d.ts +15 -0
- package/dist/src/cli/artifact-files.js +86 -0
- package/dist/src/cli/parse-args.d.ts +6 -5
- package/dist/src/cli/parse-args.js +162 -136
- package/dist/src/cli/run.js +4 -1
- package/dist/src/cli/usage.d.ts +1 -0
- package/dist/src/cli/usage.js +33 -0
- package/dist/src/cli/write-artifacts.js +18 -91
- package/dist/src/core/compile.js +51 -274
- package/dist/src/core/conditional-assembly.d.ts +6 -0
- package/dist/src/core/conditional-assembly.js +181 -0
- package/dist/src/expansion/op-constant-expression.d.ts +3 -0
- package/dist/src/expansion/op-constant-expression.js +52 -0
- package/dist/src/expansion/op-expand-selected.d.ts +5 -0
- package/dist/src/expansion/op-expand-selected.js +143 -0
- package/dist/src/expansion/op-expansion.d.ts +5 -53
- package/dist/src/expansion/op-expansion.js +85 -815
- package/dist/src/expansion/op-instruction-instantiation.d.ts +3 -0
- package/dist/src/expansion/op-instruction-instantiation.js +194 -0
- package/dist/src/expansion/op-local-labels.d.ts +8 -0
- package/dist/src/expansion/op-local-labels.js +166 -0
- package/dist/src/expansion/op-operand-splitting.d.ts +1 -0
- package/dist/src/expansion/op-operand-splitting.js +44 -0
- package/dist/src/expansion/op-operands.d.ts +53 -0
- package/dist/src/expansion/op-operands.js +66 -0
- package/dist/src/expansion/op-selection.d.ts +18 -0
- package/dist/src/expansion/op-selection.js +172 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/model/diagnostic.d.ts +4 -0
- package/dist/src/model/diagnostic.js +4 -0
- package/dist/src/outputs/asm80-expression-evaluation.d.ts +10 -0
- package/dist/src/outputs/asm80-expression-evaluation.js +75 -0
- package/dist/src/outputs/asm80-expressions.d.ts +5 -0
- package/dist/src/outputs/asm80-expressions.js +47 -0
- package/dist/src/outputs/asm80-instruction-operands.d.ts +16 -0
- package/dist/src/outputs/asm80-instruction-operands.js +38 -0
- package/dist/src/outputs/asm80-instructions.d.ts +5 -0
- package/dist/src/outputs/asm80-instructions.js +272 -0
- package/dist/src/outputs/asm80-ld-operands.d.ts +10 -0
- package/dist/src/outputs/asm80-ld-operands.js +157 -0
- package/dist/src/outputs/asm80-strings.d.ts +4 -0
- package/dist/src/outputs/asm80-strings.js +14 -0
- package/dist/src/outputs/d8-files.d.ts +10 -0
- package/dist/src/outputs/d8-files.js +103 -0
- package/dist/src/outputs/d8-helpers.d.ts +21 -0
- package/dist/src/outputs/d8-helpers.js +136 -0
- package/dist/src/outputs/hex.js +26 -18
- package/dist/src/outputs/types.d.ts +16 -10
- package/dist/src/outputs/write-asm80.js +68 -597
- package/dist/src/outputs/write-d8.js +6 -216
- package/dist/src/register-contracts/accept-output.d.ts +2 -0
- package/dist/src/register-contracts/analyze-helpers.d.ts +29 -0
- package/dist/src/register-contracts/analyze-helpers.js +162 -0
- package/dist/src/{register-care → register-contracts}/analyze.d.ts +6 -6
- package/dist/src/register-contracts/analyze.js +73 -0
- package/dist/src/register-contracts/annotate.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/annotate.js +3 -3
- package/dist/src/register-contracts/annotations.d.ts +8 -0
- package/dist/src/{register-care → register-contracts}/annotations.js +3 -3
- package/dist/src/register-contracts/boundaryHints.d.ts +3 -0
- package/dist/src/register-contracts/boundaryHints.js +24 -0
- package/dist/src/register-contracts/carriers.d.ts +2 -0
- package/dist/src/register-contracts/constants.d.ts +4 -0
- package/dist/src/register-contracts/constants.js +51 -0
- package/dist/src/register-contracts/controlFlow.d.ts +5 -0
- package/dist/src/register-contracts/controlFlow.js +55 -0
- package/dist/src/register-contracts/fix.d.ts +11 -0
- package/dist/src/{register-care → register-contracts}/fix.js +47 -30
- package/dist/src/register-contracts/instruction-head.d.ts +2 -0
- package/dist/src/register-contracts/instruction-head.js +3 -0
- package/dist/src/register-contracts/instruction-operands.d.ts +3 -0
- package/dist/src/register-contracts/instruction-operands.js +101 -0
- package/dist/src/register-contracts/instruction-predicates.d.ts +6 -0
- package/dist/src/register-contracts/instruction-predicates.js +44 -0
- package/dist/src/register-contracts/interfaceContracts.d.ts +2 -0
- package/dist/src/register-contracts/interfaceContracts.js +68 -0
- package/dist/src/register-contracts/liveness.d.ts +3 -0
- package/dist/src/{register-care → register-contracts}/liveness.js +111 -79
- package/dist/src/register-contracts/operand-register-name.d.ts +2 -0
- package/dist/src/register-contracts/operand-register-name.js +13 -0
- package/dist/src/{register-care → register-contracts}/profiles.d.ts +5 -5
- package/dist/src/{register-care → register-contracts}/profiles.js +13 -2
- package/dist/src/register-contracts/programModel-boundaries.d.ts +6 -0
- package/dist/src/register-contracts/programModel-boundaries.js +64 -0
- package/dist/src/register-contracts/programModel-routines.d.ts +7 -0
- package/dist/src/register-contracts/programModel-routines.js +128 -0
- package/dist/src/register-contracts/programModel.d.ts +3 -0
- package/dist/src/register-contracts/programModel.js +14 -0
- package/dist/src/register-contracts/report.d.ts +5 -0
- package/dist/src/{register-care → register-contracts}/report.js +34 -17
- package/dist/src/register-contracts/routine-summaries.d.ts +6 -0
- package/dist/src/{register-care → register-contracts}/routine-summaries.js +11 -1
- package/dist/src/register-contracts/smartCommentBlocks.d.ts +5 -0
- package/dist/src/register-contracts/smartCommentBlocks.js +30 -0
- package/dist/src/register-contracts/smartCommentParsing.d.ts +3 -0
- package/dist/src/register-contracts/smartCommentParsing.js +80 -0
- package/dist/src/register-contracts/smartComments.d.ts +5 -0
- package/dist/src/register-contracts/smartComments.js +92 -0
- package/dist/src/register-contracts/summaries.d.ts +12 -0
- package/dist/src/{register-care → register-contracts}/summaries.js +7 -7
- package/dist/src/register-contracts/summary-boundary.d.ts +2 -0
- package/dist/src/register-contracts/summary-boundary.js +40 -0
- package/dist/src/register-contracts/summary-contract.d.ts +2 -0
- package/dist/src/register-contracts/summary-contract.js +45 -0
- package/dist/src/register-contracts/summary-result.d.ts +7 -0
- package/dist/src/register-contracts/summary-result.js +122 -0
- package/dist/src/register-contracts/summary-state.d.ts +23 -0
- package/dist/src/register-contracts/summary-state.js +88 -0
- package/dist/src/register-contracts/summary-token-transfer.d.ts +3 -0
- package/dist/src/register-contracts/summary-token-transfer.js +67 -0
- package/dist/src/register-contracts/summary.d.ts +3 -0
- package/dist/src/register-contracts/summary.js +266 -0
- package/dist/src/register-contracts/tooling.d.ts +57 -0
- package/dist/src/{register-care → register-contracts}/tooling.js +8 -6
- package/dist/src/register-contracts/types.d.ts +188 -0
- package/dist/src/semantics/binary-operators.d.ts +2 -0
- package/dist/src/semantics/binary-operators.js +15 -0
- package/dist/src/semantics/byte-functions.d.ts +2 -0
- package/dist/src/semantics/byte-functions.js +7 -0
- package/dist/src/semantics/constant-operator-types.d.ts +10 -0
- package/dist/src/semantics/constant-operator-types.js +1 -0
- package/dist/src/semantics/constant-operators.d.ts +3 -0
- package/dist/src/semantics/constant-operators.js +3 -0
- package/dist/src/semantics/diagnostics.d.ts +3 -0
- package/dist/src/semantics/diagnostics.js +10 -0
- package/dist/src/semantics/expression-evaluation.d.ts +11 -19
- package/dist/src/semantics/expression-evaluation.js +22 -334
- package/dist/src/semantics/layout-evaluation.d.ts +23 -0
- package/dist/src/semantics/layout-evaluation.js +202 -0
- package/dist/src/semantics/layout-format.d.ts +5 -0
- package/dist/src/semantics/layout-format.js +31 -0
- package/dist/src/semantics/layout-path.d.ts +24 -0
- package/dist/src/semantics/layout-path.js +58 -0
- package/dist/src/semantics/unary-operators.d.ts +2 -0
- package/dist/src/semantics/unary-operators.js +8 -0
- package/dist/src/source/line-comment-scanner.d.ts +1 -0
- package/dist/src/source/line-comment-scanner.js +51 -0
- package/dist/src/source/strip-line-comment.js +8 -44
- package/dist/src/syntax/directive-aliases.js +36 -22
- package/dist/src/syntax/expression-tokenizer.d.ts +30 -0
- package/dist/src/syntax/expression-tokenizer.js +310 -0
- package/dist/src/syntax/parse-directive-statement.d.ts +14 -0
- package/dist/src/syntax/parse-directive-statement.js +307 -0
- package/dist/src/syntax/parse-expression.d.ts +2 -2
- package/dist/src/syntax/parse-expression.js +7 -568
- package/dist/src/syntax/parse-layout-declarations.d.ts +9 -0
- package/dist/src/syntax/parse-layout-declarations.js +180 -0
- package/dist/src/syntax/parse-layout-expression.d.ts +5 -0
- package/dist/src/syntax/parse-layout-expression.js +175 -0
- package/dist/src/syntax/parse-line.js +4 -272
- package/dist/src/syntax/parse-token-expression.d.ts +3 -0
- package/dist/src/syntax/parse-token-expression.js +133 -0
- package/dist/src/tooling/case-style.js +47 -30
- package/dist/src/z80/effect-groups.d.ts +38 -0
- package/dist/src/z80/effect-groups.js +265 -0
- package/dist/src/z80/effect-units.d.ts +18 -0
- package/dist/src/z80/effect-units.js +165 -0
- package/dist/src/z80/effects.d.ts +1 -1
- package/dist/src/z80/effects.js +94 -557
- package/dist/src/z80/encode-core.d.ts +2 -0
- package/dist/src/z80/encode-core.js +42 -0
- package/dist/src/z80/encode-ld-helpers.d.ts +25 -0
- package/dist/src/z80/encode-ld-helpers.js +172 -0
- package/dist/src/z80/encode-ld.d.ts +2 -0
- package/dist/src/z80/encode-ld.js +285 -0
- package/dist/src/z80/encode.js +190 -542
- package/dist/src/z80/ld-support.d.ts +3 -0
- package/dist/src/z80/ld-support.js +146 -0
- package/dist/src/z80/operand-split-state.d.ts +8 -0
- package/dist/src/z80/operand-split-state.js +46 -0
- package/dist/src/z80/operand-split.d.ts +1 -0
- package/dist/src/z80/operand-split.js +13 -0
- package/dist/src/z80/parse-basic.d.ts +4 -0
- package/dist/src/z80/parse-basic.js +39 -0
- package/dist/src/z80/parse-branch.d.ts +4 -0
- package/dist/src/z80/parse-branch.js +218 -0
- package/dist/src/z80/parse-conditions.d.ts +6 -0
- package/dist/src/z80/parse-conditions.js +10 -0
- package/dist/src/z80/parse-exchange.d.ts +2 -0
- package/dist/src/z80/parse-exchange.js +30 -0
- package/dist/src/z80/parse-instruction.js +224 -1010
- package/dist/src/z80/parse-io-control.d.ts +5 -0
- package/dist/src/z80/parse-io-control.js +108 -0
- package/dist/src/z80/parse-ld.d.ts +2 -0
- package/dist/src/z80/parse-ld.js +83 -0
- package/dist/src/z80/parse-operands.d.ts +41 -0
- package/dist/src/z80/parse-operands.js +259 -0
- package/docs/reference/cli.md +42 -35
- package/docs/reference/tooling-api.md +20 -16
- package/package.json +1 -1
- package/dist/src/register-care/accept-output.d.ts +0 -2
- package/dist/src/register-care/analyze.js +0 -166
- package/dist/src/register-care/annotate.d.ts +0 -11
- package/dist/src/register-care/annotations.d.ts +0 -8
- package/dist/src/register-care/boundaryHints.d.ts +0 -3
- package/dist/src/register-care/boundaryHints.js +0 -80
- package/dist/src/register-care/carriers.d.ts +0 -2
- package/dist/src/register-care/controlFlow.d.ts +0 -5
- package/dist/src/register-care/controlFlow.js +0 -38
- package/dist/src/register-care/fix.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.d.ts +0 -11
- package/dist/src/register-care/instruction-shape.js +0 -129
- package/dist/src/register-care/liveness.d.ts +0 -3
- package/dist/src/register-care/programModel.d.ts +0 -3
- package/dist/src/register-care/programModel.js +0 -266
- package/dist/src/register-care/report.d.ts +0 -5
- package/dist/src/register-care/routine-summaries.d.ts +0 -6
- package/dist/src/register-care/smartComments.d.ts +0 -5
- package/dist/src/register-care/smartComments.js +0 -243
- package/dist/src/register-care/summaries.d.ts +0 -12
- package/dist/src/register-care/summary.d.ts +0 -3
- package/dist/src/register-care/summary.js +0 -474
- package/dist/src/register-care/tooling.d.ts +0 -43
- package/dist/src/register-care/types.d.ts +0 -172
- /package/dist/src/{register-care → register-contracts}/accept-output.js +0 -0
- /package/dist/src/{register-care → register-contracts}/carriers.js +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.d.ts +0 -0
- /package/dist/src/{register-care → register-contracts}/sourceText.js +0 -0
- /package/dist/src/{register-care → register-contracts}/types.js +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const CORE_OPCODES = {
|
|
2
|
+
di: [0xf3],
|
|
3
|
+
ei: [0xfb],
|
|
4
|
+
scf: [0x37],
|
|
5
|
+
ccf: [0x3f],
|
|
6
|
+
cpl: [0x2f],
|
|
7
|
+
daa: [0x27],
|
|
8
|
+
exx: [0xd9],
|
|
9
|
+
halt: [0x76],
|
|
10
|
+
rlca: [0x07],
|
|
11
|
+
rrca: [0x0f],
|
|
12
|
+
rla: [0x17],
|
|
13
|
+
rra: [0x1f],
|
|
14
|
+
neg: [0xed, 0x44],
|
|
15
|
+
rrd: [0xed, 0x67],
|
|
16
|
+
rld: [0xed, 0x6f],
|
|
17
|
+
ldi: [0xed, 0xa0],
|
|
18
|
+
ldir: [0xed, 0xb0],
|
|
19
|
+
ldd: [0xed, 0xa8],
|
|
20
|
+
lddr: [0xed, 0xb8],
|
|
21
|
+
cpi: [0xed, 0xa1],
|
|
22
|
+
cpir: [0xed, 0xb1],
|
|
23
|
+
cpd: [0xed, 0xa9],
|
|
24
|
+
cpdr: [0xed, 0xb9],
|
|
25
|
+
ini: [0xed, 0xa2],
|
|
26
|
+
inir: [0xed, 0xb2],
|
|
27
|
+
ind: [0xed, 0xaa],
|
|
28
|
+
indr: [0xed, 0xba],
|
|
29
|
+
outi: [0xed, 0xa3],
|
|
30
|
+
otir: [0xed, 0xb3],
|
|
31
|
+
outd: [0xed, 0xab],
|
|
32
|
+
otdr: [0xed, 0xbb],
|
|
33
|
+
reti: [0xed, 0x4d],
|
|
34
|
+
retn: [0xed, 0x45],
|
|
35
|
+
};
|
|
36
|
+
export function encodeCore(mnemonic) {
|
|
37
|
+
const opcode = CORE_OPCODES[mnemonic];
|
|
38
|
+
return {
|
|
39
|
+
size: opcode.length,
|
|
40
|
+
fragments: [{ kind: 'bytes', bytes: opcode }],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EncodedZ80Instruction, Z80IndexRegister16, Z80Instruction, Z80Operand, Z80Register16, Z80Register8, Z80RegisterIndirect } from './instruction.js';
|
|
2
|
+
export type Z80InstructionTarget = Extract<Z80Instruction, {
|
|
3
|
+
readonly expression: unknown;
|
|
4
|
+
}>['expression'];
|
|
5
|
+
export type HalfIndexLdOperand = Extract<Z80Operand, {
|
|
6
|
+
readonly kind: 'reg8' | 'reg-half-index';
|
|
7
|
+
}>;
|
|
8
|
+
export type LoadSpSourceOperand = Extract<Z80Operand, {
|
|
9
|
+
readonly kind: 'reg16' | 'reg-index16';
|
|
10
|
+
}>;
|
|
11
|
+
export declare function absoluteLd(opcode: number, expression: Z80InstructionTarget): EncodedZ80Instruction;
|
|
12
|
+
export declare function prefixedAbsoluteLd(prefix: number, opcode: number, expression: Z80InstructionTarget): EncodedZ80Instruction;
|
|
13
|
+
export declare function absoluteRegister16Load(register: Z80Register16, expression: Z80InstructionTarget): EncodedZ80Instruction;
|
|
14
|
+
export declare function absoluteRegister16Store(register: Z80Register16, expression: Z80InstructionTarget): EncodedZ80Instruction;
|
|
15
|
+
export declare function isHalfIndexTransferLd(target: Z80Operand, source: Z80Operand): boolean;
|
|
16
|
+
export declare function isLoadSpFromWordRegister(target: Z80Operand, source: Z80Operand): boolean;
|
|
17
|
+
export declare function loadSpOpcode(register: Z80Register16 | Z80IndexRegister16): readonly number[];
|
|
18
|
+
export declare function halfIndexPrefix(target: HalfIndexLdOperand, source: HalfIndexLdOperand): number;
|
|
19
|
+
export declare function byteRegisterCode(operand: HalfIndexLdOperand): number;
|
|
20
|
+
export declare function oneByteInstruction(opcode: number): EncodedZ80Instruction;
|
|
21
|
+
export declare function indexPrefix(register: 'ix' | 'iy'): number;
|
|
22
|
+
export declare function register8Code(register: Z80Register8): number;
|
|
23
|
+
export declare function register16Code(register: Z80Register16): number;
|
|
24
|
+
export declare function loadAFromIndirectOpcode(register: Z80RegisterIndirect): number;
|
|
25
|
+
export declare function storeAToIndirectOpcode(register: Z80RegisterIndirect): number;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
export function absoluteLd(opcode, expression) {
|
|
2
|
+
return {
|
|
3
|
+
size: 3,
|
|
4
|
+
fragments: [
|
|
5
|
+
{ kind: 'bytes', bytes: [opcode] },
|
|
6
|
+
{ kind: 'abs16', expression },
|
|
7
|
+
],
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function prefixedAbsoluteLd(prefix, opcode, expression) {
|
|
11
|
+
return {
|
|
12
|
+
size: 4,
|
|
13
|
+
fragments: [
|
|
14
|
+
{ kind: 'bytes', bytes: [prefix, opcode] },
|
|
15
|
+
{ kind: 'abs16', expression },
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function absoluteRegister16Load(register, expression) {
|
|
20
|
+
switch (register) {
|
|
21
|
+
case 'hl':
|
|
22
|
+
return absoluteLd(0x2a, expression);
|
|
23
|
+
case 'bc':
|
|
24
|
+
return prefixedAbsoluteLd(0xed, 0x4b, expression);
|
|
25
|
+
case 'de':
|
|
26
|
+
return prefixedAbsoluteLd(0xed, 0x5b, expression);
|
|
27
|
+
case 'sp':
|
|
28
|
+
return prefixedAbsoluteLd(0xed, 0x7b, expression);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function absoluteRegister16Store(register, expression) {
|
|
32
|
+
switch (register) {
|
|
33
|
+
case 'hl':
|
|
34
|
+
return absoluteLd(0x22, expression);
|
|
35
|
+
case 'bc':
|
|
36
|
+
return prefixedAbsoluteLd(0xed, 0x43, expression);
|
|
37
|
+
case 'de':
|
|
38
|
+
return prefixedAbsoluteLd(0xed, 0x53, expression);
|
|
39
|
+
case 'sp':
|
|
40
|
+
return prefixedAbsoluteLd(0xed, 0x73, expression);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function isHalfIndexTransferLd(target, source) {
|
|
44
|
+
return ((target.kind === 'reg8' || target.kind === 'reg-half-index') &&
|
|
45
|
+
(source.kind === 'reg8' || source.kind === 'reg-half-index') &&
|
|
46
|
+
isEncodableHalfIndexLd(target, source));
|
|
47
|
+
}
|
|
48
|
+
export function isLoadSpFromWordRegister(target, source) {
|
|
49
|
+
return (target.kind === 'reg16' &&
|
|
50
|
+
target.register === 'sp' &&
|
|
51
|
+
((source.kind === 'reg16' && source.register === 'hl') || source.kind === 'reg-index16'));
|
|
52
|
+
}
|
|
53
|
+
export function loadSpOpcode(register) {
|
|
54
|
+
switch (register) {
|
|
55
|
+
case 'hl':
|
|
56
|
+
return [0xf9];
|
|
57
|
+
case 'ix':
|
|
58
|
+
return [0xdd, 0xf9];
|
|
59
|
+
case 'iy':
|
|
60
|
+
return [0xfd, 0xf9];
|
|
61
|
+
default:
|
|
62
|
+
throw new Error(`unsupported LD SP source register: ${register}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function halfIndexPrefix(target, source) {
|
|
66
|
+
const register = target.kind === 'reg-half-index'
|
|
67
|
+
? target.register
|
|
68
|
+
: source.kind === 'reg-half-index'
|
|
69
|
+
? source.register
|
|
70
|
+
: undefined;
|
|
71
|
+
if (!register) {
|
|
72
|
+
throw new Error('expected half-index register');
|
|
73
|
+
}
|
|
74
|
+
return register.startsWith('ix') ? 0xdd : 0xfd;
|
|
75
|
+
}
|
|
76
|
+
export function byteRegisterCode(operand) {
|
|
77
|
+
return operand.kind === 'reg8'
|
|
78
|
+
? register8Code(operand.register)
|
|
79
|
+
: halfIndexRegisterCode(operand.register);
|
|
80
|
+
}
|
|
81
|
+
export function oneByteInstruction(opcode) {
|
|
82
|
+
return {
|
|
83
|
+
size: 1,
|
|
84
|
+
fragments: [{ kind: 'bytes', bytes: [opcode] }],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function indexPrefix(register) {
|
|
88
|
+
return register === 'ix' ? 0xdd : 0xfd;
|
|
89
|
+
}
|
|
90
|
+
export function register8Code(register) {
|
|
91
|
+
switch (register) {
|
|
92
|
+
case 'b':
|
|
93
|
+
return 0;
|
|
94
|
+
case 'c':
|
|
95
|
+
return 1;
|
|
96
|
+
case 'd':
|
|
97
|
+
return 2;
|
|
98
|
+
case 'e':
|
|
99
|
+
return 3;
|
|
100
|
+
case 'h':
|
|
101
|
+
return 4;
|
|
102
|
+
case 'l':
|
|
103
|
+
return 5;
|
|
104
|
+
case 'a':
|
|
105
|
+
return 7;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export function register16Code(register) {
|
|
109
|
+
switch (register) {
|
|
110
|
+
case 'bc':
|
|
111
|
+
return 0;
|
|
112
|
+
case 'de':
|
|
113
|
+
return 1;
|
|
114
|
+
case 'hl':
|
|
115
|
+
return 2;
|
|
116
|
+
case 'sp':
|
|
117
|
+
return 3;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export function loadAFromIndirectOpcode(register) {
|
|
121
|
+
switch (register) {
|
|
122
|
+
case 'bc':
|
|
123
|
+
return 0x0a;
|
|
124
|
+
case 'de':
|
|
125
|
+
return 0x1a;
|
|
126
|
+
case 'hl':
|
|
127
|
+
return 0x7e;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function storeAToIndirectOpcode(register) {
|
|
131
|
+
switch (register) {
|
|
132
|
+
case 'bc':
|
|
133
|
+
return 0x02;
|
|
134
|
+
case 'de':
|
|
135
|
+
return 0x12;
|
|
136
|
+
case 'hl':
|
|
137
|
+
return 0x77;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function isEncodableHalfIndexLd(target, source) {
|
|
141
|
+
if (target.kind !== 'reg-half-index' && source.kind !== 'reg-half-index') {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return (isSameHalfIndexFamily(target, source) &&
|
|
145
|
+
isHalfIndexCompatibleByteOperand(target) &&
|
|
146
|
+
isHalfIndexCompatibleByteOperand(source));
|
|
147
|
+
}
|
|
148
|
+
function isSameHalfIndexFamily(target, source) {
|
|
149
|
+
const targetFamily = halfIndexFamily(target);
|
|
150
|
+
const sourceFamily = halfIndexFamily(source);
|
|
151
|
+
return !targetFamily || !sourceFamily || targetFamily === sourceFamily;
|
|
152
|
+
}
|
|
153
|
+
function halfIndexFamily(operand) {
|
|
154
|
+
if (operand.kind !== 'reg-half-index') {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return operand.register.startsWith('ix') ? 'ix' : 'iy';
|
|
158
|
+
}
|
|
159
|
+
function isHalfIndexCompatibleByteOperand(operand) {
|
|
160
|
+
return (operand.kind === 'reg-half-index' ||
|
|
161
|
+
(operand.kind === 'reg8' && operand.register !== 'h' && operand.register !== 'l'));
|
|
162
|
+
}
|
|
163
|
+
function halfIndexRegisterCode(register) {
|
|
164
|
+
switch (register) {
|
|
165
|
+
case 'ixh':
|
|
166
|
+
case 'iyh':
|
|
167
|
+
return 4;
|
|
168
|
+
case 'ixl':
|
|
169
|
+
case 'iyl':
|
|
170
|
+
return 5;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { absoluteLd, absoluteRegister16Load, absoluteRegister16Store, byteRegisterCode, halfIndexPrefix, indexPrefix, isHalfIndexTransferLd, isLoadSpFromWordRegister, loadAFromIndirectOpcode, loadSpOpcode, oneByteInstruction, prefixedAbsoluteLd, register16Code, register8Code, storeAToIndirectOpcode, } from './encode-ld-helpers.js';
|
|
2
|
+
const LD_UNSUPPORTED_FORM_MESSAGE = 'ld expects a supported register/memory/immediate transfer form';
|
|
3
|
+
const BYTE_REGISTER_LD_ENCODERS = [
|
|
4
|
+
encodeReg8ImmediateLd,
|
|
5
|
+
encodeReg8RegisterLd,
|
|
6
|
+
encodeLoadAFromAbsoluteLd,
|
|
7
|
+
encodeStoreAToAbsoluteLd,
|
|
8
|
+
encodeHalfIndexTransferLd,
|
|
9
|
+
];
|
|
10
|
+
const WORD_REGISTER_LD_ENCODERS = [
|
|
11
|
+
encodeReg16ImmediateLd,
|
|
12
|
+
encodeIndex16ImmediateLd,
|
|
13
|
+
encodeLoadSpFromWordRegisterLd,
|
|
14
|
+
encodeAbsoluteRegister16LoadLd,
|
|
15
|
+
encodeAbsoluteIndex16LoadLd,
|
|
16
|
+
encodeAbsoluteRegister16StoreLd,
|
|
17
|
+
encodeAbsoluteIndex16StoreLd,
|
|
18
|
+
];
|
|
19
|
+
const HL_INDIRECT_LD_ENCODERS = [
|
|
20
|
+
encodeStoreReg8ToHlLd,
|
|
21
|
+
encodeStoreImmToHlLd,
|
|
22
|
+
encodeLoadReg8FromHlLd,
|
|
23
|
+
];
|
|
24
|
+
export function encodeLd(target, source) {
|
|
25
|
+
const encoded = encodeLegacyReg16ByteTransferLd(target, source) ??
|
|
26
|
+
encodeSpecialRegisterLd(target, source) ??
|
|
27
|
+
firstLdEncoding(BYTE_REGISTER_LD_ENCODERS, target, source) ??
|
|
28
|
+
firstLdEncoding(WORD_REGISTER_LD_ENCODERS, target, source) ??
|
|
29
|
+
encodeAccumulatorIndirectLd(target, source) ??
|
|
30
|
+
firstLdEncoding(HL_INDIRECT_LD_ENCODERS, target, source) ??
|
|
31
|
+
encodeIndexedLd(target, source);
|
|
32
|
+
if (encoded)
|
|
33
|
+
return encoded;
|
|
34
|
+
return {
|
|
35
|
+
size: 0,
|
|
36
|
+
fragments: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function firstLdEncoding(encoders, target, source) {
|
|
40
|
+
for (const encoder of encoders) {
|
|
41
|
+
const encoded = encoder(target, source);
|
|
42
|
+
if (encoded)
|
|
43
|
+
return encoded;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function encodeReg8ImmediateLd(target, source) {
|
|
48
|
+
if (target.kind !== 'reg8' || source.kind !== 'imm')
|
|
49
|
+
return undefined;
|
|
50
|
+
return {
|
|
51
|
+
size: 2,
|
|
52
|
+
fragments: [
|
|
53
|
+
{ kind: 'bytes', bytes: [0x06 + register8Code(target.register) * 8] },
|
|
54
|
+
{
|
|
55
|
+
kind: 'imm8',
|
|
56
|
+
expression: source.expression,
|
|
57
|
+
failureMessage: LD_UNSUPPORTED_FORM_MESSAGE,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function encodeReg8RegisterLd(target, source) {
|
|
63
|
+
if (target.kind !== 'reg8' || source.kind !== 'reg8')
|
|
64
|
+
return undefined;
|
|
65
|
+
return oneByteInstruction(0x40 + register8Code(target.register) * 8 + register8Code(source.register));
|
|
66
|
+
}
|
|
67
|
+
function encodeLoadAFromAbsoluteLd(target, source) {
|
|
68
|
+
if (target.kind !== 'reg8' || target.register !== 'a' || source.kind !== 'mem-abs') {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return absoluteLd(0x3a, source.expression);
|
|
72
|
+
}
|
|
73
|
+
function encodeStoreAToAbsoluteLd(target, source) {
|
|
74
|
+
if (target.kind !== 'mem-abs' || source.kind !== 'reg8' || source.register !== 'a') {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return absoluteLd(0x32, target.expression);
|
|
78
|
+
}
|
|
79
|
+
function encodeHalfIndexTransferLd(target, source) {
|
|
80
|
+
if (!isHalfIndexTransferLd(target, source))
|
|
81
|
+
return undefined;
|
|
82
|
+
const ldTarget = target;
|
|
83
|
+
const ldSource = source;
|
|
84
|
+
const prefix = halfIndexPrefix(ldTarget, ldSource);
|
|
85
|
+
return {
|
|
86
|
+
size: 2,
|
|
87
|
+
fragments: [
|
|
88
|
+
{
|
|
89
|
+
kind: 'bytes',
|
|
90
|
+
bytes: [prefix, 0x40 + byteRegisterCode(ldTarget) * 8 + byteRegisterCode(ldSource)],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function encodeReg16ImmediateLd(target, source) {
|
|
96
|
+
if (target.kind !== 'reg16' || source.kind !== 'imm')
|
|
97
|
+
return undefined;
|
|
98
|
+
return {
|
|
99
|
+
size: 3,
|
|
100
|
+
fragments: [
|
|
101
|
+
{ kind: 'bytes', bytes: [0x01 + register16Code(target.register) * 0x10] },
|
|
102
|
+
{ kind: 'abs16', expression: source.expression },
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function encodeIndex16ImmediateLd(target, source) {
|
|
107
|
+
if (target.kind !== 'reg-index16' || source.kind !== 'imm')
|
|
108
|
+
return undefined;
|
|
109
|
+
return {
|
|
110
|
+
size: 4,
|
|
111
|
+
fragments: [
|
|
112
|
+
{ kind: 'bytes', bytes: [indexPrefix(target.register), 0x21] },
|
|
113
|
+
{ kind: 'abs16', expression: source.expression },
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function encodeLoadSpFromWordRegisterLd(target, source) {
|
|
118
|
+
if (!isLoadSpFromWordRegister(target, source))
|
|
119
|
+
return undefined;
|
|
120
|
+
const ldSource = source;
|
|
121
|
+
return {
|
|
122
|
+
size: ldSource.kind === 'reg-index16' ? 2 : 1,
|
|
123
|
+
fragments: [{ kind: 'bytes', bytes: loadSpOpcode(ldSource.register) }],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function encodeAbsoluteRegister16LoadLd(target, source) {
|
|
127
|
+
if (target.kind !== 'reg16' || source.kind !== 'mem-abs')
|
|
128
|
+
return undefined;
|
|
129
|
+
return absoluteRegister16Load(target.register, source.expression);
|
|
130
|
+
}
|
|
131
|
+
function encodeAbsoluteIndex16LoadLd(target, source) {
|
|
132
|
+
if (target.kind !== 'reg-index16' || source.kind !== 'mem-abs')
|
|
133
|
+
return undefined;
|
|
134
|
+
return prefixedAbsoluteLd(indexPrefix(target.register), 0x2a, source.expression);
|
|
135
|
+
}
|
|
136
|
+
function encodeAbsoluteRegister16StoreLd(target, source) {
|
|
137
|
+
if (target.kind !== 'mem-abs' || source.kind !== 'reg16')
|
|
138
|
+
return undefined;
|
|
139
|
+
return absoluteRegister16Store(source.register, target.expression);
|
|
140
|
+
}
|
|
141
|
+
function encodeAbsoluteIndex16StoreLd(target, source) {
|
|
142
|
+
if (target.kind !== 'mem-abs' || source.kind !== 'reg-index16')
|
|
143
|
+
return undefined;
|
|
144
|
+
return prefixedAbsoluteLd(indexPrefix(source.register), 0x22, target.expression);
|
|
145
|
+
}
|
|
146
|
+
function encodeAccumulatorIndirectLd(target, source) {
|
|
147
|
+
return (encodeLoadAFromRegisterIndirectLd(target, source) ??
|
|
148
|
+
encodeStoreAToRegisterIndirectLd(target, source));
|
|
149
|
+
}
|
|
150
|
+
function encodeLoadAFromRegisterIndirectLd(target, source) {
|
|
151
|
+
if (target.kind !== 'reg8' || target.register !== 'a' || source.kind !== 'reg-indirect') {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
return oneByteInstruction(loadAFromIndirectOpcode(source.register));
|
|
155
|
+
}
|
|
156
|
+
function encodeStoreAToRegisterIndirectLd(target, source) {
|
|
157
|
+
if (target.kind !== 'reg-indirect' || source.kind !== 'reg8' || source.register !== 'a') {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return oneByteInstruction(storeAToIndirectOpcode(target.register));
|
|
161
|
+
}
|
|
162
|
+
function encodeStoreReg8ToHlLd(target, source) {
|
|
163
|
+
if (target.kind !== 'reg-indirect' || target.register !== 'hl' || source.kind !== 'reg8') {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
return oneByteInstruction(0x70 + register8Code(source.register));
|
|
167
|
+
}
|
|
168
|
+
function encodeStoreImmToHlLd(target, source) {
|
|
169
|
+
if (target.kind !== 'reg-indirect' || target.register !== 'hl' || source.kind !== 'imm') {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
size: 2,
|
|
174
|
+
fragments: [
|
|
175
|
+
{ kind: 'bytes', bytes: [0x36] },
|
|
176
|
+
{
|
|
177
|
+
kind: 'imm8',
|
|
178
|
+
expression: source.expression,
|
|
179
|
+
failureMessage: LD_UNSUPPORTED_FORM_MESSAGE,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function encodeLoadReg8FromHlLd(target, source) {
|
|
185
|
+
if (target.kind !== 'reg8' || source.kind !== 'reg-indirect' || source.register !== 'hl') {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
return oneByteInstruction(0x46 + register8Code(target.register) * 8);
|
|
189
|
+
}
|
|
190
|
+
function encodeIndexedLd(target, source) {
|
|
191
|
+
return (encodeLoadReg8FromIndexedLd(target, source) ??
|
|
192
|
+
encodeStoreReg8ToIndexedLd(target, source) ??
|
|
193
|
+
encodeStoreImmToIndexedLd(target, source));
|
|
194
|
+
}
|
|
195
|
+
function encodeLoadReg8FromIndexedLd(target, source) {
|
|
196
|
+
if (target.kind !== 'reg8' || source.kind !== 'indexed')
|
|
197
|
+
return undefined;
|
|
198
|
+
return {
|
|
199
|
+
size: 3,
|
|
200
|
+
fragments: [
|
|
201
|
+
{
|
|
202
|
+
kind: 'bytes',
|
|
203
|
+
bytes: [indexPrefix(source.register), 0x46 + register8Code(target.register) * 8],
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
kind: 'disp8',
|
|
207
|
+
expression: source.displacement,
|
|
208
|
+
message: 'ld (ix/iy+disp) expects disp8',
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function encodeStoreReg8ToIndexedLd(target, source) {
|
|
214
|
+
if (target.kind !== 'indexed' || source.kind !== 'reg8')
|
|
215
|
+
return undefined;
|
|
216
|
+
return {
|
|
217
|
+
size: 3,
|
|
218
|
+
fragments: [
|
|
219
|
+
{
|
|
220
|
+
kind: 'bytes',
|
|
221
|
+
bytes: [indexPrefix(target.register), 0x70 + register8Code(source.register)],
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
kind: 'disp8',
|
|
225
|
+
expression: target.displacement,
|
|
226
|
+
message: 'ld (ix/iy+disp) expects disp8',
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function encodeStoreImmToIndexedLd(target, source) {
|
|
232
|
+
if (target.kind !== 'indexed' || source.kind !== 'imm')
|
|
233
|
+
return undefined;
|
|
234
|
+
return {
|
|
235
|
+
size: 4,
|
|
236
|
+
fragments: [
|
|
237
|
+
{ kind: 'bytes', bytes: [indexPrefix(target.register), 0x36] },
|
|
238
|
+
{
|
|
239
|
+
kind: 'disp8',
|
|
240
|
+
expression: target.displacement,
|
|
241
|
+
message: 'ld (ix/iy+disp), n expects disp8',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
kind: 'imm8',
|
|
245
|
+
expression: source.expression,
|
|
246
|
+
failureMessage: LD_UNSUPPORTED_FORM_MESSAGE,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function encodeLegacyReg16ByteTransferLd(target, source) {
|
|
252
|
+
if (target.kind !== 'reg16' || source.kind !== 'reg16') {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
const transfers = legacyReg16ByteTransferOpcodes(target.register, source.register);
|
|
256
|
+
if (!transfers) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
size: transfers.length,
|
|
261
|
+
fragments: [{ kind: 'bytes', bytes: transfers }],
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function legacyReg16ByteTransferOpcodes(target, source) {
|
|
265
|
+
if (target === 'hl' && source === 'de')
|
|
266
|
+
return [0x62, 0x6b];
|
|
267
|
+
if (target === 'bc' && source === 'de')
|
|
268
|
+
return [0x42, 0x4b];
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
function encodeSpecialRegisterLd(target, source) {
|
|
272
|
+
if (target.kind === 'special8' && source.kind === 'reg8' && source.register === 'a') {
|
|
273
|
+
return {
|
|
274
|
+
size: 2,
|
|
275
|
+
fragments: [{ kind: 'bytes', bytes: [0xed, target.register === 'i' ? 0x47 : 0x4f] }],
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'special8') {
|
|
279
|
+
return {
|
|
280
|
+
size: 2,
|
|
281
|
+
fragments: [{ kind: 'bytes', bytes: [0xed, source.register === 'i' ? 0x57 : 0x5f] }],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|