Fixes for flag boolean types (fixes #123)

This commit is contained in:
Karol Stasiak 2021-09-13 09:26:27 +02:00
parent 90e5360bfd
commit 3b0aa9a425
4 changed files with 230 additions and 3 deletions

View File

@ -688,7 +688,20 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case FatBooleanType => compileToB(ctx, expr)
case t: ConstantBooleanType =>
List(MLine.immediate(MOpcode.LDB, if (t.value) 1 else 0))
case BuiltInBooleanType | _: FlagBooleanType =>
case t: FlagBooleanType =>
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, NoBranching)
condition ++ (t.jumpIfFalse.m6809 match {
case BCC => List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
case BCS => List(MLine.immediate(LDB, 0), MLine.inherentB(ROL), MLine.immediate(EORB, 1))
case o =>
val label = ctx.env.nextLabel("bo")
List(
MLine.immediate(LDB, 0),
MLine.shortBranch(o, label),
MLine.inherentB(INC),
MLine.label(label))
})
case BuiltInBooleanType =>
val label = ctx.env.nextLabel("bo")
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
val conditionWithoutJump = condition.init

View File

@ -476,7 +476,20 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
compileToA(ctx, expr)
case t: ConstantBooleanType =>
List(AssemblyLine.immediate(LDA, if (t.value) 1 else 0))
case _: FlagBooleanType | BuiltInBooleanType =>
case t: FlagBooleanType =>
val condition = compile(ctx, expr, None, NoBranching)
condition ++ (t.jumpIfFalse.mosOpcode match {
case BCC => List(AssemblyLine.immediate(LDA, 0), AssemblyLine.implied(ROL))
case BCS => List(AssemblyLine.immediate(LDA, 0), AssemblyLine.implied(ROL), AssemblyLine.immediate(EOR, 1))
case o =>
val label = env.nextLabel("bo")
List(
AssemblyLine.immediate(LDA, 0),
AssemblyLine.relative(o, label),
AssemblyLine.immediate(LDA, 1),
AssemblyLine.label(label))
})
case BuiltInBooleanType =>
val label = env.nextLabel("bo")
val condition = compile(ctx, expr, None, BranchIfFalse(label))
if (condition.isEmpty) {

View File

@ -27,7 +27,18 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case FatBooleanType => compileToA(ctx, expression)
case t: ConstantBooleanType =>
List(ZLine.ldImm8(ZRegister.A, if (t.value) 1 else 0))
case BuiltInBooleanType | _: FlagBooleanType =>
case t: FlagBooleanType =>
val condition = Z80ExpressionCompiler.compile(ctx, expression, ZExpressionTarget.NOTHING, NoBranching)
condition ++ (t.jumpIfFalse.z80Flags match {
case o =>
val label = ctx.env.nextLabel("bo")
List(
ZLine.ldImm8(ZRegister.A, 0),
ZLine.jumpR(ctx, label, o),
ZLine.register(INC, ZRegister.A),
ZLine.label(label))
})
case BuiltInBooleanType =>
// TODO optimize if using CARRY
// TODO: helper functions to convert flags to booleans, to make code smaller
val label = ctx.env.nextLabel("bo")

View File

@ -0,0 +1,190 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotCompile}
import org.scalatest.{AppendedClues, FunSuite, Matchers}
/**
* @author Karol Stasiak
*/
class BooleanFlagTypesSuite extends FunSuite with Matchers with AppendedClues {
test("clear_carry") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| asm clear_carry testCarryResult(byte register(a) dummy)
|{
| // we always set carry, so this is always false:
| #if ARCH_6502
| STA param
| SEC
| RTS
| #elseif ARCH_I80
| #pragma zilog_syntax
| LD (param),A
| OR A
| CCF
| RET
| #elseif ARCH_6809
| STA param
| COMA
| RTS
| #else
| #error unknown arch
| #endif
|}
|
|byte output @$c000
|byte param @$c001
|
|void main() {
| bool clearCarry
| clearCarry = testCarryResult(55)
| if clearCarry {
| output = 0
| } else {
| output = 1
| }
|}
""".stripMargin) { m =>
m.readByte(0xc000) should equal(1)
m.readByte(0xc001) should equal(55)
}
}
test("set_carry") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| asm set_carry testCarryResult(byte register(a) dummy)
|{
| // we always set carry, so this is always true:
| #if ARCH_6502
| STA param
| SEC
| RTS
| #elseif ARCH_I80
| #pragma zilog_syntax
| LD (param),A
| OR A
| CCF
| RET
| #elseif ARCH_6809
| STA param
| COMA
| RTS
| #else
| #error unknown arch
| #endif
|}
|
|byte output @$c000
|byte param @$c001
|
|void main() {
| bool setCarry
| setCarry = testCarryResult(55)
| if setCarry {
| output = 1
| } else {
| output = 0
| }
|}
""".stripMargin) { m =>
m.readByte(0xc000) should equal(1)
m.readByte(0xc001) should equal(55)
}
}
test("set_zero") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| asm set_zero testCarryResult(byte register(a) dummy)
|{
| // we always set zero, so this is always true:
| #if ARCH_6502
| STA param
| LDA #0
| RTS
| #elseif ARCH_I80
| #pragma zilog_syntax
| LD (param),A
| XOR A
| CCF
| RET
| #elseif ARCH_6809
| STA param
| LDA #0
| RTS
| #else
| #error unknown arch
| #endif
|}
|
|byte output @$c000
|byte param @$c001
|
|void main() {
| bool setZero
| setZero = testCarryResult(55)
| if setZero {
| output = 1
| } else {
| output = 0
| }
|}
""".stripMargin) { m =>
m.readByte(0xc000) should equal(1)
m.readByte(0xc001) should equal(55)
}
}
test("clear_zero") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| asm clear_zero testCarryResult(byte register(a) dummy)
|{
| // we always set zero, so this is always false:
| #if ARCH_6502
| STA param
| LDA #0
| RTS
| #elseif ARCH_I80
| #pragma zilog_syntax
| LD (param),A
| XOR A
| CCF
| RET
| #elseif ARCH_6809
| STA param
| LDA #0
| RTS
| #else
| #error unknown arch
| #endif
|}
|
|byte output @$c000
|byte param @$c001
|
|void main() {
| bool clearZero
| clearZero = testCarryResult(55)
| if clearZero {
| output = 0
| } else {
| output = 1
| }
|}
""".stripMargin) { m =>
m.readByte(0xc000) should equal(1)
m.readByte(0xc001) should equal(55)
}
}
}