1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-09 16:29:34 +00:00

6502: Fix sbyte to word promotion in some contexts

This commit is contained in:
Karol Stasiak 2021-01-13 14:18:28 +01:00
parent bd8078cc47
commit 2a5933e115
4 changed files with 95 additions and 9 deletions

View File

@ -422,7 +422,7 @@ object AssemblyLine {
private val opcodesForZeroedVariableOperation = Set(ADC, EOR, ORA, AND, SBC, CMP, CPX, CPY)
private val opcodesForZeroedOrSignExtendedVariableOperation = Set(LDA, LDX, LDY, LDZ)
def variable(ctx: CompilationContext, opcode: Opcode.Value, variable: Variable, offset: Int = 0): List[AssemblyLine] =
def variable(ctx: CompilationContext, opcode: Opcode.Value, variable: Variable, offset: Int = 0, preserveA: Boolean = false): List[AssemblyLine] =
if (offset >= variable.typ.size) {
if (opcodesForNopVariableOperation(opcode)) {
Nil
@ -432,16 +432,28 @@ object AssemblyLine {
} else if (opcodesForZeroedOrSignExtendedVariableOperation(opcode)) {
if (variable.typ.isSigned) {
val label = ctx.nextLabel("sx")
AssemblyLine.variable(ctx, LDA, variable, variable.typ.size - 1) ++ List(
val loadHiByteToA = AssemblyLine.variable(ctx, LDA, variable, variable.typ.size - 1)
val signExtend = List(
AssemblyLine.immediate(ORA, 0x7f),
AssemblyLine.relative(BMI, label),
AssemblyLine.immediate(LDA, 0),
AssemblyLine.label(label)) ++ (opcode match {
case LDA => Nil
case LDX | LAX => List(AssemblyLine.implied(TAX))
case LDY => List(AssemblyLine.implied(TAY))
case LDZ => List(AssemblyLine.implied(TAZ))
})
AssemblyLine.label(label))
if (preserveA) {
opcode match {
case LDA => loadHiByteToA ++ signExtend
case LAX => loadHiByteToA ++ signExtend ++ List(AssemblyLine.implied(TAX))
case LDX => loadHiByteToA ++ List(AssemblyLine.implied(PHA)) ++ signExtend ++ List(AssemblyLine.implied(TAX), AssemblyLine.implied(PLA))
case LDY => loadHiByteToA ++ List(AssemblyLine.implied(PHA)) ++ signExtend ++ List(AssemblyLine.implied(TAY), AssemblyLine.implied(PLA))
case LDZ => loadHiByteToA ++ List(AssemblyLine.implied(PHA)) ++ signExtend ++ List(AssemblyLine.implied(TAZ), AssemblyLine.implied(PLA))
}
} else {
opcode match {
case LDA => loadHiByteToA ++ signExtend
case LDX | LAX => loadHiByteToA ++ signExtend ++ List(AssemblyLine.implied(TAX))
case LDY => loadHiByteToA ++ signExtend ++ List(AssemblyLine.implied(TAY))
case LDZ => loadHiByteToA ++ signExtend ++ List(AssemblyLine.implied(TAZ))
}
}
} else {
List(AssemblyLine.immediate(opcode, 0))
}

View File

@ -733,7 +733,14 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
AssemblyLine.implied(PLA))
} else AssemblyLine.variable(ctx, LDA, source) :+ AssemblyLine.immediate(LDX, 0)
case 2 =>
AssemblyLine.variable(ctx, LDA, source) ++ AssemblyLine.variable(ctx, LDX, source, 1)
val lo = AssemblyLine.variable(ctx, LDA, source)
if (lo.exists(_.concernsX)) {
lo ++ AssemblyLine.variable(ctx, LDX, source, 1, preserveA = true)
} else {
val hi = AssemblyLine.variable(ctx, LDX, source, 1)
if (hi.length == 1 && hi.head.opcode == LDX) lo ++ hi
else hi ++ lo
}
}
case RegisterVariable(MosRegister.AY, _) =>
exprType.size match {

View File

@ -32,6 +32,21 @@ class SignExtensionSuite extends FunSuite with Matchers {
| }
""".stripMargin){m => m.readWord(0xc000) should equal(0xfffe)}
}
test("Sbyte to Word 3") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)("""
| import zp_reg
| word output @$c000
| void main () {
| sbyte x,y
| x = b(1)
| y = b(31)
| output = word(x) * word(y)
| }
| noinline sbyte b(sbyte x) = x
""".stripMargin){m => m.readWord(0xc000) should equal(31)}
}
test("Sbyte to Long") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)("""
| long output @$c000

View File

@ -762,4 +762,56 @@ class WordMathSuite extends FunSuite with Matchers with AppendedClues {
}
}
}
test("Sign extension in multiplication") {
for {
x <- Seq(0, -10, 10, 120, -120)
y <- Seq(0, -10, 10, 120, -120)
angle <- Seq(0, 156, 100, 67)
} {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
s"""
| import zp_reg
| array(sbyte) sinTable @$$c100= for i,0,to,256+64-1 [sin(i,127)]
| sbyte outputX @$$c000
| sbyte outputY @$$c001
| noinline sbyte rotatePointX(sbyte x,sbyte y,byte angle) {
| sbyte rx
| sbyte s,c
| s = sinTable[angle]
| angle = angle + 64
| c = sinTable[angle]
| rx = lo(((word(x)*word(c))>>7) - ((word(y)*word(s))>>7))
|
| return rx;
|}
|
|noinline sbyte rotatePointY(sbyte x,sbyte y,byte angle) {
| sbyte ry
| sbyte s,c
| s = sinTable[angle]
| angle = angle + 64
| c = sinTable[angle]
| ry = lo(((word(x)*word(s))>>7) + ((word(y)*word(c))>>7))
| return ry;
|}
| void main () {
| outputX = rotatePointX($x, $y, $angle)
| outputY = rotatePointY($x, $y, $angle)
| }
""".
stripMargin){m =>
for (a <- 0 until (256+64)) {
val expected = (127 * math.sin(a * math.Pi / 128)).round.toInt
m.readByte(0xc100 + a).toByte should equal(expected.toByte) withClue s"= sin($a)"
}
val s = (127 * math.sin(angle * math.Pi / 128)).round.toInt
val c = (127 * math.sin((angle + 64) * math.Pi / 128)).round.toInt
val rx = (x * c >> 7) - (y * s >> 7)
val ry = (x * s >> 7) + (y * c >> 7)
m.readByte(0xc000).toByte should equal(rx.toByte) withClue s"= x of ($x,$y) @ $angle"
m.readByte(0xc001).toByte should equal(ry.toByte) withClue s"= y of ($x,$y) @ $angle"
}
}
}
}