mirror of
https://github.com/KarolS/millfork.git
synced 2025-07-25 03:24:53 +00:00
6809: Improve booleans
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
package millfork.compiler.m6809
|
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.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
|
||||||
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
|
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
|
||||||
import millfork.assembly.m6809.MOpcode._
|
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
|
import scala.collection.GenTraversableOnce
|
||||||
|
|
||||||
@@ -140,7 +140,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
}
|
}
|
||||||
case fce@FunctionCallExpression(functionName, params) =>
|
case fce@FunctionCallExpression(functionName, params) =>
|
||||||
functionName match {
|
functionName match {
|
||||||
case "not" => ???
|
case "not" =>
|
||||||
|
assertBool(ctx, "not", params, 1)
|
||||||
|
compile(ctx, params.head, target, branches.flip)
|
||||||
case "nonet" =>
|
case "nonet" =>
|
||||||
if (params.length != 1) {
|
if (params.length != 1) {
|
||||||
ctx.log.error("Invalid number of parameters", fce.position)
|
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 label = ctx.env.nextLabel("bo")
|
||||||
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
|
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
|
||||||
val conditionWithoutJump = condition.init
|
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 {
|
condition.last.opcode match {
|
||||||
case BCC =>
|
case BCC =>
|
||||||
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
|
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
|
||||||
@@ -697,4 +715,24 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
|||||||
compile(ctx, conjunction, target, branches)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,9 +3,9 @@ package millfork.compiler.m6809
|
|||||||
import millfork.assembly.BranchingOpcodeMapping
|
import millfork.assembly.BranchingOpcodeMapping
|
||||||
import millfork.assembly.m6809.{MLine, NonExistent}
|
import millfork.assembly.m6809.{MLine, NonExistent}
|
||||||
import millfork.compiler.{AbstractCompiler, AbstractExpressionCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
|
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.assembly.m6809.MOpcode._
|
||||||
import millfork.env.{FatBooleanType, Label, ThingInMemory}
|
import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, ThingInMemory}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
@@ -45,11 +45,26 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
|
|||||||
case Assignment(destination, source) =>
|
case Assignment(destination, source) =>
|
||||||
if (destination == BlackHoleExpression) return M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) -> Nil
|
if (destination == BlackHoleExpression) return M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) -> Nil
|
||||||
val destinationType = AbstractExpressionCompiler.getExpressionType(ctx, destination)
|
val destinationType = AbstractExpressionCompiler.getExpressionType(ctx, destination)
|
||||||
|
val sourceType = AbstractExpressionCompiler.getExpressionType(ctx, source)
|
||||||
AbstractExpressionCompiler.checkAssignmentType(ctx, source, destinationType)
|
AbstractExpressionCompiler.checkAssignmentType(ctx, source, destinationType)
|
||||||
destinationType.size match {
|
(destinationType.size match {
|
||||||
case 1 => (M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)) -> Nil
|
case 0 => sourceType match {
|
||||||
case 2 => (M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)) -> Nil
|
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) =>
|
case ExpressionStatement(expression) =>
|
||||||
M6809ExpressionCompiler.compile(ctx, expression, MExpressionTarget.NOTHING) -> Nil
|
M6809ExpressionCompiler.compile(ctx, expression, MExpressionTarget.NOTHING) -> Nil
|
||||||
case s:IfStatement =>
|
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 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] =
|
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 = ???
|
override def replaceLabel(ctx: CompilationContext, line: MLine, from: String, to: String): MLine = ???
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
|
|||||||
class BooleanSuite extends FunSuite with Matchers {
|
class BooleanSuite extends FunSuite with Matchers {
|
||||||
|
|
||||||
test("Not") {
|
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
|
| byte output @$c000
|
||||||
| array input = [5,6,7]
|
| array input = [5,6,7]
|
||||||
@@ -28,7 +28,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
|
|
||||||
|
|
||||||
test("And") {
|
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
|
| byte output @$c000
|
||||||
| array input = [5,6,7]
|
| array input = [5,6,7]
|
||||||
@@ -47,7 +47,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
|
|
||||||
|
|
||||||
test("Or") {
|
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
|
| byte output @$c000
|
||||||
| array input = [5,6,7]
|
| array input = [5,6,7]
|
||||||
@@ -89,7 +89,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
| inline void pass() { output += 1 }
|
| inline void pass() { output += 1 }
|
||||||
| noinline void fail() { outside[0] = 0 }
|
| noinline void fail() { outside[0] = 0 }
|
||||||
""".stripMargin
|
""".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") {
|
test("Fat boolean") {
|
||||||
@@ -136,7 +136,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
| bool never() = false
|
| bool never() = false
|
||||||
|
|
|
|
||||||
""".stripMargin
|
""".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") {
|
test("Fat boolean optimization") {
|
||||||
@@ -153,7 +153,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
""".stripMargin
|
""".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") {
|
test("Constant booleans") {
|
||||||
@@ -183,7 +183,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
""".stripMargin
|
""".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") {
|
test("Constant booleans mini") {
|
||||||
@@ -224,7 +224,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
|||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
""".stripMargin
|
""".stripMargin
|
||||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(code){ m =>
|
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code){ m =>
|
||||||
m.readByte(0xc000) should equal(1)
|
m.readByte(0xc000) should equal(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen
|
|||||||
|
|
||||||
override def store(addr: Int, `val`: Int): Unit = {
|
override def store(addr: Int, `val`: Int): Unit = {
|
||||||
if (!memoryBank.writeable(addr)) {
|
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
|
memoryBank.output(addr) = `val`.toByte
|
||||||
|
Reference in New Issue
Block a user