added most essential of the new in-place assignment code

This commit is contained in:
Irmen de Jong 2020-08-21 00:17:28 +02:00
parent 39ea5c5f99
commit 8d6220ce51
6 changed files with 543 additions and 48 deletions

View File

@ -40,9 +40,22 @@ read_byte_from_address_on_stack .proc
; -- read the byte from the memory address on the top of the stack, return in A (stack remains unchanged)
lda c64.ESTACK_LO+1,x
ldy c64.ESTACK_HI+1,x
sta (+) +1
sty (+) +2
+ lda $ffff ; modified
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
ldy #0
lda (c64.SCRATCH_ZPWORD2),y
rts
.pend
write_byte_to_address_on_stack .proc
; -- write the byte in A to the memory address on the top of the stack (stack remains unchanged)
ldy c64.ESTACK_LO+1,x
sty c64.SCRATCH_ZPWORD2
ldy c64.ESTACK_HI+1,x
sty c64.SCRATCH_ZPWORD2+1
ldy #0
lda (c64.SCRATCH_ZPWORD2),y
rts
.pend

View File

@ -336,24 +336,28 @@ open class Assignment(var target: AssignTarget, var value: Expression, override
get() {
val binExpr = value as? BinaryExpression
if(binExpr!=null) {
if(binExpr.left isSameAs target)
return true // A = A <operator> 5
if(binExpr.right !is BinaryExpression && binExpr.left isSameAs target)
return true // A = A <operator> v
if(binExpr.operator in associativeOperators) {
if (binExpr.right isSameAs target)
if (binExpr.left !is BinaryExpression && binExpr.right isSameAs target)
return true // A = v <associative-operator> A
val leftBinExpr = binExpr.left as? BinaryExpression
if(leftBinExpr?.operator == binExpr.operator) {
// one of these?
// A = (A <associative-operator> x) <same-operator> y
// A = (x <associative-operator> A) <same-operator> y
return leftBinExpr.left isSameAs target || leftBinExpr.right isSameAs target
// A = (x <associative-operator> y) <same-operator> A
return leftBinExpr.left isSameAs target || leftBinExpr.right isSameAs target || binExpr.right isSameAs target
}
val rightBinExpr = binExpr.right as? BinaryExpression
if(rightBinExpr?.operator == binExpr.operator) {
// one of these?
// A = y <associative-operator> (A <same-operator> x)
// A = y <associative-operator> (x <same-operator> y)
return rightBinExpr.left isSameAs target || rightBinExpr.right isSameAs target
// A = A <associative-operator> (x <same-operator> y)
return rightBinExpr.left isSameAs target || rightBinExpr.right isSameAs target || binExpr.left isSameAs target
}
}
}

View File

@ -14,9 +14,9 @@ class AssemblyProgram(override val name: String, outputDir: Path) : IAssemblyPro
private val viceMonListFile = outputDir.resolve("$name.vice-mon-list")
override fun assemble(options: CompilationOptions) {
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps
// add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently)
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-strict-bool", "-Wno-shadow", "-Werror", "-Wno-error=long-branch",
"-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror",
"--dump-labels", "--vice-labels", "-l", viceMonListFile.toString(), "--no-monitor")
val outFile = when (options.output) {

View File

@ -72,9 +72,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
assignFromMemoryByte(assign.target, null, read.addressExpression as IdentifierReference)
}
else -> {
asmgen.translateExpression(read.addressExpression)
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
assignFromRegister(assign.target, CpuRegister.A)
TODO("assign from memread $assign") // see inplaceModification() ?
// asmgen.translateExpression(read.addressExpression)
// asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
// assignFromRegister(assign.target, CpuRegister.A)
}
}
}
@ -375,24 +376,24 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val pointerVarName = asmgen.asmIdentifierName(addressExpr)
asmgen.out("""
lda $pointerVarName
sta ${C64Zeropage.SCRATCH_W1}
sta ${C64Zeropage.SCRATCH_W2}
lda $pointerVarName+1
sta ${C64Zeropage.SCRATCH_W1+1}
sta ${C64Zeropage.SCRATCH_W2+1}
lda $ldaInstructionArg
ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y""")
sta (${C64Zeropage.SCRATCH_W2}),y""")
}
else -> {
asmgen.translateExpression(addressExpr)
asmgen.out("""
inx
lda $ESTACK_LO_HEX,x
sta ${C64Zeropage.SCRATCH_W1}
sta ${C64Zeropage.SCRATCH_W2}
lda $ESTACK_HI_HEX,x
sta ${C64Zeropage.SCRATCH_W1+1}
sta ${C64Zeropage.SCRATCH_W2+1}
lda $ldaInstructionArg
ldy #0
sta (${C64Zeropage.SCRATCH_W1}),y""")
sta (${C64Zeropage.SCRATCH_W2}),y""")
}
}
}

