mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-10 11:54:30 +00:00
Fix and extend Z80 word/long operations
This commit is contained in:
parent
57bde60ced
commit
0da4637036
@ -102,6 +102,10 @@ object ZLine {
|
|||||||
def ldAbs8(target: Constant, source: ZRegister.Value): ZLine = ZLine(LD, TwoRegisters(MEM_ABS_8, source), target)
|
def ldAbs8(target: Constant, source: ZRegister.Value): ZLine = ZLine(LD, TwoRegisters(MEM_ABS_8, source), target)
|
||||||
|
|
||||||
def ldAbs16(target: Constant, source: ZRegister.Value): ZLine = ZLine(LD_16, TwoRegisters(MEM_ABS_16, source), target)
|
def ldAbs16(target: Constant, source: ZRegister.Value): ZLine = ZLine(LD_16, TwoRegisters(MEM_ABS_16, source), target)
|
||||||
|
|
||||||
|
def ldViaIx(target: ZRegister.Value, sourceOffset: Int): ZLine = ZLine(LD, TwoRegisters(target, ZRegister.MEM_IX_D), NumericConstant(sourceOffset, 1))
|
||||||
|
|
||||||
|
def ldViaIx(targetOffset: Int, source: ZRegister.Value): ZLine = ZLine(LD, TwoRegisters(ZRegister.MEM_IX_D, source), NumericConstant(targetOffset, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Constant, elidable: Boolean = true) extends AbstractCode {
|
case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Constant, elidable: Boolean = true) extends AbstractCode {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package millfork.compiler.z80
|
package millfork.compiler.z80
|
||||||
|
|
||||||
|
import millfork.CompilationFlag
|
||||||
import millfork.assembly.z80._
|
import millfork.assembly.z80._
|
||||||
import millfork.compiler._
|
import millfork.compiler._
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
@ -88,12 +89,22 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
def stashHLIfChanged(lines: List[ZLine]): List[ZLine] = if (lines.exists(changesHL))
|
def stashHLIfChanged(lines: List[ZLine]): List[ZLine] = if (lines.exists(changesHL))
|
||||||
ZLine.register(PUSH, ZRegister.HL) :: (lines :+ ZLine.register(POP, ZRegister.HL)) else lines
|
ZLine.register(PUSH, ZRegister.HL) :: (lines :+ ZLine.register(POP, ZRegister.HL)) else lines
|
||||||
|
|
||||||
def targetifyA(target: ZExpressionTarget.Value, lines: List[ZLine]): List[ZLine] = target match {
|
def targetifyA(target: ZExpressionTarget.Value, lines: List[ZLine], isSigned: Boolean): List[ZLine] = target match {
|
||||||
case ZExpressionTarget.NOTHING | ZExpressionTarget.A => lines
|
case ZExpressionTarget.NOTHING | ZExpressionTarget.A => lines
|
||||||
case ZExpressionTarget.HL => lines ++ List(
|
case ZExpressionTarget.HL => lines ++ (if (isSigned) {
|
||||||
|
val label = Z80Compiler.nextLabel("sx")
|
||||||
|
List(
|
||||||
ZLine.ld8(ZRegister.L, ZRegister.A),
|
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||||
ZLine.ldImm8(ZRegister.H, 0)
|
ZLine.ldImm8(ZRegister.H, 0xff),
|
||||||
)
|
ZLine.imm8(OR, 0x7f),
|
||||||
|
ZLine.jump(label, IfFlagSet(ZFlag.S)), // TODO: gameboy has no S flag
|
||||||
|
ZLine.ldImm8(ZRegister.H, 0),
|
||||||
|
ZLine.label(label))
|
||||||
|
} else {
|
||||||
|
List(
|
||||||
|
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||||
|
ZLine.ldImm8(ZRegister.H, 0))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
def targetifyHL(target: ZExpressionTarget.Value, lines: List[ZLine]): List[ZLine] = target match {
|
def targetifyHL(target: ZExpressionTarget.Value, lines: List[ZLine]): List[ZLine] = target match {
|
||||||
@ -139,7 +150,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
}
|
}
|
||||||
case SumExpression(params, decimal) =>
|
case SumExpression(params, decimal) =>
|
||||||
getParamMaxSize(ctx, params.map(_._2)) match {
|
getParamMaxSize(ctx, params.map(_._2)) match {
|
||||||
case 1 => targetifyA(target, ZBuiltIns.compile8BitSum(ctx, params, decimal))
|
case 1 => targetifyA(target, ZBuiltIns.compile8BitSum(ctx, params, decimal), isSigned = false)
|
||||||
case 2 => targetifyHL(target, ZBuiltIns.compile16BitSum(ctx, params, decimal))
|
case 2 => targetifyHL(target, ZBuiltIns.compile16BitSum(ctx, params, decimal))
|
||||||
}
|
}
|
||||||
case f@FunctionCallExpression(name, params) =>
|
case f@FunctionCallExpression(name, params) =>
|
||||||
@ -147,8 +158,47 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
case "not" =>
|
case "not" =>
|
||||||
assertBool(ctx, "not", params, 1)
|
assertBool(ctx, "not", params, 1)
|
||||||
compile(ctx, params.head, target, branches.flip)
|
compile(ctx, params.head, target, branches.flip)
|
||||||
case "hi" | "lo" => ??? // TODO
|
case "hi" =>
|
||||||
case "nonet" => ??? // TODO
|
if (params.length != 1) {
|
||||||
|
ErrorReporting.error("Too many parameters for hi/lo", f.position)
|
||||||
|
Nil
|
||||||
|
} else {
|
||||||
|
compileToHL(ctx, params.head) ++ (target match {
|
||||||
|
case ZExpressionTarget.NOTHING => Nil
|
||||||
|
case ZExpressionTarget.A=> List(ZLine.ld8(ZRegister.A, ZRegister.H))
|
||||||
|
case ZExpressionTarget.HL=> List(ZLine.ld8(ZRegister.L, ZRegister.H), ZLine.ldImm8(ZRegister.H, 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case "lo" =>
|
||||||
|
if (params.length != 1) {
|
||||||
|
ErrorReporting.error("Too many parameters for hi/lo", f.position)
|
||||||
|
Nil
|
||||||
|
} else {
|
||||||
|
compileToHL(ctx, params.head) ++ (target match {
|
||||||
|
case ZExpressionTarget.NOTHING => Nil
|
||||||
|
case ZExpressionTarget.A => List(ZLine.ld8(ZRegister.A, ZRegister.L))
|
||||||
|
case ZExpressionTarget.HL => List(ZLine.ldImm8(ZRegister.H, 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case "nonet" =>
|
||||||
|
if (params.length != 1) {
|
||||||
|
ErrorReporting.error("Invalid number of parameters", f.position)
|
||||||
|
Nil
|
||||||
|
} else {
|
||||||
|
compileToA(ctx, params.head) ++ (target match {
|
||||||
|
case ZExpressionTarget.NOTHING => Nil
|
||||||
|
case ZExpressionTarget.A => Nil
|
||||||
|
case ZExpressionTarget.HL =>
|
||||||
|
if (ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)) {
|
||||||
|
List(
|
||||||
|
ZLine.ld8(ZRegister.L, ZRegister.A),
|
||||||
|
ZLine.ldImm8(ZRegister.H, 0),
|
||||||
|
ZLine.register(RL, ZRegister.H))
|
||||||
|
} else {
|
||||||
|
???
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
case "&&" =>
|
case "&&" =>
|
||||||
assertBool(ctx, "&&", params)
|
assertBool(ctx, "&&", params)
|
||||||
branches match {
|
branches match {
|
||||||
@ -175,18 +225,18 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
|
|
||||||
case "&" =>
|
case "&" =>
|
||||||
getParamMaxSize(ctx, params) match {
|
getParamMaxSize(ctx, params) match {
|
||||||
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, AND, params))
|
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, AND, params), isSigned = false)
|
||||||
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, AND, params))
|
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, AND, params))
|
||||||
}
|
}
|
||||||
case "*" => ???
|
case "*" => ???
|
||||||
case "|" =>
|
case "|" =>
|
||||||
getParamMaxSize(ctx, params) match {
|
getParamMaxSize(ctx, params) match {
|
||||||
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, OR, params))
|
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, OR, params), isSigned = false)
|
||||||
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, OR, params))
|
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, OR, params))
|
||||||
}
|
}
|
||||||
case "^" =>
|
case "^" =>
|
||||||
getParamMaxSize(ctx, params) match {
|
getParamMaxSize(ctx, params) match {
|
||||||
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, XOR, params))
|
case 1 => targetifyA(target, ZBuiltIns.compile8BitOperation(ctx, XOR, params), isSigned = false)
|
||||||
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, XOR, params))
|
case 2 => targetifyHL(target, ZBuiltIns.compile16BitOperation(ctx, XOR, params))
|
||||||
}
|
}
|
||||||
case ">>>>" =>
|
case ">>>>" =>
|
||||||
@ -195,14 +245,14 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
case "<<" =>
|
case "<<" =>
|
||||||
val (l, r, size) = assertBinary(ctx, params)
|
val (l, r, size) = assertBinary(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => targetifyA(target, Z80Shifting.compile8BitShift(ctx, l, r, left = true))
|
case 1 => targetifyA(target, Z80Shifting.compile8BitShift(ctx, l, r, left = true), isSigned = false)
|
||||||
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = true)
|
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = true)
|
||||||
case _ => ???
|
case _ => ???
|
||||||
}
|
}
|
||||||
case ">>" =>
|
case ">>" =>
|
||||||
val (l, r, size) = assertBinary(ctx, params)
|
val (l, r, size) = assertBinary(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => targetifyA(target, Z80Shifting.compile8BitShift(ctx, l, r, left = false))
|
case 1 => targetifyA(target, Z80Shifting.compile8BitShift(ctx, l, r, left = false), isSigned = false)
|
||||||
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = false)
|
case 2 => Z80Shifting.compile16BitShift(ctx, l, r, left = false)
|
||||||
case _ => ???
|
case _ => ???
|
||||||
}
|
}
|
||||||
@ -266,25 +316,25 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, ADD)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, ADD)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, ADD, ADC, size, decimal = false)
|
||||||
}
|
}
|
||||||
case "-=" =>
|
case "-=" =>
|
||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, SUB)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, SUB)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, SUB, SBC, size, decimal = false)
|
||||||
}
|
}
|
||||||
case "+'=" =>
|
case "+'=" =>
|
||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, ADD, decimal = true)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, ADD, decimal = true)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, ADD, ADC, size, decimal = true)
|
||||||
}
|
}
|
||||||
case "-'=" =>
|
case "-'=" =>
|
||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, SUB, decimal = true)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, SUB, decimal = true)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, SUB, SBC, size, decimal = true)
|
||||||
}
|
}
|
||||||
Nil
|
Nil
|
||||||
case "<<=" =>
|
case "<<=" =>
|
||||||
@ -319,19 +369,19 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, AND)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, AND)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, AND, AND, size, decimal = false)
|
||||||
}
|
}
|
||||||
case "^=" =>
|
case "^=" =>
|
||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, XOR)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, XOR)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, XOR, XOR, size, decimal = false)
|
||||||
}
|
}
|
||||||
case "|=" =>
|
case "|=" =>
|
||||||
val (l, r, size) = assertAssignmentLike(ctx, params)
|
val (l, r, size) = assertAssignmentLike(ctx, params)
|
||||||
size match {
|
size match {
|
||||||
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, OR)
|
case 1 => ZBuiltIns.perform8BitInPlace(ctx, l, r, OR)
|
||||||
case _ => ???
|
case _ => ZBuiltIns.performLongInPlace(ctx, l, r, OR, OR, size, decimal = false)
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
env.maybeGet[Type](f.functionName) match {
|
env.maybeGet[Type](f.functionName) match {
|
||||||
@ -351,7 +401,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
return sourceType.size match {
|
return sourceType.size match {
|
||||||
case 1 => targetifyA(target, compileToA(ctx, params.head))
|
case 1 => targetifyA(target, compileToA(ctx, params.head), isSigned = sourceType.isSigned)
|
||||||
case 2 => targetifyHL(target, compileToHL(ctx, params.head))
|
case 2 => targetifyHL(target, compileToHL(ctx, params.head))
|
||||||
case _ => ???
|
case _ => ???
|
||||||
}
|
}
|
||||||
@ -390,9 +440,16 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
}
|
}
|
||||||
} ++ List(ZLine(CALL, NoRegisters, function.toAddress))
|
} ++ List(ZLine(CALL, NoRegisters, function.toAddress))
|
||||||
}
|
}
|
||||||
|
function.returnType.size match {
|
||||||
|
case 1 =>
|
||||||
|
targetifyA(target, result, isSigned = function.returnType.isSigned)
|
||||||
|
case 2 =>
|
||||||
|
targetifyHL(target, result)
|
||||||
|
case _ =>
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,4 +617,107 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
|||||||
compile(ctx, conjunction, target, branches)
|
compile(ctx, conjunction, target, branches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def compileByteReads(ctx: CompilationContext, rhs: Expression, size: Int): List[List[ZLine]] = {
|
||||||
|
if (size == 1) throw new IllegalArgumentException
|
||||||
|
val env = ctx.env
|
||||||
|
env.eval(rhs) match {
|
||||||
|
case Some(constant) =>
|
||||||
|
List.tabulate(size)(i => List(ZLine.ldImm8(ZRegister.A, constant.subbyte(i))))
|
||||||
|
case None =>
|
||||||
|
rhs match {
|
||||||
|
case VariableExpression(vname) =>
|
||||||
|
env.get[Variable](vname) match {
|
||||||
|
case v: VariableInMemory =>
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i < size) {
|
||||||
|
List(ZLine.ldAbs8(ZRegister.A, v.toAddress + i))
|
||||||
|
} else if (v.typ.isSigned) {
|
||||||
|
???
|
||||||
|
} else {
|
||||||
|
List(ZLine.ldImm8(ZRegister.A, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case v: StackVariable =>
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i < size) {
|
||||||
|
List(ZLine.ldViaIx(ZRegister.A, v.baseOffset + i))
|
||||||
|
} else if (v.typ.isSigned) {
|
||||||
|
???
|
||||||
|
} else {
|
||||||
|
List(ZLine.ldImm8(ZRegister.A, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SeparateBytesExpression(hi, lo) =>
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i == 0) {
|
||||||
|
compileToA(ctx, lo)
|
||||||
|
} else if (i == 1) {
|
||||||
|
compileToA(ctx, hi)
|
||||||
|
} else {
|
||||||
|
List(ZLine.ldImm8(ZRegister.A, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i == 0) {
|
||||||
|
compileToHL(ctx, rhs) :+ ZLine.ld8(ZRegister.A, ZRegister.L)
|
||||||
|
} else if (i == 1) {
|
||||||
|
List(ZLine.ld8(ZRegister.A, ZRegister.H))
|
||||||
|
} else {
|
||||||
|
// TODO: signed words?
|
||||||
|
List(ZLine.ldImm8(ZRegister.A, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def compileByteStores(ctx: CompilationContext, lhs: LhsExpression, size: Int): List[List[ZLine]] = {
|
||||||
|
if (size == 1) throw new IllegalArgumentException
|
||||||
|
val env = ctx.env
|
||||||
|
lhs match {
|
||||||
|
case VariableExpression(vname) =>
|
||||||
|
env.get[Variable](vname) match {
|
||||||
|
case v: VariableInMemory =>
|
||||||
|
if (v.typ.size < size) {
|
||||||
|
ErrorReporting.error(s"Variable `$vname` is too small", lhs.position)
|
||||||
|
}
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i < size) {
|
||||||
|
List(ZLine.ldAbs8(v.toAddress + i, ZRegister.A))
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case v: StackVariable =>
|
||||||
|
if (v.typ.size < size) {
|
||||||
|
ErrorReporting.error(s"Variable `$vname` is too small", lhs.position)
|
||||||
|
}
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i < size) {
|
||||||
|
List(ZLine.ldViaIx(v.baseOffset + i, ZRegister.A))
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SeparateBytesExpression(hi: LhsExpression, lo: LhsExpression) =>
|
||||||
|
if (size > 2) {
|
||||||
|
ErrorReporting.error(s"Left hand side is too small", lhs.position)
|
||||||
|
}
|
||||||
|
List.tabulate(size) { i =>
|
||||||
|
if (i == 0) {
|
||||||
|
storeA(ctx, lo, signedSource = false)
|
||||||
|
} else if (i == 1) {
|
||||||
|
storeA(ctx, hi, signedSource = false)
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package millfork.compiler.z80
|
package millfork.compiler.z80
|
||||||
|
|
||||||
import millfork.assembly.z80.{ZLine, ZOpcode}
|
import millfork.assembly.z80.{TwoRegisters, ZLine, ZOpcode}
|
||||||
import millfork.compiler.CompilationContext
|
import millfork.compiler.CompilationContext
|
||||||
import millfork.node._
|
import millfork.node._
|
||||||
import ZOpcode._
|
import ZOpcode._
|
||||||
@ -47,7 +47,7 @@ object ZBuiltIns {
|
|||||||
|
|
||||||
def compile16BitOperation(ctx: CompilationContext, op: ZOpcode.Value, params: List[Expression]): List[ZLine] = {
|
def compile16BitOperation(ctx: CompilationContext, op: ZOpcode.Value, params: List[Expression]): List[ZLine] = {
|
||||||
var const = op match {
|
var const = op match {
|
||||||
case AND => NumericConstant(0xffff, 1)
|
case AND => NumericConstant(0xffff, 2)
|
||||||
case OR | XOR => Constant.Zero
|
case OR | XOR => Constant.Zero
|
||||||
}
|
}
|
||||||
var hasConst = false
|
var hasConst = false
|
||||||
@ -157,7 +157,7 @@ object ZBuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def compile16BitSum(ctx: CompilationContext, params: List[(Boolean, Expression)], decimal: Boolean): List[ZLine] = {
|
def compile16BitSum(ctx: CompilationContext, params: List[(Boolean, Expression)], decimal: Boolean): List[ZLine] = {
|
||||||
var const = Constant.Zero
|
var const: Constant = NumericConstant(0, 2)
|
||||||
var hasConst = false
|
var hasConst = false
|
||||||
var result = mutable.ListBuffer[ZLine]()
|
var result = mutable.ListBuffer[ZLine]()
|
||||||
if (decimal) {
|
if (decimal) {
|
||||||
@ -239,8 +239,7 @@ object ZBuiltIns {
|
|||||||
}
|
}
|
||||||
if (hasConst) {
|
if (hasConst) {
|
||||||
result ++= List(
|
result ++= List(
|
||||||
ZLine.ldImm8(ZRegister.D, const.hiByte),
|
ZLine.ldImm16(ZRegister.DE, const),
|
||||||
ZLine.ldImm8(ZRegister.E, const.loByte),
|
|
||||||
ZLine.registers(ADD_16, ZRegister.HL, ZRegister.DE)
|
ZLine.registers(ADD_16, ZRegister.HL, ZRegister.DE)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -322,7 +321,7 @@ object ZBuiltIns {
|
|||||||
ZLine.register(XOR, ZRegister.MEM_HL),
|
ZLine.register(XOR, ZRegister.MEM_HL),
|
||||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A))
|
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A))
|
||||||
}
|
}
|
||||||
case XOR =>
|
case OR =>
|
||||||
constantRight match {
|
constantRight match {
|
||||||
case Some(NumericConstant(0, _)) =>
|
case Some(NumericConstant(0, _)) =>
|
||||||
calculateAddress
|
calculateAddress
|
||||||
@ -330,7 +329,7 @@ object ZBuiltIns {
|
|||||||
calculateAddress :+ ZLine.ldImm8(ZRegister.MEM_HL, 0xff)
|
calculateAddress :+ ZLine.ldImm8(ZRegister.MEM_HL, 0xff)
|
||||||
case _ =>
|
case _ =>
|
||||||
setup ++ List(
|
setup ++ List(
|
||||||
ZLine.register(XOR, ZRegister.MEM_HL),
|
ZLine.register(OR, ZRegister.MEM_HL),
|
||||||
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A))
|
ZLine.ld8(ZRegister.MEM_HL, ZRegister.A))
|
||||||
}
|
}
|
||||||
case AND =>
|
case AND =>
|
||||||
@ -347,4 +346,34 @@ object ZBuiltIns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def performLongInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, opcodeFirst: ZOpcode.Value, opcodeLater: ZOpcode.Value, size: Int, decimal: Boolean = false): List[ZLine] = {
|
||||||
|
if (size == 2 && !decimal) {
|
||||||
|
if (opcodeFirst == ZOpcode.ADD) {
|
||||||
|
val loadRight = Z80ExpressionCompiler.compileToHL(ctx, rhs) ++ List(ZLine.ld8(ZRegister.D, ZRegister.H), ZLine.ld8(ZRegister.E, ZRegister.L))
|
||||||
|
val loadLeft = Z80ExpressionCompiler.stashDEIfChanged(Z80ExpressionCompiler.compileToHL(ctx, lhs))
|
||||||
|
val calculateAndStore = ZLine.registers(ADD_16, ZRegister.HL, ZRegister.DE) :: Z80ExpressionCompiler.storeHL(ctx, lhs, signedSource = false)
|
||||||
|
return loadRight ++ loadLeft ++ calculateAndStore
|
||||||
|
}
|
||||||
|
if (opcodeFirst == ZOpcode.SUB && ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) {
|
||||||
|
val loadRight = Z80ExpressionCompiler.compileToHL(ctx, rhs) ++ List(ZLine.ld8(ZRegister.D, ZRegister.H), ZLine.ld8(ZRegister.E, ZRegister.L))
|
||||||
|
val loadLeft = Z80ExpressionCompiler.stashDEIfChanged(Z80ExpressionCompiler.compileToHL(ctx, lhs))
|
||||||
|
// OR A clears carry before SBC
|
||||||
|
val calculateAndStore = List(
|
||||||
|
ZLine.register(OR, ZRegister.A),
|
||||||
|
ZLine.registers(SBC_16, ZRegister.HL, ZRegister.DE)) ++
|
||||||
|
Z80ExpressionCompiler.storeHL(ctx, lhs, signedSource = false)
|
||||||
|
return loadRight ++ loadLeft ++ calculateAndStore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val store = Z80ExpressionCompiler.compileByteStores(ctx, lhs, size)
|
||||||
|
val loadLeft = Z80ExpressionCompiler.compileByteReads(ctx, lhs, size)
|
||||||
|
val loadRight = Z80ExpressionCompiler.compileByteReads(ctx, rhs, size)
|
||||||
|
List.tabulate(size) {i =>
|
||||||
|
// TODO: stash things correctly?
|
||||||
|
val firstPhase = loadRight(i) ++ List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++ (loadLeft(i) :+ ZLine.register(if (i==0) opcodeFirst else opcodeLater, ZRegister.E))
|
||||||
|
val secondPhase = if (decimal) firstPhase :+ ZLine.implied(ZOpcode.DAA) else firstPhase
|
||||||
|
secondPhase ++ store(i)
|
||||||
|
}.flatten
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user