@jhlagado/azm 0.1.1 → 0.2.1
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 +103 -70
- package/dist/{src → legacy-root-azm/src}/formats/index.d.ts +1 -1
- package/dist/{src → legacy-root-azm/src}/formats/index.js +1 -1
- package/dist/{src → legacy-root-azm/src}/formats/types.d.ts +67 -7
- package/dist/{src → legacy-root-azm/src}/formats/writeHex.d.ts +0 -1
- package/dist/{src → legacy-root-azm/src}/formats/writeHex.js +0 -1
- package/dist/{src → legacy-root-azm/src}/pipeline.d.ts +3 -5
- package/dist/legacy-root-azm/src/z80/effects.d.ts +3 -0
- package/dist/legacy-root-azm/src/z80/effects.js +516 -0
- package/dist/legacy-root-azm/src/z80/encode.d.ts +10 -0
- package/dist/legacy-root-azm/src/z80/encode.js +412 -0
- package/dist/src/api-compile.d.ts +49 -8
- package/dist/src/api-compile.js +313 -3
- package/dist/src/api-tooling.d.ts +7 -25
- package/dist/src/api-tooling.js +3 -21
- package/dist/src/assembly/address-planning.d.ts +19 -0
- package/dist/src/assembly/address-planning.js +268 -0
- package/dist/src/assembly/assemble-program.d.ts +13 -0
- package/dist/src/assembly/assemble-program.js +34 -0
- package/dist/src/assembly/fixup-emission.d.ts +10 -0
- package/dist/src/assembly/fixup-emission.js +247 -0
- package/dist/src/assembly/placement.d.ts +26 -0
- package/dist/src/assembly/placement.js +79 -0
- package/dist/src/assembly/program-emission.d.ts +13 -0
- package/dist/src/assembly/program-emission.js +268 -0
- package/dist/src/cli/parse-args.d.ts +29 -0
- package/dist/src/cli/parse-args.js +372 -0
- package/dist/src/cli/run.d.ts +2 -0
- package/dist/src/cli/run.js +35 -0
- package/dist/src/cli/write-artifacts.d.ts +21 -0
- package/dist/src/cli/write-artifacts.js +175 -0
- package/dist/src/cli.d.ts +1 -30
- package/dist/src/cli.js +20 -524
- package/dist/src/core/compile-artifacts.d.ts +26 -0
- package/dist/src/core/compile-artifacts.js +17 -0
- package/dist/src/core/compile.d.ts +26 -0
- package/dist/src/core/compile.js +164 -0
- package/dist/src/diagnostics/format.d.ts +4 -0
- package/dist/src/diagnostics/format.js +9 -0
- package/dist/src/expansion/op-expansion.d.ts +96 -0
- package/dist/src/expansion/op-expansion.js +913 -0
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.js +7 -2
- package/dist/src/model/diagnostic.d.ts +50 -0
- package/dist/src/model/diagnostic.js +29 -0
- package/dist/src/model/expression.d.ts +51 -0
- package/dist/src/model/expression.js +1 -0
- package/dist/src/model/fixup.d.ts +18 -0
- package/dist/src/model/fixup.js +1 -0
- package/dist/src/model/source-item.d.ts +87 -0
- package/dist/src/model/source-item.js +1 -0
- package/dist/src/model/symbol.d.ts +1 -0
- package/dist/src/model/symbol.js +1 -0
- package/dist/src/node/source-host.d.ts +19 -0
- package/dist/src/node/source-host.js +146 -0
- package/dist/src/outputs/hex.d.ts +1 -0
- package/dist/src/outputs/hex.js +75 -0
- package/dist/src/outputs/index.d.ts +3 -0
- package/dist/src/outputs/index.js +13 -0
- package/dist/src/outputs/range.d.ts +3 -0
- package/dist/src/outputs/range.js +31 -0
- package/dist/src/outputs/types.d.ts +182 -0
- package/dist/src/outputs/types.js +1 -0
- package/dist/src/outputs/write-asm80.d.ts +7 -0
- package/dist/src/outputs/write-asm80.js +666 -0
- package/dist/src/outputs/write-bin.d.ts +2 -0
- package/dist/src/outputs/write-bin.js +27 -0
- package/dist/src/outputs/write-d8.d.ts +2 -0
- package/dist/src/outputs/write-d8.js +257 -0
- package/dist/src/outputs/write-hex.d.ts +2 -0
- package/dist/src/outputs/write-hex.js +53 -0
- package/dist/src/outputs/write-listing.d.ts +2 -0
- package/dist/src/outputs/write-listing.js +79 -0
- package/dist/src/register-care/accept-output.d.ts +2 -0
- package/dist/src/register-care/accept-output.js +35 -0
- package/dist/src/register-care/analyze.d.ts +26 -0
- package/dist/src/register-care/analyze.js +115 -0
- package/dist/src/register-care/annotate.d.ts +11 -0
- package/dist/src/register-care/annotate.js +76 -0
- package/dist/src/register-care/annotations.d.ts +8 -0
- package/dist/src/register-care/annotations.js +41 -0
- package/dist/src/register-care/boundaryHints.d.ts +2 -0
- package/dist/src/register-care/boundaryHints.js +11 -0
- package/dist/src/register-care/carriers.d.ts +2 -0
- package/dist/src/register-care/carriers.js +78 -0
- package/dist/src/register-care/controlFlow.d.ts +5 -0
- package/dist/src/register-care/controlFlow.js +38 -0
- package/dist/src/register-care/fix.d.ts +11 -0
- package/dist/src/register-care/fix.js +130 -0
- package/dist/src/register-care/instruction-shape.d.ts +11 -0
- package/dist/src/register-care/instruction-shape.js +129 -0
- package/dist/src/register-care/liveness.d.ts +3 -0
- package/dist/src/register-care/liveness.js +197 -0
- package/dist/src/register-care/profiles.d.ts +9 -0
- package/dist/src/register-care/profiles.js +47 -0
- package/dist/src/register-care/programModel.d.ts +3 -0
- package/dist/src/register-care/programModel.js +188 -0
- package/dist/src/register-care/report.d.ts +5 -0
- package/dist/src/register-care/report.js +139 -0
- package/dist/src/register-care/routine-summaries.d.ts +6 -0
- package/dist/src/register-care/routine-summaries.js +89 -0
- package/dist/src/register-care/smartComments.d.ts +5 -0
- package/dist/src/register-care/smartComments.js +243 -0
- package/dist/src/register-care/sourceText.d.ts +8 -0
- package/dist/src/register-care/sourceText.js +15 -0
- package/dist/src/register-care/summaries.d.ts +12 -0
- package/dist/src/register-care/summaries.js +121 -0
- package/dist/src/register-care/summary.d.ts +3 -0
- package/dist/src/register-care/summary.js +474 -0
- package/dist/src/{registerCare → register-care}/tooling.d.ts +7 -6
- package/dist/src/{registerCare → register-care}/tooling.js +17 -6
- package/dist/src/register-care/types.d.ts +170 -0
- package/dist/src/register-care/types.js +1 -0
- package/dist/src/semantics/expression-evaluation.d.ts +29 -0
- package/dist/src/semantics/expression-evaluation.js +409 -0
- package/dist/src/source/logical-lines.d.ts +7 -0
- package/dist/src/source/logical-lines.js +11 -0
- package/dist/src/source/source-file.d.ts +5 -0
- package/dist/src/source/source-file.js +3 -0
- package/dist/src/source/source-span.d.ts +5 -0
- package/dist/src/source/source-span.js +1 -0
- package/dist/src/source/strip-line-comment.d.ts +6 -0
- package/dist/src/source/strip-line-comment.js +53 -0
- package/dist/src/syntax/directive-aliases.d.ts +10 -0
- package/dist/src/syntax/directive-aliases.js +199 -0
- package/dist/src/syntax/parse-diagnostics.d.ts +12 -0
- package/dist/src/syntax/parse-diagnostics.js +18 -0
- package/dist/src/syntax/parse-expression.d.ts +3 -0
- package/dist/src/syntax/parse-expression.js +551 -0
- package/dist/src/syntax/parse-line.d.ts +12 -0
- package/dist/src/syntax/parse-line.js +382 -0
- package/dist/src/tooling/api.d.ts +42 -0
- package/dist/src/tooling/api.js +42 -0
- package/dist/src/tooling/case-style.d.ts +8 -0
- package/dist/src/tooling/case-style.js +163 -0
- package/dist/src/z80/effects.d.ts +3 -3
- package/dist/src/z80/effects.js +349 -302
- package/dist/src/z80/encode.d.ts +2 -10
- package/dist/src/z80/encode.js +951 -374
- package/dist/src/z80/instruction.d.ts +226 -0
- package/dist/src/z80/instruction.js +1 -0
- package/dist/src/z80/parse-instruction.d.ts +7 -0
- package/dist/src/z80/parse-instruction.js +1068 -0
- package/docs/reference/tooling-api.md +68 -9
- package/package.json +22 -3
- /package/dist/{src → legacy-root-azm/src}/analysis.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/analysis.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/compile.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/compile.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/compileShared.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/compileShared.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/diagnosticTypes.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/diagnosticTypes.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/range.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/range.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/types.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeAsm80.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeAsm80.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeBin.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeBin.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeD8m.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeD8m.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeListing.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/formats/writeListing.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/asmLine.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/asmLine.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/parseAsmRawValues.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/parseAsmRawValues.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/quoteScan.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/asm80/quoteScan.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/ast.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/ast.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/directiveAliases.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/directiveAliases.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/grammarData.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/grammarData.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/immExprUtils.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/immExprUtils.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmFlatDirectiveLine.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmFlatDirectiveLine.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmInstruction.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmInstruction.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmStatements.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmStatements.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmStream.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmStream.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmTopLevel.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseAsmTopLevel.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseDiagnostics.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseDiagnostics.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseEnum.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseEnum.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseImm.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseImm.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseLogicalLines.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseLogicalLines.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOp.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOp.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOpHeader.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOpHeader.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOperands.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseOperands.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParams.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParams.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParserRecovery.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParserRecovery.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParserShared.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseParserShared.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRawDataDirectiveStart.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRawDataDirectiveStart.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRawDataDirectives.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRawDataDirectives.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRecordFieldDecl.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseRecordFieldDecl.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseSourceItemDispatch.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseSourceItemDispatch.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseSourceItemTable.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseSourceItemTable.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseTopLevelCommon.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseTopLevelCommon.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseTypes.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parseTypes.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parser.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/parser.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/source.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/source.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/sourceExtensions.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/frontend/sourceExtensions.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lintCaseStyle.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lintCaseStyle.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmDirectiveLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmDirectiveLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmDirectiveTraversal.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmDirectiveTraversal.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmEquResolution.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmEquResolution.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionLdHelpers.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionLdHelpers.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionStream.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmInstructionStream.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringBranchCall.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringBranchCall.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringHost.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringHost.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringLd.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmLoweringLd.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmRangeLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmRangeLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmRawDataLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmRawDataLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmSourceEmitter.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmSourceEmitter.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmSourceInstructionLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmSourceInstructionLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmUtils.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/asmUtils.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerFlowSetup.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerFlowSetup.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringContext.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringContext.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringContextSplit.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringContextSplit.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringPhases.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/assemblerLoweringPhases.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/bytePlacement.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/bytePlacement.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/capabilities.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/capabilities.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/eaResolution.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/eaResolution.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emissionCore.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emissionCore.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emit.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emit.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitContextBuilder.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitContextBuilder.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitFinalization.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitFinalization.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitFinalizationSetup.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitFinalizationSetup.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1BuildProgramLoweringContext.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1BuildProgramLoweringContext.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Helpers.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Helpers.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Types.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Types.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1WirePipeline.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1WirePipeline.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Workspace.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPhase1Workspace.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPipeline.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitPipeline.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitProgramContext.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitProgramContext.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitState.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/emitState.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/fixupBaseResolution.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/fixupBaseResolution.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/fixupEmission.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/fixupEmission.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/immMath.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/immMath.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/inputAssets.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/inputAssets.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldEncoding.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldEncoding.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldEncodingRegMemHelpers.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldEncodingRegMemHelpers.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldFormSelection.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldFormSelection.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/ldLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmByteEmission.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmByteEmission.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmPlacement.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmPlacement.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmStreamRecording.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmStreamRecording.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmTypes.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredAsmTypes.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredFormat.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredFormat.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredItemSize.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweredItemSize.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweringDiagnostics.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweringDiagnostics.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweringTypes.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/loweringTypes.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opCandidateRegistry.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opCandidateRegistry.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionExecution.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionExecution.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionOrchestration.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionOrchestration.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionStream.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opExpansionStream.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opMatching.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opMatching.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opSubstitution.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/opSubstitution.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/prescanTypes.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/prescanTypes.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLowering.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLowering.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringDeclarations.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringDeclarations.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringFinalize.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringFinalize.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringTraversal.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programLoweringTraversal.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programPrescan.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/programPrescan.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/traceFormat.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/lowering/traceFormat.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/packageInfo.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/packageInfo.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/pathCompare.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/pathCompare.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/pipeline.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/analyze.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/analyze.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/annotate.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/annotate.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/boundaryHints.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/boundaryHints.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/carriers.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/carriers.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/controlFlow.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/controlFlow.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/fix.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/fix.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/liveness.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/liveness.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/profiles.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/profiles.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/programModel.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/programModel.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/report.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/report.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/smartComments.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/smartComments.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/sourceText.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/sourceText.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/summary.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/summary.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/types.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/registerCare/types.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/declVisitor.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/declVisitor.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/env.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/env.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/layout.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/layout.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/layoutCastFold.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/layoutCastFold.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/semanticsDiagnostics.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/semanticsDiagnostics.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/typeQueries.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/semantics/typeQueries.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceIncludeExpansion.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceIncludeExpansion.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceIncludePaths.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceIncludePaths.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceLoader.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/sourceLoader.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeAlu.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeAlu.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeBitOps.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeBitOps.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeContext.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeContext.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeControl.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeControl.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeCoreOps.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeCoreOps.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeIo.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeIo.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeLd.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encodeLd.js +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encoderRegistry.d.ts +0 -0
- /package/dist/{src → legacy-root-azm/src}/z80/encoderRegistry.js +0 -0
|
@@ -0,0 +1,1068 @@
|
|
|
1
|
+
import { parseExpression } from '../syntax/parse-expression.js';
|
|
2
|
+
export function parseZ80Instruction(text) {
|
|
3
|
+
const nop = /^NOP(?:\s+(.*))?$/i.exec(text);
|
|
4
|
+
if (nop) {
|
|
5
|
+
return nop[1] === undefined
|
|
6
|
+
? { instruction: { mnemonic: 'nop' } }
|
|
7
|
+
: { error: 'nop expects no operands' };
|
|
8
|
+
}
|
|
9
|
+
const ret = /^RET(?:\s+(.*))?$/i.exec(text);
|
|
10
|
+
if (ret) {
|
|
11
|
+
const operandText = ret[1] ?? '';
|
|
12
|
+
if (operandText.trim().length === 0) {
|
|
13
|
+
return { instruction: { mnemonic: 'ret' } };
|
|
14
|
+
}
|
|
15
|
+
const parts = splitInstructionOperands(operandText);
|
|
16
|
+
if (parts.length !== 1) {
|
|
17
|
+
return { error: 'ret expects no operands or one condition code' };
|
|
18
|
+
}
|
|
19
|
+
const condition = parseCondition(parts[0] ?? '');
|
|
20
|
+
return condition
|
|
21
|
+
? { instruction: { mnemonic: 'ret-cc', condition } }
|
|
22
|
+
: { error: 'ret cc expects a valid condition code' };
|
|
23
|
+
}
|
|
24
|
+
const noOperandCore = /^(DI|EI|SCF|CCF|CPL|DAA|EXX|HALT|RLCA|RRCA|RLA|RRA|NEG|RRD|RLD|LDI|LDIR|LDD|LDDR|CPI|CPIR|CPD|CPDR|INI|INIR|IND|INDR|OUTI|OTIR|OUTD|OTDR|RETI|RETN)(?:\s+(.*))?$/i.exec(text);
|
|
25
|
+
if (noOperandCore) {
|
|
26
|
+
const mnemonic = (noOperandCore[1] ?? '').toLowerCase();
|
|
27
|
+
return noOperandCore[2] === undefined
|
|
28
|
+
? { instruction: { mnemonic } }
|
|
29
|
+
: { error: `${mnemonic} expects no operands` };
|
|
30
|
+
}
|
|
31
|
+
const input = /^IN(?:\s+(.*))?$/i.exec(text);
|
|
32
|
+
if (input) {
|
|
33
|
+
const operandText = input[1] ?? '';
|
|
34
|
+
const parts = splitInstructionOperands(operandText);
|
|
35
|
+
if (operandText.trim().length === 0 || parts.length > 2) {
|
|
36
|
+
return { error: 'in expects one or two operands' };
|
|
37
|
+
}
|
|
38
|
+
if (parts.length === 1) {
|
|
39
|
+
const port = parsePortOperand(parts[0] ?? '');
|
|
40
|
+
return port?.kind === 'c'
|
|
41
|
+
? { instruction: { mnemonic: 'in', port } }
|
|
42
|
+
: { error: 'in (c) is the only one-operand in form' };
|
|
43
|
+
}
|
|
44
|
+
const target = parseRegister8Operand(parts[0] ?? '');
|
|
45
|
+
if (!target) {
|
|
46
|
+
return parseIndexHalfRegister(parts[0] ?? '')
|
|
47
|
+
? { error: 'in destination must use plain reg8 B/C/D/E/H/L/A' }
|
|
48
|
+
: { error: 'in expects a reg8 destination' };
|
|
49
|
+
}
|
|
50
|
+
const port = parsePortOperand(parts[1] ?? '');
|
|
51
|
+
if (!port) {
|
|
52
|
+
return { error: 'in expects a port operand (c) or (imm8)' };
|
|
53
|
+
}
|
|
54
|
+
if (port.kind === 'imm' && target.register !== 'a') {
|
|
55
|
+
return { error: 'in a,(n) immediate port form requires destination A' };
|
|
56
|
+
}
|
|
57
|
+
return { instruction: { mnemonic: 'in', target, port } };
|
|
58
|
+
}
|
|
59
|
+
const output = /^OUT(?:\s+(.*))?$/i.exec(text);
|
|
60
|
+
if (output) {
|
|
61
|
+
const operandText = output[1] ?? '';
|
|
62
|
+
const parts = splitInstructionOperands(operandText);
|
|
63
|
+
if (operandText.trim().length === 0 || parts.length !== 2) {
|
|
64
|
+
return { error: 'out expects two operands' };
|
|
65
|
+
}
|
|
66
|
+
const port = parsePortOperand(parts[0] ?? '');
|
|
67
|
+
if (!port) {
|
|
68
|
+
return { error: 'out expects a port operand (c) or (imm8)' };
|
|
69
|
+
}
|
|
70
|
+
const source = parseRegister8Operand(parts[1] ?? '');
|
|
71
|
+
if (source) {
|
|
72
|
+
if (port.kind === 'imm' && source.register !== 'a') {
|
|
73
|
+
return { error: 'out (n),a immediate port form requires source A' };
|
|
74
|
+
}
|
|
75
|
+
return { instruction: { mnemonic: 'out', port, source } };
|
|
76
|
+
}
|
|
77
|
+
if (parseIndexHalfRegister(parts[1] ?? '')) {
|
|
78
|
+
return { error: 'out source must use plain reg8 B/C/D/E/H/L/A' };
|
|
79
|
+
}
|
|
80
|
+
const zero = parseConstantExpression(parts[1] ?? '');
|
|
81
|
+
if (zero !== undefined && port.kind === 'c') {
|
|
82
|
+
return zero === 0
|
|
83
|
+
? { instruction: { mnemonic: 'out', port, source: { kind: 'zero' } } }
|
|
84
|
+
: { error: 'out (c), n immediate form supports n=0 only' };
|
|
85
|
+
}
|
|
86
|
+
return { error: 'out expects a reg8 source' };
|
|
87
|
+
}
|
|
88
|
+
const im = /^IM(?:\s+(.*))?$/i.exec(text);
|
|
89
|
+
if (im) {
|
|
90
|
+
const operandText = im[1] ?? '';
|
|
91
|
+
const parts = splitInstructionOperands(operandText);
|
|
92
|
+
if (operandText.trim().length === 0 || parts.length !== 1) {
|
|
93
|
+
return { error: 'im expects one operand' };
|
|
94
|
+
}
|
|
95
|
+
const mode = parseConstantExpression(parts[0] ?? '');
|
|
96
|
+
if (mode !== 0 && mode !== 1 && mode !== 2) {
|
|
97
|
+
return { error: 'im expects 0, 1, or 2' };
|
|
98
|
+
}
|
|
99
|
+
return { instruction: { mnemonic: 'im', mode } };
|
|
100
|
+
}
|
|
101
|
+
const rst = /^RST(?:\s+(.*))?$/i.exec(text);
|
|
102
|
+
if (rst) {
|
|
103
|
+
const operandText = rst[1] ?? '';
|
|
104
|
+
const parts = splitInstructionOperands(operandText);
|
|
105
|
+
if (operandText.trim().length === 0 || parts.length !== 1) {
|
|
106
|
+
return { error: 'rst expects one operand' };
|
|
107
|
+
}
|
|
108
|
+
const vector = parseConstantExpression(parts[0] ?? '');
|
|
109
|
+
if (!isRstVector(vector)) {
|
|
110
|
+
return { error: 'rst expects an imm8 multiple of 8 (0..56)' };
|
|
111
|
+
}
|
|
112
|
+
return { instruction: { mnemonic: 'rst', vector } };
|
|
113
|
+
}
|
|
114
|
+
const exchange = /^EX\s+(.+)$/i.exec(text);
|
|
115
|
+
if (exchange) {
|
|
116
|
+
const operandText = exchange[1] ?? '';
|
|
117
|
+
const parts = splitInstructionOperands(operandText);
|
|
118
|
+
if (parts.length !== 2) {
|
|
119
|
+
return { error: 'ex expects two operands' };
|
|
120
|
+
}
|
|
121
|
+
const left = (parts[0] ?? '').toLowerCase();
|
|
122
|
+
const right = (parts[1] ?? '').toLowerCase();
|
|
123
|
+
if ((left === 'af' && right === "af'") || (left === "af'" && right === 'af')) {
|
|
124
|
+
return { instruction: { mnemonic: 'ex', form: 'af-af' } };
|
|
125
|
+
}
|
|
126
|
+
if (left === 'de' && right === 'hl') {
|
|
127
|
+
return { instruction: { mnemonic: 'ex', form: 'de-hl' } };
|
|
128
|
+
}
|
|
129
|
+
if (left === '(sp)' && right === 'hl') {
|
|
130
|
+
return { instruction: { mnemonic: 'ex', form: 'sp-hl' } };
|
|
131
|
+
}
|
|
132
|
+
if ((left === '(sp)' && right === 'ix') || (left === 'ix' && right === '(sp)')) {
|
|
133
|
+
return { instruction: { mnemonic: 'ex', form: 'sp-ix' } };
|
|
134
|
+
}
|
|
135
|
+
if ((left === '(sp)' && right === 'iy') || (left === 'iy' && right === '(sp)')) {
|
|
136
|
+
return { instruction: { mnemonic: 'ex', form: 'sp-iy' } };
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
error: `ex supports "AF, AF'", "DE, HL", "(SP), HL", "(SP), IX", and "(SP), IY" only`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const incDec = /^(INC|DEC)(?:\s+(.*))?$/i.exec(text);
|
|
143
|
+
if (incDec) {
|
|
144
|
+
const mnemonic = (incDec[1] ?? '').toLowerCase();
|
|
145
|
+
const operandText = incDec[2] ?? '';
|
|
146
|
+
const parts = splitInstructionOperands(operandText);
|
|
147
|
+
if (operandText.trim().length === 0 || parts.length !== 1) {
|
|
148
|
+
return { error: `${mnemonic} expects one operand` };
|
|
149
|
+
}
|
|
150
|
+
const indexedBracket = indexedBracketError(parts[0] ?? '');
|
|
151
|
+
if (indexedBracket) {
|
|
152
|
+
return { error: indexedBracket };
|
|
153
|
+
}
|
|
154
|
+
const operand = parseIncDecOperand(parts[0] ?? '');
|
|
155
|
+
return operand
|
|
156
|
+
? { instruction: { mnemonic, operand } }
|
|
157
|
+
: { error: `${mnemonic} expects r8/rr/(hl) operand` };
|
|
158
|
+
}
|
|
159
|
+
const stack = /^(PUSH|POP)(?:\s+(.*))?$/i.exec(text);
|
|
160
|
+
if (stack) {
|
|
161
|
+
const mnemonic = (stack[1] ?? '').toLowerCase();
|
|
162
|
+
const operandText = stack[2] ?? '';
|
|
163
|
+
const parts = splitInstructionOperands(operandText);
|
|
164
|
+
if (operandText.trim().length === 0 || parts.length !== 1) {
|
|
165
|
+
return { error: `${mnemonic} expects one operand` };
|
|
166
|
+
}
|
|
167
|
+
const register = parseStackRegister(parts[0] ?? '');
|
|
168
|
+
return register
|
|
169
|
+
? { instruction: { mnemonic, register } }
|
|
170
|
+
: { error: `${mnemonic} supports BC/DE/HL/AF/IX/IY only` };
|
|
171
|
+
}
|
|
172
|
+
const ld = /^LD\s+(.+)$/i.exec(text);
|
|
173
|
+
if (ld) {
|
|
174
|
+
const operandText = ld[1] ?? '';
|
|
175
|
+
const parts = splitInstructionOperands(operandText);
|
|
176
|
+
if (parts.length !== 2) {
|
|
177
|
+
return { error: 'ld expects two operands' };
|
|
178
|
+
}
|
|
179
|
+
const indexedBracket = indexedBracketError(parts[0] ?? '') ?? indexedBracketError(parts[1] ?? '');
|
|
180
|
+
if (indexedBracket) {
|
|
181
|
+
return { error: indexedBracket };
|
|
182
|
+
}
|
|
183
|
+
const leftText = parts[0] ?? '';
|
|
184
|
+
const rightText = parts[1] ?? '';
|
|
185
|
+
if (/^AF$/i.test(leftText) || /^AF$/i.test(rightText)) {
|
|
186
|
+
return { error: 'ld does not support AF in this form' };
|
|
187
|
+
}
|
|
188
|
+
const target = parseLdOperand(leftText);
|
|
189
|
+
const source = parseLdOperand(rightText);
|
|
190
|
+
if (!target || !source) {
|
|
191
|
+
const operandDiagnostics = [
|
|
192
|
+
...invalidLdOperandDiagnostics(leftText),
|
|
193
|
+
...invalidLdOperandDiagnostics(rightText),
|
|
194
|
+
];
|
|
195
|
+
if (operandDiagnostics.length > 0) {
|
|
196
|
+
const error = operandDiagnostics[operandDiagnostics.length - 1];
|
|
197
|
+
return {
|
|
198
|
+
error,
|
|
199
|
+
diagnostics: operandDiagnostics,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { error: 'ld expects a supported register/memory/immediate transfer form' };
|
|
203
|
+
}
|
|
204
|
+
if (target.kind === 'reg8' &&
|
|
205
|
+
target.register !== 'a' &&
|
|
206
|
+
source.kind === 'reg-indirect' &&
|
|
207
|
+
source.register !== 'hl') {
|
|
208
|
+
return { error: 'ld r8, (bc/de) supports destination A only' };
|
|
209
|
+
}
|
|
210
|
+
if (target.kind === 'reg-indirect' &&
|
|
211
|
+
source.kind === 'reg8' &&
|
|
212
|
+
source.register !== 'a' &&
|
|
213
|
+
target.register !== 'hl') {
|
|
214
|
+
return { error: 'ld (bc/de), r8 supports source A only' };
|
|
215
|
+
}
|
|
216
|
+
if (target.kind === 'reg-half-index' && source.kind === 'reg-indirect') {
|
|
217
|
+
return {
|
|
218
|
+
error: `ld ${target.register.toUpperCase()}, source expects (ix+disp)`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const unsupportedReason = unsupportedLdReason(target, source);
|
|
222
|
+
if (unsupportedReason) {
|
|
223
|
+
return { error: unsupportedReason };
|
|
224
|
+
}
|
|
225
|
+
if (!isSupportedLd(target, source)) {
|
|
226
|
+
return { error: 'ld expects a supported register/memory/immediate transfer form' };
|
|
227
|
+
}
|
|
228
|
+
return { instruction: { mnemonic: 'ld', target, source } };
|
|
229
|
+
}
|
|
230
|
+
const bitLike = /^(BIT|RES|SET)(?:\s+(.*))?$/i.exec(text);
|
|
231
|
+
if (bitLike) {
|
|
232
|
+
const mnemonic = (bitLike[1] ?? '').toLowerCase();
|
|
233
|
+
const operandText = bitLike[2] ?? '';
|
|
234
|
+
const parts = splitInstructionOperands(operandText);
|
|
235
|
+
if (operandText.trim().length === 0 || parts.length < 2) {
|
|
236
|
+
return {
|
|
237
|
+
error: mnemonic === 'bit'
|
|
238
|
+
? 'bit expects two operands'
|
|
239
|
+
: `${mnemonic} expects two operands, or three with indexed source + reg8 destination`,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (mnemonic === 'bit' && parts.length !== 2) {
|
|
243
|
+
return { error: 'bit expects two operands' };
|
|
244
|
+
}
|
|
245
|
+
if (mnemonic !== 'bit' && parts.length > 3) {
|
|
246
|
+
return {
|
|
247
|
+
error: `${mnemonic} expects two operands, or three with indexed source + reg8 destination`,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const bit = parseBitIndex(parts[0] ?? '');
|
|
251
|
+
if (bit === undefined) {
|
|
252
|
+
return { error: `${mnemonic} expects bit index 0..7` };
|
|
253
|
+
}
|
|
254
|
+
const operand = parseCbOperand(parts[1] ?? '');
|
|
255
|
+
if (!operand) {
|
|
256
|
+
return { error: `${mnemonic} expects reg8 or (hl)` };
|
|
257
|
+
}
|
|
258
|
+
if (parts.length === 2) {
|
|
259
|
+
return { instruction: { mnemonic, bit, operand } };
|
|
260
|
+
}
|
|
261
|
+
if (operand.kind !== 'indexed') {
|
|
262
|
+
return { error: `${mnemonic} b,(ix/iy+disp),r requires an indexed memory source` };
|
|
263
|
+
}
|
|
264
|
+
const destination = parseRegister8Operand(parts[2] ?? '');
|
|
265
|
+
if (destination) {
|
|
266
|
+
return { instruction: { mnemonic, bit, operand, destination } };
|
|
267
|
+
}
|
|
268
|
+
const halfDestination = parseIndexHalfRegister(parts[2] ?? '');
|
|
269
|
+
if (halfDestination) {
|
|
270
|
+
return halfIndexFamilyFromRegister(halfDestination) === operand.register
|
|
271
|
+
? {
|
|
272
|
+
error: `${mnemonic} indexed destination must use plain reg8 B/C/D/E/H/L/A`,
|
|
273
|
+
}
|
|
274
|
+
: {
|
|
275
|
+
error: `${mnemonic} indexed destination family must match source index base`,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return { error: `${mnemonic} b,(ix/iy+disp),r expects reg8 destination` };
|
|
279
|
+
}
|
|
280
|
+
const rotateShift = /^(RLC|RRC|RL|RR|SLA|SRA|SLL|SLS|SRL)(?:\s+(.*))?$/i.exec(text);
|
|
281
|
+
if (rotateShift) {
|
|
282
|
+
const mnemonic = (rotateShift[1] ?? '').toLowerCase();
|
|
283
|
+
const operandText = rotateShift[2] ?? '';
|
|
284
|
+
const parts = splitInstructionOperands(operandText);
|
|
285
|
+
if (operandText.trim().length === 0) {
|
|
286
|
+
return {
|
|
287
|
+
error: `${mnemonic} expects one operand, or two with indexed source + reg8 destination`,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (parts.length > 2) {
|
|
291
|
+
return {
|
|
292
|
+
error: `${mnemonic} expects one operand, or two with indexed source + reg8 destination`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (parts.length === 2) {
|
|
296
|
+
const operand = parseCbOperand(parts[0] ?? '');
|
|
297
|
+
if (operand?.kind !== 'indexed') {
|
|
298
|
+
return { error: `${mnemonic} two-operand form requires (ix/iy+disp) source` };
|
|
299
|
+
}
|
|
300
|
+
const destination = parseRegister8Operand(parts[1] ?? '');
|
|
301
|
+
if (destination) {
|
|
302
|
+
return { instruction: { mnemonic, operand, destination } };
|
|
303
|
+
}
|
|
304
|
+
const halfDestination = parseIndexHalfRegister(parts[1] ?? '');
|
|
305
|
+
if (halfDestination) {
|
|
306
|
+
return halfIndexFamilyFromRegister(halfDestination) === operand.register
|
|
307
|
+
? {
|
|
308
|
+
error: `${mnemonic} indexed destination must use plain reg8 B/C/D/E/H/L/A`,
|
|
309
|
+
}
|
|
310
|
+
: {
|
|
311
|
+
error: `${mnemonic} indexed destination family must match source index base`,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
return { error: `${mnemonic} (ix/iy+disp),r expects reg8 destination` };
|
|
315
|
+
}
|
|
316
|
+
if (parts.length !== 1) {
|
|
317
|
+
return {
|
|
318
|
+
error: `${mnemonic} expects one operand, or two with indexed source + reg8 destination`,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
const operand = parseCbOperand(parts[0] ?? '');
|
|
322
|
+
return operand
|
|
323
|
+
? { instruction: { mnemonic, operand } }
|
|
324
|
+
: { error: `${mnemonic} expects reg8 or (hl)` };
|
|
325
|
+
}
|
|
326
|
+
const accumulatorAlu = /^(ADD|ADC|SBC)(?:\s+(.*))?$/i.exec(text);
|
|
327
|
+
if (accumulatorAlu) {
|
|
328
|
+
const mnemonic = (accumulatorAlu[1] ?? '').toLowerCase();
|
|
329
|
+
const operandText = accumulatorAlu[2] ?? '';
|
|
330
|
+
if (operandText.trim().length === 0) {
|
|
331
|
+
return {
|
|
332
|
+
error: mnemonic === 'add'
|
|
333
|
+
? 'add expects two operands'
|
|
334
|
+
: `${mnemonic} expects one operand, two with destination A, or HL,rr form`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const parts = splitInstructionOperands(operandText);
|
|
338
|
+
if (parts.length !== 2) {
|
|
339
|
+
return {
|
|
340
|
+
error: mnemonic === 'add'
|
|
341
|
+
? 'add expects two operands'
|
|
342
|
+
: `${mnemonic} expects one operand, two with destination A, or HL,rr form`,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
const target = parseRegister8Operand(parts[0] ?? '');
|
|
346
|
+
if (target?.register === 'a') {
|
|
347
|
+
const source = parseAluOperand(parts[1] ?? '');
|
|
348
|
+
if (!source) {
|
|
349
|
+
return { error: `invalid ${mnemonic.toUpperCase()} operand: ${parts[1] ?? ''}` };
|
|
350
|
+
}
|
|
351
|
+
const imm8Error = source.kind === 'imm' ? aluImm8RangeError(source.expression, mnemonic) : undefined;
|
|
352
|
+
if (imm8Error) {
|
|
353
|
+
return { error: imm8Error };
|
|
354
|
+
}
|
|
355
|
+
return { instruction: { mnemonic, source } };
|
|
356
|
+
}
|
|
357
|
+
const target16 = parseRegister16Operand(parts[0] ?? '');
|
|
358
|
+
if (target16?.register === 'hl') {
|
|
359
|
+
const source = parseRegister16Operand(parts[1] ?? '');
|
|
360
|
+
return source
|
|
361
|
+
? { instruction: { mnemonic: mnemonic, target: target16, source } }
|
|
362
|
+
: { error: `${mnemonic} HL, rr expects BC/DE/HL/SP` };
|
|
363
|
+
}
|
|
364
|
+
const targetIndex16 = parseIndexRegister16(parts[0] ?? '');
|
|
365
|
+
if (mnemonic === 'add' && targetIndex16) {
|
|
366
|
+
const target = { kind: 'reg-index16', register: targetIndex16 };
|
|
367
|
+
const source16 = parseRegister16Operand(parts[1] ?? '');
|
|
368
|
+
if (source16 && source16.register !== 'hl') {
|
|
369
|
+
return { instruction: { mnemonic, target, source: source16 } };
|
|
370
|
+
}
|
|
371
|
+
const sourceIndex16 = parseIndexRegister16(parts[1] ?? '');
|
|
372
|
+
if (sourceIndex16 === targetIndex16) {
|
|
373
|
+
return {
|
|
374
|
+
instruction: {
|
|
375
|
+
mnemonic,
|
|
376
|
+
target,
|
|
377
|
+
source: { kind: 'reg-index16', register: sourceIndex16 },
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
error: `add ${targetIndex16.toUpperCase()}, rr supports BC/DE/SP and same-index pair only`,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
return mnemonic === 'add'
|
|
386
|
+
? { error: 'add expects destination A, HL, IX, or IY' }
|
|
387
|
+
: { error: `${mnemonic} expects destination A or HL` };
|
|
388
|
+
}
|
|
389
|
+
const alu = /^(SUB|AND|OR|XOR|CP)(?:\s+(.*))?$/i.exec(text);
|
|
390
|
+
if (alu) {
|
|
391
|
+
const mnemonic = (alu[1] ?? '').toLowerCase();
|
|
392
|
+
const operandText = alu[2] ?? '';
|
|
393
|
+
if (operandText.trim().length === 0) {
|
|
394
|
+
return { error: `${mnemonic} expects one operand, or two with destination A` };
|
|
395
|
+
}
|
|
396
|
+
const parts = splitInstructionOperands(operandText);
|
|
397
|
+
if (parts.length === 2) {
|
|
398
|
+
const target = parseRegister8Operand(parts[0] ?? '');
|
|
399
|
+
if (target?.register === 'a') {
|
|
400
|
+
const source = parseAluOperand(parts[1] ?? '');
|
|
401
|
+
if (!source) {
|
|
402
|
+
return { error: `invalid ${mnemonic.toUpperCase()} operand: ${parts[1] ?? ''}` };
|
|
403
|
+
}
|
|
404
|
+
const imm8Error = source.kind === 'imm' ? aluImm8RangeError(source.expression, mnemonic) : undefined;
|
|
405
|
+
if (imm8Error) {
|
|
406
|
+
return { error: imm8Error };
|
|
407
|
+
}
|
|
408
|
+
return { instruction: { mnemonic, source } };
|
|
409
|
+
}
|
|
410
|
+
return { error: `${mnemonic} two-operand form requires destination A` };
|
|
411
|
+
}
|
|
412
|
+
if (parts.length !== 1) {
|
|
413
|
+
return { error: `${mnemonic} expects one operand, or two with destination A` };
|
|
414
|
+
}
|
|
415
|
+
const source = parseAluOperand(parts[0] ?? '');
|
|
416
|
+
if (!source) {
|
|
417
|
+
return { error: `invalid ${mnemonic.toUpperCase()} operand: ${operandText}` };
|
|
418
|
+
}
|
|
419
|
+
const imm8Error = source.kind === 'imm' ? aluImm8RangeError(source.expression, mnemonic) : undefined;
|
|
420
|
+
if (imm8Error) {
|
|
421
|
+
return { error: imm8Error };
|
|
422
|
+
}
|
|
423
|
+
return { instruction: { mnemonic, source } };
|
|
424
|
+
}
|
|
425
|
+
const jump = /^JP(?:\s+(.*))?$/i.exec(text);
|
|
426
|
+
if (jump) {
|
|
427
|
+
const operandText = jump[1] ?? '';
|
|
428
|
+
const parts = splitInstructionOperands(operandText);
|
|
429
|
+
if (operandText.trim().length === 0) {
|
|
430
|
+
return {
|
|
431
|
+
error: 'jp expects one operand (nn/(hl)/(ix)/(iy)) or two operands (cc, nn)',
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if (parts.length === 2) {
|
|
435
|
+
const condition = parseCondition(parts[0] ?? '');
|
|
436
|
+
if (!condition) {
|
|
437
|
+
return { error: 'jp cc expects valid condition code NZ/Z/NC/C/PO/PE/P/M' };
|
|
438
|
+
}
|
|
439
|
+
const targetText = parts[1] ?? '';
|
|
440
|
+
if (/^\(.*\)$/.test(targetText.trim())) {
|
|
441
|
+
return { error: 'jp cc, nn does not support indirect targets' };
|
|
442
|
+
}
|
|
443
|
+
const expression = parseAbsoluteBranchTarget(targetText);
|
|
444
|
+
return expression
|
|
445
|
+
? { instruction: { mnemonic: 'jp-cc', condition, expression } }
|
|
446
|
+
: { error: 'jp cc, nn expects imm16' };
|
|
447
|
+
}
|
|
448
|
+
if (parts.length !== 1) {
|
|
449
|
+
return {
|
|
450
|
+
error: 'jp expects one operand (nn/(hl)/(ix)/(iy)) or two operands (cc, nn)',
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const single = parts[0] ?? '';
|
|
454
|
+
const condition = parseCondition(single);
|
|
455
|
+
if (condition) {
|
|
456
|
+
return { error: 'jp cc, nn expects two operands (cc, nn)' };
|
|
457
|
+
}
|
|
458
|
+
const indirect = parseJumpIndirect(single);
|
|
459
|
+
if (indirect) {
|
|
460
|
+
return { instruction: { mnemonic: 'jp-indirect', register: indirect } };
|
|
461
|
+
}
|
|
462
|
+
if (/^\(.*\)$/.test(single.trim())) {
|
|
463
|
+
return { error: 'jp indirect form supports (hl), (ix), or (iy) only' };
|
|
464
|
+
}
|
|
465
|
+
if (isRegisterName(single)) {
|
|
466
|
+
if (/^(HL|IX|IY)$/i.test(single.trim())) {
|
|
467
|
+
return { error: 'jp indirect form requires parentheses; use (hl), (ix), or (iy)' };
|
|
468
|
+
}
|
|
469
|
+
return { error: 'jp does not support register targets; use imm16' };
|
|
470
|
+
}
|
|
471
|
+
const expression = parseExpression(single);
|
|
472
|
+
return expression
|
|
473
|
+
? { instruction: { mnemonic: 'jp', expression } }
|
|
474
|
+
: { error: `invalid JP target: ${single}` };
|
|
475
|
+
}
|
|
476
|
+
const call = /^CALL(?:\s+(.*))?$/i.exec(text);
|
|
477
|
+
if (call) {
|
|
478
|
+
const operandText = call[1] ?? '';
|
|
479
|
+
const parts = splitInstructionOperands(operandText);
|
|
480
|
+
if (operandText.trim().length === 0) {
|
|
481
|
+
return { error: 'call expects one operand (nn) or two operands (cc, nn)' };
|
|
482
|
+
}
|
|
483
|
+
if (parts.length === 2) {
|
|
484
|
+
const condition = parseCondition(parts[0] ?? '');
|
|
485
|
+
if (!condition) {
|
|
486
|
+
return { error: 'call cc expects valid condition code NZ/Z/NC/C/PO/PE/P/M' };
|
|
487
|
+
}
|
|
488
|
+
const targetText = parts[1] ?? '';
|
|
489
|
+
if (/^\(.*\)$/.test(targetText.trim())) {
|
|
490
|
+
return { error: 'call cc, nn does not support indirect targets' };
|
|
491
|
+
}
|
|
492
|
+
const expression = parseAbsoluteBranchTarget(targetText);
|
|
493
|
+
return expression
|
|
494
|
+
? { instruction: { mnemonic: 'call-cc', condition, expression } }
|
|
495
|
+
: { error: 'call cc, nn expects imm16' };
|
|
496
|
+
}
|
|
497
|
+
if (parts.length !== 1) {
|
|
498
|
+
return { error: 'call expects one operand (nn) or two operands (cc, nn)' };
|
|
499
|
+
}
|
|
500
|
+
const single = parts[0] ?? '';
|
|
501
|
+
const condition = parseCondition(single);
|
|
502
|
+
if (condition) {
|
|
503
|
+
return { error: 'call cc, nn expects two operands (cc, nn)' };
|
|
504
|
+
}
|
|
505
|
+
if (/^\(.*\)$/.test(single.trim())) {
|
|
506
|
+
return { error: 'call does not support indirect targets; use imm16' };
|
|
507
|
+
}
|
|
508
|
+
if (isRegisterName(single)) {
|
|
509
|
+
return { error: 'call does not support register targets; use imm16' };
|
|
510
|
+
}
|
|
511
|
+
const expression = parseExpression(single);
|
|
512
|
+
return expression
|
|
513
|
+
? { instruction: { mnemonic: 'call', expression } }
|
|
514
|
+
: { error: `invalid CALL target: ${single}` };
|
|
515
|
+
}
|
|
516
|
+
const relativeBranch = /^(JR|DJNZ)(?:\s+(.*))?$/i.exec(text);
|
|
517
|
+
if (relativeBranch) {
|
|
518
|
+
const mnemonic = (relativeBranch[1] ?? '').toLowerCase();
|
|
519
|
+
const operandText = (relativeBranch[2] ?? '').trim();
|
|
520
|
+
if (operandText.length === 0) {
|
|
521
|
+
return {
|
|
522
|
+
error: mnemonic === 'djnz'
|
|
523
|
+
? 'djnz expects one operand (disp8)'
|
|
524
|
+
: 'jr expects one operand (disp8) or two operands (cc, disp8)',
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
const parts = splitInstructionOperands(operandText);
|
|
528
|
+
if (mnemonic === 'djnz') {
|
|
529
|
+
if (parts.length !== 1) {
|
|
530
|
+
return { error: 'djnz expects one operand (disp8)' };
|
|
531
|
+
}
|
|
532
|
+
const targetText = parts[0] ?? '';
|
|
533
|
+
const targetError = relativeDispTargetError(targetText, {
|
|
534
|
+
indirect: 'djnz does not support indirect targets; expects disp8',
|
|
535
|
+
register: 'djnz does not support register targets; expects disp8',
|
|
536
|
+
});
|
|
537
|
+
if (targetError) {
|
|
538
|
+
return { error: targetError };
|
|
539
|
+
}
|
|
540
|
+
const expression = parseExpression(targetText);
|
|
541
|
+
return expression
|
|
542
|
+
? { instruction: { mnemonic: 'djnz', expression } }
|
|
543
|
+
: { error: 'djnz expects disp8' };
|
|
544
|
+
}
|
|
545
|
+
if (parts.length === 1) {
|
|
546
|
+
const targetText = parts[0] ?? '';
|
|
547
|
+
const targetError = relativeDispTargetError(targetText, {
|
|
548
|
+
indirect: 'jr does not support indirect targets; expects disp8',
|
|
549
|
+
register: 'jr does not support register targets; expects disp8',
|
|
550
|
+
});
|
|
551
|
+
if (targetError) {
|
|
552
|
+
return { error: targetError };
|
|
553
|
+
}
|
|
554
|
+
if (parseRelativeCondition(targetText)) {
|
|
555
|
+
return { error: 'jr cc, disp expects two operands (cc, disp8)' };
|
|
556
|
+
}
|
|
557
|
+
const expression = parseExpression(targetText);
|
|
558
|
+
return expression
|
|
559
|
+
? { instruction: { mnemonic: 'jr', expression } }
|
|
560
|
+
: { error: 'jr expects disp8' };
|
|
561
|
+
}
|
|
562
|
+
if (parts.length === 2) {
|
|
563
|
+
const condition = parseRelativeCondition(parts[0] ?? '');
|
|
564
|
+
if (!condition) {
|
|
565
|
+
return { error: 'jr cc expects valid condition code NZ/Z/NC/C' };
|
|
566
|
+
}
|
|
567
|
+
const targetText = parts[1] ?? '';
|
|
568
|
+
const targetError = relativeDispTargetError(targetText, {
|
|
569
|
+
indirect: 'jr cc, disp does not support indirect targets',
|
|
570
|
+
register: 'jr cc, disp does not support register targets; expects disp8',
|
|
571
|
+
});
|
|
572
|
+
if (targetError) {
|
|
573
|
+
return { error: targetError };
|
|
574
|
+
}
|
|
575
|
+
const expression = parseExpression(targetText);
|
|
576
|
+
return expression
|
|
577
|
+
? { instruction: { mnemonic: 'jr-cc', condition, expression } }
|
|
578
|
+
: { error: 'jr cc, disp expects disp8' };
|
|
579
|
+
}
|
|
580
|
+
return { error: 'jr expects one operand (disp8) or two operands (cc, disp8)' };
|
|
581
|
+
}
|
|
582
|
+
return undefined;
|
|
583
|
+
}
|
|
584
|
+
function parseLdOperand(text) {
|
|
585
|
+
const trimmed = text.trim();
|
|
586
|
+
const indexed = parseIndexedOperand(trimmed);
|
|
587
|
+
if (indexed) {
|
|
588
|
+
return indexed;
|
|
589
|
+
}
|
|
590
|
+
const memory = /^\((BC|DE|HL)\)$/i.exec(trimmed);
|
|
591
|
+
if (memory) {
|
|
592
|
+
return {
|
|
593
|
+
kind: 'reg-indirect',
|
|
594
|
+
register: (memory[1] ?? '').toLowerCase(),
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (trimmed.startsWith('(') && trimmed.endsWith(')')) {
|
|
598
|
+
const expression = parseExpression(trimmed.slice(1, -1).trim());
|
|
599
|
+
return expression ? { kind: 'mem-abs', expression } : undefined;
|
|
600
|
+
}
|
|
601
|
+
if (/^(A|B|C|D|E|H|L)$/i.test(trimmed)) {
|
|
602
|
+
return { kind: 'reg8', register: trimmed.toLowerCase() };
|
|
603
|
+
}
|
|
604
|
+
const index16 = parseIndexRegister16(trimmed);
|
|
605
|
+
if (index16) {
|
|
606
|
+
return { kind: 'reg-index16', register: index16 };
|
|
607
|
+
}
|
|
608
|
+
const half = parseIndexHalfRegister(trimmed);
|
|
609
|
+
if (half) {
|
|
610
|
+
return { kind: 'reg-half-index', register: half };
|
|
611
|
+
}
|
|
612
|
+
if (/^(BC|DE|HL|SP)$/i.test(trimmed)) {
|
|
613
|
+
return parseRegister16Operand(trimmed);
|
|
614
|
+
}
|
|
615
|
+
const special8 = parseSpecialRegister8(trimmed);
|
|
616
|
+
if (special8) {
|
|
617
|
+
return { kind: 'special8', register: special8 };
|
|
618
|
+
}
|
|
619
|
+
const expression = parseExpression(trimmed);
|
|
620
|
+
return expression ? { kind: 'imm', expression } : undefined;
|
|
621
|
+
}
|
|
622
|
+
function invalidLdOperandDiagnostics(text) {
|
|
623
|
+
const trimmed = text.trim();
|
|
624
|
+
if (trimmed === '?') {
|
|
625
|
+
return ['Invalid imm expression: ?', 'Unsupported operand: ?'];
|
|
626
|
+
}
|
|
627
|
+
if (trimmed.startsWith("'") && parseExpression(trimmed) === undefined) {
|
|
628
|
+
return [`Invalid imm expression: ${trimmed}`];
|
|
629
|
+
}
|
|
630
|
+
return [];
|
|
631
|
+
}
|
|
632
|
+
function aluImm8RangeError(expression, mnemonic) {
|
|
633
|
+
const value = constantExpressionValue(expression);
|
|
634
|
+
if (value === undefined) {
|
|
635
|
+
return undefined;
|
|
636
|
+
}
|
|
637
|
+
if (value < -128 || value > 255) {
|
|
638
|
+
return `${mnemonic} expects imm8`;
|
|
639
|
+
}
|
|
640
|
+
return undefined;
|
|
641
|
+
}
|
|
642
|
+
function parseRelativeCondition(text) {
|
|
643
|
+
const trimmed = text.trim().toLowerCase();
|
|
644
|
+
return /^(nz|z|nc|c)$/.test(trimmed) ? trimmed : undefined;
|
|
645
|
+
}
|
|
646
|
+
function relativeDispTargetError(text, messages) {
|
|
647
|
+
const trimmed = text.trim();
|
|
648
|
+
if (/^\(.*\)$/.test(trimmed)) {
|
|
649
|
+
return messages.indirect;
|
|
650
|
+
}
|
|
651
|
+
if (isRegisterName(trimmed)) {
|
|
652
|
+
return messages.register;
|
|
653
|
+
}
|
|
654
|
+
const expression = parseExpression(trimmed);
|
|
655
|
+
if (expression?.kind === 'symbol' && isRegisterName(expression.name)) {
|
|
656
|
+
return messages.register;
|
|
657
|
+
}
|
|
658
|
+
return undefined;
|
|
659
|
+
}
|
|
660
|
+
function parseAluOperand(text) {
|
|
661
|
+
const trimmed = text.trim();
|
|
662
|
+
const indexed = parseIndexedOperand(trimmed);
|
|
663
|
+
if (indexed) {
|
|
664
|
+
return indexed;
|
|
665
|
+
}
|
|
666
|
+
const memory = /^\(HL\)$/i.exec(trimmed);
|
|
667
|
+
if (memory) {
|
|
668
|
+
return { kind: 'reg-indirect', register: 'hl' };
|
|
669
|
+
}
|
|
670
|
+
if (trimmed.startsWith('(') && trimmed.endsWith(')')) {
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
const register = parseRegister8Operand(trimmed);
|
|
674
|
+
if (register) {
|
|
675
|
+
return register;
|
|
676
|
+
}
|
|
677
|
+
const half = parseIndexHalfRegister(trimmed);
|
|
678
|
+
if (half) {
|
|
679
|
+
return { kind: 'reg-half-index', register: half };
|
|
680
|
+
}
|
|
681
|
+
const expression = parseExpression(trimmed);
|
|
682
|
+
return expression ? { kind: 'imm', expression } : undefined;
|
|
683
|
+
}
|
|
684
|
+
function parseCbOperand(text) {
|
|
685
|
+
const trimmed = text.trim();
|
|
686
|
+
const indexed = parseIndexedOperand(trimmed);
|
|
687
|
+
if (indexed) {
|
|
688
|
+
return indexed;
|
|
689
|
+
}
|
|
690
|
+
if (/^\(HL\)$/i.test(trimmed)) {
|
|
691
|
+
return { kind: 'reg-indirect', register: 'hl' };
|
|
692
|
+
}
|
|
693
|
+
return parseRegister8Operand(trimmed);
|
|
694
|
+
}
|
|
695
|
+
function parseRegister8Operand(text) {
|
|
696
|
+
const trimmed = text.trim();
|
|
697
|
+
if (/^(A|B|C|D|E|H|L)$/i.test(trimmed)) {
|
|
698
|
+
return { kind: 'reg8', register: trimmed.toLowerCase() };
|
|
699
|
+
}
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
702
|
+
function parseRegister16Operand(text) {
|
|
703
|
+
const trimmed = text.trim();
|
|
704
|
+
if (/^(BC|DE|HL|SP)$/i.test(trimmed)) {
|
|
705
|
+
return { kind: 'reg16', register: trimmed.toLowerCase() };
|
|
706
|
+
}
|
|
707
|
+
return undefined;
|
|
708
|
+
}
|
|
709
|
+
function parseIncDecOperand(text) {
|
|
710
|
+
const trimmed = text.trim();
|
|
711
|
+
const indexed = parseIndexedOperand(trimmed);
|
|
712
|
+
if (indexed) {
|
|
713
|
+
return indexed;
|
|
714
|
+
}
|
|
715
|
+
if (/^\(HL\)$/i.test(trimmed)) {
|
|
716
|
+
return { kind: 'reg-indirect', register: 'hl' };
|
|
717
|
+
}
|
|
718
|
+
const register8 = parseRegister8Operand(trimmed);
|
|
719
|
+
if (register8) {
|
|
720
|
+
return register8;
|
|
721
|
+
}
|
|
722
|
+
const register16 = parseRegister16Operand(trimmed);
|
|
723
|
+
if (register16) {
|
|
724
|
+
return register16;
|
|
725
|
+
}
|
|
726
|
+
const index16 = parseIndexRegister16(trimmed);
|
|
727
|
+
if (index16) {
|
|
728
|
+
return { kind: 'reg16', register: index16 };
|
|
729
|
+
}
|
|
730
|
+
const half = parseIndexHalfRegister(trimmed);
|
|
731
|
+
return half ? { kind: 'reg-half-index', register: half } : undefined;
|
|
732
|
+
}
|
|
733
|
+
function parseIndexRegister16(text) {
|
|
734
|
+
const trimmed = text.trim();
|
|
735
|
+
return /^(IX|IY)$/i.test(trimmed) ? trimmed.toLowerCase() : undefined;
|
|
736
|
+
}
|
|
737
|
+
function parseIndexHalfRegister(text) {
|
|
738
|
+
const trimmed = text.trim();
|
|
739
|
+
return /^(IXH|IXL|IYH|IYL)$/i.test(trimmed)
|
|
740
|
+
? trimmed.toLowerCase()
|
|
741
|
+
: undefined;
|
|
742
|
+
}
|
|
743
|
+
function halfIndexFamilyFromRegister(register) {
|
|
744
|
+
return register.startsWith('ix') ? 'ix' : 'iy';
|
|
745
|
+
}
|
|
746
|
+
function parseSpecialRegister8(text) {
|
|
747
|
+
const trimmed = text.trim();
|
|
748
|
+
return /^(I|R)$/i.test(trimmed) ? trimmed.toLowerCase() : undefined;
|
|
749
|
+
}
|
|
750
|
+
function parseStackRegister(text) {
|
|
751
|
+
const trimmed = text.trim();
|
|
752
|
+
return /^(BC|DE|HL|AF|IX|IY)$/i.test(trimmed)
|
|
753
|
+
? trimmed.toLowerCase()
|
|
754
|
+
: undefined;
|
|
755
|
+
}
|
|
756
|
+
function parseIndexedOperand(text) {
|
|
757
|
+
const trimmed = text.trim();
|
|
758
|
+
if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
const inner = trimmed.slice(1, -1).trim();
|
|
762
|
+
const match = /^(IX|IY)(?:\s*([+-])\s*(.+))?$/i.exec(inner);
|
|
763
|
+
if (!match) {
|
|
764
|
+
return undefined;
|
|
765
|
+
}
|
|
766
|
+
const register = (match[1] ?? '').toLowerCase();
|
|
767
|
+
const sign = match[2];
|
|
768
|
+
const displacementText = match[3] ?? '0';
|
|
769
|
+
const parsed = parseExpression(sign === '-' ? `-${displacementText}` : displacementText);
|
|
770
|
+
if (!parsed) {
|
|
771
|
+
return undefined;
|
|
772
|
+
}
|
|
773
|
+
return { kind: 'indexed', register, displacement: parsed };
|
|
774
|
+
}
|
|
775
|
+
function parsePortOperand(text) {
|
|
776
|
+
const trimmed = text.trim();
|
|
777
|
+
if (/^\(C\)$/i.test(trimmed)) {
|
|
778
|
+
return { kind: 'c' };
|
|
779
|
+
}
|
|
780
|
+
if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) {
|
|
781
|
+
return undefined;
|
|
782
|
+
}
|
|
783
|
+
const expression = parseExpression(trimmed.slice(1, -1).trim());
|
|
784
|
+
return expression ? { kind: 'imm', expression } : undefined;
|
|
785
|
+
}
|
|
786
|
+
function indexedBracketError(text) {
|
|
787
|
+
const match = /^\(?\s*((IX|IY)\s*\[\s*.+?\s*\])\s*\)?$/i.exec(text.trim());
|
|
788
|
+
return match
|
|
789
|
+
? `Indexed memory operands use (ix+disp)/(iy+disp), not ${match[1]?.toLowerCase().replace(/\s+/g, '')}.`
|
|
790
|
+
: undefined;
|
|
791
|
+
}
|
|
792
|
+
function parseAbsoluteBranchTarget(text) {
|
|
793
|
+
const trimmed = text.trim();
|
|
794
|
+
if (/^\(.*\)$/.test(trimmed) || isRegisterName(trimmed)) {
|
|
795
|
+
return undefined;
|
|
796
|
+
}
|
|
797
|
+
return parseExpression(trimmed);
|
|
798
|
+
}
|
|
799
|
+
function parseCondition(text) {
|
|
800
|
+
const trimmed = text.trim();
|
|
801
|
+
return /^(NZ|Z|NC|C|PO|PE|P|M)$/i.test(trimmed)
|
|
802
|
+
? trimmed.toLowerCase()
|
|
803
|
+
: undefined;
|
|
804
|
+
}
|
|
805
|
+
function parseJumpIndirect(text) {
|
|
806
|
+
const indirect = /^\((HL|IX|IY)\)$/i.exec(text.trim());
|
|
807
|
+
return indirect ? (indirect[1] ?? '').toLowerCase() : undefined;
|
|
808
|
+
}
|
|
809
|
+
function isRegisterName(text) {
|
|
810
|
+
return /^(A|B|C|D|E|H|L|I|R|AF|BC|DE|HL|SP|IX|IY|IXH|IXL|IYH|IYL)$/i.test(text.trim());
|
|
811
|
+
}
|
|
812
|
+
function parseConstantExpression(text) {
|
|
813
|
+
const expression = parseExpression(text);
|
|
814
|
+
return expression ? constantExpressionValue(expression) : undefined;
|
|
815
|
+
}
|
|
816
|
+
function isRstVector(value) {
|
|
817
|
+
return (value === 0 ||
|
|
818
|
+
value === 8 ||
|
|
819
|
+
value === 16 ||
|
|
820
|
+
value === 24 ||
|
|
821
|
+
value === 32 ||
|
|
822
|
+
value === 40 ||
|
|
823
|
+
value === 48 ||
|
|
824
|
+
value === 56);
|
|
825
|
+
}
|
|
826
|
+
function parseBitIndex(text) {
|
|
827
|
+
const value = parseConstantExpression(text);
|
|
828
|
+
return isBitIndex(value) ? value : undefined;
|
|
829
|
+
}
|
|
830
|
+
function isBitIndex(value) {
|
|
831
|
+
return (value === 0 ||
|
|
832
|
+
value === 1 ||
|
|
833
|
+
value === 2 ||
|
|
834
|
+
value === 3 ||
|
|
835
|
+
value === 4 ||
|
|
836
|
+
value === 5 ||
|
|
837
|
+
value === 6 ||
|
|
838
|
+
value === 7);
|
|
839
|
+
}
|
|
840
|
+
function constantExpressionValue(expression) {
|
|
841
|
+
switch (expression.kind) {
|
|
842
|
+
case 'number':
|
|
843
|
+
return expression.value;
|
|
844
|
+
case 'unary':
|
|
845
|
+
return constantUnaryExpressionValue(expression);
|
|
846
|
+
case 'binary':
|
|
847
|
+
return constantBinaryExpressionValue(expression);
|
|
848
|
+
case 'symbol':
|
|
849
|
+
case 'current-location':
|
|
850
|
+
return undefined;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function constantUnaryExpressionValue(expression) {
|
|
854
|
+
const value = constantExpressionValue(expression.expression);
|
|
855
|
+
if (value === undefined) {
|
|
856
|
+
return undefined;
|
|
857
|
+
}
|
|
858
|
+
switch (expression.operator) {
|
|
859
|
+
case '+':
|
|
860
|
+
return value;
|
|
861
|
+
case '-':
|
|
862
|
+
return -value;
|
|
863
|
+
case '~':
|
|
864
|
+
return ~value;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
function constantBinaryExpressionValue(expression) {
|
|
868
|
+
const left = constantExpressionValue(expression.left);
|
|
869
|
+
const right = constantExpressionValue(expression.right);
|
|
870
|
+
if (left === undefined || right === undefined) {
|
|
871
|
+
return undefined;
|
|
872
|
+
}
|
|
873
|
+
switch (expression.operator) {
|
|
874
|
+
case '+':
|
|
875
|
+
return left + right;
|
|
876
|
+
case '-':
|
|
877
|
+
return left - right;
|
|
878
|
+
case '*':
|
|
879
|
+
return left * right;
|
|
880
|
+
case '/':
|
|
881
|
+
return Math.trunc(left / right);
|
|
882
|
+
case '%':
|
|
883
|
+
return left % right;
|
|
884
|
+
case '&':
|
|
885
|
+
return left & right;
|
|
886
|
+
case '^':
|
|
887
|
+
return left ^ right;
|
|
888
|
+
case '|':
|
|
889
|
+
return left | right;
|
|
890
|
+
case '<<':
|
|
891
|
+
return left << right;
|
|
892
|
+
case '>>':
|
|
893
|
+
return left >> right;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function splitInstructionOperands(text) {
|
|
897
|
+
const values = [];
|
|
898
|
+
let depth = 0;
|
|
899
|
+
let quote;
|
|
900
|
+
let escaped = false;
|
|
901
|
+
let start = 0;
|
|
902
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
903
|
+
const char = text[index];
|
|
904
|
+
if (escaped) {
|
|
905
|
+
escaped = false;
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (char === '\\' && quote) {
|
|
909
|
+
escaped = true;
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if ((char === '"' || char === "'") &&
|
|
913
|
+
!(char === "'" && quote === undefined && /[A-Za-z0-9_]/.test(text[index - 1] ?? ''))) {
|
|
914
|
+
quote = quote === char ? undefined : (quote ?? char);
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (quote) {
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
if (char === '(') {
|
|
921
|
+
depth += 1;
|
|
922
|
+
}
|
|
923
|
+
else if (char === ')') {
|
|
924
|
+
depth -= 1;
|
|
925
|
+
}
|
|
926
|
+
else if (char === ',' && depth === 0) {
|
|
927
|
+
values.push(text.slice(start, index));
|
|
928
|
+
start = index + 1;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
values.push(text.slice(start));
|
|
932
|
+
return values.map((value) => value.trim());
|
|
933
|
+
}
|
|
934
|
+
function isSupportedLd(target, source) {
|
|
935
|
+
if (isSupportedSpecialRegisterLd(target, source)) {
|
|
936
|
+
return true;
|
|
937
|
+
}
|
|
938
|
+
if (isSupportedHalfIndexLd(target, source)) {
|
|
939
|
+
return true;
|
|
940
|
+
}
|
|
941
|
+
if (target.kind === 'reg8' && (source.kind === 'reg8' || source.kind === 'imm')) {
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
if (target.kind === 'reg8' && source.kind === 'indexed') {
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
if (target.kind === 'indexed' && (source.kind === 'reg8' || source.kind === 'imm')) {
|
|
948
|
+
return true;
|
|
949
|
+
}
|
|
950
|
+
if (target.kind === 'reg16' && source.kind === 'imm') {
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
if (target.kind === 'reg16' &&
|
|
954
|
+
source.kind === 'reg16' &&
|
|
955
|
+
isLegacyReg16ByteTransferPair(target.register, source.register)) {
|
|
956
|
+
return true;
|
|
957
|
+
}
|
|
958
|
+
if (target.kind === 'reg-index16' && source.kind === 'imm') {
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
if (target.kind === 'reg16' &&
|
|
962
|
+
target.register === 'sp' &&
|
|
963
|
+
(source.kind === 'reg16' || source.kind === 'reg-index16') &&
|
|
964
|
+
(source.register === 'hl' || source.register === 'ix' || source.register === 'iy')) {
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
if ((target.kind === 'reg8' || target.kind === 'reg16' || target.kind === 'reg-index16') &&
|
|
968
|
+
source.kind === 'mem-abs' &&
|
|
969
|
+
(target.kind !== 'reg8' || target.register === 'a')) {
|
|
970
|
+
return true;
|
|
971
|
+
}
|
|
972
|
+
if (target.kind === 'mem-abs' &&
|
|
973
|
+
(source.kind === 'reg16' ||
|
|
974
|
+
source.kind === 'reg-index16' ||
|
|
975
|
+
(source.kind === 'reg8' && source.register === 'a'))) {
|
|
976
|
+
return true;
|
|
977
|
+
}
|
|
978
|
+
if (target.kind === 'reg8' && target.register === 'a' && source.kind === 'reg-indirect') {
|
|
979
|
+
return true;
|
|
980
|
+
}
|
|
981
|
+
if (target.kind === 'reg-indirect' && source.kind === 'reg8' && source.register === 'a') {
|
|
982
|
+
return true;
|
|
983
|
+
}
|
|
984
|
+
if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'reg8') {
|
|
985
|
+
return true;
|
|
986
|
+
}
|
|
987
|
+
if (target.kind === 'reg-indirect' && target.register === 'hl' && source.kind === 'imm') {
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
return target.kind === 'reg8' && source.kind === 'reg-indirect' && source.register === 'hl';
|
|
991
|
+
}
|
|
992
|
+
function unsupportedLdReason(target, source) {
|
|
993
|
+
if (isMemoryOperand(target) && isMemoryOperand(source)) {
|
|
994
|
+
return 'ld does not support memory-to-memory transfers';
|
|
995
|
+
}
|
|
996
|
+
if (hasHalfIndexRegister(target, source)) {
|
|
997
|
+
if (!isSameIndexHalfFamily(target, source)) {
|
|
998
|
+
return 'ld between IX* and IY* byte registers is not supported';
|
|
999
|
+
}
|
|
1000
|
+
if (usesPlainHlCounterpart(target, source)) {
|
|
1001
|
+
return 'ld with IX*/IY* does not support plain H/L counterpart operands';
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
if (target.kind === 'reg-index16' &&
|
|
1005
|
+
source.kind === 'reg-index16' &&
|
|
1006
|
+
target.register !== source.register) {
|
|
1007
|
+
return 'ld rr, rr supports SP <- HL/IX/IY only';
|
|
1008
|
+
}
|
|
1009
|
+
if (target.kind === 'reg16' &&
|
|
1010
|
+
source.kind !== 'imm' &&
|
|
1011
|
+
(source.kind === 'reg16' || source.kind === 'reg-index16')) {
|
|
1012
|
+
if (target.register === 'sp' &&
|
|
1013
|
+
(source.register === 'hl' || source.register === 'ix' || source.register === 'iy')) {
|
|
1014
|
+
return undefined;
|
|
1015
|
+
}
|
|
1016
|
+
if (source.kind === 'reg16' &&
|
|
1017
|
+
isLegacyReg16ByteTransferPair(target.register, source.register)) {
|
|
1018
|
+
return undefined;
|
|
1019
|
+
}
|
|
1020
|
+
return 'ld rr, rr supports SP <- HL/IX/IY only';
|
|
1021
|
+
}
|
|
1022
|
+
return undefined;
|
|
1023
|
+
}
|
|
1024
|
+
function isLegacyReg16ByteTransferPair(target, source) {
|
|
1025
|
+
return ((target === 'hl' && source === 'de') ||
|
|
1026
|
+
(target === 'bc' && source === 'de'));
|
|
1027
|
+
}
|
|
1028
|
+
function isSupportedSpecialRegisterLd(target, source) {
|
|
1029
|
+
return ((target.kind === 'special8' && source.kind === 'reg8' && source.register === 'a') ||
|
|
1030
|
+
(target.kind === 'reg8' && target.register === 'a' && source.kind === 'special8'));
|
|
1031
|
+
}
|
|
1032
|
+
function isMemoryOperand(operand) {
|
|
1033
|
+
return (operand.kind === 'reg-indirect' || operand.kind === 'indexed' || operand.kind === 'mem-abs');
|
|
1034
|
+
}
|
|
1035
|
+
function isSupportedHalfIndexLd(target, source) {
|
|
1036
|
+
if (!hasHalfIndexRegister(target, source)) {
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
if (!isSameIndexHalfFamily(target, source) || usesPlainHlCounterpart(target, source)) {
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
return isHalfIndexCompatibleByteOperand(target) && isHalfIndexCompatibleByteOperand(source);
|
|
1043
|
+
}
|
|
1044
|
+
function hasHalfIndexRegister(target, source) {
|
|
1045
|
+
return target.kind === 'reg-half-index' || source.kind === 'reg-half-index';
|
|
1046
|
+
}
|
|
1047
|
+
function isSameIndexHalfFamily(target, source) {
|
|
1048
|
+
const targetFamily = indexHalfFamily(target);
|
|
1049
|
+
const sourceFamily = indexHalfFamily(source);
|
|
1050
|
+
return !targetFamily || !sourceFamily || targetFamily === sourceFamily;
|
|
1051
|
+
}
|
|
1052
|
+
function indexHalfFamily(operand) {
|
|
1053
|
+
if (operand.kind !== 'reg-half-index') {
|
|
1054
|
+
return undefined;
|
|
1055
|
+
}
|
|
1056
|
+
return operand.register.startsWith('ix') ? 'ix' : 'iy';
|
|
1057
|
+
}
|
|
1058
|
+
function usesPlainHlCounterpart(target, source) {
|
|
1059
|
+
return ((target.kind === 'reg-half-index' && isPlainHlReg8(source)) ||
|
|
1060
|
+
(source.kind === 'reg-half-index' && isPlainHlReg8(target)));
|
|
1061
|
+
}
|
|
1062
|
+
function isPlainHlReg8(operand) {
|
|
1063
|
+
return operand.kind === 'reg8' && (operand.register === 'h' || operand.register === 'l');
|
|
1064
|
+
}
|
|
1065
|
+
function isHalfIndexCompatibleByteOperand(operand) {
|
|
1066
|
+
return (operand.kind === 'reg-half-index' ||
|
|
1067
|
+
(operand.kind === 'reg8' && operand.register !== 'h' && operand.register !== 'l'));
|
|
1068
|
+
}
|