1
0
mirror of https://github.com/KarolS/millfork.git synced 2026-04-19 10:42:10 +00:00

Z80: Compile 8-bit values directly into registers other than A

This commit is contained in:
Karol Stasiak
2018-07-31 01:00:17 +02:00
parent 7e6f2dd4ea
commit 2046f94b55
5 changed files with 49 additions and 11 deletions
+9 -2
View File
@@ -126,8 +126,15 @@ Non-macro functions can only have their parameters passed via registers:
* `word hl`, `word bc`, `word de`: a 2-byte word byte passed via given 16-bit register
**Work in progress**:
Currently, only 3 parameter signatures are supported for non-macro assembly functions:
`()`, `(byte a)` and `(word hl)`. More parameters or parameters passed via other registers do not work yet.
Currently, only few parameter signatures are supported for non-macro assembly functions:
* `()`
* `(byte a)`, `(byte b)`, `(byte c)`, `(byte d)`, `(byte e)`, `(byte h)`, `(byte l)` ("byte" may be any other 2-byte type)
* `(word hl)`, `(word bc)`, `(word de)` ("word" may be any other 2-byte type)
More parameters or parameters passed via other registers do not work yet.
Macro assembly functions cannot have any parameter passed via registers.
@@ -159,11 +159,11 @@ object Z80BulkMemoryOperations {
val loopRegister = if (useC) ZRegister.C else ZRegister.B
val countDown = f.direction == ForDirection.ParallelTo || f.direction == ForDirection.ParallelUntil || f.direction == ForDirection.DownTo
val countDownDespiteSyntax = f.direction == ForDirection.ParallelTo || f.direction == ForDirection.ParallelUntil
val initC = if (useC) Z80ExpressionCompiler.compileToA(ctx, f.direction match {
val initC = if (useC) Z80ExpressionCompiler.compile8BitTo(ctx, f.direction match {
case ForDirection.ParallelTo => f.end
case ForDirection.ParallelUntil => SumExpression(List(false -> f.end, true -> LiteralExpression(1, 1)), decimal = false)
case _ => f.start
}) :+ ZLine.ld8(ZRegister.C, ZRegister.A) else Nil
}, ZRegister.C) else Nil
val nextC = if (useC) List(ZLine.register(if (countDown) DEC else INC, ZRegister.C)) else Nil
ExtraLoopRegister(loopRegister, initC, nextC, countDownDespiteSyntax)
}
@@ -369,8 +369,7 @@ object Z80BulkMemoryOperations {
val ldr = z80Bulk(decreasing)
val smallCount = indexVariableSize == 1 && (ldr.isEmpty || !ctx.options.flag(CompilationFlag.EmitZ80Opcodes))
val calculateByteCount = if (smallCount) {
Z80ExpressionCompiler.compileToA(ctx, byteCountExpression) ++
List(ZLine.ld8(ZRegister.B, ZRegister.A))
Z80ExpressionCompiler.compile8BitTo(ctx, byteCountExpression, ZRegister.B)
} else {
Z80ExpressionCompiler.compileToHL(ctx, byteCountExpression) ++
List(ZLine.ld8(ZRegister.B, ZRegister.H), ZLine.ld8(ZRegister.C, ZRegister.L))
@@ -19,6 +19,26 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
def compileToA(ctx: CompilationContext, expression: Expression): List[ZLine] = compile(ctx, expression, ZExpressionTarget.A)
def compile8BitTo(ctx: CompilationContext, expression: Expression, register: ZRegister.Value): List[ZLine] = {
if (ZRegister.A == register) compileToA(ctx, expression) else {
val toA = compileToA(ctx, expression)
if (toA.isEmpty) Nil else {
toA.last match {
case ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, source), _, _) if source == register =>
toA.init
case ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, source@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.MEM_HL)), _, _) =>
toA.init :+ ZLine.ld8(register, source)
case ZLine(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IX_D, offset), _, _) =>
toA.init :+ ZLine.ldViaIx(register, offset)
case ZLine(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IY_D, offset), _, _) =>
toA.init :+ ZLine.ldViaIy(register, offset)
case _ =>
toA :+ ZLine.ld8(register, ZRegister.A)
}
}
}
}
def compileToHL(ctx: CompilationContext, expression: Expression): List[ZLine] = compile(ctx, expression, ZExpressionTarget.HL)
def compileToEHL(ctx: CompilationContext, expression: Expression): List[ZLine] = compile(ctx, expression, ZExpressionTarget.EHL)
@@ -786,9 +806,20 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(ZRegister.A, typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 1 && typ2.size == 1 =>
compileToA(ctx, params.head) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(
register@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.H | ZRegister.L),
typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 1 && typ2.size == 1 =>
compile8BitTo(ctx, params.head, register) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(ZRegister.HL, typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 2 && typ2.size == 2 =>
compileToHL(ctx, params.head) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(ZRegister.DE, typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 2 && typ2.size == 2 =>
compileToDE(ctx, params.head) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(ZRegister.BC, typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 2 && typ2.size == 2 =>
compileToBC(ctx, params.head) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(Nil) =>
List(ZLine(CALL, NoRegisters, function.toAddress))
case AssemblyParamSignature(paramConvs) =>
@@ -48,7 +48,8 @@ object Z80MacroExpander extends MacroExpander[ZLine] {
hadRegisterParam = true
paramPreparation = (register, typ.size) match {
case (ZRegister.A, 1) => Z80ExpressionCompiler.compileToA(ctx, actualParam)
case (r@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.H | ZRegister.L), 1) => Z80ExpressionCompiler.compileToA(ctx, actualParam) :+ ZLine.ld8(r, ZRegister.A)
case (r@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.H | ZRegister.L), 1) =>
Z80ExpressionCompiler.compile8BitTo(ctx, actualParam, r)
case (ZRegister.HL, 2) => Z80ExpressionCompiler.compileToHL(ctx, actualParam)
case (ZRegister.BC, 2) => Z80ExpressionCompiler.compileToBC(ctx, actualParam)
case (ZRegister.DE, 2) => Z80ExpressionCompiler.compileToDE(ctx, actualParam)
@@ -41,7 +41,7 @@ object Z80Shifting {
l ++ List.tabulate(i.toInt)(_ => op) ++ fixAfterShiftIfNeeded(extendedOps, left, i)
}
case _ =>
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
val calcCount = Z80ExpressionCompiler.compile8BitTo(ctx, rhs, ZRegister.B)
val l = Z80ExpressionCompiler.stashBCIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, lhs))
val loopBody = op :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val label = Z80Compiler.nextLabel("sh")
@@ -117,7 +117,7 @@ object Z80Shifting {
}
}
case _ =>
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
val calcCount = Z80ExpressionCompiler.compile8BitTo(ctx, rhs, ZRegister.B)
val l = Z80ExpressionCompiler.stashBCIfChanged(ctx, Z80ExpressionCompiler.compileToA(ctx, lhs))
val loopBody = ZLine.register(op, ZRegister.A) :: fixAfterShiftIfNeeded(extendedOps, left, 1)
val label = Z80Compiler.nextLabel("sh")
@@ -168,7 +168,7 @@ object Z80Shifting {
}
}
case _ =>
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
val calcCount = Z80ExpressionCompiler.compile8BitTo(ctx, rhs, ZRegister.B)
val loopBody =
if (extendedOps) {
if (left) {
@@ -271,7 +271,7 @@ object Z80Shifting {
List.fill(n.toInt)(shiftOne).flatten
case _ =>
val label = Z80Compiler.nextLabel("sh")
val calcCount = Z80ExpressionCompiler.compileToA(ctx, rhs) :+ ZLine.ld8(ZRegister.B, ZRegister.A)
val calcCount = Z80ExpressionCompiler.compile8BitTo(ctx, rhs, ZRegister.B)
calcCount ++ List(ZLine.label(label)) ++ shiftOne ++ ZLine.djnz(ctx, label)
}
}