1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-02-11 18:30:52 +00:00

8080: implement signed byte comparisons for CPU's without the overflow flag

This commit is contained in:
Karol Stasiak 2019-05-29 14:07:57 +02:00
parent 0410cbea34
commit 138dcfa19f
4 changed files with 56 additions and 8 deletions

View File

@ -35,6 +35,14 @@ object ComparisonType extends Enumeration {
case NotEqual => Equal
}
def toUnsigned(x: ComparisonType.Value): ComparisonType.Value = x match {
case LessSigned => LessUnsigned
case GreaterSigned => GreaterUnsigned
case LessOrEqualSigned => LessOrEqualUnsigned
case GreaterOrEqualSigned => GreaterOrEqualUnsigned
case x => x
}
def isSigned(x: ComparisonType.Value): Boolean = x match {
case LessSigned => true
case GreaterSigned => true

View File

@ -4,7 +4,7 @@ import millfork.CompilationFlag
import millfork.assembly.z80._
import millfork.compiler.{ComparisonType, _}
import millfork.env.NumericConstant
import millfork.node.{Expression, ZRegister}
import millfork.node.{Expression, FunctionCallExpression, LiteralExpression, ZRegister}
/**
* @author Karol Stasiak
@ -15,6 +15,12 @@ object Z80Comparisons {
def compile8BitComparison(ctx: CompilationContext, compType: ComparisonType.Value, l: Expression, r: Expression, branches: BranchSpec): List[ZLine] = {
handleConstantComparison(ctx, compType, l, r, branches).foreach(return _)
if (ComparisonType.isSigned(compType) && !ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) {
return compile8BitComparison(ctx, ComparisonType.toUnsigned(compType),
FunctionCallExpression("^", List(l, LiteralExpression(0x80, 1).pos(l.position))).pos(l.position),
FunctionCallExpression("^", List(r, LiteralExpression(0x80, 1).pos(r.position))).pos(r.position),
branches)
}
compType match {
case GreaterUnsigned | LessOrEqualUnsigned | GreaterSigned | LessOrEqualSigned =>
return compile8BitComparison(ctx, ComparisonType.flip(compType), r, l, branches)
@ -30,7 +36,7 @@ object Z80Comparisons {
ZLine.jump(fixup, IfFlagClear(ZFlag.P)),
ZLine.imm8(ZOpcode.XOR, 0x80),
ZLine.label(fixup))
} else if (ComparisonType.isSigned(compType) && !ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
} else if (ComparisonType.isSigned(compType) && !ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) {
List(ZLine.register(ZOpcode.SUB, ZRegister.E))
} else List(ZLine.register(ZOpcode.CP, ZRegister.E))
if (branches == NoBranching) return prepareAE ++ calculateFlags

View File

@ -365,6 +365,7 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
}
case (NumericConstant(lv, ls), NumericConstant(rv, rs)) =>
var size = ls max rs
val bitmask = (1L << (8*size)) - 1
val value = operator match {
case MathOperator.Plus => lv + rv
case MathOperator.Minus => lv - rv
@ -374,9 +375,9 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
case MathOperator.Shl9 => (lv << rv) & 0x1ff
case MathOperator.Plus9 => (lv + rv) & 0x1ff
case MathOperator.Shr9 => (lv & 0x1ff) >> rv
case MathOperator.Exor => lv ^ rv
case MathOperator.Exor => (lv ^ rv) & bitmask
case MathOperator.Or => lv | rv
case MathOperator.And => lv & rv
case MathOperator.And => lv & rv & bitmask
case MathOperator.DecimalPlus if ls == 1 && rs == 1 =>
asDecimal(lv & 0xff, rv & 0xff, _ + _) & 0xff
case MathOperator.DecimalMinus if ls == 1 && rs == 1 && lv.&(0xff) >= rv.&(0xff) =>

View File

@ -233,9 +233,6 @@ class ComparisonSuite extends FunSuite with Matchers {
}
test("Signed comparison with overflow") {
// These examples require a CPU with an overflow flag.
// Good: 6502, Z80
// Bad: 8080, LR35902
val src =
"""
| byte output @$c000
@ -266,7 +263,7 @@ class ComparisonSuite extends FunSuite with Matchers {
| if c > -1 { output += 1 }
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(src)(_.readByte(0xc000) should equal(src.count(_ == '+')))
}
test("Signed comparison < and <=") {
@ -460,4 +457,40 @@ class ComparisonSuite extends FunSuite with Matchers {
m.readByte(0xc000) should equal(11)
}
}
test("Signed compare to 0") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output @$c000
| void main() {
| stuff(0)
| }
| noinline void stuff (sbyte x) {
| if x >= 0 {
| output = 11
| }
| }
""".stripMargin
) { m =>
m.readByte(0xc000) should equal(11)
}
}
test("Signed compare to 1") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output @$c000
| void main() {
| stuff(2)
| }
| noinline void stuff (sbyte x) {
| if x > 1 {
| output = 11
| }
| }
""".stripMargin
) { m =>
m.readByte(0xc000) should equal(11)
}
}
}