start with yet another codegen restructure, this time to make the assignment of values even more explicit for the codegen

This commit is contained in:
Irmen de Jong 2020-08-23 02:05:01 +02:00
parent 5075901830
commit d9e3895c45
4 changed files with 457 additions and 392 deletions

View File

@ -0,0 +1,122 @@
package prog8.compiler.target.c64.codegen
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment
import prog8.ast.statements.DirectMemoryWrite
import prog8.compiler.AssemblyError
enum class AsmTargetStorageType {
VARIABLE,
ARRAY,
MEMORY,
REGISTER,
STACK
}
enum class AsmSourceStorageType {
LITERALNUMBER,
VARIABLE,
ARRAY,
MEMORY,
REGISTER,
STACK, // value is already present on stack
EXPRESSION, // expression still to be evaluated
}
internal class AsmAssignTarget(val type: AsmTargetStorageType,
program: Program,
asmgen: AsmGen,
val datatype: DataType,
val astVariable: IdentifierReference?,
val astArray: ArrayIndexedExpression?,
val astMemory: DirectMemoryWrite?,
val register: RegisterOrPair?,
val origAstTarget: AssignTarget?, // TODO get rid of this eventually?
)
{
val constMemoryAddress by lazy { astMemory?.addressExpression?.constValue(program)?.number?.toInt() ?: 0}
val constArrayIndexValue by lazy { astArray?.arrayspec?.size() ?: 0 }
val vardecl by lazy { astVariable?.targetVarDecl(program.namespace)!! }
val asmName by lazy {
if(astVariable!=null)
asmgen.asmIdentifierName(astVariable)
else
asmgen.asmIdentifierName(astArray!!.identifier)
}
lateinit var origAssign: AsmAssignment
init {
if(astVariable!=null && vardecl.type == VarDeclType.CONST)
throw AssemblyError("can't assign to a constant")
if(register!=null && datatype !in IntegerDatatypes)
throw AssemblyError("register must be integer type")
}
companion object {
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget = with(assign.target) {
val dt = inferType(program, assign).typeOrElse(DataType.STRUCT)
when {
identifier != null -> AsmAssignTarget(AsmTargetStorageType.VARIABLE, program, asmgen, dt, identifier, null, null, null, this)
arrayindexed != null -> AsmAssignTarget(AsmTargetStorageType.ARRAY, program, asmgen, dt, null, arrayindexed, null, null, this)
memoryAddress != null -> AsmAssignTarget(AsmTargetStorageType.MEMORY, program, asmgen, dt, null, null, memoryAddress, null, this)
else -> throw AssemblyError("weird target")
}
}
}
}
internal class AsmAssignSource(val type: AsmSourceStorageType,
private val program: Program,
val astVariable: IdentifierReference? = null,
val astArray: ArrayIndexedExpression? = null,
val astMemory: DirectMemoryRead? = null,
val register: RegisterOrPair? = null,
val numLitval: NumericLiteralValue? = null,
val astExpression: Expression? = null
)
{
val constMemoryAddress by lazy { astMemory?.addressExpression?.constValue(program)?.number?.toInt() ?: 0}
val constArrayIndexValue by lazy { astArray?.arrayspec?.size() ?: 0 }
val vardecl by lazy { astVariable?.targetVarDecl(program.namespace)!! }
companion object {
fun fromAstSource(value: Expression, program: Program): AsmAssignSource {
val cv = value.constValue(program)
if(cv!=null)
return AsmAssignSource(AsmSourceStorageType.LITERALNUMBER, program, numLitval = cv)
return when(value) {
is NumericLiteralValue -> AsmAssignSource(AsmSourceStorageType.LITERALNUMBER, program, numLitval = cv)
is StringLiteralValue -> throw AssemblyError("string literal value should not occur anymore for asm generation")
is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation")
is IdentifierReference -> AsmAssignSource(AsmSourceStorageType.VARIABLE, program, astVariable = value)
is DirectMemoryRead -> AsmAssignSource(AsmSourceStorageType.MEMORY, program, astMemory = value)
is ArrayIndexedExpression -> AsmAssignSource(AsmSourceStorageType.ARRAY, program, astArray = value)
else -> AsmAssignSource(AsmSourceStorageType.EXPRESSION, program, astExpression = value)
}
}
}
fun getAstValue(): Expression = when(type) {
AsmSourceStorageType.LITERALNUMBER -> numLitval!!
AsmSourceStorageType.VARIABLE -> astVariable!!
AsmSourceStorageType.ARRAY -> astArray!!
AsmSourceStorageType.MEMORY -> astMemory!!
AsmSourceStorageType.EXPRESSION -> astExpression!!
AsmSourceStorageType.REGISTER -> TODO()
AsmSourceStorageType.STACK -> TODO()
}
}
internal class AsmAssignment(val source: AsmAssignSource,
val target: AsmAssignTarget,
val isAugmentable: Boolean,
val position: Position) {
}

View File