View File

@ -1,13 +1,14 @@
package prog8.compiler.target.c64.codegen
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.base.IterableDatatypes
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment
import prog8.compiler.AssemblyError
import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex
internal class AugmentableAssignmentAsmGen(private val program: Program,
@ -35,9 +36,423 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
private fun inplaceBinary(target: AssignTarget, binaryExpression: BinaryExpression, assign: Assignment) {
println("TODO optimize binexpr assignment ${binaryExpression.position}")
assignmentAsmGen.translateOtherAssignment(assign) // TODO get rid of this fallback
private fun inplaceBinary(target: AssignTarget, binExpr: BinaryExpression, assign: Assignment) {
if (binExpr.right !is BinaryExpression && binExpr.left isSameAs target) {
// A = A <operator> 5
return inplaceModification(target, binExpr.operator, binExpr.right, assign)
}
if (binExpr.operator in associativeOperators)
{
val leftBinExpr = binExpr.left as? BinaryExpression
if (leftBinExpr!=null && binExpr.right isSameAs target) {
// A = 5 <operator> A
return inplaceModification(target, binExpr.operator, binExpr.left, assign)
}
if (leftBinExpr?.operator == binExpr.operator) {
// TODO better optimize the chained asm to avoid intermediate stores/loads?
when {
binExpr.right isSameAs target -> {
// A = (x <associative-operator> y) <same-operator> A
inplaceModification(target, binExpr.operator, leftBinExpr.left, assign)
inplaceModification(target, binExpr.operator, leftBinExpr.right, assign)
return
}
leftBinExpr.left isSameAs target -> {
// A = (A <associative-operator> x) <same-operator> y
inplaceModification(target, binExpr.operator, leftBinExpr.right, assign)
inplaceModification(target, binExpr.operator, binExpr.right, assign)
return
}
leftBinExpr.right isSameAs target -> {
// A = (x <associative-operator> A) <same-operator> y
inplaceModification(target, binExpr.operator, leftBinExpr.left, assign)
inplaceModification(target, binExpr.operator, binExpr.right, assign)
return
}
}
}
val rightBinExpr = binExpr.right as? BinaryExpression
if (rightBinExpr?.operator == binExpr.operator) {
when {
binExpr.left isSameAs target -> {
// A = A <associative-operator> (x <same-operator> y)
inplaceModification(target, binExpr.operator, rightBinExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.right, assign)
return
}
rightBinExpr.left isSameAs target -> {
// A = y <associative-operator> (A <same-operator> x)
inplaceModification(target, binExpr.operator, binExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.right, assign)
return
}
rightBinExpr.right isSameAs target -> {
// A = y <associative-operator> (x <same-operator> y)
inplaceModification(target, binExpr.operator, binExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.left, assign)
return
}
}
}
}
throw FatalAstException("assignment should be augmentable $assign\nleft=${binExpr.left}\nright=${binExpr.right}")
}
private fun inplaceModification(target: AssignTarget, operator: String, value: Expression, origAssign: Assignment) {
val arrayIdx = target.arrayindexed
val identifier = target.identifier
val memory = target.memoryAddress
val valueLv = (value as? NumericLiteralValue)?.number?.toDouble()
val ident = value as? IdentifierReference
when {
identifier!=null -> {
val name = asmgen.asmIdentifierName(identifier)
val dt = identifier.inferType(program).typeOrElse(DataType.STRUCT)
when (dt) {
in ByteDatatypes -> {
when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(name, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(name, operator, ident)
// TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(name, operator, value)
}
}
in WordDatatypes -> {
when {
valueLv!=null -> inplaceModification_word_litval_to_variable(name, operator, valueLv)
ident!=null -> inplaceModification_word_variable_to_variable(name, operator, ident)
// TODO more specialized code for types such as memory read etc.
else -> inplaceModification_word_value_to_variable(name, operator, value)
}
}
else -> {
// TODO fix this one it is used in several examples.
println("TODO 1c optimize simple inplace assignment [$dt] $name $operator= $value")
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback
}
}
}
memory!=null -> {
when (memory.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toInt()
// re-use code to assign a variable, instead this time, use a direct memory address
when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(addr.toHex(), operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(addr.toHex(), operator, ident)
// TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(addr.toHex(), operator, value)
}
}
is IdentifierReference -> {
val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference)
when {
valueLv!=null -> inplaceModification_byte_litval_to_memory(name, operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_memory(name, operator, ident)
// TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_memory(name, operator, value, origAssign)
}
}
else -> {
asmgen.translateExpression(memory.addressExpression)
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.
when {
valueLv!=null -> inplaceModification_byte_litval_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, valueLv)
ident!=null -> inplaceModification_byte_variable_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, ident)
// TODO more specialized code for types such as memory read etc.
else -> inplaceModification_byte_value_to_variable(C64Zeropage.SCRATCH_B1.toHex(), operator, value)
}
asmgen.out(" lda ${C64Zeropage.SCRATCH_B1} | jsr prog8_lib.write_byte_to_address_on_stack | inx")
}
}
}
arrayIdx!=null -> {
println("TODO 3 optimize simple inplace array assignment $arrayIdx $operator= $value")
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback
}
}
}
private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression, origAssign: Assignment) {
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback
TODO("Not yet implemented")
}
private fun inplaceModification_byte_variable_to_memory(pointername: String, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmIdentifierName(ident)
fun loadByteFromPointerInA() {
asmgen.out("""
lda $pointername
ldy $pointername+1
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y""")
}
when(operator) {
// note: ** (power) operator requires floats.
"+" -> {
loadByteFromPointerInA()
asmgen.out(" clc | adc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y")
}
"-" -> {
loadByteFromPointerInA()
asmgen.out(" sec | sbc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y")
}
"*" -> 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("byte remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> TODO("byte asl")
">>" -> TODO("byte lsr")
"&" -> {
loadByteFromPointerInA()
asmgen.out(" and $otherName | (${C64Zeropage.SCRATCH_W1}),y")
}
"^" -> {
loadByteFromPointerInA()
asmgen.out(" xor $otherName | (${C64Zeropage.SCRATCH_W1}),y")
}
"|" -> {
loadByteFromPointerInA()
asmgen.out(" ora $otherName | (${C64Zeropage.SCRATCH_W1}),y")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceModification_byte_litval_to_memory(pointername: String, operator: String, value: Double) {
fun loadByteFromPointerInA() {
asmgen.out("""
lda $pointername
ldy $pointername+1
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1+1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y""")
}
when(operator) {
// note: ** (power) operator requires floats.
"+" -> {
loadByteFromPointerInA()
asmgen.out(" clc | adc #$value | sta (${C64Zeropage.SCRATCH_W1}),y")
}
"-" -> {
loadByteFromPointerInA()
asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y")
}
"*" -> 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("byte remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> {
if(value>1) {
loadByteFromPointerInA()
repeat(value.toInt()) { asmgen.out(" asl a") }
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
}
}
">>" -> {
if(value>1) {
loadByteFromPointerInA()
repeat(value.toInt()) { asmgen.out(" lsr a") }
asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y")
}
}
"&" -> {
loadByteFromPointerInA()
asmgen.out(" and #$value | (${C64Zeropage.SCRATCH_W1}),y")
}
"^" -> {
loadByteFromPointerInA()
asmgen.out(" xor #$value | (${C64Zeropage.SCRATCH_W1}),y")
}
"|" -> {
loadByteFromPointerInA()
asmgen.out(" ora #$value | (${C64Zeropage.SCRATCH_W1}),y")
}
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceModification_word_litval_to_variable(name: String, operator: String, value: Double) {
when(operator) {
// 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 | 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("word remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> {
if(value>1) {
asmgen.out(" lda $name")
TODO("word asl")
asmgen.out(" sta $name")
}
}
">>" -> {
if(value>1) {
asmgen.out(" lda $name")
TODO("word lsr")
asmgen.out(" sta $name")
}
}
"&" -> asmgen.out(" lda $name | and #<$value | sta $name | lda $name+1 | and #>$value | sta $name+1")
"^" -> asmgen.out(" lda $name | xor #<$value | sta $name | lda $name+1 | xor #>$value | sta $name+1")
"|" -> asmgen.out(" lda $name | ora #<$value | sta $name | lda $name+1 | ora #>$value | sta $name+1")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceModification_word_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmIdentifierName(ident)
when(operator) {
// 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 | sec | sbc $otherName | sta $name | lda $name+1 | sbc $otherName+1 | 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("word remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> TODO()
">>" -> TODO()
"&" -> asmgen.out(" lda $name | and $otherName | sta $name | lda $name+1 | and $otherName+1 | sta $name+1")
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name | lda $name+1 | xor $otherName+1 | sta $name+1")
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name | lda $name+1 | ora $otherName+1 | sta $name+1")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceModification_word_value_to_variable(name: String, operator: String, value: Expression) {
// this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow).
asmgen.translateExpression(value)
when(operator) {
// 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 | sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | sbc $ESTACK_HI_PLUS1_HEX,x | 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("word remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> TODO()
">>" -> TODO()
"&" -> asmgen.out(" lda $name | and $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | and $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
"^" -> asmgen.out(" lda $name | xor $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | xor $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
"|" -> asmgen.out(" lda $name | ora $ESTACK_LO_PLUS1_HEX,x | sta $name | lda $name+1 | ora $ESTACK_HI_PLUS1_HEX,x | sta $name+1")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
asmgen.out(" inx")
}
private fun inplaceModification_byte_value_to_variable(name: String, operator: String, value: Expression) {
// this should be the last resort for code generation for this,
// because the value is evaluated onto the eval stack (=slow).
asmgen.translateExpression(value)
when(operator) {
// note: ** (power) operator requires floats.
"+" -> 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")
"*" -> 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("byte remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> TODO()
">>" -> TODO()
"&" -> asmgen.out(" lda $name | and $ESTACK_LO_PLUS1_HEX,x | sta $name")
"^" -> asmgen.out(" lda $name | xor $ESTACK_LO_PLUS1_HEX,x | sta $name")
"|" -> asmgen.out(" lda $name | ora $ESTACK_LO_PLUS1_HEX,x | sta $name")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
asmgen.out(" inx")
}
private fun inplaceModification_byte_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmIdentifierName(ident)
when(operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc $otherName | 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("byte remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> TODO()
">>" -> TODO()
"&" -> asmgen.out(" lda $name | and $otherName | sta $name")
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name")
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceModification_byte_litval_to_variable(name: String, operator: String, value: Double) {
when(operator) {
// note: ** (power) operator requires floats.
"+" -> asmgen.out(" lda $name | clc | adc #$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("byte remainder")
// if(types==DataType.BYTE)
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
// asmgen.out(" jsr prog8_lib.remainder_ub")
}
"<<" -> {
if(value>1) {
asmgen.out(" lda $name")
repeat(value.toInt()) { asmgen.out(" asl a") }
asmgen.out(" sta $name")
}
}
">>" -> {
if(value>1) {
asmgen.out(" lda $name")
repeat(value.toInt()) { asmgen.out(" lsr a") }
asmgen.out(" sta $name")
}
}
"&" -> asmgen.out(" lda $name | and #$value | sta $name")
"^" -> asmgen.out(" lda $name | xor #$value | sta $name")
"|" -> asmgen.out(" lda $name | ora #$value | sta $name")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
private fun inplaceCast(target: AssignTarget, cast: TypecastExpression, assign: Assignment) {
@ -87,7 +502,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when(dt) {
DataType.UBYTE -> {
when {
identifier!=null -> {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
asmgen.out("""
lda $name
@ -96,7 +511,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+ eor #1
sta $name""")
}
memory!=null -> {
memory != null -> {
when (memory.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toHex()
@ -113,7 +528,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lda $name
sta ${C64Zeropage.SCRATCH_W1}
lda $name+1
sta ${C64Zeropage.SCRATCH_W1+1}
sta ${C64Zeropage.SCRATCH_W1 + 1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y
beq +
@ -121,10 +536,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
+ eor #1
sta (${C64Zeropage.SCRATCH_W1}),y""")
}
else -> throw AssemblyError("weird address value")
else -> {
TODO("$memory")
}
}
}
arrayIdx!=null -> {
arrayIdx != null -> {
TODO("in-place not of ubyte array")
}
}
@ -159,14 +576,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when(dt) {
DataType.UBYTE -> {
when {
identifier!=null -> {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
asmgen.out("""
lda $name
eor #255
sta $name""")
}
memory!=null -> {
memory != null -> {
when (memory.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toHex()
@ -181,15 +598,18 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
lda $name
sta ${C64Zeropage.SCRATCH_W1}
lda $name+1
sta ${C64Zeropage.SCRATCH_W1+1}
sta ${C64Zeropage.SCRATCH_W1 + 1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y
eor #255
sta (${C64Zeropage.SCRATCH_W1}),y""")
}
else -> throw AssemblyError("weird address value")
} }
arrayIdx!=null -> {
else -> {
TODO("$memory")
}
}
}
arrayIdx != null -> {
TODO("in-place invert ubyte array")
}
}

View File

@ -7,22 +7,79 @@ main {
sub start() {
@($d020) += @($d020) ; TODO fix compiler hang
;ubyte @(addr)=0
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')
ubyte A
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = 33 + @(addr)
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
A = 44+A
@(addr) = 11
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
@(addr) = (@(addr) + 33) + B
c64scr.print_ub(@(addr))
c64.CHROUT('\n')
; ubyte A = 10
; @($c00a) = $4a
; @($c000+A) ++ ; TODO implement this
;
; c64scr.print_ubhex(@($c00a), true)
; c64.CHROUT('\n')
; @($c000+A) -- ; TODO implement this
;
; c64scr.print_ubhex(@($c00a), true)
; 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')
}
}