1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-01 06:29:53 +00:00

6809: Improve booleans

This commit is contained in:
Karol Stasiak 2020-01-24 02:16:19 +01:00
parent f247516187
commit d6fd1e8b77
4 changed files with 80 additions and 20 deletions

View File

@ -1,10 +1,10 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, MLine, MLine0, MOpcode, TwoRegisters}
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, InherentB, MLine, MLine0, MOpcode, RegisterSet, TwoRegisters}
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{AssemblyParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
import millfork.env.{AssemblyParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
import scala.collection.GenTraversableOnce
@ -140,7 +140,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
}
case fce@FunctionCallExpression(functionName, params) =>
functionName match {
case "not" => ???
case "not" =>
assertBool(ctx, "not", params, 1)
compile(ctx, params.head, target, branches.flip)
case "nonet" =>
if (params.length != 1) {
ctx.log.error("Invalid number of parameters", fce.position)
@ -486,6 +488,22 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
val label = ctx.env.nextLabel("bo")
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
val conditionWithoutJump = condition.init
if (conditionWithoutJump.exists(l => l.parameter match {
case MemoryAddressConstant(Label(l)) if l == label => true
case _ => false
})){
val label2 = ctx.env.nextLabel("bo")
return condition ++ List(
MLine.immediate(LDB, 1),
MLine.shortBranch(BRA, label2),
MLine.label(label),
MLine.immediate(LDB, 0),
MLine.label(label2),
MLine.inherentB(ROL)
)
}
condition.last.opcode match {
case BCC =>
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
@ -697,4 +715,24 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
compile(ctx, conjunction, target, branches)
}
}
def areNZFlagsBasedOnB(code: List[MLine]): Boolean = {
for (line <- code.reverse) {
line.opcode match {
case ADDB | ADCB | SUBB | SBCB | ANDB | ORB => return true
case CLR | ASL | LSR | ASR | ROL | ROR | INC | DEC | NEG => return line.addrMode == InherentB
case CMPB => return line.addrMode == Immediate && line.parameter.isProvablyZero
case PULS | PULU =>
line.addrMode match {
case r: RegisterSet =>
if (r.contains(M6809Register.B)) return false
if (r.contains(M6809Register.CC)) return false
case _ =>
}
case LEAS | LEAU | PSHS | PSHU | TFR | NOP | ABX => // loop
case _ => return false
}
}
false
}
}

View File

@ -3,9 +3,9 @@ package millfork.compiler.m6809
import millfork.assembly.BranchingOpcodeMapping
import millfork.assembly.m6809.{MLine, NonExistent}
import millfork.compiler.{AbstractCompiler, AbstractExpressionCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, IfStatement, M6809AssemblyStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, FunctionCallExpression, IfStatement, M6809AssemblyStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{FatBooleanType, Label, ThingInMemory}
import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, ThingInMemory}
/**
* @author Karol Stasiak
@ -45,11 +45,26 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
case Assignment(destination, source) =>
if (destination == BlackHoleExpression) return M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) -> Nil
val destinationType = AbstractExpressionCompiler.getExpressionType(ctx, destination)
val sourceType = AbstractExpressionCompiler.getExpressionType(ctx, source)
AbstractExpressionCompiler.checkAssignmentType(ctx, source, destinationType)
destinationType.size match {
case 1 => (M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)) -> Nil
case 2 => (M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)) -> Nil
}
(destinationType.size match {
case 0 => sourceType match {
case _: ConstantBooleanType =>
M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
case _: BooleanType =>
M6809ExpressionCompiler.compileToFatBooleanInB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
case _ =>
ctx.log.error("Cannot assign a void expression", statement.position)
M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) ++
M6809ExpressionCompiler.compile(ctx, destination, MExpressionTarget.NOTHING, BranchSpec.None)
}
case 1 => sourceType match {
case _: BooleanType =>
M6809ExpressionCompiler.compileToFatBooleanInB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
case _ => M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
}
case 2 => M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)
}) -> Nil
case ExpressionStatement(expression) =>
M6809ExpressionCompiler.compile(ctx, expression, MExpressionTarget.NOTHING) -> Nil
case s:IfStatement =>
@ -86,10 +101,17 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
override def jmpChunk(label: Label): List[MLine] = List(MLine.absolute(JMP, label.toAddress))
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] = ???
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] =
List(MLine.shortBranch(opcode.m6809, labelName)) // TODO: ???
override def compileExpressionForBranching(ctx: CompilationContext, expr: Expression, branching: BranchSpec): List[MLine] =
M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.NOTHING, branching)
if (AbstractExpressionCompiler.getExpressionType(ctx, expr) == FatBooleanType) {
val prepareB = M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.B, branching)
if (M6809ExpressionCompiler.areNZFlagsBasedOnB(prepareB)) prepareB
else prepareB :+ MLine.immediate(CMPB, 0)
} else {
M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.NOTHING, branching)
}
override def replaceLabel(ctx: CompilationContext, line: MLine, from: String, to: String): MLine = ???

View File

@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
class BooleanSuite extends FunSuite with Matchers {
test("Not") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| byte output @$c000
| array input = [5,6,7]
@ -28,7 +28,7 @@ class BooleanSuite extends FunSuite with Matchers {
test("And") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| byte output @$c000
| array input = [5,6,7]
@ -47,7 +47,7 @@ class BooleanSuite extends FunSuite with Matchers {
test("Or") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| byte output @$c000
| array input = [5,6,7]
@ -89,7 +89,7 @@ class BooleanSuite extends FunSuite with Matchers {
| inline void pass() { output += 1 }
| noinline void fail() { outside[0] = 0 }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
}
test("Fat boolean") {
@ -136,7 +136,7 @@ class BooleanSuite extends FunSuite with Matchers {
| bool never() = false
|
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
}
test("Fat boolean optimization") {
@ -153,7 +153,7 @@ class BooleanSuite extends FunSuite with Matchers {
| }
|
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readByte(0xc000) should equal(7))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(7))
}
test("Constant booleans") {
@ -183,7 +183,7 @@ class BooleanSuite extends FunSuite with Matchers {
| }
|
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readWord(0xc000) should equal(13))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readWord(0xc000) should equal(13))
}
test("Constant booleans mini") {
@ -224,7 +224,7 @@ class BooleanSuite extends FunSuite with Matchers {
| }
|
""".stripMargin
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(code){ m =>
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code){ m =>
m.readByte(0xc000) should equal(1)
}
}

View File

@ -30,7 +30,7 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen
override def store(addr: Int, `val`: Int): Unit = {
if (!memoryBank.writeable(addr)) {
println(s"Accessing memory for write at $$${addr.toHexString}")
println(s"Accessing memory for write at $$${addr.toHexString}, writing $$${`val`.toHexString}")
???
}
memoryBank.output(addr) = `val`.toByte