@ -11,39 +11,21 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.toHex
// TODO optimize the array indexes where the index is a constant
enum class AsmAssignTargetType {
VARIABLE,
ARRAY,
MEMORY,
REGISTER,
STACK
}
internal sealed class AsmAssignTarget(type: AsmAssignTargetType,
astVariable: IdentifierReference?,
astArray: ArrayIndexedExpression?,
astMemory: DirectMemoryWrite?,
register: RegisterOrPair?,
program: Program
)
{
val constMemoryAddress by lazy { astMemory?.addressExpression.constValue(program) }
val constArrayIndexValue by lazy { astArray?.arrayspec.index
init {
astMemory!!.addressExpression.
}
}
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen)
internal fun translate(assign: Assignment) {
internal fun translate(assignment: Assignment) {
val source = AsmAssignSource.fromAstSource(assignment.value, program)
val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen)
val assign = AsmAssignment(source, target, assignment.isAugmentable, assignment.position)
when {
assign.value is NumericLiteralValue -> translateConstantValueAssignment(assign)
assign.value is IdentifierReference -> translateVariableAssignment(assign)
source.type==AsmSourceStorageType.LITERALNUMBER -> translateConstantValueAssignment(assign)
source.type==AsmSourceStorageType.VARIABLE -> translateVariableAssignment(assign)
assign.isAugmentable -> augmentableAsmGen.translate(assign)
else -> translateOtherAssignment(assign)
}
@ -58,19 +40,19 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun translateVariableAssignment(assign: Assignment) {
val identifier = assign.value as IdentifierReference
when (val type = assign.target.inferType(program, assign).typeOrElse(DataType.STRUCT)) {
private fun translateVariableAssignment(assign: AsmAssignment) {
val identifier = assign.source.astVariable!!
when (assign.target.datatype) {
DataType.UBYTE, DataType.BYTE -> assignFromByteVariable(assign.target, identifier)
DataType.UWORD, DataType.WORD -> assignFromWordVariable(assign.target, identifier)
DataType.FLOAT -> assignFromFloatVariable(assign.target, identifier)
in PassByReferenceDatatypes -> assignFromAddressOf(assign.target, identifier)
else -> throw AssemblyError("unsupported assignment target type $type")
else -> throw AssemblyError("unsupported assignment target type ${assign.target.datatype}")
}
}
private fun translateConstantValueAssignment(assign: Assignment) {
val numVal = assign.value as NumericLiteralValue
private fun translateConstantValueAssignment(assign: AsmAssignment) {
val numVal = assign.source.numLitval!!
when (numVal.type) {
DataType.UBYTE, DataType.BYTE -> assignFromByteConstant(assign.target, numVal.number.toShort())
DataType.UWORD, DataType.WORD -> assignFromWordConstant(assign.target, numVal.number.toInt())
@ -79,44 +61,45 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
internal fun translateOtherAssignment(assign: Assignment) {
when (assign.value) {
internal fun translateOtherAssignment(assign: AsmAssignment) {
// source: expression, register, stack (only expression implemented for now)
// TODO use source type enum
val value=assign.source.getAstValue()
when (value) {
is AddressOf -> {
val identifier = (assign.value as AddressOf).identifier
assignFromAddressOf(assign.target, identifier)
assignFromAddressOf(assign.target, value.identifier)
}
is DirectMemoryRead -> {
val read = (assign.value as DirectMemoryRead)
when (read.addressExpression) {
when (value.addressExpression) {
is NumericLiteralValue -> {
val address = (read.addressExpression as NumericLiteralValue).number.toInt()
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
assignFromMemoryByte(assign.target, address, null)
}
is IdentifierReference -> {
assignFromMemoryByte(assign.target, null, read.addressExpression as IdentifierReference)
assignFromMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
}
else -> {
asmgen.translateExpression(read.addressExpression)
asmgen.translateExpression(value.addressExpression)
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | inx")
assignFromRegister(assign.target, CpuRegister.A)
}
}
}
is PrefixExpression -> {
asmgen.translateExpression(assign.value as PrefixExpression)
asmgen.translateExpression(value)
assignFromEvalResult(assign.target)
}
is BinaryExpression -> {
asmgen.translateExpression(assign.value as BinaryExpression)
asmgen.translateExpression(value)
assignFromEvalResult(assign.target)
}
is ArrayIndexedExpression -> {
val arrayExpr = assign.value as ArrayIndexedExpression
val arrayDt = arrayExpr.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val index = arrayExpr.arrayspec.index
val arrayDt = value.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val index = value.arrayspec.index
if (index is NumericLiteralValue) {
// constant array index value
val arrayVarName = asmgen.asmIdentifierName(arrayExpr.identifier)
val arrayVarName = asmgen.asmIdentifierName(value.identifier)
val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize()
when (arrayDt) {
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B ->
@ -129,83 +112,79 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
throw AssemblyError("weird array type")
}
} else {
asmgen.translateArrayIndexIntoA(arrayExpr)
asmgen.readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier)
asmgen.translateArrayIndexIntoA(value)
asmgen.readAndPushArrayvalueWithIndexA(arrayDt, value.identifier)
}
assignFromEvalResult(assign.target)
}
is TypecastExpression -> {
val cast = assign.value as TypecastExpression
val sourceType = cast.expression.inferType(program)
val sourceType = value.expression.inferType(program)
if (sourceType.isKnown &&
(sourceType.typeOrElse(DataType.STRUCT) in ByteDatatypes && cast.type in ByteDatatypes) ||
(sourceType.typeOrElse(DataType.STRUCT) in WordDatatypes && cast.type in WordDatatypes)) {
(sourceType.typeOrElse(DataType.STRUCT) in ByteDatatypes && value.type in ByteDatatypes) ||
(sourceType.typeOrElse(DataType.STRUCT) in WordDatatypes && value.type in WordDatatypes)) {
// no need for a type cast
assign.value = cast.expression
translate(assign)
TODO("no typecast $value")
// value = value.expression
// val newAssign = AsmAssignment(assign.source, assign.target, assign.isAugmentable, assign.position)
// translate(newAssign)
} else {
asmgen.translateExpression(assign.value as TypecastExpression)
asmgen.translateExpression(value)
assignFromEvalResult(assign.target)
}
}
is FunctionCall -> {
asmgen.translateExpression(assign.value as FunctionCall)
asmgen.translateExpression(value)
assignFromEvalResult(assign.target)
}
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign")
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}")
else -> throw AssemblyError("assignment value type ${assign.value} should have been handled elsewhere")
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${value.position}")
else -> throw AssemblyError("assignment value type $value should have been handled elsewhere")
}
}
private fun assignFromEvalResult(target: AssignTarget) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when (val targetDt = targetIdent.inferType(program).typeOrElse(DataType.STRUCT)) {
private fun assignFromEvalResult(target: AsmAssignTarget) {
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
when (target.datatype) {
DataType.UBYTE, DataType.BYTE -> {
asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta $targetName")
asmgen.out(" inx | lda $ESTACK_LO_HEX,x | sta ${target.asmName}")
}
DataType.UWORD, DataType.WORD -> {
asmgen.out("""
inx
lda $ESTACK_LO_HEX,x
sta $targetName
sta ${target.asmName}
lda $ESTACK_HI_HEX,x
sta $targetName+1
sta ${target.asmName}+1
""")
}
DataType.FLOAT -> {
asmgen.out("""
lda #<$targetName
ldy #>$targetName
lda #<${target.asmName}
ldy #>${target.asmName}
jsr c64flt.pop_float
""")
}
else -> throw AssemblyError("weird target variable type $targetDt")
else -> throw AssemblyError("weird target variable type ${target.datatype}")
}
}
targetMemory != null -> {
AsmTargetStorageType.MEMORY -> {
asmgen.out(" inx")
storeByteViaRegisterAInMemoryAddress("$ESTACK_LO_HEX,x", targetMemory)
storeByteViaRegisterAInMemoryAddress("$ESTACK_LO_HEX,x", target.astMemory!!)
}
targetArrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
val targetArrayIdx = target.astArray!!
val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT)
val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
asmgen.translateExpression(targetArrayIdx.arrayspec.index)
asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
popAndWriteArrayvalueWithIndexA(arrayDt, arrayVarName)
popAndWriteArrayvalueWithIndexA(arrayDt, target.asmName)
}
else -> throw AssemblyError("weird assignment target $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun assignFromAddressOf(target: AssignTarget, name: IdentifierReference) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
private fun assignFromAddressOf(target: AsmAssignTarget, name: IdentifierReference) {
val struct = name.memberOfStruct(program.namespace)
val sourceName = if (struct != null) {
// take the address of the first struct member instead
@ -219,81 +198,76 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
asmgen.fixNameSymbols(name.nameInSource.joinToString("."))
}
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda #<$sourceName
ldy #>$sourceName
sta $targetName
sty $targetName+1
sta ${target.asmName}
sty ${target.asmName}+1
""")
}
target.memoryAddress != null -> {
AsmTargetStorageType.MEMORY -> {
throw AssemblyError("no asm gen for assign address $sourceName to memory word $target")
}
targetArrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
val targetArrayIdx = target.astArray!!
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
throw AssemblyError("no asm gen for assign address $sourceName to array $targetName [ $index ]")
throw AssemblyError("no asm gen for assign address $sourceName to array ${target.asmName} [ $index ]")
}
else -> throw AssemblyError("no asm gen for assign address $sourceName to $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun assignFromWordVariable(target: AssignTarget, variable: IdentifierReference) {
private fun assignFromWordVariable(target: AsmAssignTarget, variable: IdentifierReference) {
val sourceName = asmgen.asmIdentifierName(variable)
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $sourceName
ldy $sourceName+1
sta $targetName
sty $targetName+1
sta ${target.asmName}
sty ${target.asmName}+1
""")
}
target.memoryAddress != null -> {
throw AssemblyError("no asm gen for assign wordvar $sourceName to memory ${target.memoryAddress}")
AsmTargetStorageType.MEMORY -> {
throw AssemblyError("no asm gen for assign wordvar $sourceName to memory ${target.astMemory}")
}
targetArrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
val targetArrayIdx = target.astArray!!
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
asmgen.out(" lda $sourceName | sta $ESTACK_LO_HEX,x | lda $sourceName+1 | sta $ESTACK_HI_HEX,x | dex")
asmgen.translateExpression(index)
asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT)
popAndWriteArrayvalueWithIndexA(arrayDt, targetName)
popAndWriteArrayvalueWithIndexA(arrayDt, target.asmName)
}
else -> throw AssemblyError("no asm gen for assign wordvar to $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun assignFromFloatVariable(target: AssignTarget, variable: IdentifierReference) {
private fun assignFromFloatVariable(target: AsmAssignTarget, variable: IdentifierReference) {
val sourceName = asmgen.asmIdentifierName(variable)
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $sourceName
sta $targetName
sta ${target.asmName}
lda $sourceName+1
sta $targetName+1
sta ${target.asmName}+1
lda $sourceName+2
sta $targetName+2
sta ${target.asmName}+2
lda $sourceName+3
sta $targetName+3
sta ${target.asmName}+3
lda $sourceName+4
sta $targetName+4
sta ${target.asmName}+4
""")
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val targetName = asmgen.asmIdentifierName(target.astArray.identifier)
asmgen.out(" lda #<$sourceName | ldy #>$sourceName | jsr c64flt.push_float")
asmgen.translateExpression(index)
asmgen.out(" lda #<$targetName | ldy #>$targetName | jsr c64flt.pop_float_to_indexed_var")
@ -302,56 +276,50 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignFromByteVariable(target: AssignTarget, variable: IdentifierReference) {
private fun assignFromByteVariable(target: AsmAssignTarget, variable: IdentifierReference) {
val sourceName = asmgen.asmIdentifierName(variable)
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $sourceName
sta $targetName
sta ${target.asmName}
""")
}
targetMemory != null -> {
storeByteViaRegisterAInMemoryAddress(sourceName, targetMemory)
AsmTargetStorageType.MEMORY -> {
storeByteViaRegisterAInMemoryAddress(sourceName, target.astMemory!!)
}
targetArrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
val targetArrayIdx = target.astArray!!
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
val arrayDt = targetArrayIdx.identifier.inferType(program).typeOrElse(DataType.STRUCT)
asmgen.out(" lda $sourceName | sta $ESTACK_LO_HEX,x | dex")
asmgen.translateExpression(index)
asmgen.out(" inx | lda $ESTACK_LO_HEX,x")
popAndWriteArrayvalueWithIndexA(arrayDt, targetName)
popAndWriteArrayvalueWithIndexA(arrayDt, target.asmName)
}
else -> throw AssemblyError("no asm gen for assign bytevar to $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun assignFromRegister(target: AssignTarget, register: CpuRegister) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
asmgen.out(" st${register.name.toLowerCase()} $targetName")
private fun assignFromRegister(target: AsmAssignTarget, register: CpuRegister) {
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out(" st${register.name.toLowerCase()} ${target.asmName}")
}
target.memoryAddress != null -> {
storeRegisterInMemoryAddress(register, target.memoryAddress)
AsmTargetStorageType.MEMORY -> {
storeRegisterInMemoryAddress(register, target.astMemory!!)
}
targetArrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
val targetArrayIdx = target.astArray!!
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
when (index) {
is NumericLiteralValue -> {
val memindex = index.number.toInt()
when (register) {
CpuRegister.A -> asmgen.out(" sta $targetName+$memindex")
CpuRegister.X -> asmgen.out(" stx $targetName+$memindex")
CpuRegister.Y -> asmgen.out(" sty $targetName+$memindex")
CpuRegister.A -> asmgen.out(" sta ${target.asmName}+$memindex")
CpuRegister.X -> asmgen.out(" stx ${target.asmName}+$memindex")
CpuRegister.Y -> asmgen.out(" sty ${target.asmName}+$memindex")
}
}
is IdentifierReference -> {
@ -364,7 +332,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
lda ${asmgen.asmIdentifierName(index)}
tay
lda ${C64Zeropage.SCRATCH_B1}
sta $targetName,y
sta ${target.asmName},y
""")
}
else -> {
@ -381,12 +349,13 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
lda $ESTACK_LO_HEX,x
tay
lda ${C64Zeropage.SCRATCH_B1}
sta $targetName,y
sta ${target.asmName},y
""")
}
}
}
else -> throw AssemblyError("no asm gen for assign register $register to $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
@ -463,34 +432,31 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignFromWordConstant(target: AssignTarget, word: Int) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
private fun assignFromWordConstant(target: AsmAssignTarget, word: Int) {
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
if (word ushr 8 == word and 255) {
// lsb=msb
asmgen.out("""
lda #${(word and 255).toHex()}
sta $targetName
sta $targetName+1
sta ${target.asmName}
sta ${target.asmName}+1
""")
} else {
asmgen.out("""
lda #<${word.toHex()}
ldy #>${word.toHex()}
sta $targetName
sty $targetName+1
sta ${target.asmName}
sty ${target.asmName}+1
""")
}
}
target.memoryAddress != null -> {
throw AssemblyError("no asm gen for assign word $word to memory ${target.memoryAddress}")
AsmTargetStorageType.MEMORY -> {
throw AssemblyError("no asm gen for assign word $word to memory ${target.astMemory}")
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val targetName = asmgen.asmIdentifierName(target.astArray.identifier)
asmgen.translateExpression(index)
asmgen.out("""
inx
@ -503,25 +469,22 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
sta $targetName+1,y
""")
}
else -> throw AssemblyError("no asm gen for assign word $word to $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun assignFromByteConstant(target: AssignTarget, byte: Short) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
asmgen.out(" lda #${byte.toHex()} | sta $targetName ")
private fun assignFromByteConstant(target: AsmAssignTarget, byte: Short) {
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmName} ")
}
targetMemory != null -> {
storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", targetMemory)
AsmTargetStorageType.MEMORY -> {
storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", target.astMemory!!)
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val targetName = asmgen.asmIdentifierName(target.astArray.identifier)
asmgen.translateExpression(index)
asmgen.out("""
inx
@ -534,42 +497,38 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignFromFloatConstant(target: AssignTarget, float: Double) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
private fun assignFromFloatConstant(target: AsmAssignTarget, float: Double) {
if (float == 0.0) {
// optimized case for float zero
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda #0
sta $targetName
sta $targetName+1
sta $targetName+2
sta $targetName+3
sta $targetName+4
sta ${target.asmName}
sta ${target.asmName}+1
sta ${target.asmName}+2
sta ${target.asmName}+3
sta ${target.asmName}+4
""")
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
if (index is NumericLiteralValue) {
val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE
asmgen.out("""
lda #0
sta $targetName+$indexValue
sta $targetName+$indexValue+1
sta $targetName+$indexValue+2
sta $targetName+$indexValue+3
sta $targetName+$indexValue+4
sta ${target.asmName}+$indexValue
sta ${target.asmName}+$indexValue+1
sta ${target.asmName}+$indexValue+2
sta ${target.asmName}+$indexValue+3
sta ${target.asmName}+$indexValue+4
""")
} else {
asmgen.translateExpression(index)
asmgen.out("""
lda #<${targetName}
lda #<${target.asmName}
sta ${C64Zeropage.SCRATCH_W1}
lda #>${targetName}
lda #>${target.asmName}
sta ${C64Zeropage.SCRATCH_W1 + 1}
jsr c64flt.set_0_array_float
""")
@ -580,25 +539,24 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
} else {
// non-zero value
val constFloat = asmgen.getFloatConst(float)
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $constFloat
sta $targetName
sta ${target.asmName}
lda $constFloat+1
sta $targetName+1
sta ${target.asmName}+1
lda $constFloat+2
sta $targetName+2
sta ${target.asmName}+2
lda $constFloat+3
sta $targetName+3
sta ${target.asmName}+3
lda $constFloat+4
sta $targetName+4
sta ${target.asmName}+4
""")
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val arrayVarName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val arrayVarName = asmgen.asmIdentifierName(target.astArray.identifier)
if (index is NumericLiteralValue) {
val indexValue = index.number.toInt() * C64MachineDefinition.FLOAT_MEM_SIZE
asmgen.out("""
@ -633,34 +591,30 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
}
private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed
val targetMemory = target.memoryAddress
private fun assignFromMemoryByte(target: AsmAssignTarget, address: Int?, identifier: IdentifierReference?) {
if (address != null) {
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda ${address.toHex()}
sta $targetName
sta ${target.asmName}
""")
}
targetMemory != null -> {
storeByteViaRegisterAInMemoryAddress(address.toHex(), targetMemory)
AsmTargetStorageType.MEMORY -> {
storeByteViaRegisterAInMemoryAddress(address.toHex(), target.astMemory!!)
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val targetName = asmgen.asmIdentifierName(target.astArray.identifier)
throw AssemblyError("no asm gen for assign memory byte at $address to array $targetName [ $index ]")
}
else -> throw AssemblyError("no asm gen for assign memory byte $target")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
} else if (identifier != null) {
val sourceName = asmgen.asmIdentifierName(identifier)
when {
targetIdent != null -> {
val targetName = asmgen.asmIdentifierName(targetIdent)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $sourceName
sta ${C64Zeropage.SCRATCH_W1}
@ -668,14 +622,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
sta ${C64Zeropage.SCRATCH_W1+1}
ldy #0
lda (${C64Zeropage.SCRATCH_W1}),y
sta $targetName""")
sta ${target.asmName}""")
}
targetMemory != null -> {
storeByteViaRegisterAInMemoryAddress(sourceName, targetMemory)
AsmTargetStorageType.MEMORY -> {
storeByteViaRegisterAInMemoryAddress(sourceName, target.astMemory!!)
}
targetArrayIdx != null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmgen.asmIdentifierName(targetArrayIdx.identifier)
AsmTargetStorageType.ARRAY -> {
val index = target.astArray!!.arrayspec.index
val targetName = asmgen.asmIdentifierName(target.astArray.identifier)
throw AssemblyError("no asm gen for assign memory byte $sourceName to array $targetName [ $index ]")
}
else -> throw AssemblyError("no asm gen for assign memory byte $target")

View File

@ -3,8 +3,6 @@ package prog8.compiler.target.c64.codegen
import prog8.ast.Program
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
@ -14,15 +12,16 @@ import prog8.compiler.toHex
internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen) {
fun translate(assign: Assignment) {
fun translate(assign: AsmAssignment) {
require(assign.isAugmentable)
require(assign.source.type==AsmSourceStorageType.EXPRESSION)
when (assign.value) {
val value = assign.source.astExpression!!
when (value) {
is PrefixExpression -> {
// A = -A , A = +A, A = ~A, A = not A
val px = assign.value as PrefixExpression
val type = px.inferType(program).typeOrElse(DataType.STRUCT)
when (px.operator) {
val type = value.inferType(program).typeOrElse(DataType.STRUCT)
when (value.operator) {
"+" -> {
}
"-" -> inplaceNegate(assign.target, type)
@ -31,44 +30,45 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else -> throw AssemblyError("invalid prefix operator")
}
}
is TypecastExpression -> inplaceCast(assign.target, assign.value as TypecastExpression, assign)
is BinaryExpression -> inplaceBinary(assign.target, assign.value as BinaryExpression, assign)
is TypecastExpression -> inplaceCast(assign.target, value, assign.position)
is BinaryExpression -> inplaceBinary(assign.target, value)
else -> throw AssemblyError("invalid aug assign value type")
}
}
private fun inplaceBinary(target: AssignTarget, binExpr: BinaryExpression, assign: Assignment) {
if (binExpr.left isSameAs target) {
private fun inplaceBinary(target: AsmAssignTarget, binExpr: BinaryExpression) {
val astTarget = target.origAstTarget!!
if (binExpr.left isSameAs astTarget) {
// A = A <operator> Something
return inplaceModification(target, binExpr.operator, binExpr.right, assign)
return inplaceModification(target, binExpr.operator, binExpr.right)
}
if (binExpr.operator in associativeOperators) {
if (binExpr.right isSameAs target) {
if (binExpr.right isSameAs astTarget) {
// A = 5 <operator> A
return inplaceModification(target, binExpr.operator, binExpr.left, assign)
return inplaceModification(target, binExpr.operator, binExpr.left)
}
val leftBinExpr = binExpr.left as? BinaryExpression
if (leftBinExpr?.operator == binExpr.operator) {
// TODO better optimize the chained asm to avoid intermediate stores/loads?
when {
binExpr.right isSameAs target -> {
binExpr.right isSameAs astTarget -> {
// A = (x <associative-operator> y) <same-operator> A
inplaceModification(target, binExpr.operator, leftBinExpr.left, assign)
inplaceModification(target, binExpr.operator, leftBinExpr.right, assign)
inplaceModification(target, binExpr.operator, leftBinExpr.left)
inplaceModification(target, binExpr.operator, leftBinExpr.right)
return
}
leftBinExpr.left isSameAs target -> {
leftBinExpr.left isSameAs astTarget -> {
// A = (A <associative-operator> x) <same-operator> y
inplaceModification(target, binExpr.operator, leftBinExpr.right, assign)
inplaceModification(target, binExpr.operator, binExpr.right, assign)
inplaceModification(target, binExpr.operator, leftBinExpr.right)
inplaceModification(target, binExpr.operator, binExpr.right)
return
}
leftBinExpr.right isSameAs target -> {
leftBinExpr.right isSameAs astTarget -> {
// A = (x <associative-operator> A) <same-operator> y
inplaceModification(target, binExpr.operator, leftBinExpr.left, assign)
inplaceModification(target, binExpr.operator, binExpr.right, assign)
inplaceModification(target, binExpr.operator, leftBinExpr.left)
inplaceModification(target, binExpr.operator, binExpr.right)
return
}
}
@ -76,59 +76,54 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
val rightBinExpr = binExpr.right as? BinaryExpression
if (rightBinExpr?.operator == binExpr.operator) {
when {
binExpr.left isSameAs target -> {
binExpr.left isSameAs astTarget -> {
// A = A <associative-operator> (x <same-operator> y)
inplaceModification(target, binExpr.operator, rightBinExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.right, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.left)
inplaceModification(target, binExpr.operator, rightBinExpr.right)
return
}
rightBinExpr.left isSameAs target -> {
rightBinExpr.left isSameAs astTarget -> {
// A = y <associative-operator> (A <same-operator> x)
inplaceModification(target, binExpr.operator, binExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.right, assign)
inplaceModification(target, binExpr.operator, binExpr.left)
inplaceModification(target, binExpr.operator, rightBinExpr.right)
return
}
rightBinExpr.right isSameAs target -> {
rightBinExpr.right isSameAs astTarget -> {
// A = y <associative-operator> (x <same-operator> y)
inplaceModification(target, binExpr.operator, binExpr.left, assign)
inplaceModification(target, binExpr.operator, rightBinExpr.left, assign)
inplaceModification(target, binExpr.operator, binExpr.left)
inplaceModification(target, binExpr.operator, rightBinExpr.left)
return
}
}
}
}
throw FatalAstException("assignment should be augmentable $assign\nleft=${binExpr.left}\nright=${binExpr.right}")
throw FatalAstException("assignment should be augmentable $binExpr")
}
private fun inplaceModification(target: AssignTarget, operator: String, value: Expression, origAssign: Assignment) {
val arrayIdx = target.arrayindexed
val identifier = target.identifier
val memory = target.memoryAddress
private fun inplaceModification(target: AsmAssignTarget, operator: String, value: Expression) {
val valueLv = (value as? NumericLiteralValue)?.number
val ident = value as? IdentifierReference
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
val dt = identifier.inferType(program).typeOrElse(DataType.STRUCT)
when (dt) {
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
when (target.datatype) {
in ByteDatatypes -> {
when {
valueLv != null -> inplaceModification_byte_litval_to_variable(name, dt, operator, valueLv.toInt())
ident != null -> inplaceModification_byte_variable_to_variable(name, dt, operator, ident)
valueLv != null -> inplaceModification_byte_litval_to_variable(target.asmName, target.datatype, operator, valueLv.toInt())
ident != null -> inplaceModification_byte_variable_to_variable(target.asmName, target.datatype, operator, ident)
// TODO more specialized code for types such as memory read etc.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
inplaceModification_byte_value_to_variable(name, dt, operator, value)
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_byte_value_to_variable(target.asmName, target.datatype, operator, value)
}
else -> inplaceModification_byte_value_to_variable(name, dt, operator, value)
else -> inplaceModification_byte_value_to_variable(target.asmName, target.datatype, operator, value)
}
}
in WordDatatypes -> {
when {
valueLv != null -> inplaceModification_word_litval_to_variable(name, dt, operator, valueLv.toInt())
ident != null -> inplaceModification_word_variable_to_variable(name, dt, operator, ident)
valueLv != null -> inplaceModification_word_litval_to_variable(target.asmName, target.datatype, operator, valueLv.toInt())
ident != null -> inplaceModification_word_variable_to_variable(target.asmName, target.datatype, operator, ident)
// TODO more specialized code for types such as memory read etc.
// value is DirectMemoryRead -> {
// println("warning: slow stack evaluation used (8): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
@ -143,28 +138,29 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// // TODO
// }
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
inplaceModification_word_value_to_variable(name, dt, operator, value)
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_word_value_to_variable(target.asmName, target.datatype, operator, value)
}
else -> inplaceModification_word_value_to_variable(name, dt, operator, value)
else -> inplaceModification_word_value_to_variable(target.asmName, target.datatype, operator, value)
}
}
DataType.FLOAT -> {
when {
valueLv != null -> inplaceModification_float_litval_to_variable(name, operator, valueLv.toDouble())
ident != null -> inplaceModification_float_variable_to_variable(name, operator, ident)
valueLv != null -> inplaceModification_float_litval_to_variable(target.asmName, operator, valueLv.toDouble())
ident != null -> inplaceModification_float_variable_to_variable(target.asmName, operator, ident)
// TODO more specialized code for types such as memory read etc.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
inplaceModification_float_value_to_variable(name, operator, value)
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_float_value_to_variable(target.asmName, operator, value)
}
else -> inplaceModification_float_value_to_variable(name, operator, value)
else -> inplaceModification_float_value_to_variable(target.asmName, operator, value)
}
}
else -> throw AssemblyError("weird type to do in-place modification on $dt")
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
}
}
memory != null -> {
AsmTargetStorageType.MEMORY -> {
val memory = target.astMemory!!
when (memory.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toInt()
@ -174,7 +170,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
ident != null -> inplaceModification_byte_variable_to_variable(addr.toHex(), DataType.UBYTE, operator, ident)
// TODO more specialized code for types such as memory read etc.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value)
}
else -> inplaceModification_byte_value_to_variable(addr.toHex(), DataType.UBYTE, operator, value)
@ -187,7 +183,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
ident != null -> inplaceModification_byte_variable_to_memory(name, operator, ident)
// TODO more specialized code for types such as memory read etc.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_byte_value_to_memory(name, operator, value)
}
else -> inplaceModification_byte_value_to_memory(name, operator, value)
@ -203,7 +199,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
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.
value is TypecastExpression -> {
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
if (tryRemoveRedundantCast(value, target, operator)) return
inplaceModification_byte_value_to_variable(C64Zeropage.SCRATCH_B1.toHex(), DataType.UBYTE, operator, value)
}
else -> inplaceModification_byte_value_to_variable(C64Zeropage.SCRATCH_B1.toHex(), DataType.UBYTE, operator, value)
@ -212,20 +208,21 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
}
arrayIdx != null -> {
println("*** TODO optimize simple inplace array assignment $arrayIdx $operator= $value")
assignmentAsmGen.translateOtherAssignment(origAssign) // TODO get rid of this fallback for the most common cases here
AsmTargetStorageType.ARRAY -> {
println("*** TODO optimize simple inplace array assignment ${target.astArray} $operator= $value")
assignmentAsmGen.translateOtherAssignment(target.origAssign) // TODO get rid of this fallback for the most common cases here
}
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
private fun tryRemoveRedundantCast(value: TypecastExpression, target: AssignTarget, operator: String, origAssign: Assignment): Boolean {
val targetDt = target.inferType(program, origAssign).typeOrElse(DataType.STRUCT)
if (targetDt == value.type) {
private fun tryRemoveRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean {
if (target.datatype == value.type) {
val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT)
if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) {
// this typecast is redundant here; the rest of the code knows how to deal with the uncasted value.
inplaceModification(target, operator, value.expression, origAssign)
inplaceModification(target, operator, value.expression)
return true
}
}
@ -1009,22 +1006,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
private fun inplaceCast(target: AssignTarget, cast: TypecastExpression, assign: Assignment) {
val targetDt = target.inferType(program, assign).typeOrElse(DataType.STRUCT)
private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) {
val outerCastDt = cast.type
val innerCastDt = (cast.expression as? TypecastExpression)?.type
if (innerCastDt == null) {
// simple typecast where the value is the target
when (targetDt) {
when (target.datatype) {
DataType.UBYTE, DataType.BYTE -> { /* byte target can't be casted to anything else at all */
}
DataType.UWORD, DataType.WORD -> {
when (outerCastDt) {
DataType.UBYTE, DataType.BYTE -> {
if (target.identifier != null) {
val name = asmgen.asmIdentifierName(target.identifier!!)
asmgen.out(" lda #0 | sta $name+1")
if(target.type==AsmTargetStorageType.VARIABLE) {
asmgen.out(" lda #0 | sta ${target.asmName}+1")
} else
throw AssemblyError("weird value")
}
@ -1045,32 +1040,28 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// calculate singular cast that is required
val castDt = if (outerCastDt largerThan innerCastDt) innerCastDt else outerCastDt
val value = (cast.expression as TypecastExpression).expression
val resultingCast = TypecastExpression(value, castDt, false, assign.position)
inplaceCast(target, resultingCast, assign)
val resultingCast = TypecastExpression(value, castDt, false, position)
inplaceCast(target, resultingCast, position)
}
}
private fun inplaceBooleanNot(target: AssignTarget, dt: DataType) {
val arrayIdx = target.arrayindexed
val identifier = target.identifier
val memory = target.memoryAddress
private fun inplaceBooleanNot(target: AsmAssignTarget, dt: DataType) {
when (dt) {
DataType.UBYTE -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $name
lda ${target.asmName}
beq +
lda #1
+ eor #1
sta $name""")
sta ${target.asmName}""")
}
memory != null -> {
when (memory.addressExpression) {
AsmTargetStorageType.MEMORY-> {
val mem = target.astMemory!!
when (mem.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toHex()
val addr = (mem.addressExpression as NumericLiteralValue).number.toHex()
asmgen.out("""
lda $addr
beq +
@ -1079,7 +1070,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sta $addr""")
}
is IdentifierReference -> {
val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference)
val name = asmgen.asmIdentifierName(mem.addressExpression as IdentifierReference)
asmgen.out("""
lda $name
sta ${C64Zeropage.SCRATCH_W1}
@ -1093,8 +1084,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
sta (${C64Zeropage.SCRATCH_W1}),y""")
}
else -> {
println("warning: slow stack evaluation used (6): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO
asmgen.translateExpression(memory.addressExpression)
println("warning: slow stack evaluation used (6): ${mem.addressExpression::class.simpleName} at ${mem.addressExpression.position}") // TODO
asmgen.translateExpression(mem.addressExpression)
asmgen.out("""
jsr prog8_lib.read_byte_from_address_on_stack
beq +
@ -1105,49 +1096,48 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
}
arrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
TODO("in-place not of ubyte array")
}
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
DataType.UWORD -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $name
ora $name+1
lda ${target.asmName}
ora ${target.asmName}+1
beq +
lda #1
+ eor #1
sta $name
sta ${target.asmName}
lsr a
sta $name+1""")
sta ${target.asmName}+1""")
}
arrayIdx != null -> TODO("in-place not of uword array")
memory != null -> throw AssemblyError("no asm gen for uword-memory not")
AsmTargetStorageType.MEMORY -> throw AssemblyError("no asm gen for uword-memory not")
AsmTargetStorageType.ARRAY -> TODO("in-place not of uword array")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
else -> throw AssemblyError("boolean-not of invalid type")
}
}
private fun inplaceInvert(target: AssignTarget, dt: DataType) {
val arrayIdx = target.arrayindexed
val identifier = target.identifier
val memory = target.memoryAddress
private fun inplaceInvert(target: AsmAssignTarget, dt: DataType) {
when (dt) {
DataType.UBYTE -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $name
lda ${target.asmName}
eor #255
sta $name""")
sta ${target.asmName}""")
}
memory != null -> {
AsmTargetStorageType.MEMORY -> {
val memory = target.astMemory!!
when (memory.addressExpression) {
is NumericLiteralValue -> {
val addr = (memory.addressExpression as NumericLiteralValue).number.toHex()
@ -1179,86 +1169,88 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
}
}
arrayIdx != null -> {
AsmTargetStorageType.ARRAY -> {
TODO("in-place invert ubyte array")
}
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
DataType.UWORD -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda $name
lda ${target.asmName}
eor #255
sta $name
lda $name+1
sta ${target.asmName}
lda ${target.asmName}+1
eor #255
sta $name+1""")
sta ${target.asmName}+1""")
}
arrayIdx != null -> TODO("in-place invert uword array")
memory != null -> throw AssemblyError("no asm gen for uword-memory invert")
AsmTargetStorageType.MEMORY -> throw AssemblyError("no asm gen for uword-memory invert")
AsmTargetStorageType.ARRAY -> TODO("in-place invert uword array")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
else -> throw AssemblyError("invert of invalid type")
}
}
private fun inplaceNegate(target: AssignTarget, dt: DataType) {
val arrayIdx = target.arrayindexed
val identifier = target.identifier
val memory = target.memoryAddress
private fun inplaceNegate(target: AsmAssignTarget, dt: DataType) {
when (dt) {
DataType.BYTE -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when (target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda #0
sec
sbc $name
sta $name""")
sbc ${target.asmName}
sta ${target.asmName}""")
}
memory != null -> throw AssemblyError("can't in-place negate memory ubyte")
arrayIdx != null -> TODO("in-place negate byte array")
AsmTargetStorageType.MEMORY -> throw AssemblyError("can't in-place negate memory ubyte")
AsmTargetStorageType.ARRAY -> TODO("in-place negate byte array")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
DataType.WORD -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
lda #0
sec
sbc $name
sta $name
sbc ${target.asmName}
sta ${target.asmName}
lda #0
sbc $name+1
sta $name+1""")
sbc ${target.asmName}+1
sta ${target.asmName}+1""")
}
arrayIdx != null -> TODO("in-place negate word array")
memory != null -> throw AssemblyError("no asm gen for word memory negate")
AsmTargetStorageType.ARRAY -> TODO("in-place negate word array")
AsmTargetStorageType.MEMORY -> throw AssemblyError("no asm gen for word memory negate")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
DataType.FLOAT -> {
when {
identifier != null -> {
val name = asmgen.asmIdentifierName(identifier)
when(target.type) {
AsmTargetStorageType.VARIABLE -> {
asmgen.out("""
stx ${C64Zeropage.SCRATCH_REG_X}
lda #<$name
ldy #>$name
lda #<${target.asmName}
ldy #>${target.asmName}
jsr c64flt.MOVFM
jsr c64flt.NEGOP
ldx #<$name
ldy #>$name
ldx #<${target.asmName}
ldy #>${target.asmName}
jsr c64flt.MOVMF
ldx ${C64Zeropage.SCRATCH_REG_X}
""")
}
arrayIdx != null -> TODO("in-place negate float array")
memory != null -> throw AssemblyError("no asm gen for float memory negate")
AsmTargetStorageType.ARRAY -> TODO("in-place negate float array")
AsmTargetStorageType.MEMORY -> throw AssemblyError("no asm gen for float memory negate")
AsmTargetStorageType.REGISTER -> TODO()
AsmTargetStorageType.STACK -> TODO()
}
}
else -> throw AssemblyError("negate of invalid type")

View File

@ -11,9 +11,6 @@ main {
ubyte[] array=[1,2,3]
str string = "hello"
string = 3
array = 5
foo = $c100
c64scr.print_uwhex(foo, 1)
foo[100]=10