This commit is contained in:
Irmen de Jong 2020-08-21 04:02:10 +02:00
parent c83a61c460
commit ef7744dbda
5 changed files with 198 additions and 191 deletions

View File

@ -52,6 +52,7 @@ multiply_words .proc
; -- multiply two 16-bit words into a 32-bit result (signed and unsigned) ; -- multiply two 16-bit words into a 32-bit result (signed and unsigned)
; input: A/Y = first 16-bit number, c64.SCRATCH_ZPWORD1 in ZP = second 16-bit number ; input: A/Y = first 16-bit number, c64.SCRATCH_ZPWORD1 in ZP = second 16-bit number
; output: multiply_words.result 4-bytes/32-bits product, LSB order (low-to-high) ; output: multiply_words.result 4-bytes/32-bits product, LSB order (low-to-high)
; clobbers: A
sta c64.SCRATCH_ZPWORD2 sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1 sty c64.SCRATCH_ZPWORD2+1

View File

@ -55,7 +55,7 @@ write_byte_to_address_on_stack .proc
ldy c64.ESTACK_HI+1,x ldy c64.ESTACK_HI+1,x
sty c64.SCRATCH_ZPWORD2+1 sty c64.SCRATCH_ZPWORD2+1
ldy #0 ldy #0
lda (c64.SCRATCH_ZPWORD2),y sta (c64.SCRATCH_ZPWORD2),y
rts rts
.pend .pend
@ -343,9 +343,7 @@ mul_word .proc
sta c64.SCRATCH_ZPWORD1+1 sta c64.SCRATCH_ZPWORD1+1
lda c64.ESTACK_LO+1,x lda c64.ESTACK_LO+1,x
ldy c64.ESTACK_HI+1,x ldy c64.ESTACK_HI+1,x
stx c64.SCRATCH_ZPREGX
jsr math.multiply_words jsr math.multiply_words
ldx c64.SCRATCH_ZPREGX
lda math.multiply_words.result lda math.multiply_words.result
sta c64.ESTACK_LO+1,x sta c64.ESTACK_LO+1,x
lda math.multiply_words.result+1 lda math.multiply_words.result+1

View File

@ -371,29 +371,31 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val addressExpr = memoryAddress.addressExpression val addressExpr = memoryAddress.addressExpression
val addressLv = addressExpr as? NumericLiteralValue val addressLv = addressExpr as? NumericLiteralValue
when { when {
addressLv != null -> asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}") addressLv != null -> {
asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}")
}
addressExpr is IdentifierReference -> { addressExpr is IdentifierReference -> {
val pointerVarName = asmgen.asmIdentifierName(addressExpr) val pointerVarName = asmgen.asmIdentifierName(addressExpr)
asmgen.out(""" asmgen.out("""
lda $pointerVarName lda $pointerVarName
sta ${C64Zeropage.SCRATCH_W2} sta ${C64Zeropage.SCRATCH_W2}
lda $pointerVarName+1 lda $pointerVarName+1
sta ${C64Zeropage.SCRATCH_W2+1} sta ${C64Zeropage.SCRATCH_W2+1}
lda $ldaInstructionArg lda $ldaInstructionArg
ldy #0 ldy #0
sta (${C64Zeropage.SCRATCH_W2}),y""") sta (${C64Zeropage.SCRATCH_W2}),y""")
} }
else -> { else -> {
asmgen.translateExpression(addressExpr) asmgen.translateExpression(addressExpr)
asmgen.out(""" asmgen.out("""
inx inx
lda $ESTACK_LO_HEX,x lda $ESTACK_LO_HEX,x
sta ${C64Zeropage.SCRATCH_W2} sta ${C64Zeropage.SCRATCH_W2}
lda $ESTACK_HI_HEX,x lda $ESTACK_HI_HEX,x
sta ${C64Zeropage.SCRATCH_W2+1} sta ${C64Zeropage.SCRATCH_W2+1}
lda $ldaInstructionArg lda $ldaInstructionArg
ldy #0 ldy #0
sta (${C64Zeropage.SCRATCH_W2}),y""") sta (${C64Zeropage.SCRATCH_W2}),y""")
} }
} }
} }
@ -404,7 +406,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val addressLv = addressExpr as? NumericLiteralValue val addressLv = addressExpr as? NumericLiteralValue
val registerName = register.name.toLowerCase() val registerName = register.name.toLowerCase()
when { when {
addressLv != null -> asmgen.out(" st$registerName ${addressLv.number.toHex()}") addressLv != null -> {
asmgen.out(" st$registerName ${addressLv.number.toHex()}")
}
addressExpr is IdentifierReference -> { addressExpr is IdentifierReference -> {
val targetName = asmgen.asmIdentifierName(addressExpr) val targetName = asmgen.asmIdentifierName(addressExpr)
when (register) { when (register) {
@ -413,25 +417,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
CpuRegister.Y -> asmgen.out(" tya") CpuRegister.Y -> asmgen.out(" tya")
} }
asmgen.out(""" asmgen.out("""
ldy $targetName ldy $targetName
sty ${C64Zeropage.SCRATCH_W1} sty ${C64Zeropage.SCRATCH_W1}
ldy $targetName+1 ldy $targetName+1
sty ${C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0 ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y""") sta (${C64Zeropage.SCRATCH_W1}),y""")
} }
else -> { else -> {
asmgen.saveRegister(register) asmgen.saveRegister(register)
asmgen.translateExpression(addressExpr) asmgen.translateExpression(addressExpr)
asmgen.restoreRegister(CpuRegister.A) asmgen.restoreRegister(CpuRegister.A)
asmgen.out(""" asmgen.out("""
inx inx
ldy $ESTACK_LO_HEX,x ldy $ESTACK_LO_HEX,x
sty ${C64Zeropage.SCRATCH_W1} sty ${C64Zeropage.SCRATCH_W1}
ldy $ESTACK_HI_HEX,x ldy $ESTACK_HI_HEX,x
sty ${C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0 ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y""") sta (${C64Zeropage.SCRATCH_W1}),y""")
} }
} }
} }

