import { R8 } from "./cpu"
|
|
import { Loc, LocType } from "../ir/loc"
|
|
import { Operand, AbsInsn2, insnReduce2 } from "../ir/insn"
|
|
import { BinaryOp, UnaryOp } from "../ast"
|
|
import type { SM83Insn } from "./insn"
|
|
import { BasicBlock } from "../ir/block"
|
|
|
|
export const realizeBlock = (block: BasicBlock): Array<SM83Insn> => block.insns.flatMap(realizeInsn)
|
|
|
|
export const realizeInsn = (insn: AbsInsn2): Array<SM83Insn> => insnReduce2(
|
|
realizeCopy,
|
|
realizeLabel,
|
|
realizeGoto,
|
|
realizeUnary,
|
|
insn,
|
|
)
|
|
|
|
const getSourceName = (source: Operand): string => typeof source === "number"
|
|
? source.toString()
|
|
: source.asmName()
|
|
|
|
export const realizeCopy = (dest: Loc, source: Operand): Array<SM83Insn> => [
|
|
`LD ${dest.asmName()}, ${getSourceName(source)}`
|
|
]
|
|
|
|
export const realizeLabel = (name: string): Array<SM83Insn> => [
|
|
`${name}:`,
|
|
]
|
|
|
|
export const realizeGoto = (name: string): Array<SM83Insn> => [
|
|
`JR ${name}`,
|
|
]
|
|
|
|
export const realizeUnary = (dest: Loc, op: UnaryOp | BinaryOp, source: Operand): Array<SM83Insn> => {
|
|
if (!isA(dest)) {
|
|
throw new Error("unexpected form for unary operation")
|
|
}
|
|
|
|
let output: Array<SM83Insn> = []
|
|
|
|
switch (op) {
|
|
case "add":
|
|
return [`ADD ${getSourceName(source)}`]
|
|
|
|
case "subtract":
|
|
return [`SUB ${getSourceName(source)}`]
|
|
|
|
case "bit_and":
|
|
return [`AND ${getSourceName(source)}`]
|
|
|
|
case "bit_or":
|
|
return [`OR ${getSourceName(source)}`]
|
|
|
|
case "bit_xor":
|
|
return [`XOR ${getSourceName(source)}`]
|
|
|
|
case "shift_left":
|
|
for (let i = 0; i < source; ++i) {
|
|
output.push("SLA A")
|
|
}
|
|
return output
|
|
|
|
case "shift_right":
|
|
for (let i = 0; i < source; ++i) {
|
|
output.push("SRL A")
|
|
}
|
|
return output
|
|
|
|
case "arith_negate":
|
|
return ["CPL", "INC A"]
|
|
|
|
case "bit_negate":
|
|
return ["CPL"]
|
|
}
|
|
}
|
|
|
|
const isA = (loc: Operand): boolean =>
|
|
typeof loc === "object" && loc.type === LocType.REGISTER && loc.name === R8.A
|