From b2d1757e5afb31f46ee469bd6dc6bb65506fa074 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 10 Oct 2020 15:39:48 +0200 Subject: [PATCH] asmgen: byte to word sign extensions --- .../compiler/target/c64/codegen/AsmGen.kt | 20 ++++- .../target/c64/codegen/ExpressionsAsmGen.kt | 2 +- .../codegen/assignment/AssignmentAsmGen.kt | 78 +++++++++++++++++-- .../assignment/AugmentableAssignmentAsmGen.kt | 16 ++-- examples/test.p8 | 6 ++ 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index f4e231f2c..947c757e4 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -1220,7 +1220,7 @@ $counterVar .byte 0""") assemblyLines.add(assembly) } - internal fun signExtendStackByte(valueDt: DataType) { + internal fun signExtendStackLsb(valueDt: DataType) { // sign extend signed byte on stack to signed word when(valueDt) { DataType.UBYTE -> { @@ -1237,4 +1237,22 @@ $counterVar .byte 0""") else -> throw AssemblyError("need byte type") } } + + internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) { + // sign extend signed byte in a word variable + when(valueDt) { + DataType.UBYTE -> { + out(" lda #0 | sta $asmvar+1") + } + DataType.BYTE -> { + out(""" + lda $asmvar+1 + ora #$7f + bmi + + lda #0 ++ sta $asmvar+1""") + } + else -> throw AssemblyError("need byte type") + } + } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 3a7b20a8d..aeb2c8d00 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -1013,7 +1013,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge DataType.BYTE -> { when(typecast.type) { DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.signExtendStackByte(DataType.BYTE) + DataType.UWORD, DataType.WORD -> asmgen.signExtendStackLsb(DataType.BYTE) DataType.FLOAT -> asmgen.out(" jsr floats.stack_b2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") else -> throw AssemblyError("weird type") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index 71b39c68a..c918861e0 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -166,9 +166,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val valueDt = value.inferType(program).typeOrElse(DataType.STRUCT) when(value) { is IdentifierReference -> { - if (valueDt == DataType.UBYTE || valueDt == DataType.BYTE) { - if(targetDt in WordDatatypes) { - assignVariableByteIntoWord(target, value, valueDt) + if(targetDt in WordDatatypes) { + if(valueDt==DataType.UBYTE) { + assignVariableUByteIntoWord(target, value) + return + } + if(valueDt==DataType.BYTE) { + assignVariableByteIntoWord(target, value) return } } @@ -606,10 +610,68 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference, valueDt: DataType) { - if(valueDt == DataType.BYTE) - TODO("sign extend byte to word") + private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) { + val sourceName = asmgen.asmVariableName(bytevar) + when (wordtarget.kind) { + TargetStorageKind.VARIABLE -> { + asmgen.out(""" + lda $sourceName + sta ${wordtarget.asmVarname} + ora #$7f + bmi + + lda #0 ++ sta ${wordtarget.asmVarname}+1 + """) + } + TargetStorageKind.ARRAY -> { + // TODO optimize slow stack evaluation for this case, see assignVariableUByteIntoWord + println("warning: slow stack evaluation used for sign-extend byte typecast at ${bytevar.position}") + asmgen.translateExpression(wordtarget.origAssign.source.expression!!) + assignStackValue(wordtarget) + } + TargetStorageKind.REGISTER -> { + when(wordtarget.register!!) { + RegisterOrPair.AX -> asmgen.out(""" + lda $sourceName + pha + ora #$7f + bmi + + ldx #0 ++ tax + pla""") + RegisterOrPair.AY -> asmgen.out(""" + lda $sourceName + pha + ora #$7f + bmi + + ldy #0 ++ tay + pla""") + RegisterOrPair.XY -> asmgen.out(""" + lda $sourceName + tax + ora #$7f + bmi + + ldy #0 ++ tay""") + else -> throw AssemblyError("only reg pairs are words") + } + } + TargetStorageKind.STACK -> { + asmgen.out(""" + lda $sourceName + sta P8ESTACK_LO,x + ora #$7f + bmi + + lda #0 ++ sta P8ESTACK_HI,x + dex""") + } + else -> throw AssemblyError("target type isn't word") + } + } + private fun assignVariableUByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) { val sourceName = asmgen.asmVariableName(bytevar) when(wordtarget.kind) { TargetStorageKind.VARIABLE -> { @@ -649,13 +711,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } TargetStorageKind.STACK -> { asmgen.out(""" - lda #$sourceName + lda $sourceName sta P8ESTACK_LO,x lda #0 sta P8ESTACK_HI,x dex""") } - else -> throw AssemblyError("other types aren't word") + else -> throw AssemblyError("target type isn't word") } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 078d53781..19cd2a1e3 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -605,7 +605,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sec sbc P8ZP_SCRATCH_B1 sta $name""") - // TODO: more operators + // TODO: tuned code for more operators } else -> { inplaceModification_byte_value_to_variable(name, dt, operator, memread); @@ -636,7 +636,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, bcc + dec $name+1 +""") - // TODO: more operators + // TODO: tuned code for more operators } else -> { inplaceModification_word_value_to_variable(name, dt, operator, memread); @@ -1150,17 +1150,17 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "*" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation - asmgen.signExtendStackByte(valueDt) + asmgen.signExtendStackLsb(valueDt) multiplyWord() } "/" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation - asmgen.signExtendStackByte(valueDt) + asmgen.signExtendStackLsb(valueDt) divideWord() } "%" -> { // stack contains (u) byte value, sign extend that and proceed with regular 16 bit operation - asmgen.signExtendStackByte(valueDt) + asmgen.signExtendStackLsb(valueDt) remainderWord() } "<<" -> { @@ -1201,9 +1201,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, +""") } } - "&" -> TODO("bitand (u)word (u)byte") - "^" -> TODO("bitxor (u)word (u)byte") - "|" -> TODO("bitor (u)word (u)byte") + "&" -> TODO("bitand (u)word (u)byte on stack") + "^" -> TODO("bitxor (u)word (u)byte on stack") + "|" -> TODO("bitor (u)word (u)byte on stack") else -> throw AssemblyError("invalid operator for in-place modification $operator") } } diff --git a/examples/test.p8 b/examples/test.p8 index e5ca95d4a..094c92c4c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,6 +7,12 @@ main { sub start() { + word wv + byte bv + + wv = bv + + } asmsub testX() {