View File

@ -12,8 +12,8 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex import prog8.compiler.toHex
internal class AugmentableAssignmentAsmGen(private val program: Program, internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen, private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen) { private val asmgen: AsmGen) {
fun translate(assign: Assignment) { fun translate(assign: Assignment) {
require(assign.isAugmentable) require(assign.isAugmentable)
@ -22,8 +22,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// A = -A , A = +A, A = ~A // A = -A , A = +A, A = ~A
val px = assign.value as PrefixExpression val px = assign.value as PrefixExpression
val type = px.inferType(program).typeOrElse(DataType.STRUCT) val type = px.inferType(program).typeOrElse(DataType.STRUCT)
when(px.operator) { when (px.operator) {
"+" -> {} "+" -> {
}
"-" -> inplaceNegate(assign.target, type) "-" -> inplaceNegate(assign.target, type)
"~" -> inplaceInvert(assign.target, type) "~" -> inplaceInvert(assign.target, type)
"not" -> inplaceBooleanNot(assign.target, type) "not" -> inplaceBooleanNot(assign.target, type)
@ -43,10 +44,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
return inplaceModification(target, binExpr.operator, binExpr.right, assign) return inplaceModification(target, binExpr.operator, binExpr.right, assign)
} }
if (binExpr.operator in associativeOperators) if (binExpr.operator in associativeOperators) {
{
val leftBinExpr = binExpr.left as? BinaryExpression val leftBinExpr = binExpr.left as? BinaryExpression
if (leftBinExpr!=null && binExpr.right isSameAs target) { if (leftBinExpr != null && binExpr.right isSameAs target) {
// A = 5 <operator> A // A = 5 <operator> A
return inplaceModification(target, binExpr.operator, binExpr.left, assign) return inplaceModification(target, binExpr.operator, binExpr.left, assign)
} }
@ -110,30 +110,30 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val ident = value as? IdentifierReference val ident = value as? IdentifierReference
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
val dt = identifier.inferType(program).typeOrElse(DataType.STRUCT) val dt = identifier.inferType(program).typeOrElse(DataType.STRUCT)
when (dt) { when (dt) {
in ByteDatatypes -> { in ByteDatatypes -> {
when { when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(name, operator, valueLv) valueLv != null -> inplaceModification_byte_litval_to_variable(name, dt, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(name, operator, ident) ident != null -> inplaceModification_byte_variable_to_variable(name, dt, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(name, operator, value) else -> inplaceModification_byte_value_to_variable(name, dt, operator, value)
} }
} }
in WordDatatypes -> { in WordDatatypes -> {
when { when {
valueLv!=null -> inplaceModification_word_litval_to_variable(name, operator, valueLv) valueLv != null -> inplaceModification_word_litval_to_variable(name, operator, valueLv)
ident!=null -> inplaceModification_word_variable_to_variable(name, operator, ident) ident != null -> inplaceModification_word_variable_to_variable(name, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_word_value_to_variable(name, operator, value) else -> inplaceModification_word_value_to_variable(name, operator, value)
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
when { when {
valueLv!=null -> inplaceModification_float_litval_to_variable(name, operator, valueLv) valueLv != null -> inplaceModification_float_litval_to_variable(name, operator, valueLv)
ident!=null -> inplaceModification_float_variable_to_variable(name, operator, ident) ident != null -> inplaceModification_float_variable_to_variable(name, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_float_value_to_variable(name, operator, value) else -> inplaceModification_float_value_to_variable(name, operator, value)
} }
@ -144,23 +144,23 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
} }
} }
memory!=null -> { memory != null -> {
when (memory.addressExpression) { when (memory.addressExpression) {
is NumericLiteralValue -> { is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toInt() val addr = (memory.addressExpression as NumericLiteralValue).number.toInt()
// re-use code to assign a variable, instead this time, use a direct memory address // re-use code to assign a variable, instead this time, use a direct memory address
when { when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(addr.toHex(), operator, valueLv) valueLv != null -> inplaceModification_byte_litval_to_variable(addr.toHex(), DataType.UBYTE, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(addr.toHex(), operator, ident) ident != null -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(addr.toHex(), operator, value) else -> inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value)
} }
} }
is IdentifierReference -> { is IdentifierReference -> {
val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference) val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference)
when { when {
valueLv!=null -> inplaceModification_byte_litval_to_memory(name, operator, valueLv) valueLv != null -> inplaceModification_byte_litval_to_memory(name, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_memory(name, operator, ident) ident != null -> inplaceModification_byte_variable_to_memory(name, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_memory(name, operator, value, origAssign) else -> inplaceModification_byte_value_to_memory(name, operator, value, origAssign)
} }
@ -170,16 +170,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta ${C64Zeropage.SCRATCH_B1}") asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta ${C64Zeropage.SCRATCH_B1}")
// the original memory byte's value is now in the scratch B1 location. // the original memory byte's value is now in the scratch B1 location.
when { when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, valueLv) valueLv != null -> inplaceModification_byte_litval_to_variable(C64Zeropage.SCRATCH_B1.toHex(), DataType.UBYTE, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, ident) ident != null -> inplaceModification_byte_variable_to_variable(C64Zeropage.SCRATCH_B1.toHex(), DataType.UBYTE, operator, ident)
// TODO more specialized code for types such as memory read etc. // TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, value) else -> inplaceModification_byte_value_to_variable(C64Zeropage.SCRATCH_B1.toHex(), DataType.UBYTE, operator, value)
} }
asmgen.out(" lda ${C64Zeropage.SCRATCH_B1} | jsr prog8_lib.write_byte_to_address_on_stack | inx") asmgen.out(" lda ${C64Zeropage.SCRATCH_B1} | jsr prog8_lib.write_byte_to_address_on_stack | inx")
} }
} }
} }
arrayIdx!=null -> { arrayIdx != null -> {
println("TODO 3 optimize simple inplace array assignment $arrayIdx $operator= $value") println("TODO 3 optimize simple inplace array assignment $arrayIdx $operator= $value")
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback
} }
@ -190,7 +190,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// this should be the last resort for code generation for this, // this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow). // because the value is evaluated onto the eval stack (=slow).
asmgen.translateExpression(value) asmgen.translateExpression(value)
when(operator) { when (operator) {
"**" -> TODO("pow") "**" -> TODO("pow")
"+" -> { "+" -> {
asmgen.out(""" asmgen.out("""
@ -207,7 +207,18 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
""") """)
} }
"-" -> { "-" -> {
TODO("-") asmgen.out("""
jsr c64flt.pop_float_fac1
stx ${C64Zeropage.SCRATCH_REG_X}
lda #<$name
ldy #>$name
jsr c64flt.CONUPK
jsr c64flt.FSUBT
ldx #<$name
ldy #>$name
jsr c64flt.MOVMF
ldx ${C64Zeropage.SCRATCH_REG_X}
""")
} }
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
"/" -> { "/" -> {
@ -231,10 +242,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) { private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) {
val constValueName = asmgen.getFloatConst(value) val constValueName = asmgen.getFloatConst(value)
when(operator) { when (operator) {
"**" -> TODO("pow") "**" -> TODO("pow")
"+" -> { "+" -> {
if(value==0.0) if (value == 0.0)
return return
asmgen.out(""" asmgen.out("""
stx ${C64Zeropage.SCRATCH_REG_X} stx ${C64Zeropage.SCRATCH_REG_X}
@ -252,13 +263,26 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
""") """)
} }
"-" -> { "-" -> {
if(value==0.0) if (value == 0.0)
return return
TODO("-") asmgen.out("""
stx ${C64Zeropage.SCRATCH_REG_X}
lda #<$constValueName
ldy #>$constValueName
jsr c64flt.MOVFM
lda #<$name
ldy #>$name
jsr c64flt.CONUPK
jsr c64flt.FSUBT
ldx #<$name
ldy #>$name
jsr c64flt.MOVMF
ldx ${C64Zeropage.SCRATCH_REG_X}
""")
} }
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
"/" -> { "/" -> {
if(value==0.0) if (value == 0.0)
throw AssemblyError("division by zero") throw AssemblyError("division by zero")
TODO() TODO()
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") // asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
@ -275,7 +299,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression, origAssign: Assignment) { private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression, origAssign: Assignment) {
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback
TODO("Not yet implemented") TODO("inplaceModification_byte_value_to_memory")
} }
private fun inplaceModification_byte_variable_to_memory(pointername: String, operator: String, ident: IdentifierReference) { private fun inplaceModification_byte_variable_to_memory(pointername: String, operator: String, ident: IdentifierReference) {
@ -285,11 +309,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lda $pointername lda $pointername
ldy $pointername+1 ldy $pointername+1
sta ${C64Zeropage.SCRATCH_W1} sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1 + 1}
ldy #0 ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y""") lda (${C64Zeropage.SCRATCH_W1}),y""")
} }
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> { "+" -> {
loadByteFromPointerInA() loadByteFromPointerInA()
@ -331,11 +355,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lda $pointername lda $pointername
ldy $pointername+1 ldy $pointername+1
sta ${C64Zeropage.SCRATCH_W1} sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1} sty ${C64Zeropage.SCRATCH_W1 + 1}
ldy #0 ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y""") lda (${C64Zeropage.SCRATCH_W1}),y""")
} }
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> { "+" -> {
loadByteFromPointerInA() loadByteFromPointerInA()
@ -354,14 +378,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// asmgen.out(" jsr prog8_lib.remainder_ub") // asmgen.out(" jsr prog8_lib.remainder_ub")
} }
"<<" -> { "<<" -> {
if(value>1) { if (value > 1) {
loadByteFromPointerInA() loadByteFromPointerInA()
repeat(value.toInt()) { asmgen.out(" asl a") } repeat(value.toInt()) { asmgen.out(" asl a") }
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
} }
} }
">>" -> { ">>" -> {
if(value>1) { if (value > 1) {
loadByteFromPointerInA() loadByteFromPointerInA()
repeat(value.toInt()) { asmgen.out(" lsr a") } repeat(value.toInt()) { asmgen.out(" lsr a") }
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
@ -384,27 +408,41 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
private fun inplaceModification_word_litval_to_variable(name: String, operator: String, value: Double) { private fun inplaceModification_word_litval_to_variable(name: String, operator: String, value: Double) {
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc #<$value | sta $name | lda $name+1 | adc #>$value | sta $name+1") "+" -> asmgen.out(" lda $name | clc | adc #<$value | sta $name | lda $name+1 | adc #>$value | sta $name+1")
"-" -> asmgen.out(" lda $name | sec | sbc #<$value | sta $name | lda $name+1 | sbc #>$value | sta $name+1") "-" -> asmgen.out(" lda $name | sec | sbc #<$value | sta $name | lda $name+1 | sbc #>$value | sta $name+1")
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "*" -> {
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") // TODO what about the optimized routines?
asmgen.out("""
lda $name
sta c64.SCRATCH_ZPWORD1
lda $name+1
sta c64.SCRATCH_ZPWORD1+1
lda #<$value
ldy #>$value
jsr math.multiply_words
lda math.multiply_words.result
sta $name
lda math.multiply_words.result+1
sta $name+1,x""")
}
"/" -> TODO("word $name /= $value")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
"%" -> { "%" -> {
TODO("word remainder") TODO("word remainder $value")
// if(types==DataType.BYTE) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // asmgen.out(" jsr prog8_lib.remainder_ub")
} }
"<<" -> { "<<" -> {
if(value>1) { if (value > 1) {
asmgen.out(" lda $name") asmgen.out(" lda $name")
TODO("word asl") TODO("word asl")
asmgen.out(" sta $name") asmgen.out(" sta $name")
} }
} }
">>" -> { ">>" -> {
if(value>1) { if (value > 1) {
asmgen.out(" lda $name") asmgen.out(" lda $name")
TODO("word lsr") TODO("word lsr")
asmgen.out(" sta $name") asmgen.out(" sta $name")
@ -419,7 +457,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_word_variable_to_variable(name: String, operator: String, ident: IdentifierReference) { private fun inplaceModification_word_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmIdentifierName(ident) val otherName = asmgen.asmIdentifierName(ident)
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name | lda $name+1 | adc $otherName+1 | sta $name+1") "+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name | lda $name+1 | adc $otherName+1 | sta $name+1")
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name | lda $name+1 | sbc $otherName+1 | sta $name+1") "-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name | lda $name+1 | sbc $otherName+1 | sta $name+1")
@ -444,7 +482,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// this should be the last resort for code generation for this, // this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow). // because the value is evaluated onto the eval stack (=slow).
asmgen.translateExpression(value) asmgen.translateExpression(value)
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | adc $ESTACK_HI_PLUS1_HEX,x | sta $name+1") "+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | adc $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
"-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | sbc $ESTACK_HI_PLUS1_HEX,x | sta $name+1") "-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | sbc $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
@ -466,11 +504,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" inx") asmgen.out(" inx")
} }
private fun inplaceModification_byte_value_to_variable(name: String, operator: String, value: Expression) { private fun inplaceModification_byte_value_to_variable(name: String, dt: DataType, operator: String, value: Expression) {
// this should be the last resort for code generation for this, // this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow). // because the value is evaluated onto the eval stack (=slow).
asmgen.translateExpression(value) asmgen.translateExpression(value)
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name") "+" -> asmgen.out(" lda $name | clc | adc $ESTACK_LO_PLUS1_HEX,x | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name")
@ -492,9 +530,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" inx") asmgen.out(" inx")
} }
private fun inplaceModification_byte_variable_to_variable(name: String, operator: String, ident: IdentifierReference) { private fun inplaceModification_byte_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmIdentifierName(ident) val otherName = asmgen.asmIdentifierName(ident)
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name") "+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc $otherName | sta $name")
@ -515,28 +553,45 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
} }
private fun inplaceModification_byte_litval_to_variable(name: String, operator: String, value: Double) { private fun inplaceModification_byte_litval_to_variable(name: String, dt: DataType, operator: String, value: Double) {
when(operator) { when (operator) {
// note: ** (power) operator requires floats. // note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc #$value | sta $name") "+" -> asmgen.out(" lda $name | clc | adc #$value | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name")
"*" -> TODO()// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "*" -> {
"/" -> TODO()// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") // TODO what about the optimized routines?
TODO("$dt mul $name *= $value")
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
}
"/" -> {
if (dt == DataType.UBYTE) {
asmgen.out("""
lda $name
ldy #$value
jsr math.divmod_ub
sty $name
""")
} else {
// BYTE
// requires to use unsigned division and fix sign afterwards, see idiv_b in prog8lib
TODO("BYTE div $name /= $value")
}
}
"%" -> { "%" -> {
TODO("byte remainder") TODO("$dt remainder")
// if(types==DataType.BYTE) // if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") // throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub") // asmgen.out(" jsr prog8_lib.remainder_ub")
} }
"<<" -> { "<<" -> {
if(value>1) { if (value > 1) {
asmgen.out(" lda $name") asmgen.out(" lda $name")
repeat(value.toInt()) { asmgen.out(" asl a") } repeat(value.toInt()) { asmgen.out(" asl a") }
asmgen.out(" sta $name") asmgen.out(" sta $name")
} }
} }
">>" -> { ">>" -> {
if(value>1) { if (value > 1) {
asmgen.out(" lda $name") asmgen.out(" lda $name")
repeat(value.toInt()) { asmgen.out(" lsr a") } repeat(value.toInt()) { asmgen.out(" lsr a") }
asmgen.out(" sta $name") asmgen.out(" sta $name")
@ -554,26 +609,28 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val outerCastDt = cast.type val outerCastDt = cast.type
val innerCastDt = (cast.expression as? TypecastExpression)?.type val innerCastDt = (cast.expression as? TypecastExpression)?.type
if(innerCastDt==null) { if (innerCastDt == null) {
// simple typecast where the value is the target // simple typecast where the value is the target
when(targetDt) { when (targetDt) {
DataType.UBYTE, DataType.BYTE -> { /* byte target can't be casted to anything else at all */ } DataType.UBYTE, DataType.BYTE -> { /* byte target can't be casted to anything else at all */
}
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
when(outerCastDt) { when (outerCastDt) {
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
if(target.identifier!=null) { if (target.identifier != null) {
val name = asmgen.asmIdentifierName(target.identifier!!) val name = asmgen.asmIdentifierName(target.identifier!!)
asmgen.out(" lda #0 | sta $name+1") asmgen.out(" lda #0 | sta $name+1")
} else } else
throw AssemblyError("weird value") throw AssemblyError("weird value")
} }
DataType.UWORD, DataType.WORD, in IterableDatatypes -> {} DataType.UWORD, DataType.WORD, in IterableDatatypes -> {
}
DataType.FLOAT -> throw AssemblyError("incompatible cast type") DataType.FLOAT -> throw AssemblyError("incompatible cast type")
else -> throw AssemblyError("weird cast type") else -> throw AssemblyError("weird cast type")
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
if(outerCastDt!=DataType.FLOAT) if (outerCastDt != DataType.FLOAT)
throw AssemblyError("in-place cast of a float makes no sense") throw AssemblyError("in-place cast of a float makes no sense")
} }
else -> throw AssemblyError("invalid cast target type") else -> throw AssemblyError("invalid cast target type")
@ -581,19 +638,19 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} else { } else {
// typecast with nested typecast, that has the target as a value // typecast with nested typecast, that has the target as a value
// calculate singular cast that is required // calculate singular cast that is required
val castDt = if(outerCastDt largerThan innerCastDt) innerCastDt else outerCastDt val castDt = if (outerCastDt largerThan innerCastDt) innerCastDt else outerCastDt
val value = (cast.expression as TypecastExpression).expression val value = (cast.expression as TypecastExpression).expression
val resultingCast = TypecastExpression(value, castDt, false, assign.position) val resultingCast = TypecastExpression(value, castDt, false, assign.position)
inplaceCast(target, resultingCast, assign) inplaceCast(target, resultingCast, assign)
} }
} }
private fun inplaceBooleanNot(target: AssignTarget, dt: DataType) { private fun inplaceBooleanNot(target: AssignTarget, dt: DataType) {
val arrayIdx = target.arrayindexed val arrayIdx = target.arrayindexed
val identifier = target.identifier val identifier = target.identifier
val memory = target.memoryAddress val memory = target.memoryAddress
when(dt) { when (dt) {
DataType.UBYTE -> { DataType.UBYTE -> {
when { when {
identifier != null -> { identifier != null -> {
@ -631,7 +688,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sta (${C64Zeropage.SCRATCH_W1}),y""") sta (${C64Zeropage.SCRATCH_W1}),y""")
} }
else -> { else -> {
TODO("$memory") asmgen.translateExpression(memory.addressExpression)
asmgen.out("""
jsr prog8_lib.read_byte_from_address_on_stack
beq +
lda #1
+ eor #1
jsr prog8_lib.write_byte_to_address_on_stack
inx""")
} }
} }
} }
@ -642,7 +706,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
DataType.UWORD -> { DataType.UWORD -> {
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
asmgen.out(""" asmgen.out("""
lda $name lda $name
@ -654,8 +718,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lsr a lsr a
sta $name+1""") sta $name+1""")
} }
arrayIdx!=null -> TODO("in-place not of uword array") arrayIdx != null -> TODO("in-place not of uword array")
memory!=null -> throw AssemblyError("no asm gen for uword-memory not") memory != null -> throw AssemblyError("no asm gen for uword-memory not")
} }
} }
else -> throw AssemblyError("boolean-not of invalid type") else -> throw AssemblyError("boolean-not of invalid type")
@ -667,7 +731,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val identifier = target.identifier val identifier = target.identifier
val memory = target.memoryAddress val memory = target.memoryAddress
when(dt) { when (dt) {
DataType.UBYTE -> { DataType.UBYTE -> {
when { when {
identifier != null -> { identifier != null -> {
@ -699,7 +763,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sta (${C64Zeropage.SCRATCH_W1}),y""") sta (${C64Zeropage.SCRATCH_W1}),y""")
} }
else -> { else -> {
TODO("$memory") asmgen.translateExpression(memory.addressExpression)
asmgen.out("""
jsr prog8_lib.read_byte_from_address_on_stack
eor #255
jsr prog8_lib.write_byte_to_address_on_stack
inx""")
} }
} }
} }
@ -710,7 +779,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
DataType.UWORD -> { DataType.UWORD -> {
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
asmgen.out(""" asmgen.out("""
lda $name lda $name
@ -720,8 +789,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
eor #255 eor #255
sta $name+1""") sta $name+1""")
} }
arrayIdx!=null -> TODO("in-place invert uword array") arrayIdx != null -> TODO("in-place invert uword array")
memory!=null -> throw AssemblyError("no asm gen for uword-memory invert") memory != null -> throw AssemblyError("no asm gen for uword-memory invert")
} }
} }
else -> throw AssemblyError("invert of invalid type") else -> throw AssemblyError("invert of invalid type")
@ -733,10 +802,10 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val identifier = target.identifier val identifier = target.identifier
val memory = target.memoryAddress val memory = target.memoryAddress
when(dt) { when (dt) {
DataType.BYTE -> { DataType.BYTE -> {
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
asmgen.out(""" asmgen.out("""
lda #0 lda #0
@ -744,13 +813,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sbc $name sbc $name
sta $name""") sta $name""")
} }
memory!=null -> throw AssemblyError("can't in-place negate memory ubyte") memory != null -> throw AssemblyError("can't in-place negate memory ubyte")
arrayIdx!=null -> TODO("in-place negate byte array") arrayIdx != null -> TODO("in-place negate byte array")
} }
} }
DataType.WORD -> { DataType.WORD -> {
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
asmgen.out(""" asmgen.out("""
lda #0 lda #0
@ -761,13 +830,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sbc $name+1 sbc $name+1
sta $name+1""") sta $name+1""")
} }
arrayIdx!=null -> TODO("in-place negate word array") arrayIdx != null -> TODO("in-place negate word array")
memory!=null -> throw AssemblyError("no asm gen for word memory negate") memory != null -> throw AssemblyError("no asm gen for word memory negate")
} }
} }
DataType.FLOAT -> { DataType.FLOAT -> {
when { when {
identifier!=null -> { identifier != null -> {
val name = asmgen.asmIdentifierName(identifier) val name = asmgen.asmIdentifierName(identifier)
asmgen.out(""" asmgen.out("""
stx ${C64Zeropage.SCRATCH_REG_X} stx ${C64Zeropage.SCRATCH_REG_X}
@ -781,8 +850,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
ldx ${C64Zeropage.SCRATCH_REG_X} ldx ${C64Zeropage.SCRATCH_REG_X}
""") """)
} }
arrayIdx!=null -> TODO("in-place negate float array") arrayIdx != null -> TODO("in-place negate float array")
memory!=null -> throw AssemblyError("no asm gen for float memory negate") memory != null -> throw AssemblyError("no asm gen for float memory negate")
} }
} }
else -> throw AssemblyError("negate of invalid type") else -> throw AssemblyError("negate of invalid type")

View File

@ -7,79 +7,14 @@ main {
sub start() { sub start() {
;ubyte @(addr)=0 uword addr = $c002
uword addr = $02
uword addr2 = $03
ubyte B = 22
; all optimized:
@(addr) = B
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr2-1) = @(addr2-1) +33
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11 @(addr-2) = $f8
c64scr.print_ub(@(addr)) @(addr-2) = not @(addr-2)
c64scr.print_ubhex(@($c000), true)
c64.CHROUT('\n') c64.CHROUT('\n')
@(addr) = 33 + @(addr) @(addr-2) = not @(addr-2)
c64scr.print_ub(@(addr)) c64scr.print_ubhex(@($c000), true)
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = (@(addr) + 33) + B
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = (33 + @(addr)) + B
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = (@(addr) + B) + 33
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = (B + @(addr)) + 33
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = B+ (@(addr) + 33)
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = B+(33 + @(addr))
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 33+(@(addr) + B)
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 33+(B + @(addr))
c64scr.print_ub(@(addr))
c64.CHROUT('\n') c64.CHROUT('\n')
} }
} }