2022-01-27 23:32:09 +00:00
|
|
|
package prog8.codegen.cpu6502.assignment
|
2019-08-16 20:49:29 +00:00
|
|
|
|
|
|
|
import prog8.ast.Program
|
|
|
|
import prog8.ast.expressions.*
|
2020-08-20 13:18:24 +00:00
|
|
|
import prog8.ast.statements.*
|
2022-03-10 21:38:16 +00:00
|
|
|
import prog8.code.core.*
|
2022-02-06 21:56:17 +00:00
|
|
|
import prog8.codegen.cpu6502.AsmGen
|
2022-02-08 20:38:27 +00:00
|
|
|
import prog8.codegen.cpu6502.VariableAllocator
|
2022-03-11 19:35:25 +00:00
|
|
|
import prog8.compiler.builtinFunctionReturnType
|
2019-10-26 21:27:27 +00:00
|
|
|
|
2020-08-22 21:39:27 +00:00
|
|
|
|
2022-02-08 20:38:27 +00:00
|
|
|
internal class AssignmentAsmGen(private val program: Program,
|
|
|
|
private val asmgen: AsmGen,
|
|
|
|
private val allocator: VariableAllocator) {
|
|
|
|
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
|
2020-08-20 16:07:48 +00:00
|
|
|
|
2020-08-23 14:08:31 +00:00
|
|
|
fun translate(assignment: Assignment) {
|
2020-08-23 00:05:01 +00:00
|
|
|
val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen)
|
2021-10-31 01:34:17 +00:00
|
|
|
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
|
2020-08-23 10:52:27 +00:00
|
|
|
|
2021-02-19 18:02:29 +00:00
|
|
|
val assign = AsmAssignment(source, target, assignment.isAugmentable, program.memsizer, assignment.position)
|
2020-08-23 16:20:57 +00:00
|
|
|
target.origAssign = assign
|
2020-08-23 11:31:14 +00:00
|
|
|
|
2020-08-23 14:08:31 +00:00
|
|
|
if(assign.isAugmentable)
|
|
|
|
augmentableAsmGen.translate(assign)
|
|
|
|
else
|
|
|
|
translateNormalAssignment(assign)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun translateNormalAssignment(assign: AsmAssignment) {
|
2021-11-06 13:47:11 +00:00
|
|
|
if(assign.isAugmentable) {
|
|
|
|
augmentableAsmGen.translate(assign)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-23 14:08:31 +00:00
|
|
|
when(assign.source.kind) {
|
|
|
|
SourceStorageKind.LITERALNUMBER -> {
|
2020-08-23 12:36:24 +00:00
|
|
|
// simple case: assign a constant number
|
|
|
|
val num = assign.source.number!!.number
|
2020-10-10 23:35:38 +00:00
|
|
|
when (assign.target.datatype) {
|
2021-11-20 23:48:23 +00:00
|
|
|
DataType.UBYTE, DataType.BYTE -> assignConstantByte(assign.target, num.toInt())
|
2020-08-23 12:36:24 +00:00
|
|
|
DataType.UWORD, DataType.WORD -> assignConstantWord(assign.target, num.toInt())
|
2021-11-16 22:52:30 +00:00
|
|
|
DataType.FLOAT -> assignConstantFloat(assign.target, num)
|
2020-08-23 12:36:24 +00:00
|
|
|
else -> throw AssemblyError("weird numval type")
|
|
|
|
}
|
|
|
|
}
|
2020-08-23 14:08:31 +00:00
|
|
|
SourceStorageKind.VARIABLE -> {
|
2020-08-23 12:36:24 +00:00
|
|
|
// simple case: assign from another variable
|
2020-10-15 21:36:03 +00:00
|
|
|
val variable = assign.source.asmVarname
|
2020-10-10 23:35:38 +00:00
|
|
|
when (assign.target.datatype) {
|
2020-08-23 12:36:24 +00:00
|
|
|
DataType.UBYTE, DataType.BYTE -> assignVariableByte(assign.target, variable)
|
2020-11-09 23:35:24 +00:00
|
|
|
DataType.WORD -> assignVariableWord(assign.target, variable)
|
|
|
|
DataType.UWORD -> {
|
|
|
|
if(assign.source.datatype in PassByReferenceDatatypes)
|
|
|
|
assignAddressOf(assign.target, variable)
|
|
|
|
else
|
|
|
|
assignVariableWord(assign.target, variable)
|
|
|
|
}
|
2020-08-23 12:36:24 +00:00
|
|
|
DataType.FLOAT -> assignVariableFloat(assign.target, variable)
|
2020-10-04 16:18:58 +00:00
|
|
|
DataType.STR -> assignVariableString(assign.target, variable)
|
2020-08-23 12:36:24 +00:00
|
|
|
else -> throw AssemblyError("unsupported assignment target type ${assign.target.datatype}")
|
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
SourceStorageKind.ARRAY -> {
|
|
|
|
val value = assign.source.array!!
|
2020-08-23 12:36:24 +00:00
|
|
|
val elementDt = assign.source.datatype
|
2020-10-17 14:00:49 +00:00
|
|
|
val arrayVarName = asmgen.asmVariableName(value.arrayvar)
|
2022-06-04 15:18:24 +00:00
|
|
|
|
|
|
|
val arrayVarDecl = value.arrayvar.targetVarDecl(program)!!
|
|
|
|
if(arrayVarDecl.datatype==DataType.UWORD) {
|
|
|
|
// indexing a pointer var instead of a real array or string
|
|
|
|
if(elementDt !in ByteDatatypes)
|
|
|
|
throw AssemblyError("non-array var indexing requires bytes dt")
|
2022-06-04 15:49:25 +00:00
|
|
|
if(value.inferType(program) isnot DataType.UBYTE)
|
|
|
|
throw AssemblyError("non-array var indexing requires bytes index")
|
2022-06-04 15:18:24 +00:00
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
|
|
|
if(asmgen.isZpVar(value.arrayvar)) {
|
|
|
|
asmgen.out(" lda ($arrayVarName),y")
|
|
|
|
} else {
|
|
|
|
asmgen.out(" lda $arrayVarName | sta P8ZP_SCRATCH_W1 | lda $arrayVarName+1 | sta P8ZP_SCRATCH_W1+1")
|
|
|
|
asmgen.out(" lda (P8ZP_SCRATCH_W1),y")
|
|
|
|
}
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = value.indexer.constIndex()
|
|
|
|
if (constIndex!=null) {
|
2019-08-16 20:49:29 +00:00
|
|
|
// constant array index value
|
2021-03-22 18:33:57 +00:00
|
|
|
val indexValue = constIndex * program.memsizer.memorySize(elementDt)
|
2020-08-23 10:03:52 +00:00
|
|
|
when (elementDt) {
|
2020-11-22 16:16:07 +00:00
|
|
|
in ByteDatatypes -> {
|
|
|
|
asmgen.out(" lda $arrayVarName+$indexValue")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
asmgen.out(" lda $arrayVarName+$indexValue | ldy $arrayVarName+$indexValue+1")
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
2022-01-09 15:18:13 +00:00
|
|
|
asmgen.out(" lda #<($arrayVarName+$indexValue) | ldy #>($arrayVarName+$indexValue)")
|
2020-11-22 16:16:07 +00:00
|
|
|
assignFloatFromAY(assign.target)
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
else ->
|
|
|
|
throw AssemblyError("weird array type")
|
|
|
|
}
|
|
|
|
} else {
|
2020-08-23 18:25:00 +00:00
|
|
|
when (elementDt) {
|
|
|
|
in ByteDatatypes -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
2020-11-22 16:16:07 +00:00
|
|
|
asmgen.out(" lda $arrayVarName,y")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
2020-08-23 18:25:00 +00:00
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
|
2020-11-22 16:16:07 +00:00
|
|
|
asmgen.out(" lda $arrayVarName,y | pha | lda $arrayVarName+1,y | tay | pla")
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
2020-08-23 18:25:00 +00:00
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.A)
|
|
|
|
asmgen.out("""
|
|
|
|
ldy #>$arrayVarName
|
|
|
|
clc
|
|
|
|
adc #<$arrayVarName
|
|
|
|
bcc +
|
|
|
|
iny
|
2020-11-22 16:16:07 +00:00
|
|
|
+""")
|
|
|
|
assignFloatFromAY(assign.target)
|
2020-08-23 18:25:00 +00:00
|
|
|
}
|
|
|
|
else ->
|
|
|
|
throw AssemblyError("weird array elt type")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
SourceStorageKind.MEMORY -> {
|
2021-01-15 18:52:53 +00:00
|
|
|
fun assignViaExprEval(expression: Expression) {
|
2021-06-12 15:31:09 +00:00
|
|
|
assignExpressionToVariable(expression, "P8ZP_SCRATCH_W2", DataType.UWORD, assign.target.scope)
|
2021-12-04 03:48:07 +00:00
|
|
|
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2")
|
2021-01-15 18:52:53 +00:00
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
|
2020-08-23 11:56:21 +00:00
|
|
|
val value = assign.source.memory!!
|
2020-08-23 09:07:35 +00:00
|
|
|
when (value.addressExpression) {
|
2022-02-10 23:21:40 +00:00
|
|
|
is NumericLiteral -> {
|
|
|
|
val address = (value.addressExpression as NumericLiteral).number.toUInt()
|
2020-08-23 12:36:24 +00:00
|
|
|
assignMemoryByte(assign.target, address, null)
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
|
|
|
is IdentifierReference -> {
|
2020-08-23 12:36:24 +00:00
|
|
|
assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference)
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
2021-01-15 18:52:53 +00:00
|
|
|
is BinaryExpression -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) {
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
} else {
|
2021-01-15 20:33:57 +00:00
|
|
|
assignViaExprEval(value.addressExpression)
|
2021-01-19 18:25:23 +00:00
|
|
|
}
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
2021-01-15 18:52:53 +00:00
|
|
|
else -> assignViaExprEval(value.addressExpression)
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
SourceStorageKind.EXPRESSION -> {
|
2022-02-20 17:34:30 +00:00
|
|
|
assignExpression(assign)
|
|
|
|
}
|
|
|
|
SourceStorageKind.REGISTER -> {
|
|
|
|
asmgen.assignRegister(assign.source.register!!, assign.target)
|
|
|
|
}
|
|
|
|
SourceStorageKind.STACK -> {
|
|
|
|
if(assign.target.kind!=TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype)
|
|
|
|
assignStackValue(assign.target)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun assignExpression(assign: AsmAssignment) {
|
|
|
|
when(val value = assign.source.expression!!) {
|
|
|
|
is AddressOf -> {
|
|
|
|
val sourceName = asmgen.asmSymbolName(value.identifier)
|
|
|
|
assignAddressOf(assign.target, sourceName)
|
|
|
|
}
|
|
|
|
is NumericLiteral -> throw AssemblyError("source kind should have been literalnumber")
|
|
|
|
is IdentifierReference -> throw AssemblyError("source kind should have been variable")
|
|
|
|
is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array")
|
|
|
|
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
|
|
|
|
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
|
|
|
|
is FunctionCallExpression -> {
|
|
|
|
val sub = value.target.targetSubroutine(program)!!
|
|
|
|
asmgen.saveXbeforeCall(value)
|
|
|
|
asmgen.translateFunctionCall(value, true)
|
|
|
|
val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?:
|
|
|
|
sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null }
|
|
|
|
when (returnValue.first) {
|
|
|
|
DataType.STR -> {
|
|
|
|
asmgen.restoreXafterCall(value)
|
|
|
|
when(assign.target.datatype) {
|
|
|
|
DataType.UWORD -> {
|
|
|
|
// assign the address of the string result value
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
}
|
|
|
|
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
2022-04-23 00:15:51 +00:00
|
|
|
throw AssemblyError("stringvalue assignment should have been replaced by a call to strcpy")
|
2022-02-20 01:01:48 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
else -> throw AssemblyError("weird target dt")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
// float result from function sits in FAC1
|
|
|
|
asmgen.restoreXafterCall(value)
|
|
|
|
assignFAC1float(assign.target)
|
|
|
|
}
|
|
|
|
else -> {
|
|
|
|
// do NOT restore X register before assigning the result values first
|
|
|
|
when (returnValue.second.registerOrPair) {
|
|
|
|
RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X)
|
|
|
|
RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y)
|
2022-08-09 21:38:29 +00:00
|
|
|
RegisterOrPair.AX -> assignVirtualRegister(assign.target, RegisterOrPair.AX)
|
|
|
|
RegisterOrPair.AY -> assignVirtualRegister(assign.target, RegisterOrPair.AY)
|
|
|
|
RegisterOrPair.XY -> assignVirtualRegister(assign.target, RegisterOrPair.XY)
|
|
|
|
RegisterOrPair.R0 -> assignVirtualRegister(assign.target, RegisterOrPair.R0)
|
|
|
|
RegisterOrPair.R1 -> assignVirtualRegister(assign.target, RegisterOrPair.R1)
|
|
|
|
RegisterOrPair.R2 -> assignVirtualRegister(assign.target, RegisterOrPair.R2)
|
|
|
|
RegisterOrPair.R3 -> assignVirtualRegister(assign.target, RegisterOrPair.R3)
|
|
|
|
RegisterOrPair.R4 -> assignVirtualRegister(assign.target, RegisterOrPair.R4)
|
|
|
|
RegisterOrPair.R5 -> assignVirtualRegister(assign.target, RegisterOrPair.R5)
|
|
|
|
RegisterOrPair.R6 -> assignVirtualRegister(assign.target, RegisterOrPair.R6)
|
|
|
|
RegisterOrPair.R7 -> assignVirtualRegister(assign.target, RegisterOrPair.R7)
|
|
|
|
RegisterOrPair.R8 -> assignVirtualRegister(assign.target, RegisterOrPair.R8)
|
|
|
|
RegisterOrPair.R9 -> assignVirtualRegister(assign.target, RegisterOrPair.R9)
|
|
|
|
RegisterOrPair.R10 -> assignVirtualRegister(assign.target, RegisterOrPair.R10)
|
|
|
|
RegisterOrPair.R11 -> assignVirtualRegister(assign.target, RegisterOrPair.R11)
|
|
|
|
RegisterOrPair.R12 -> assignVirtualRegister(assign.target, RegisterOrPair.R12)
|
|
|
|
RegisterOrPair.R13 -> assignVirtualRegister(assign.target, RegisterOrPair.R13)
|
|
|
|
RegisterOrPair.R14 -> assignVirtualRegister(assign.target, RegisterOrPair.R14)
|
|
|
|
RegisterOrPair.R15 -> assignVirtualRegister(assign.target, RegisterOrPair.R15)
|
2022-02-20 01:01:48 +00:00
|
|
|
else -> {
|
2022-02-20 17:34:30 +00:00
|
|
|
val sflag = returnValue.second.statusflag
|
|
|
|
if(sflag!=null)
|
|
|
|
assignStatusFlagByte(assign.target, sflag)
|
|
|
|
else
|
|
|
|
throw AssemblyError("should be just one register byte result value")
|
2020-10-27 23:29:34 +00:00
|
|
|
}
|
2022-02-20 01:01:48 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
// we've processed the result value in the X register by now, so it's now finally safe to restore it
|
|
|
|
asmgen.restoreXafterCall(value)
|
2022-02-20 01:01:48 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is BuiltinFunctionCall -> {
|
|
|
|
asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register)
|
|
|
|
if(assign.target.register==null) {
|
|
|
|
// still need to assign the result to the target variable/etc.
|
2022-04-13 21:23:59 +00:00
|
|
|
val returntype = builtinFunctionReturnType(value.name)
|
2022-02-20 17:34:30 +00:00
|
|
|
if(!returntype.isKnown)
|
|
|
|
throw AssemblyError("unknown dt")
|
|
|
|
when(returntype.getOr(DataType.UNDEFINED)) {
|
|
|
|
in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A
|
|
|
|
in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY
|
|
|
|
DataType.STR -> {
|
|
|
|
when (assign.target.datatype) {
|
2022-02-20 01:01:48 +00:00
|
|
|
DataType.STR -> {
|
2022-02-20 17:34:30 +00:00
|
|
|
asmgen.out("""
|
2021-01-29 00:52:49 +00:00
|
|
|
pha
|
|
|
|
lda #<${assign.target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
lda #>${assign.target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W1+1
|
|
|
|
pla
|
|
|
|
jsr prog8_lib.strcpy""")
|
2022-02-20 01:01:48 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
else -> throw AssemblyError("str return value type mismatch with target")
|
2020-10-06 22:06:42 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
DataType.FLOAT -> {
|
|
|
|
// float result from function sits in FAC1
|
|
|
|
assignFAC1float(assign.target)
|
2022-01-09 17:49:44 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
else -> throw AssemblyError("weird result type")
|
2022-01-09 17:49:44 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
is PrefixExpression -> {
|
2022-10-27 19:58:37 +00:00
|
|
|
if(assign.target.array==null) {
|
|
|
|
// First assign the value to the target then apply the operator in place on the target.
|
|
|
|
// This saves a temporary variable
|
|
|
|
translateNormalAssignment(
|
|
|
|
AsmAssignment(
|
|
|
|
AsmAssignSource.fromAstSource(value.expression, program, asmgen),
|
|
|
|
assign.target,
|
|
|
|
false, program.memsizer, assign.position
|
|
|
|
)
|
|
|
|
)
|
|
|
|
when (value.operator) {
|
|
|
|
"+" -> {}
|
2022-11-27 15:50:44 +00:00
|
|
|
"-" -> augmentableAsmGen.inplaceNegate(assign, true)
|
2022-10-27 21:31:57 +00:00
|
|
|
"~" -> augmentableAsmGen.inplaceInvert(assign)
|
2022-10-27 19:58:37 +00:00
|
|
|
else -> throw AssemblyError("invalid prefix operator")
|
|
|
|
}
|
|
|
|
} else {
|
2022-10-27 21:08:40 +00:00
|
|
|
assignPrefixedExpressionToArrayElt(assign)
|
2022-02-20 17:34:30 +00:00
|
|
|
}
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
is ContainmentCheck -> {
|
|
|
|
containmentCheckIntoA(value)
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
is BinaryExpression -> {
|
2022-06-12 20:55:23 +00:00
|
|
|
if(!attemptAssignOptimizedBinexpr(value, assign)) {
|
2022-02-20 17:34:30 +00:00
|
|
|
// All remaining binary expressions just evaluate via the stack for now.
|
|
|
|
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
|
|
|
|
// because the code here is the implementation of exactly that...)
|
|
|
|
fallbackToStackEval(assign)
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2022-02-20 17:34:30 +00:00
|
|
|
else -> throw AssemblyError("weird assignment value type $value")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2022-10-27 21:08:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal fun assignPrefixedExpressionToArrayElt(assign: AsmAssignment) {
|
|
|
|
require(assign.source.expression is PrefixExpression)
|
2022-11-03 19:08:46 +00:00
|
|
|
if(assign.source.datatype==DataType.FLOAT) {
|
|
|
|
// floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array.
|
|
|
|
assignExpressionToRegister(assign.source.expression, RegisterOrPair.FAC1, true)
|
|
|
|
assignFAC1float(assign.target)
|
|
|
|
} else {
|
|
|
|
// array[x] = -value ... use a tempvar then store that back into the array.
|
|
|
|
val tempvar = asmgen.getTempVarName(assign.target.datatype).joinToString(".")
|
|
|
|
val assignToTempvar = AsmAssignment(assign.source,
|
|
|
|
AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, assign.target.datatype, assign.target.scope, variableAsmName=tempvar, origAstTarget = assign.target.origAstTarget),
|
|
|
|
false, program.memsizer, assign.position)
|
|
|
|
asmgen.translateNormalAssignment(assignToTempvar)
|
|
|
|
when(assign.target.datatype) {
|
|
|
|
in ByteDatatypes -> assignVariableByte(assign.target, tempvar)
|
|
|
|
in WordDatatypes -> assignVariableWord(assign.target, tempvar)
|
|
|
|
DataType.FLOAT -> assignVariableFloat(assign.target, tempvar)
|
|
|
|
else -> throw AssemblyError("weird dt")
|
|
|
|
}
|
2022-10-27 21:08:40 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 21:38:29 +00:00
|
|
|
private fun assignVirtualRegister(target: AsmAssignTarget, register: RegisterOrPair) {
|
|
|
|
when(target.datatype) {
|
|
|
|
in ByteDatatypes -> {
|
|
|
|
asmgen.out(" lda cx16.${register.toString().lowercase()}L")
|
|
|
|
assignRegisterByte(target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
in WordDatatypes -> assignRegisterpairWord(target, register)
|
|
|
|
else -> throw AssemblyError("expected byte or word")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 20:54:54 +00:00
|
|
|
private fun attemptAssignOptimizedBinexpr(expr: BinaryExpression, assign: AsmAssignment): Boolean {
|
2022-06-12 20:55:23 +00:00
|
|
|
if(expr.operator in ComparisonOperators) {
|
2022-07-04 21:42:49 +00:00
|
|
|
if(expr.right.constValue(program)?.number == 0.0) {
|
|
|
|
if(expr.operator == "==" || expr.operator=="!=") {
|
|
|
|
when(assign.target.datatype) {
|
|
|
|
in ByteDatatypes -> if(attemptAssignToByteCompareZero(expr, assign)) return true
|
|
|
|
else -> {
|
|
|
|
// do nothing, this is handled by a type cast.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-12 20:55:23 +00:00
|
|
|
val origTarget = assign.target.origAstTarget
|
|
|
|
if(origTarget!=null) {
|
2022-07-04 21:42:49 +00:00
|
|
|
assignConstantByte(assign.target, 0)
|
2022-06-12 20:55:23 +00:00
|
|
|
val assignTrue = AnonymousScope(mutableListOf(
|
|
|
|
Assignment(origTarget, NumericLiteral.fromBoolean(true, assign.position), AssignmentOrigin.ASMGEN, assign.position)
|
|
|
|
), assign.position)
|
|
|
|
val assignFalse = AnonymousScope(mutableListOf(), assign.position)
|
|
|
|
val ifelse = IfElse(expr.copy(), assignTrue, assignFalse, assign.position)
|
|
|
|
ifelse.linkParents(expr)
|
|
|
|
asmgen.translate(ifelse)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 20:54:54 +00:00
|
|
|
if(!expr.inferType(program).isInteger)
|
|
|
|
return false
|
2022-06-12 20:55:23 +00:00
|
|
|
|
2022-12-06 19:01:50 +00:00
|
|
|
fun simpleLogicalBytesExpr() {
|
|
|
|
// both left and right expression operands are simple.
|
|
|
|
if (expr.right is NumericLiteral || expr.right is IdentifierReference)
|
|
|
|
assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right)
|
|
|
|
else if (expr.left is NumericLiteral || expr.left is IdentifierReference)
|
|
|
|
assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left)
|
|
|
|
else {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.A, false)
|
|
|
|
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine)
|
|
|
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
|
|
|
when (expr.operator) {
|
|
|
|
"&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1")
|
|
|
|
"|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1")
|
|
|
|
"^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1")
|
|
|
|
else -> throw AssemblyError("invalid operator")
|
|
|
|
}
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun simpleLogicalWordsExpr() {
|
|
|
|
// both left and right expression operands are simple.
|
|
|
|
if (expr.right is NumericLiteral || expr.right is IdentifierReference)
|
|
|
|
assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right)
|
|
|
|
else if (expr.left is NumericLiteral || expr.left is IdentifierReference)
|
|
|
|
assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left)
|
|
|
|
else {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.AY, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.A, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
|
|
|
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine)
|
|
|
|
when (expr.operator) {
|
|
|
|
"&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1")
|
|
|
|
"|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1")
|
|
|
|
"^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1")
|
|
|
|
else -> throw AssemblyError("invalid operator")
|
|
|
|
}
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-31 11:38:00 +00:00
|
|
|
if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) {
|
2022-12-06 19:01:50 +00:00
|
|
|
if (expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes) {
|
|
|
|
if (expr.right.isSimple) {
|
|
|
|
simpleLogicalBytesExpr()
|
|
|
|
return true
|
2022-07-31 11:38:00 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-06 19:01:50 +00:00
|
|
|
if (expr.left.inferType(program).isWords && expr.right.inferType(program).isWords) {
|
|
|
|
if (expr.right.isSimple) {
|
|
|
|
simpleLogicalWordsExpr()
|
|
|
|
return true
|
2022-07-31 11:38:00 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-06 20:54:54 +00:00
|
|
|
return false
|
2022-07-31 11:38:00 +00:00
|
|
|
}
|
2022-06-06 20:54:54 +00:00
|
|
|
|
2022-07-31 11:38:00 +00:00
|
|
|
if(expr.operator == "==" || expr.operator == "!=") {
|
|
|
|
// expression datatype is BOOL (ubyte) but operands can be anything
|
|
|
|
if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes &&
|
|
|
|
expr.left.isSimple && expr.right.isSimple) {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.A, false)
|
|
|
|
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine)
|
|
|
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
|
|
|
if(expr.operator=="==") {
|
|
|
|
asmgen.out("""
|
|
|
|
cmp P8ZP_SCRATCH_B1
|
|
|
|
bne +
|
|
|
|
lda #1
|
|
|
|
bne ++
|
|
|
|
+ lda #0
|
|
|
|
+""")
|
|
|
|
} else {
|
|
|
|
asmgen.out("""
|
|
|
|
cmp P8ZP_SCRATCH_B1
|
|
|
|
beq +
|
|
|
|
lda #1
|
|
|
|
bne ++
|
|
|
|
+ lda #0
|
|
|
|
+""")
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
2022-07-31 11:38:00 +00:00
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
} else if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords &&
|
|
|
|
expr.left.isSimple && expr.right.isSimple) {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.AY, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.A, false)
|
|
|
|
asmgen.saveRegisterStack(CpuRegister.Y, false)
|
|
|
|
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine)
|
|
|
|
asmgen.restoreRegisterStack(CpuRegister.Y, false)
|
|
|
|
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
|
|
|
if(expr.operator=="==") {
|
|
|
|
asmgen.out("""
|
|
|
|
cmp P8ZP_SCRATCH_W1
|
|
|
|
bne +
|
|
|
|
cpy P8ZP_SCRATCH_W1+1
|
|
|
|
bne +
|
|
|
|
lda #1
|
|
|
|
bne ++
|
|
|
|
+ lda #0
|
|
|
|
+""")
|
|
|
|
} else {
|
|
|
|
asmgen.out("""
|
|
|
|
cmp P8ZP_SCRATCH_W1
|
|
|
|
bne +
|
|
|
|
cpy P8ZP_SCRATCH_W1+1
|
|
|
|
bne +
|
|
|
|
lda #0
|
|
|
|
bne ++
|
|
|
|
+ lda #1
|
|
|
|
+""")
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
2022-07-31 11:38:00 +00:00
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
2022-07-31 11:38:00 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
else if(expr.operator=="+" || expr.operator=="-") {
|
|
|
|
val dt = expr.inferType(program).getOrElse { throw AssemblyError("invalid dt") }
|
|
|
|
val left = expr.left
|
|
|
|
val right = expr.right
|
|
|
|
if(dt in ByteDatatypes) {
|
|
|
|
when (right) {
|
|
|
|
is IdentifierReference -> {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
|
|
|
|
val symname = asmgen.asmVariableName(right)
|
|
|
|
if(expr.operator=="+")
|
|
|
|
asmgen.out(" clc | adc $symname")
|
|
|
|
else
|
|
|
|
asmgen.out(" sec | sbc $symname")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
is NumericLiteral -> {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.A, dt==DataType.BYTE)
|
|
|
|
if(expr.operator=="+")
|
|
|
|
asmgen.out(" clc | adc #${right.number.toHex()}")
|
|
|
|
else
|
|
|
|
asmgen.out(" sec | sbc #${right.number.toHex()}")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
else -> return false
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
2022-07-31 11:38:00 +00:00
|
|
|
} else if(dt in WordDatatypes) {
|
|
|
|
when (right) {
|
|
|
|
is AddressOf -> {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
val symbol = asmgen.asmVariableName(right.identifier)
|
|
|
|
if(expr.operator=="+")
|
|
|
|
asmgen.out("""
|
|
|
|
clc
|
|
|
|
adc #<$symbol
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
adc #>$symbol
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
else
|
|
|
|
asmgen.out("""
|
|
|
|
sec
|
|
|
|
sbc #<$symbol
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
sbc #>$symbol
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
is IdentifierReference -> {
|
|
|
|
val symname = asmgen.asmVariableName(right)
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
if(expr.operator=="+")
|
|
|
|
asmgen.out("""
|
|
|
|
clc
|
|
|
|
adc $symname
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
adc $symname+1
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
else
|
|
|
|
asmgen.out("""
|
|
|
|
sec
|
|
|
|
sbc $symname
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
sbc $symname+1
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
is NumericLiteral -> {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
if(expr.operator=="+") {
|
|
|
|
asmgen.out("""
|
|
|
|
clc
|
|
|
|
adc #<${right.number.toHex()}
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
adc #>${right.number.toHex()}
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
} else if(expr.operator=="-") {
|
|
|
|
asmgen.out("""
|
|
|
|
sec
|
|
|
|
sbc #<${right.number.toHex()}
|
|
|
|
pha
|
|
|
|
tya
|
|
|
|
sbc #>${right.number.toHex()}
|
|
|
|
tay
|
|
|
|
pla""")
|
|
|
|
}
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
is TypecastExpression -> {
|
|
|
|
val castedValue = right.expression
|
|
|
|
if(right.type in WordDatatypes && castedValue.inferType(program).isBytes) {
|
|
|
|
if(castedValue is IdentifierReference) {
|
|
|
|
val castedSymname = asmgen.asmVariableName(castedValue)
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
if(expr.operator=="+")
|
|
|
|
asmgen.out("""
|
|
|
|
clc
|
|
|
|
adc $castedSymname
|
|
|
|
bcc +
|
|
|
|
iny
|
|
|
|
+""")
|
|
|
|
else
|
|
|
|
asmgen.out("""
|
|
|
|
sec
|
|
|
|
sbc $castedSymname
|
|
|
|
bcs +
|
|
|
|
dey
|
|
|
|
+""")
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
return true
|
|
|
|
}
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-31 11:38:00 +00:00
|
|
|
else -> return false
|
2022-06-06 20:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-15 01:45:51 +00:00
|
|
|
else if(expr.operator=="<<" || expr.operator==">>") {
|
|
|
|
val shifts = expr.right.constValue(program)?.number?.toInt()
|
|
|
|
if(shifts!=null) {
|
|
|
|
val dt = expr.left.inferType(program)
|
|
|
|
if(dt.isBytes && shifts in 0..7) {
|
|
|
|
val signed = dt istype DataType.BYTE
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.A, signed)
|
|
|
|
if(expr.operator=="<<") {
|
|
|
|
repeat(shifts) {
|
|
|
|
asmgen.out(" asl a")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(signed && shifts>0) {
|
|
|
|
asmgen.out(" ldy #$shifts | jsr math.lsr_byte_A")
|
|
|
|
} else {
|
|
|
|
repeat(shifts) {
|
|
|
|
asmgen.out(" lsr a")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
} else if(dt.isWords && shifts in 0..7) {
|
|
|
|
val signed = dt istype DataType.WORD
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed)
|
|
|
|
if(expr.operator=="<<") {
|
|
|
|
if(shifts>0) {
|
|
|
|
asmgen.out(" sty P8ZP_SCRATCH_B1")
|
|
|
|
repeat(shifts) {
|
|
|
|
asmgen.out(" asl a | rol P8ZP_SCRATCH_B1")
|
|
|
|
}
|
|
|
|
asmgen.out(" ldy P8ZP_SCRATCH_B1")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(signed) {
|
|
|
|
// TODO("shift AY >> $shifts signed")
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
if(shifts>0) {
|
|
|
|
asmgen.out(" sty P8ZP_SCRATCH_B1")
|
|
|
|
repeat(shifts) {
|
|
|
|
asmgen.out(" lsr P8ZP_SCRATCH_B1 | ror a")
|
|
|
|
}
|
|
|
|
asmgen.out(" ldy P8ZP_SCRATCH_B1")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-06 20:54:54 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:46:38 +00:00
|
|
|
private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
|
|
|
val operand = when(right) {
|
|
|
|
is NumericLiteral -> "#${right.number.toHex()}"
|
|
|
|
is IdentifierReference -> asmgen.asmSymbolName(right)
|
|
|
|
else -> throw AssemblyError("wrong right operand type")
|
|
|
|
}
|
|
|
|
when (operator) {
|
|
|
|
"&", "and" -> asmgen.out(" and $operand")
|
|
|
|
"|", "or" -> asmgen.out(" ora $operand")
|
|
|
|
"^", "xor" -> asmgen.out(" eor $operand")
|
|
|
|
else -> throw AssemblyError("invalid operator")
|
|
|
|
}
|
|
|
|
assignRegisterByte(target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun assignLogicalWithSimpleRightOperandWord(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) {
|
|
|
|
assignExpressionToRegister(left, RegisterOrPair.AY, false)
|
|
|
|
when(right) {
|
|
|
|
is NumericLiteral -> {
|
|
|
|
val number = right.number.toHex()
|
|
|
|
when (operator) {
|
|
|
|
"&", "and" -> asmgen.out(" and #<$number | pha | tya | and #>$number | tay | pla")
|
|
|
|
"|", "or" -> asmgen.out(" ora #<$number | pha | tya | ora #>$number | tay | pla")
|
|
|
|
"^", "xor" -> asmgen.out(" eor #<$number | pha | tya | eor #>$number | tay | pla")
|
|
|
|
else -> throw AssemblyError("invalid operator")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is IdentifierReference -> {
|
|
|
|
val name = asmgen.asmSymbolName(right)
|
|
|
|
when (operator) {
|
|
|
|
"&", "and" -> asmgen.out(" and $name | pha | tya | and $name+1 | tay | pla")
|
|
|
|
"|", "or" -> asmgen.out(" ora $name | pha | tya | ora $name+1 | tay | pla")
|
|
|
|
"^", "xor" -> asmgen.out(" eor $name | pha | tya | eor $name+1 | tay | pla")
|
|
|
|
else -> throw AssemblyError("invalid operator")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("wrong right operand type")
|
|
|
|
}
|
|
|
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
|
|
|
}
|
|
|
|
|
2022-07-04 21:42:49 +00:00
|
|
|
private fun attemptAssignToByteCompareZero(expr: BinaryExpression, assign: AsmAssignment): Boolean {
|
|
|
|
when (expr.operator) {
|
|
|
|
"==" -> {
|
2022-07-05 22:49:57 +00:00
|
|
|
when(val dt = expr.left.inferType(program).getOrElse { throw AssemblyError("invalid dt") }) {
|
2022-07-04 21:42:49 +00:00
|
|
|
in ByteDatatypes -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE)
|
|
|
|
asmgen.out("""
|
|
|
|
beq +
|
|
|
|
lda #0
|
|
|
|
beq ++
|
|
|
|
+ lda #1
|
|
|
|
+""")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
asmgen.out("""
|
|
|
|
sty P8ZP_SCRATCH_B1
|
|
|
|
ora P8ZP_SCRATCH_B1
|
|
|
|
beq +
|
|
|
|
lda #0
|
|
|
|
beq ++
|
|
|
|
+ lda #1
|
|
|
|
+""")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
|
|
|
asmgen.out(" jsr floats.SIGN | and #1 | eor #1")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
else->{
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"!=" -> {
|
2022-07-05 22:49:57 +00:00
|
|
|
when(val dt = expr.left.inferType(program).getOrElse { throw AssemblyError("invalid dt") }) {
|
2022-07-04 21:42:49 +00:00
|
|
|
in ByteDatatypes -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.A, dt==DataType.BYTE)
|
|
|
|
asmgen.out(" beq + | lda #1")
|
|
|
|
asmgen.out("+")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.AY, dt==DataType.WORD)
|
|
|
|
asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1")
|
|
|
|
asmgen.out(" beq + | lda #1")
|
|
|
|
asmgen.out("+")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
|
|
|
asmgen.out(" jsr floats.SIGN")
|
|
|
|
assignRegisterByte(assign.target, CpuRegister.A)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
else->{
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-15 22:16:49 +00:00
|
|
|
private fun fallbackToStackEval(assign: AsmAssignment) {
|
|
|
|
// this routine is called for assigning a binaryexpression value:
|
|
|
|
// - if it's a boolean comparison expression and the workaround isn't possible (no origTarget ast node)
|
|
|
|
// - for all other binary expressions.
|
|
|
|
asmgen.translateExpression(assign.source.expression!!)
|
2022-01-09 17:49:44 +00:00
|
|
|
if (assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
|
|
|
|
asmgen.signExtendStackLsb(assign.source.datatype)
|
|
|
|
if (assign.target.kind != TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype)
|
|
|
|
assignStackValue(assign.target)
|
|
|
|
}
|
|
|
|
|
2021-12-29 15:21:37 +00:00
|
|
|
private fun containmentCheckIntoA(containment: ContainmentCheck) {
|
|
|
|
val elementDt = containment.element.inferType(program)
|
|
|
|
val variable = (containment.iterable as? IdentifierReference)?.targetVarDecl(program)
|
2022-03-27 13:23:32 +00:00
|
|
|
?: throw AssemblyError("invalid containment iterable type")
|
|
|
|
|
|
|
|
if(variable.origin!=VarDeclOrigin.USERCODE) {
|
2021-12-29 15:21:37 +00:00
|
|
|
when(variable.datatype) {
|
|
|
|
DataType.STR -> {
|
2022-12-03 18:56:54 +00:00
|
|
|
require(elementDt.isBytes) { "must be byte string ${variable.position}" }
|
2022-03-27 13:23:32 +00:00
|
|
|
val stringVal = variable.value as StringLiteral
|
|
|
|
val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference)
|
2021-12-29 15:21:37 +00:00
|
|
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.A)
|
2021-12-29 15:21:37 +00:00
|
|
|
asmgen.out(" ldy #${stringVal.value.length}")
|
|
|
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
|
|
|
return
|
|
|
|
}
|
2022-03-27 13:23:32 +00:00
|
|
|
DataType.ARRAY_F -> {
|
|
|
|
// require(elementDt istype DataType.FLOAT)
|
|
|
|
throw AssemblyError("containment check of floats not supported")
|
2021-12-29 15:21:37 +00:00
|
|
|
}
|
2022-03-27 13:23:32 +00:00
|
|
|
in ArrayDatatypes -> {
|
2022-12-03 18:56:54 +00:00
|
|
|
require(elementDt.isInteger) { "must be integer array ${variable.position}" }
|
2022-02-10 23:21:40 +00:00
|
|
|
val arrayVal = variable.value as ArrayLiteral
|
2022-03-27 13:23:32 +00:00
|
|
|
val dt = elementDt.getOr(DataType.UNDEFINED)
|
|
|
|
val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference)
|
|
|
|
when(dt) {
|
|
|
|
in ByteDatatypes -> {
|
|
|
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.A)
|
2022-03-27 13:23:32 +00:00
|
|
|
asmgen.out(" ldy #${arrayVal.value.size}")
|
|
|
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname)
|
2022-03-27 13:23:32 +00:00
|
|
|
asmgen.out(" ldy #${arrayVal.value.size}")
|
|
|
|
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid dt")
|
|
|
|
}
|
2021-12-29 15:21:37 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid dt")
|
|
|
|
}
|
|
|
|
}
|
2022-03-27 13:23:32 +00:00
|
|
|
val varname = asmgen.asmVariableName(containment.iterable as IdentifierReference)
|
|
|
|
when(variable.datatype) {
|
|
|
|
DataType.STR -> {
|
|
|
|
// use subroutine
|
|
|
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.A)
|
2022-03-27 13:23:32 +00:00
|
|
|
val stringVal = variable.value as StringLiteral
|
|
|
|
asmgen.out(" ldy #${stringVal.value.length}")
|
|
|
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
|
|
|
return
|
2021-12-29 15:21:37 +00:00
|
|
|
}
|
2022-05-04 18:47:48 +00:00
|
|
|
DataType.ARRAY_F -> {
|
|
|
|
throw AssemblyError("containment check of floats not supported")
|
|
|
|
}
|
2022-03-27 13:23:32 +00:00
|
|
|
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
2022-12-23 12:38:34 +00:00
|
|
|
val numElements = variable.arraysize!!.constIndex()!!
|
2022-03-27 13:23:32 +00:00
|
|
|
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt istype DataType.BYTE)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.A, containment.definingSubroutine!!)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W1"), varname)
|
2022-04-01 18:46:28 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.A)
|
2022-12-23 12:38:34 +00:00
|
|
|
asmgen.out(" ldy #$numElements")
|
2022-03-27 13:23:32 +00:00
|
|
|
asmgen.out(" jsr prog8_lib.containment_bytearray")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
2022-12-23 12:38:34 +00:00
|
|
|
val numElements = variable.arraysize!!.constIndex()!!
|
2022-03-27 13:23:32 +00:00
|
|
|
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt.getOr(DataType.UNDEFINED), containment.definingSubroutine)
|
2022-07-31 11:38:00 +00:00
|
|
|
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingSubroutine, "P8ZP_SCRATCH_W2"), varname)
|
2022-12-23 12:38:34 +00:00
|
|
|
asmgen.out(" ldy #$numElements")
|
2022-03-27 13:23:32 +00:00
|
|
|
asmgen.out(" jsr prog8_lib.containment_wordarray")
|
|
|
|
return
|
2021-12-29 15:21:37 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid dt")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-22 11:44:03 +00:00
|
|
|
private fun assignStatusFlagByte(target: AsmAssignTarget, statusflag: Statusflag) {
|
|
|
|
when(statusflag) {
|
|
|
|
Statusflag.Pc -> {
|
|
|
|
asmgen.out(" lda #0 | rol a")
|
|
|
|
}
|
|
|
|
Statusflag.Pv -> {
|
|
|
|
asmgen.out("""
|
|
|
|
bvs +
|
|
|
|
lda #0
|
|
|
|
beq ++
|
|
|
|
+ lda #1
|
|
|
|
+""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("can't use Z or N flags as return 'values'")
|
|
|
|
}
|
|
|
|
assignRegisterByte(target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
|
2020-11-24 21:26:11 +00:00
|
|
|
private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origTypeCastExpression: TypecastExpression) {
|
2020-10-30 15:26:19 +00:00
|
|
|
val valueIDt = value.inferType(program)
|
2021-12-06 20:15:09 +00:00
|
|
|
val valueDt = valueIDt.getOrElse { throw AssemblyError("unknown dt") }
|
2020-11-24 21:26:11 +00:00
|
|
|
if(valueDt==targetDt)
|
|
|
|
throw AssemblyError("type cast to identical dt should have been removed")
|
|
|
|
|
2020-09-15 01:26:57 +00:00
|
|
|
when(value) {
|
|
|
|
is IdentifierReference -> {
|
2020-10-10 13:39:48 +00:00
|
|
|
if(targetDt in WordDatatypes) {
|
|
|
|
if(valueDt==DataType.UBYTE) {
|
|
|
|
assignVariableUByteIntoWord(target, value)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if(valueDt==DataType.BYTE) {
|
|
|
|
assignVariableByteIntoWord(target, value)
|
2020-09-15 01:26:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is DirectMemoryRead -> {
|
|
|
|
if(targetDt in WordDatatypes) {
|
2021-01-19 23:28:54 +00:00
|
|
|
|
|
|
|
fun assignViaExprEval(addressExpression: Expression) {
|
2021-06-12 15:31:09 +00:00
|
|
|
asmgen.assignExpressionToVariable(addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
2021-12-04 03:48:07 +00:00
|
|
|
asmgen.loadAFromZpPointerVar("P8ZP_SCRATCH_W2")
|
2022-10-23 09:57:23 +00:00
|
|
|
asmgen.out(" ldy #0")
|
|
|
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
2021-01-19 23:28:54 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 18:25:23 +00:00
|
|
|
when (value.addressExpression) {
|
2022-02-10 23:21:40 +00:00
|
|
|
is NumericLiteral -> {
|
|
|
|
val address = (value.addressExpression as NumericLiteral).number.toUInt()
|
2021-01-19 18:25:23 +00:00
|
|
|
assignMemoryByteIntoWord(target, address, null)
|
|
|
|
}
|
|
|
|
is IdentifierReference -> {
|
|
|
|
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
|
|
|
|
}
|
2021-01-19 23:28:54 +00:00
|
|
|
is BinaryExpression -> {
|
|
|
|
if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) {
|
|
|
|
asmgen.out(" ldy #0")
|
|
|
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
|
|
|
} else {
|
|
|
|
assignViaExprEval(value.addressExpression)
|
|
|
|
}
|
|
|
|
}
|
2021-01-19 18:25:23 +00:00
|
|
|
else -> {
|
2021-01-19 23:28:54 +00:00
|
|
|
assignViaExprEval(value.addressExpression)
|
2021-01-19 18:25:23 +00:00
|
|
|
}
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
2022-12-04 11:22:05 +00:00
|
|
|
return
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-10 23:21:40 +00:00
|
|
|
is NumericLiteral -> throw AssemblyError("a cast of a literal value should have been const-folded away")
|
2020-09-15 01:26:57 +00:00
|
|
|
else -> {}
|
|
|
|
}
|
|
|
|
|
2020-11-24 21:26:11 +00:00
|
|
|
|
|
|
|
// special case optimizations
|
2022-12-04 11:22:05 +00:00
|
|
|
if(target.kind == TargetStorageKind.VARIABLE) {
|
2021-04-28 22:11:41 +00:00
|
|
|
if(value is IdentifierReference && valueDt != DataType.UNDEFINED)
|
2020-11-24 23:17:42 +00:00
|
|
|
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt)
|
|
|
|
|
|
|
|
when (valueDt) {
|
2020-11-26 00:11:31 +00:00
|
|
|
in ByteDatatypes -> {
|
2021-11-06 17:48:42 +00:00
|
|
|
assignExpressionToRegister(value, RegisterOrPair.A, valueDt==DataType.BYTE)
|
2020-11-26 18:21:07 +00:00
|
|
|
assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.A, valueDt)
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
2021-11-06 17:48:42 +00:00
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, valueDt==DataType.WORD)
|
2020-11-26 18:21:07 +00:00
|
|
|
assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, valueDt)
|
2020-11-24 23:17:42 +00:00
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
2021-11-06 17:48:42 +00:00
|
|
|
assignExpressionToRegister(value, RegisterOrPair.FAC1, true)
|
2021-10-31 01:34:17 +00:00
|
|
|
assignTypeCastedFloatFAC1(target.asmVarname, targetDt)
|
2020-11-24 23:17:42 +00:00
|
|
|
}
|
|
|
|
in PassByReferenceDatatypes -> {
|
|
|
|
// str/array value cast (most likely to UWORD, take address-of)
|
2020-11-26 18:21:07 +00:00
|
|
|
assignExpressionToVariable(value, target.asmVarname, targetDt, null)
|
2020-11-24 23:17:42 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("strange dt in typecast assign to var: $valueDt --> $targetDt")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
2020-11-26 18:21:07 +00:00
|
|
|
return
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
|
2022-07-13 20:24:31 +00:00
|
|
|
if(valueDt in WordDatatypes && origTypeCastExpression.type == DataType.UBYTE) {
|
2020-12-31 00:02:36 +00:00
|
|
|
val parentTc = origTypeCastExpression.parent as? TypecastExpression
|
|
|
|
if(parentTc!=null && parentTc.type==DataType.UWORD) {
|
2022-07-13 20:24:31 +00:00
|
|
|
// typecast a word value to ubyte and directly back to uword
|
2020-12-31 00:02:36 +00:00
|
|
|
// generate code for lsb(value) here instead of the ubyte typecast
|
|
|
|
return assignCastViaLsbFunc(value, target)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-23 12:38:34 +00:00
|
|
|
if(valueDt==DataType.UBYTE || valueDt==DataType.BOOL) {
|
2020-12-31 00:02:36 +00:00
|
|
|
when(target.register) {
|
|
|
|
RegisterOrPair.A,
|
|
|
|
RegisterOrPair.X,
|
|
|
|
RegisterOrPair.Y -> {
|
2021-10-10 21:35:02 +00:00
|
|
|
// 'cast' an ubyte value to a byte register; no cast needed at all
|
2021-11-06 17:48:42 +00:00
|
|
|
return assignExpressionToRegister(value, target.register, false)
|
2020-12-31 00:02:36 +00:00
|
|
|
}
|
|
|
|
RegisterOrPair.AX,
|
|
|
|
RegisterOrPair.AY,
|
|
|
|
RegisterOrPair.XY,
|
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
// cast an ubyte value to a 16 bits register, just assign it and make use of the value extension
|
2021-11-06 17:48:42 +00:00
|
|
|
return assignExpressionToRegister(value, target.register!!, false)
|
2020-12-31 00:02:36 +00:00
|
|
|
}
|
|
|
|
else -> {}
|
|
|
|
}
|
|
|
|
} else if(valueDt==DataType.UWORD) {
|
|
|
|
when(target.register) {
|
|
|
|
RegisterOrPair.A,
|
|
|
|
RegisterOrPair.X,
|
|
|
|
RegisterOrPair.Y -> {
|
|
|
|
// cast an uword to a byte register, do this via lsb(value)
|
|
|
|
// generate code for lsb(value) here instead of the ubyte typecast
|
|
|
|
return assignCastViaLsbFunc(value, target)
|
|
|
|
}
|
|
|
|
RegisterOrPair.AX,
|
|
|
|
RegisterOrPair.AY,
|
|
|
|
RegisterOrPair.XY,
|
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
// 'cast' uword into a 16 bits register, just assign it
|
2021-11-06 17:48:42 +00:00
|
|
|
return assignExpressionToRegister(value, target.register!!, false)
|
2020-12-31 00:02:36 +00:00
|
|
|
}
|
|
|
|
else -> {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 18:02:51 +00:00
|
|
|
if(target.kind==TargetStorageKind.REGISTER) {
|
2022-05-03 21:43:38 +00:00
|
|
|
if(valueDt==DataType.FLOAT && target.datatype!=DataType.FLOAT) {
|
|
|
|
// have to typecast the float number on the fly down to an integer
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.FAC1, target.datatype in SignedDatatypes)
|
|
|
|
assignTypeCastedFloatFAC1("P8ZP_SCRATCH_W1", target.datatype)
|
|
|
|
assignVariableToRegister("P8ZP_SCRATCH_W1", target.register!!, target.datatype in SignedDatatypes)
|
2022-12-04 11:22:05 +00:00
|
|
|
return
|
2022-05-03 21:43:38 +00:00
|
|
|
} else {
|
2022-07-05 22:28:43 +00:00
|
|
|
if(!(valueDt isAssignableTo targetDt)) {
|
2022-12-04 11:22:05 +00:00
|
|
|
return if(valueDt in WordDatatypes && targetDt in ByteDatatypes) {
|
2022-07-05 22:28:43 +00:00
|
|
|
// word to byte, just take the lsb
|
2022-12-04 11:22:05 +00:00
|
|
|
assignCastViaLsbFunc(value, target)
|
2022-07-05 22:28:43 +00:00
|
|
|
} else if(valueDt in WordDatatypes && targetDt in WordDatatypes) {
|
|
|
|
// word to word, just assign
|
|
|
|
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
|
|
|
} else if(valueDt in ByteDatatypes && targetDt in ByteDatatypes) {
|
|
|
|
// byte to byte, just assign
|
|
|
|
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
2022-09-22 10:42:17 +00:00
|
|
|
} else if(valueDt in ByteDatatypes && targetDt in WordDatatypes) {
|
2022-09-22 11:00:47 +00:00
|
|
|
// byte to word, just assign
|
|
|
|
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
2022-12-04 11:22:05 +00:00
|
|
|
} else
|
2022-07-05 22:28:43 +00:00
|
|
|
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
|
|
|
|
}
|
2022-05-03 21:43:38 +00:00
|
|
|
}
|
2022-12-04 11:22:05 +00:00
|
|
|
}
|
|
|
|
|
2022-12-23 12:38:34 +00:00
|
|
|
if(targetDt in IntegerDatatypes && valueDt in IntegerDatatypes && valueDt!=targetDt && valueDt.isAssignableTo(targetDt)) {
|
|
|
|
require(targetDt in WordDatatypes && valueDt in ByteDatatypes) {
|
|
|
|
"should be byte to word assignment ${origTypeCastExpression.position}"
|
|
|
|
}
|
2022-12-04 11:22:05 +00:00
|
|
|
when(target.kind) {
|
|
|
|
// TargetStorageKind.VARIABLE -> {
|
|
|
|
// This has been handled already earlier on line 961.
|
|
|
|
// // byte to word, just assign to registers first, then assign to variable
|
|
|
|
// assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
|
|
|
// assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, targetDt)
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
// byte to word, just assign to registers first, then assign into array
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
|
|
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
// byte to word, just assign to registers
|
|
|
|
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
// byte to word, just assign to registers first, then push onto stack
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
|
|
|
|
asmgen.out("""
|
|
|
|
sta P8ESTACK_LO,x
|
|
|
|
tya
|
|
|
|
sta P8ESTACK_HI,x
|
|
|
|
dex""")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird target")
|
|
|
|
}
|
2022-01-23 18:02:51 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 18:31:19 +00:00
|
|
|
if(targetDt==DataType.FLOAT && (target.register==RegisterOrPair.FAC1 || target.register==RegisterOrPair.FAC2)) {
|
|
|
|
when(valueDt) {
|
|
|
|
DataType.UBYTE -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.Y, false)
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
2021-11-09 18:31:19 +00:00
|
|
|
asmgen.out(" jsr floats.FREADUY")
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
2021-11-09 18:31:19 +00:00
|
|
|
}
|
|
|
|
DataType.BYTE -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.A, true)
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
2021-11-09 18:31:19 +00:00
|
|
|
asmgen.out(" jsr floats.FREADSA")
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
2021-11-09 18:31:19 +00:00
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, false)
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
2021-11-09 18:31:19 +00:00
|
|
|
asmgen.out(" jsr floats.GIVUAYFAY")
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
2021-11-09 18:31:19 +00:00
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, true)
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingSubroutine!!)
|
2021-11-09 18:31:19 +00:00
|
|
|
asmgen.out(" jsr floats.GIVAYFAY")
|
2022-12-04 11:22:05 +00:00
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
2021-11-09 18:31:19 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid dt")
|
|
|
|
}
|
|
|
|
if(target.register==RegisterOrPair.FAC2) {
|
|
|
|
asmgen.out(" jsr floats.MOVEF")
|
|
|
|
}
|
2022-12-04 11:22:05 +00:00
|
|
|
return
|
2021-11-09 18:31:19 +00:00
|
|
|
}
|
2022-12-23 12:38:34 +00:00
|
|
|
|
|
|
|
// No more special optmized cases yet. Do the rest via more complex evaluation
|
|
|
|
// note: cannot use assignTypeCastedValue because that is ourselves :P
|
|
|
|
// NOTE: THIS MAY TURN INTO A STACK OVERFLOW ERROR IF IT CAN'T SIMPLIFY THE TYPECAST..... :-/
|
|
|
|
asmgen.assignExpressionTo(origTypeCastExpression, target)
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
|
2020-12-31 00:02:36 +00:00
|
|
|
private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) {
|
2022-02-20 01:01:48 +00:00
|
|
|
val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position)
|
2020-12-31 00:02:36 +00:00
|
|
|
lsb.linkParents(value.parent)
|
|
|
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
2021-02-19 18:02:29 +00:00
|
|
|
val assign = AsmAssignment(src, target, false, program.memsizer, value.position)
|
2020-12-31 00:02:36 +00:00
|
|
|
translateNormalAssignment(assign)
|
|
|
|
}
|
|
|
|
|
2021-10-31 01:34:17 +00:00
|
|
|
private fun assignTypeCastedFloatFAC1(targetAsmVarName: String, targetDt: DataType) {
|
2020-11-26 00:39:27 +00:00
|
|
|
|
|
|
|
if(targetDt==DataType.FLOAT)
|
|
|
|
throw AssemblyError("typecast to identical type")
|
2020-11-26 00:52:48 +00:00
|
|
|
|
|
|
|
when(targetDt) {
|
|
|
|
DataType.UBYTE -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName")
|
|
|
|
DataType.BYTE -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName")
|
|
|
|
DataType.UWORD -> asmgen.out(" jsr floats.cast_FAC1_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1")
|
|
|
|
DataType.WORD -> asmgen.out(" jsr floats.cast_FAC1_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
2020-11-26 00:39:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-19 21:58:38 +00:00
|
|
|
private fun assignTypeCastedIdentifier(targetAsmVarName: String, targetDt: DataType,
|
2020-11-24 21:26:11 +00:00
|
|
|
sourceAsmVarName: String, sourceDt: DataType) {
|
2020-11-19 21:58:38 +00:00
|
|
|
if(sourceDt == targetDt)
|
2020-11-26 00:39:27 +00:00
|
|
|
throw AssemblyError("typecast to identical type")
|
2020-11-19 21:58:38 +00:00
|
|
|
|
|
|
|
// also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression)
|
|
|
|
when(sourceDt) {
|
|
|
|
DataType.UBYTE -> {
|
|
|
|
when(targetDt) {
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.BYTE -> {
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
|
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
ldy #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
ldy $sourceAsmVarName
|
|
|
|
jsr floats.cast_from_ub""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.BYTE -> {
|
|
|
|
when(targetDt) {
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.UBYTE -> {
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
|
|
|
|
}
|
2020-11-24 23:18:07 +00:00
|
|
|
DataType.UWORD -> {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-11-24 23:18:07 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
|
|
|
|
asmgen.signExtendVariableLsb(targetAsmVarName, DataType.BYTE)
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
ldy #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
lda $sourceAsmVarName
|
|
|
|
jsr floats.cast_from_b""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
|
|
|
when(targetDt) {
|
|
|
|
DataType.BYTE, DataType.UBYTE -> {
|
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
|
|
|
|
}
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.WORD -> {
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
ldy #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
lda $sourceAsmVarName
|
|
|
|
ldy $sourceAsmVarName+1
|
|
|
|
jsr floats.cast_from_uw""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
|
|
|
when(targetDt) {
|
|
|
|
DataType.BYTE, DataType.UBYTE -> {
|
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
|
|
|
|
}
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.UWORD -> {
|
2020-11-19 21:58:38 +00:00
|
|
|
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
ldy #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
lda $sourceAsmVarName
|
|
|
|
ldy $sourceAsmVarName+1
|
|
|
|
jsr floats.cast_from_w""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
2020-11-26 00:39:27 +00:00
|
|
|
asmgen.out(" lda #<$sourceAsmVarName | ldy #>$sourceAsmVarName")
|
2020-11-19 21:58:38 +00:00
|
|
|
when(targetDt) {
|
|
|
|
DataType.UBYTE -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName")
|
|
|
|
DataType.BYTE -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName")
|
|
|
|
DataType.UWORD -> asmgen.out(" jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName+1")
|
|
|
|
DataType.WORD -> asmgen.out(" jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
2021-03-24 20:49:33 +00:00
|
|
|
DataType.STR -> throw AssemblyError("cannot typecast a string value")
|
2020-11-19 21:58:38 +00:00
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-26 00:11:31 +00:00
|
|
|
private fun assignTypeCastedRegisters(targetAsmVarName: String, targetDt: DataType,
|
|
|
|
regs: RegisterOrPair, sourceDt: DataType) {
|
|
|
|
if(sourceDt == targetDt)
|
2020-11-26 00:39:27 +00:00
|
|
|
throw AssemblyError("typecast to identical type")
|
2020-11-26 00:11:31 +00:00
|
|
|
|
|
|
|
// also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression)
|
|
|
|
when(sourceDt) {
|
|
|
|
DataType.UBYTE -> {
|
|
|
|
when(targetDt) {
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.BYTE -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
2022-12-04 11:22:05 +00:00
|
|
|
" st${regs.toString().lowercase()} $targetAsmVarName | stz $targetAsmVarName+1")
|
2020-11-26 00:11:31 +00:00
|
|
|
else
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
2022-12-04 11:22:05 +00:00
|
|
|
" st${regs.toString().lowercase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.A -> asmgen.out(" tay")
|
|
|
|
RegisterOrPair.X -> asmgen.out(" txa | tay")
|
|
|
|
RegisterOrPair.Y -> {}
|
|
|
|
else -> throw AssemblyError("non-byte regs")
|
|
|
|
}
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
lda #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2+1
|
|
|
|
jsr floats.cast_from_ub""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.BYTE -> {
|
|
|
|
when(targetDt) {
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.UBYTE -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
" st${
|
|
|
|
regs.toString().lowercase()
|
|
|
|
} $targetAsmVarName | stz $targetAsmVarName+1")
|
2020-11-26 00:11:31 +00:00
|
|
|
else
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
" st${
|
|
|
|
regs.toString().lowercase()
|
|
|
|
} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.A -> {}
|
|
|
|
RegisterOrPair.X -> asmgen.out(" txa")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" tya")
|
|
|
|
else -> throw AssemblyError("non-byte regs")
|
|
|
|
}
|
|
|
|
asmgen.signExtendAYlsb(sourceDt)
|
|
|
|
asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.A -> {}
|
|
|
|
RegisterOrPair.X -> asmgen.out(" txa")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" tya")
|
|
|
|
else -> throw AssemblyError("non-byte regs")
|
|
|
|
}
|
|
|
|
asmgen.out("""
|
|
|
|
ldy #<$targetAsmVarName
|
|
|
|
sty P8ZP_SCRATCH_W2
|
|
|
|
ldy #>$targetAsmVarName
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
jsr floats.cast_from_b""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
|
|
|
when(targetDt) {
|
|
|
|
DataType.BYTE, DataType.UBYTE -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.WORD -> {
|
2020-11-26 00:11:31 +00:00
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
else -> throw AssemblyError("non-word regs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
if(regs!=RegisterOrPair.AY)
|
|
|
|
throw AssemblyError("only supports AY here")
|
|
|
|
asmgen.out("""
|
|
|
|
pha
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
lda #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2+1
|
|
|
|
pla
|
|
|
|
jsr floats.cast_from_uw""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
|
|
|
when(targetDt) {
|
|
|
|
DataType.BYTE, DataType.UBYTE -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" st${regs.toString().lowercase().first()} $targetAsmVarName")
|
2020-11-26 00:11:31 +00:00
|
|
|
}
|
2022-06-12 14:15:08 +00:00
|
|
|
DataType.UWORD -> {
|
2020-11-26 00:11:31 +00:00
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
|
|
|
|
else -> throw AssemblyError("non-word regs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
if(regs!=RegisterOrPair.AY)
|
|
|
|
throw AssemblyError("only supports AY here")
|
|
|
|
asmgen.out("""
|
|
|
|
pha
|
|
|
|
lda #<$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
lda #>$targetAsmVarName
|
|
|
|
sta P8ZP_SCRATCH_W2+1
|
|
|
|
pla
|
|
|
|
jsr floats.cast_from_w""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
2021-03-24 20:49:33 +00:00
|
|
|
DataType.STR -> throw AssemblyError("cannot typecast a string value")
|
2020-11-26 00:11:31 +00:00
|
|
|
else -> throw AssemblyError("weird type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-23 12:36:24 +00:00
|
|
|
private fun assignStackValue(target: AsmAssignTarget) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-08-23 00:05:01 +00:00
|
|
|
when (target.datatype) {
|
2019-08-16 20:49:29 +00:00
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
2020-08-25 17:32:31 +00:00
|
|
|
asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
|
|
|
asmgen.out("""
|
|
|
|
inx
|
2020-08-25 17:32:31 +00:00
|
|
|
lda P8ESTACK_LO,x
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
2020-08-25 17:32:31 +00:00
|
|
|
lda P8ESTACK_HI,x
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
2020-08-23 16:20:57 +00:00
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
2020-09-20 21:49:36 +00:00
|
|
|
jsr floats.pop_float
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-10-04 19:11:42 +00:00
|
|
|
DataType.STR -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<${target.asmVarname}
|
2020-11-06 21:59:56 +00:00
|
|
|
ldy #>${target.asmVarname}
|
2020-10-04 19:11:42 +00:00
|
|
|
sta P8ZP_SCRATCH_W1
|
2020-11-06 21:59:56 +00:00
|
|
|
sty P8ZP_SCRATCH_W1+1
|
2020-10-04 19:11:42 +00:00
|
|
|
inx
|
|
|
|
lda P8ESTACK_HI,x
|
|
|
|
tay
|
|
|
|
lda P8ESTACK_LO,x
|
|
|
|
jsr prog8_lib.strcpy""")
|
|
|
|
}
|
2020-08-23 00:05:01 +00:00
|
|
|
else -> throw AssemblyError("weird target variable type ${target.datatype}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" inx | lda P8ESTACK_LO,x")
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-10-17 14:00:49 +00:00
|
|
|
if(target.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt()
|
2020-10-17 14:00:49 +00:00
|
|
|
when(target.datatype) {
|
|
|
|
in ByteDatatypes -> {
|
|
|
|
asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname}+$scaledIdx")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
in WordDatatypes -> {
|
|
|
|
asmgen.out("""
|
|
|
|
inx
|
|
|
|
lda P8ESTACK_LO,x
|
|
|
|
sta ${target.asmVarname}+$scaledIdx
|
|
|
|
lda P8ESTACK_HI,x
|
|
|
|
sta ${target.asmVarname}+$scaledIdx+1
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
2022-01-09 15:18:13 +00:00
|
|
|
lda #<(${target.asmVarname}+$scaledIdx)
|
|
|
|
ldy #>(${target.asmVarname}+$scaledIdx)
|
2020-10-17 14:00:49 +00:00
|
|
|
jsr floats.pop_float
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird target variable type ${target.datatype}")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
target.array!!
|
|
|
|
when(target.datatype) {
|
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y)
|
|
|
|
asmgen.out(" inx | lda P8ESTACK_LO,x | sta ${target.asmVarname},y")
|
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y)
|
|
|
|
asmgen.out("""
|
|
|
|
inx
|
|
|
|
lda P8ESTACK_LO,x
|
|
|
|
sta ${target.asmVarname},y
|
|
|
|
lda P8ESTACK_HI,x
|
|
|
|
sta ${target.asmVarname}+1,y
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.A)
|
|
|
|
asmgen.out("""
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
clc
|
|
|
|
adc #<${target.asmVarname}
|
|
|
|
bcc +
|
|
|
|
iny
|
2020-10-19 21:57:00 +00:00
|
|
|
+ jsr floats.pop_float""")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
else -> throw AssemblyError("weird dt")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when (target.datatype) {
|
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
|
|
|
when(target.register!!) {
|
2020-08-25 17:32:31 +00:00
|
|
|
RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x")
|
2020-09-07 00:29:03 +00:00
|
|
|
RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
2020-08-25 17:32:31 +00:00
|
|
|
RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x")
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" inx | txy | ldx #0 | lda P8ESTACK_LO,y")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" inx | ldy #0 | lda P8ESTACK_LO,x")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 22:45:26 +00:00
|
|
|
inx
|
|
|
|
lda P8ESTACK_LO,x
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 22:45:26 +00:00
|
|
|
lda #0
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-09-12 00:48:16 +00:00
|
|
|
else -> throw AssemblyError("can't assign byte from stack to register pair XY")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> {
|
|
|
|
when(target.register!!) {
|
2020-09-07 00:29:03 +00:00
|
|
|
RegisterOrPair.AX -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AY-> asmgen.out(" inx | ldy P8ESTACK_HI,x | lda P8ESTACK_LO,x")
|
2020-09-07 00:29:03 +00:00
|
|
|
RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 22:45:26 +00:00
|
|
|
inx
|
|
|
|
lda P8ESTACK_LO,x
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 22:45:26 +00:00
|
|
|
lda P8ESTACK_HI,x
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
else -> throw AssemblyError("can't assign word to single byte register")
|
|
|
|
}
|
|
|
|
}
|
2020-11-23 21:14:45 +00:00
|
|
|
DataType.FLOAT -> {
|
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.pop_float_fac1")
|
|
|
|
RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.pop_float_fac2")
|
|
|
|
else -> throw AssemblyError("can only assign float to Fac1 or 2")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 21:28:25 +00:00
|
|
|
else -> throw AssemblyError("weird dt")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:31:45 +00:00
|
|
|
private fun assignAddressOf(target: AsmAssignTarget, sourceName: String) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
|
|
|
sty ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2020-12-08 21:27:42 +00:00
|
|
|
throw AssemblyError("can't store word into memory byte")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-12-08 21:27:42 +00:00
|
|
|
asmgen.out(" lda #<$sourceName | ldy #>$sourceName")
|
|
|
|
assignRegisterpairWord(target, RegisterOrPair.AY)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #>$sourceName | lda #<$sourceName")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #>$sourceName | lda #<$sourceName")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #>$sourceName | ldx #<$sourceName")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 19:38:00 +00:00
|
|
|
lda #<$sourceName
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 19:38:00 +00:00
|
|
|
lda #>$sourceName
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 19:38:00 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
else -> throw AssemblyError("can't load address in a single 8-bit register")
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:22:51 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
2020-10-11 11:31:45 +00:00
|
|
|
lda #<$sourceName
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-10-11 11:31:45 +00:00
|
|
|
lda #>$sourceName
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_HI,x
|
2020-08-25 15:22:51 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:31:45 +00:00
|
|
|
private fun assignVariableString(target: AsmAssignTarget, sourceName: String) {
|
2020-10-04 16:18:58 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
when(target.datatype) {
|
|
|
|
DataType.UWORD -> {
|
|
|
|
asmgen.out("""
|
2020-12-06 06:52:58 +00:00
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
|
|
|
sta ${target.asmVarname}
|
|
|
|
sty ${target.asmVarname}+1
|
2020-10-04 16:18:58 +00:00
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<${target.asmVarname}
|
2020-11-06 21:59:56 +00:00
|
|
|
ldy #>${target.asmVarname}
|
2020-10-04 16:18:58 +00:00
|
|
|
sta P8ZP_SCRATCH_W1
|
2020-11-06 21:59:56 +00:00
|
|
|
sty P8ZP_SCRATCH_W1+1
|
2020-10-04 16:18:58 +00:00
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
|
|
|
jsr prog8_lib.strcpy""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("assign string to incompatible variable type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$sourceName
|
2020-11-06 21:59:56 +00:00
|
|
|
ldy #>$sourceName+1
|
2020-10-04 16:18:58 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2021-11-04 21:44:31 +00:00
|
|
|
tya
|
|
|
|
sta P8ESTACK_HI,x
|
2020-10-04 16:18:58 +00:00
|
|
|
dex""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("string-assign to weird target")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:31:45 +00:00
|
|
|
private fun assignVariableWord(target: AsmAssignTarget, sourceName: String) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
ldy $sourceName+1
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
|
|
|
sty ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
|
|
|
throw AssemblyError("no asm gen for assign wordvar $sourceName to memory ${target.memory}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-10-17 14:00:49 +00:00
|
|
|
target.array!!
|
|
|
|
if(target.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt()
|
2020-10-17 14:00:49 +00:00
|
|
|
when(target.datatype) {
|
|
|
|
in ByteDatatypes -> {
|
|
|
|
asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx")
|
|
|
|
}
|
|
|
|
in WordDatatypes -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta ${target.asmVarname}+$scaledIdx
|
|
|
|
lda $sourceName+1
|
|
|
|
sta ${target.asmVarname}+$scaledIdx+1
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
2022-01-09 15:18:13 +00:00
|
|
|
lda #<(${target.asmVarname}+$scaledIdx)
|
|
|
|
ldy #>(${target.asmVarname}+$scaledIdx)
|
2020-10-17 14:00:49 +00:00
|
|
|
jsr floats.copy_float
|
|
|
|
""")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
else -> throw AssemblyError("weird target variable type ${target.datatype}")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
when(target.datatype) {
|
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y)
|
|
|
|
asmgen.out(" lda $sourceName | sta ${target.asmVarname},y")
|
|
|
|
}
|
|
|
|
DataType.UWORD, DataType.WORD -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.Y)
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta ${target.asmVarname},y
|
|
|
|
lda $sourceName+1
|
|
|
|
sta ${target.asmVarname}+1,y
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
DataType.FLOAT -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array, target.datatype, CpuRegister.A)
|
|
|
|
asmgen.out("""
|
|
|
|
ldy #<$sourceName
|
|
|
|
sty P8ZP_SCRATCH_W1
|
|
|
|
ldy #>$sourceName
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
clc
|
|
|
|
adc #<${target.asmVarname}
|
|
|
|
bcc +
|
|
|
|
iny
|
2021-11-30 01:27:37 +00:00
|
|
|
+ jsr floats.copy_float""")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
else -> throw AssemblyError("weird dt")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx $sourceName+1 | lda $sourceName")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy $sourceName+1 | lda $sourceName")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy $sourceName+1 | ldx $sourceName")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 19:38:00 +00:00
|
|
|
lda $sourceName
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 19:38:00 +00:00
|
|
|
lda $sourceName+1
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 19:38:00 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
else -> throw AssemblyError("can't load word in a single 8-bit register")
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
2020-10-23 01:45:09 +00:00
|
|
|
lda $sourceName
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-10-23 01:45:09 +00:00
|
|
|
lda $sourceName+1
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_HI,x
|
2020-08-25 15:43:35 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-26 20:34:00 +00:00
|
|
|
internal fun assignFAC2float(target: AsmAssignTarget) {
|
|
|
|
asmgen.out(" jsr floats.MOVFA") // fac2 -> fac1
|
|
|
|
assignFAC1float(target)
|
|
|
|
}
|
|
|
|
|
2020-11-27 23:44:38 +00:00
|
|
|
internal fun assignFAC1float(target: AsmAssignTarget) {
|
2020-10-30 22:02:20 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.out("""
|
|
|
|
stx P8ZP_SCRATCH_REG
|
|
|
|
ldx #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
jsr floats.MOVMF
|
|
|
|
ldx P8ZP_SCRATCH_REG
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1""")
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = target.array!!.indexer.constIndex()
|
|
|
|
if(constIndex!=null) {
|
|
|
|
asmgen.out(" lda #$constIndex")
|
2020-10-30 22:02:20 +00:00
|
|
|
} else {
|
2021-03-22 18:33:57 +00:00
|
|
|
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference)
|
2020-10-30 22:02:20 +00:00
|
|
|
asmgen.out(" lda $asmvarname")
|
|
|
|
}
|
|
|
|
asmgen.out(" jsr floats.set_array_float_from_fac1")
|
|
|
|
}
|
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to mem byte")
|
2020-11-24 00:09:24 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
if (target.register!! != RegisterOrPair.FAC1)
|
2022-04-13 22:38:31 +00:00
|
|
|
throw AssemblyError("can't assign Fac1 float to another register")
|
2020-11-24 00:09:24 +00:00
|
|
|
}
|
2020-10-30 22:02:20 +00:00
|
|
|
TargetStorageKind.STACK -> asmgen.out(" jsr floats.push_fac1")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-22 16:16:07 +00:00
|
|
|
private fun assignFloatFromAY(target: AsmAssignTarget) {
|
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.out("""
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
jsr floats.copy_float""")
|
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
asmgen.out("""
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1""")
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = target.array!!.indexer.constIndex()
|
|
|
|
if(constIndex!=null) {
|
|
|
|
asmgen.out(" lda #$constIndex")
|
2020-11-22 16:16:07 +00:00
|
|
|
} else {
|
2021-03-22 18:33:57 +00:00
|
|
|
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference)
|
2020-11-22 16:16:07 +00:00
|
|
|
asmgen.out(" lda $asmvarname")
|
|
|
|
}
|
|
|
|
asmgen.out(" jsr floats.set_array_float")
|
|
|
|
}
|
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to mem byte")
|
2020-11-23 21:14:45 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.MOVFM")
|
|
|
|
RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.CONUPK")
|
|
|
|
else -> throw AssemblyError("can only assign float to Fac1 or 2")
|
|
|
|
}
|
|
|
|
}
|
2020-11-22 16:16:07 +00:00
|
|
|
TargetStorageKind.STACK -> asmgen.out(" jsr floats.push_float")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:31:45 +00:00
|
|
|
private fun assignVariableFloat(target: AsmAssignTarget, sourceName: String) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
2022-01-09 15:18:13 +00:00
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
jsr floats.copy_float""")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-10-19 21:57:00 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda #<$sourceName
|
|
|
|
ldy #>$sourceName
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W2
|
|
|
|
sty P8ZP_SCRATCH_W2+1""")
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = target.array!!.indexer.constIndex()
|
|
|
|
if(constIndex!=null) {
|
|
|
|
asmgen.out(" lda #$constIndex")
|
2020-10-19 21:57:00 +00:00
|
|
|
} else {
|
2021-03-22 18:33:57 +00:00
|
|
|
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference)
|
2020-10-19 21:57:00 +00:00
|
|
|
asmgen.out(" lda $asmvarname")
|
|
|
|
}
|
|
|
|
asmgen.out(" jsr floats.set_array_float")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to mem byte")
|
2020-11-23 21:14:45 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.FAC1 -> asmgen.out(" lda #<$sourceName | ldy #>$sourceName | jsr floats.MOVFM")
|
|
|
|
RegisterOrPair.FAC2 -> asmgen.out(" lda #<$sourceName | ldy #>$sourceName | jsr floats.CONUPK")
|
|
|
|
else -> throw AssemblyError("can only assign float to Fac1 or 2")
|
|
|
|
}
|
|
|
|
}
|
2020-09-20 21:49:36 +00:00
|
|
|
TargetStorageKind.STACK -> asmgen.out(" lda #<$sourceName | ldy #>$sourceName | jsr floats.push_float")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 11:31:45 +00:00
|
|
|
private fun assignVariableByte(target: AsmAssignTarget, sourceName: String) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" lda $sourceName")
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2020-08-20 16:07:48 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2022-06-06 16:30:19 +00:00
|
|
|
if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) {
|
|
|
|
// assigning an indexed pointer var
|
|
|
|
if (target.constArrayIndexValue==0u) {
|
|
|
|
asmgen.out(" lda $sourceName")
|
|
|
|
asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar)
|
|
|
|
} else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y)
|
|
|
|
if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) {
|
|
|
|
asmgen.out(" lda $sourceName | sta (${target.asmVarname}),y")
|
|
|
|
} else {
|
|
|
|
asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1")
|
|
|
|
asmgen.out(" lda $sourceName | sta (P8ZP_SCRATCH_W2),y")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
if (target.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val scaledIdx = target.constArrayIndexValue!! * program.memsizer.memorySize(target.datatype).toUInt()
|
2020-10-17 14:00:49 +00:00
|
|
|
asmgen.out(" lda $sourceName | sta ${target.asmVarname}+$scaledIdx")
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, target.datatype, CpuRegister.Y)
|
|
|
|
asmgen.out(" lda $sourceName | sta ${target.asmVarname},y")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> asmgen.out(" lda $sourceName")
|
|
|
|
RegisterOrPair.X -> asmgen.out(" ldx $sourceName")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName")
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda $sourceName")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda $sourceName")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx $sourceName")
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 22:45:26 +00:00
|
|
|
lda $sourceName
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 22:45:26 +00:00
|
|
|
lda #0
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
2020-10-23 01:45:09 +00:00
|
|
|
lda $sourceName
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-08-25 15:43:35 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-10 13:39:48 +00:00
|
|
|
private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) {
|
|
|
|
val sourceName = asmgen.asmVariableName(bytevar)
|
|
|
|
when (wordtarget.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta ${wordtarget.asmVarname}
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
lda #0
|
|
|
|
+ sta ${wordtarget.asmVarname}+1
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
2021-04-06 20:46:52 +00:00
|
|
|
if (wordtarget.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val scaledIdx = wordtarget.constArrayIndexValue!! * 2u
|
2021-04-06 20:46:52 +00:00
|
|
|
asmgen.out(" lda $sourceName")
|
|
|
|
asmgen.signExtendAYlsb(DataType.BYTE)
|
|
|
|
asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1")
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
asmgen.saveRegisterLocal(CpuRegister.X, wordtarget.scope!!)
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array!!, wordtarget.datatype, CpuRegister.X)
|
|
|
|
asmgen.out(" lda $sourceName")
|
|
|
|
asmgen.signExtendAYlsb(DataType.BYTE)
|
|
|
|
asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x")
|
|
|
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
|
|
|
}
|
2020-10-10 13:39:48 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(wordtarget.register!!) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
pha
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
2022-01-27 17:05:25 +00:00
|
|
|
lda #0
|
2020-10-10 13:39:48 +00:00
|
|
|
+ tax
|
|
|
|
pla""")
|
|
|
|
RegisterOrPair.AY -> asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
pha
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
2022-01-27 17:05:25 +00:00
|
|
|
lda #0
|
2020-10-10 13:39:48 +00:00
|
|
|
+ tay
|
|
|
|
pla""")
|
|
|
|
RegisterOrPair.XY -> asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
tax
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
2022-01-27 17:05:25 +00:00
|
|
|
lda #0
|
2020-10-10 13:39:48 +00:00
|
|
|
+ tay""")
|
2022-01-27 17:05:25 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val regname = wordtarget.register.name.lowercase()
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta cx16.$regname
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
lda #0
|
|
|
|
+ sta cx16.$regname+1""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("only reg pairs allowed as word target ${wordtarget.register}")
|
2020-10-10 13:39:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta P8ESTACK_LO,x
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
lda #0
|
|
|
|
+ sta P8ESTACK_HI,x
|
|
|
|
dex""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("target type isn't word")
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 01:26:57 +00:00
|
|
|
|
2020-10-10 13:39:48 +00:00
|
|
|
private fun assignVariableUByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference) {
|
2020-09-15 01:26:57 +00:00
|
|
|
val sourceName = asmgen.asmVariableName(bytevar)
|
|
|
|
when(wordtarget.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname}")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz ${wordtarget.asmVarname}+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta ${wordtarget.asmVarname}+1")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-10-17 14:00:49 +00:00
|
|
|
if (wordtarget.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val scaledIdx = wordtarget.constArrayIndexValue!! * 2u
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname}+$scaledIdx")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz ${wordtarget.asmVarname}+$scaledIdx+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta ${wordtarget.asmVarname}+$scaledIdx+1")
|
2020-10-17 14:00:49 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array!!, wordtarget.datatype, CpuRegister.Y)
|
2020-12-24 03:08:52 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta ${wordtarget.asmVarname},y
|
|
|
|
iny
|
|
|
|
lda #0
|
|
|
|
sta ${wordtarget.asmVarname},y""")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(wordtarget.register!!) {
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda $sourceName")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda $sourceName")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx $sourceName")
|
2022-01-27 17:05:25 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val regname = wordtarget.register.name.lowercase()
|
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
|
|
|
asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("only reg pairs allowed as word target")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz P8ESTACK_HI,x | dex")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
2020-10-10 13:39:48 +00:00
|
|
|
else -> throw AssemblyError("target type isn't word")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-27 23:44:38 +00:00
|
|
|
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) {
|
2022-10-23 09:57:23 +00:00
|
|
|
// we make an exception in the type check for assigning something to a register pair AX, AY or XY
|
|
|
|
// these will be correctly typecasted from a byte to a word value here
|
|
|
|
if(target.register !in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY))
|
2022-12-03 18:56:54 +00:00
|
|
|
require(target.datatype in ByteDatatypes) { "assign target must be byte type ${target.origAstTarget?.position ?: ""}"}
|
2020-12-25 11:36:11 +00:00
|
|
|
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" st${register.name.lowercase()} ${target.asmVarname}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-19 23:28:54 +00:00
|
|
|
when(register) {
|
|
|
|
CpuRegister.A -> {}
|
|
|
|
CpuRegister.X -> asmgen.out(" txa")
|
|
|
|
CpuRegister.Y -> asmgen.out(" tya")
|
|
|
|
}
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-12-08 21:54:20 +00:00
|
|
|
if (target.constArrayIndexValue!=null) {
|
|
|
|
when (register) {
|
|
|
|
CpuRegister.A -> asmgen.out(" sta ${target.asmVarname}+${target.constArrayIndexValue}")
|
|
|
|
CpuRegister.X -> asmgen.out(" stx ${target.asmVarname}+${target.constArrayIndexValue}")
|
|
|
|
CpuRegister.Y -> asmgen.out(" sty ${target.asmVarname}+${target.constArrayIndexValue}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-12-08 21:54:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
when (register) {
|
|
|
|
CpuRegister.A -> {}
|
|
|
|
CpuRegister.X -> asmgen.out(" txa")
|
|
|
|
CpuRegister.Y -> asmgen.out(" tya")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2021-03-22 18:33:57 +00:00
|
|
|
val indexVar = target.array!!.indexer.indexExpr as IdentifierReference
|
|
|
|
asmgen.out(" ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname},y")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(register) {
|
|
|
|
CpuRegister.A -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> {}
|
|
|
|
RegisterOrPair.X -> { asmgen.out(" tax") }
|
|
|
|
RegisterOrPair.Y -> { asmgen.out(" tay") }
|
2020-09-12 00:48:16 +00:00
|
|
|
RegisterOrPair.AY -> { asmgen.out(" ldy #0") }
|
|
|
|
RegisterOrPair.AX -> { asmgen.out(" ldx #0") }
|
|
|
|
RegisterOrPair.XY -> { asmgen.out(" tax | ldy #0") }
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
// only assign a single byte to the virtual register's Lsb
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" sta cx16.${target.register.toString().lowercase()}")
|
2020-12-21 22:45:26 +00:00
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
CpuRegister.X -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> { asmgen.out(" txa") }
|
|
|
|
RegisterOrPair.X -> { }
|
|
|
|
RegisterOrPair.Y -> { asmgen.out(" txy") }
|
2020-09-12 00:48:16 +00:00
|
|
|
RegisterOrPair.AY -> { asmgen.out(" txa | ldy #0") }
|
|
|
|
RegisterOrPair.AX -> { asmgen.out(" txa | ldx #0") }
|
|
|
|
RegisterOrPair.XY -> { asmgen.out(" ldy #0") }
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
// only assign a single byte to the virtual register's Lsb
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" stx cx16.${target.register.toString().lowercase()}")
|
2020-12-21 22:45:26 +00:00
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
CpuRegister.Y -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> { asmgen.out(" tya") }
|
|
|
|
RegisterOrPair.X -> { asmgen.out(" tyx") }
|
|
|
|
RegisterOrPair.Y -> { }
|
2020-09-12 00:48:16 +00:00
|
|
|
RegisterOrPair.AY -> { asmgen.out(" tya | ldy #0") }
|
|
|
|
RegisterOrPair.AX -> { asmgen.out(" tya | ldx #0") }
|
|
|
|
RegisterOrPair.XY -> { asmgen.out(" tya | tax | ldy #0") }
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected type cast to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
// only assign a single byte to the virtual register's Lsb
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" sty cx16.${target.register.toString().lowercase()}")
|
2020-12-25 11:36:11 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
when(register) {
|
2020-08-25 17:32:31 +00:00
|
|
|
CpuRegister.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
2020-09-07 00:29:03 +00:00
|
|
|
CpuRegister.X -> throw AssemblyError("can't use X here")
|
2020-08-25 17:32:31 +00:00
|
|
|
CpuRegister.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
2020-08-25 15:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-27 23:44:38 +00:00
|
|
|
internal fun assignRegisterpairWord(target: AsmAssignTarget, regs: RegisterOrPair) {
|
2022-12-03 18:56:54 +00:00
|
|
|
require(target.datatype in NumericDatatypes || target.datatype in PassByReferenceDatatypes) {
|
|
|
|
"assign target must be word type ${target.origAstTarget?.position ?: ""}"
|
|
|
|
}
|
2020-10-30 22:02:20 +00:00
|
|
|
if(target.datatype==DataType.FLOAT)
|
|
|
|
throw AssemblyError("float value should be from FAC1 not from registerpair memory pointer")
|
|
|
|
|
2020-10-07 00:22:25 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname} | stx ${target.asmVarname}+1")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname} | sty ${target.asmVarname}+1")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname} | sty ${target.asmVarname}+1")
|
2021-02-06 12:01:45 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val srcReg = asmgen.asmSymbolName(regs)
|
|
|
|
asmgen.out("""
|
|
|
|
lda $srcReg
|
|
|
|
sta ${target.asmVarname}
|
|
|
|
lda $srcReg+1
|
|
|
|
sta ${target.asmVarname}+1""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-12-08 21:54:20 +00:00
|
|
|
if (target.constArrayIndexValue!=null) {
|
2021-11-20 23:48:23 +00:00
|
|
|
val idx = target.constArrayIndexValue!! * 2u
|
2020-12-08 21:54:20 +00:00
|
|
|
when (regs) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname}+$idx | stx ${target.asmVarname}+$idx+1")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1")
|
2021-02-06 12:01:45 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val srcReg = asmgen.asmSymbolName(regs)
|
|
|
|
asmgen.out("""
|
|
|
|
lda $srcReg
|
|
|
|
sta ${target.asmVarname}+$idx
|
|
|
|
lda $srcReg+1
|
|
|
|
sta ${target.asmVarname}+$idx+1""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-12-08 21:54:20 +00:00
|
|
|
}
|
2020-10-28 22:13:53 +00:00
|
|
|
}
|
2020-12-08 21:54:20 +00:00
|
|
|
else {
|
2021-02-06 12:01:45 +00:00
|
|
|
if (regs !in Cx16VirtualRegisters) {
|
|
|
|
when (regs) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" pha | txa | pha")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" pha | tya | pha")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha")
|
|
|
|
else -> throw AssemblyError("expected reg pair")
|
|
|
|
}
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true)
|
|
|
|
asmgen.out("""
|
|
|
|
pla
|
|
|
|
sta ${target.asmVarname},y
|
|
|
|
dey
|
|
|
|
pla
|
|
|
|
sta ${target.asmVarname},y""")
|
|
|
|
} else {
|
|
|
|
val srcReg = asmgen.asmSymbolName(regs)
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true)
|
|
|
|
asmgen.out("""
|
|
|
|
lda $srcReg+1
|
|
|
|
sta ${target.asmVarname},y
|
|
|
|
dey
|
|
|
|
lda $srcReg
|
|
|
|
sta ${target.asmVarname},y""")
|
2020-12-08 21:54:20 +00:00
|
|
|
}
|
2021-02-06 12:01:45 +00:00
|
|
|
}
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(regs) {
|
|
|
|
RegisterOrPair.AX -> when(target.register!!) {
|
|
|
|
RegisterOrPair.AY -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG") }
|
|
|
|
RegisterOrPair.AX -> { }
|
|
|
|
RegisterOrPair.XY -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG | tax") }
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
|
|
|
stx cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2021-02-06 12:01:45 +00:00
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
RegisterOrPair.AY -> when(target.register!!) {
|
|
|
|
RegisterOrPair.AY -> { }
|
|
|
|
RegisterOrPair.AX -> { asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") }
|
|
|
|
RegisterOrPair.XY -> { asmgen.out(" tax") }
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
|
|
|
sty cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2021-02-06 12:01:45 +00:00
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
RegisterOrPair.XY -> when(target.register!!) {
|
|
|
|
RegisterOrPair.AY -> { asmgen.out(" txa") }
|
|
|
|
RegisterOrPair.AX -> { asmgen.out(" txa | sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") }
|
|
|
|
RegisterOrPair.XY -> { }
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
|
|
|
stx cx16.${target.register.toString().lowercase()}
|
|
|
|
sty cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2021-02-06 12:01:45 +00:00
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
|
|
|
}
|
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val srcReg = asmgen.asmSymbolName(regs)
|
|
|
|
if(regs!=target.register) {
|
|
|
|
when(target.register) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" lda $srcReg | ldx $srcReg+1")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" lda $srcReg | ldy $srcReg+1")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldx $srcReg | ldy $srcReg+1")
|
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val targetReg = asmgen.asmSymbolName(target.register!!)
|
|
|
|
asmgen.out(" lda $srcReg | sta $targetReg | lda $srcReg+1 | sta $targetReg+1")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid reg")
|
|
|
|
}
|
|
|
|
}
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
2021-02-06 12:01:45 +00:00
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
when(regs) {
|
2021-11-04 21:44:31 +00:00
|
|
|
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
2020-10-07 00:22:25 +00:00
|
|
|
RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't use X here")
|
2021-02-06 12:01:45 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
|
|
|
val srcReg = asmgen.asmSymbolName(regs)
|
|
|
|
asmgen.out("""
|
|
|
|
lda $srcReg
|
|
|
|
sta P8ESTACK_LO,x
|
|
|
|
lda $srcReg+1
|
|
|
|
sta P8ESTACK_HI,x
|
|
|
|
dex""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register")
|
2020-10-07 00:22:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't store word into memory byte")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 12:36:24 +00:00
|
|
|
private fun assignConstantWord(target: AsmAssignTarget, word: Int) {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(word==0 && asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
2020-12-22 16:59:47 +00:00
|
|
|
// optimize setting zero value for this processor
|
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.out(" stz ${target.asmVarname} | stz ${target.asmVarname}+1")
|
|
|
|
}
|
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-12-04 00:03:51 +00:00
|
|
|
throw AssemblyError("memory is bytes not words")
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y)
|
|
|
|
asmgen.out("""
|
|
|
|
lda #0
|
|
|
|
sta ${target.asmVarname},y
|
|
|
|
sta ${target.asmVarname}+1,y
|
|
|
|
""")
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" lda #0 | tax")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" lda #0 | tay")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldx #0 | ldy #0")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
" stz cx16.${
|
|
|
|
target.register.toString().lowercase()
|
|
|
|
} | stz cx16.${target.register.toString().lowercase()}+1")
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid register for word value")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out(" stz P8ESTACK_LO,x | stz P8ESTACK_HI,x | dex")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-04-06 16:19:14 +00:00
|
|
|
if (word ushr 8 == word and 255) {
|
2019-08-16 20:49:29 +00:00
|
|
|
// lsb=msb
|
|
|
|
asmgen.out("""
|
|
|
|
lda #${(word and 255).toHex()}
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
|
|
|
sta ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
} else {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<${word.toHex()}
|
|
|
|
ldy #>${word.toHex()}
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
|
|
|
sty ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
|
|
|
throw AssemblyError("no asm gen for assign word $word to memory ${target.memory}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-10-19 21:57:00 +00:00
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y)
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda #<${word.toHex()}
|
2020-08-23 16:32:53 +00:00
|
|
|
sta ${target.asmVarname},y
|
2019-08-16 20:49:29 +00:00
|
|
|
lda #>${word.toHex()}
|
2020-08-23 16:32:53 +00:00
|
|
|
sta ${target.asmVarname}+1,y
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
when(target.register!!) {
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #>${word.toHex()} | lda #<${word.toHex()}")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #>${word.toHex()} | lda #<${word.toHex()}")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #>${word.toHex()} | ldx #<${word.toHex()}")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 18:19:53 +00:00
|
|
|
lda #<${word.toHex()}
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 18:19:53 +00:00
|
|
|
lda #>${word.toHex()}
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 18:19:53 +00:00
|
|
|
""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid register for word value")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #<${word.toHex()}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-08-25 15:43:35 +00:00
|
|
|
lda #>${word.toHex()}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_HI,x
|
2020-08-25 15:43:35 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-20 23:48:23 +00:00
|
|
|
private fun assignConstantByte(target: AsmAssignTarget, byte: Int) {
|
|
|
|
if(byte==0 && asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
2020-12-22 16:59:47 +00:00
|
|
|
// optimize setting zero value for this cpu
|
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.out(" stz ${target.asmVarname} ")
|
|
|
|
}
|
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-12-04 00:03:51 +00:00
|
|
|
asmgen.out(" lda #0")
|
2021-01-19 18:25:23 +00:00
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
2022-06-06 16:30:19 +00:00
|
|
|
if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) {
|
|
|
|
// assigning an indexed pointer var
|
|
|
|
if (target.constArrayIndexValue==0u) {
|
|
|
|
asmgen.out(" lda #0")
|
|
|
|
asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar)
|
|
|
|
} else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y)
|
|
|
|
if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) {
|
|
|
|
asmgen.out(" lda #0 | sta (${target.asmVarname}),y")
|
|
|
|
} else {
|
|
|
|
asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1")
|
|
|
|
asmgen.out(" lda #0 | sta (P8ZP_SCRATCH_W2),y")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-12-22 16:59:47 +00:00
|
|
|
if (target.constArrayIndexValue!=null) {
|
|
|
|
val indexValue = target.constArrayIndexValue!!
|
|
|
|
asmgen.out(" stz ${target.asmVarname}+$indexValue")
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y)
|
2020-12-24 03:08:52 +00:00
|
|
|
asmgen.out(" lda #0 | sta ${target.asmVarname},y")
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> asmgen.out(" lda #0")
|
|
|
|
RegisterOrPair.X -> asmgen.out(" ldx #0")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" ldy #0")
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" lda #0 | tax")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" lda #0 | tay")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldx #0 | ldy #0")
|
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2022-06-27 20:26:40 +00:00
|
|
|
asmgen.out(" stz cx16.${target.register.toString().lowercase()} | stz cx16.${target.register.toString().lowercase()}+1")
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out(" stz P8ESTACK_LO,x | dex")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-08-23 20:36:49 +00:00
|
|
|
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname} ")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" lda #${byte.toHex()}")
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2022-06-06 16:30:19 +00:00
|
|
|
if(target.origAstTarget?.arrayindexed?.arrayvar?.targetVarDecl(program)?.datatype==DataType.UWORD) {
|
|
|
|
// assigning an indexed pointer var
|
|
|
|
if (target.constArrayIndexValue==0u) {
|
|
|
|
asmgen.out(" lda #${byte.toHex()}")
|
|
|
|
asmgen.storeAIntoPointerVar(target.origAstTarget.arrayindexed!!.arrayvar)
|
|
|
|
} else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y)
|
|
|
|
if (asmgen.isZpVar(target.origAstTarget.arrayindexed!!.arrayvar)) {
|
|
|
|
asmgen.out(" lda #${byte.toHex()} | sta (${target.asmVarname}),y")
|
|
|
|
} else {
|
|
|
|
asmgen.out(" lda ${target.asmVarname} | sta P8ZP_SCRATCH_W2 | lda ${target.asmVarname}+1 | sta P8ZP_SCRATCH_W2+1")
|
|
|
|
asmgen.out(" lda #${byte.toHex()} | sta (P8ZP_SCRATCH_W2),y")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-10-17 14:00:49 +00:00
|
|
|
if (target.constArrayIndexValue!=null) {
|
|
|
|
val indexValue = target.constArrayIndexValue!!
|
|
|
|
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname}+$indexValue")
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UBYTE, CpuRegister.Y)
|
2022-06-06 16:30:19 +00:00
|
|
|
asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname},y")
|
2020-08-23 20:36:49 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> asmgen.out(" lda #${byte.toHex()}")
|
|
|
|
RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" ldy #${byte.toHex()}")
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda #${byte.toHex()}")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda #${byte.toHex()}")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx #${byte.toHex()}")
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
" lda #${byte.toHex()} | sta cx16.${
|
|
|
|
target.register.toString().lowercase()
|
|
|
|
}")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(" stz cx16.${target.register.toString().lowercase()}+1\n")
|
2020-12-25 21:30:40 +00:00
|
|
|
else
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
" lda #0 | sta cx16.${
|
|
|
|
target.register.toString().lowercase()
|
|
|
|
}+1\n")
|
2020-12-21 22:45:26 +00:00
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda #${byte.toHex()}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-08-25 15:43:35 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 12:36:24 +00:00
|
|
|
private fun assignConstantFloat(target: AsmAssignTarget, float: Double) {
|
2020-04-06 16:19:14 +00:00
|
|
|
if (float == 0.0) {
|
2019-08-16 20:49:29 +00:00
|
|
|
// optimized case for float zero
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-08-28 19:42:53 +00:00
|
|
|
asmgen.out("""
|
|
|
|
stz ${target.asmVarname}
|
|
|
|
stz ${target.asmVarname}+1
|
|
|
|
stz ${target.asmVarname}+2
|
|
|
|
stz ${target.asmVarname}+3
|
|
|
|
stz ${target.asmVarname}+4
|
|
|
|
""")
|
|
|
|
else
|
|
|
|
asmgen.out("""
|
2019-08-16 20:49:29 +00:00
|
|
|
lda #0
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
|
|
|
sta ${target.asmVarname}+1
|
|
|
|
sta ${target.asmVarname}+2
|
|
|
|
sta ${target.asmVarname}+3
|
|
|
|
sta ${target.asmVarname}+4
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = target.array!!.indexer.constIndex()
|
|
|
|
if (constIndex!=null) {
|
|
|
|
val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT)
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out("""
|
|
|
|
stz ${target.asmVarname}+$indexValue
|
|
|
|
stz ${target.asmVarname}+$indexValue+1
|
|
|
|
stz ${target.asmVarname}+$indexValue+2
|
|
|
|
stz ${target.asmVarname}+$indexValue+3
|
|
|
|
stz ${target.asmVarname}+$indexValue+4
|
|
|
|
""")
|
|
|
|
else
|
|
|
|
asmgen.out("""
|
|
|
|
lda #0
|
|
|
|
sta ${target.asmVarname}+$indexValue
|
|
|
|
sta ${target.asmVarname}+$indexValue+1
|
|
|
|
sta ${target.asmVarname}+$indexValue+2
|
|
|
|
sta ${target.asmVarname}+$indexValue+3
|
|
|
|
sta ${target.asmVarname}+$indexValue+4
|
|
|
|
""")
|
2019-08-16 20:49:29 +00:00
|
|
|
} else {
|
2021-03-22 18:33:57 +00:00
|
|
|
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference)
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
2020-08-23 16:20:57 +00:00
|
|
|
lda #<${target.asmVarname}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W1
|
2020-08-23 16:20:57 +00:00
|
|
|
lda #>${target.asmVarname}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W1+1
|
2020-10-19 21:57:00 +00:00
|
|
|
lda $asmvarname
|
2020-09-20 21:49:36 +00:00
|
|
|
jsr floats.set_0_array_float
|
2020-04-03 20:44:10 +00:00
|
|
|
""")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte")
|
2020-11-23 21:14:45 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
2022-02-08 20:38:27 +00:00
|
|
|
val floatConst = allocator.getFloatAsmConst(float)
|
2020-11-23 21:14:45 +00:00
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM")
|
|
|
|
RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK")
|
|
|
|
else -> throw AssemblyError("can only assign float to Fac1 or 2")
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
2022-02-08 20:38:27 +00:00
|
|
|
val floatConst = allocator.getFloatAsmConst(float)
|
2020-09-20 21:49:36 +00:00
|
|
|
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
|
2020-08-25 15:43:35 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// non-zero value
|
2022-02-08 20:38:27 +00:00
|
|
|
val constFloat = allocator.getFloatAsmConst(float)
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
2022-01-09 15:18:13 +00:00
|
|
|
lda #<$constFloat
|
|
|
|
ldy #>$constFloat
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<${target.asmVarname}
|
|
|
|
ldy #>${target.asmVarname}
|
|
|
|
jsr floats.copy_float""")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-08-23 16:32:53 +00:00
|
|
|
val arrayVarName = target.asmVarname
|
2021-03-22 18:33:57 +00:00
|
|
|
val constIndex = target.array!!.indexer.constIndex()
|
|
|
|
if (constIndex!=null) {
|
|
|
|
val indexValue = constIndex * program.memsizer.memorySize(DataType.FLOAT)
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
2022-01-09 15:18:13 +00:00
|
|
|
lda #<$constFloat
|
|
|
|
ldy #>$constFloat
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
lda #<($arrayVarName+$indexValue)
|
|
|
|
ldy #>($arrayVarName+$indexValue)
|
|
|
|
jsr floats.copy_float""")
|
2019-08-16 20:49:29 +00:00
|
|
|
} else {
|
2021-03-22 18:33:57 +00:00
|
|
|
val asmvarname = asmgen.asmVariableName(target.array.indexer.indexExpr as IdentifierReference)
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
2020-04-03 20:44:10 +00:00
|
|
|
lda #<${constFloat}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W1
|
2020-04-03 20:44:10 +00:00
|
|
|
lda #>${constFloat}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W1+1
|
2020-04-03 20:44:10 +00:00
|
|
|
lda #<${arrayVarName}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W2
|
2020-04-03 20:44:10 +00:00
|
|
|
lda #>${arrayVarName}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ZP_SCRATCH_W2+1
|
2020-10-19 21:57:00 +00:00
|
|
|
lda $asmvarname
|
2020-09-20 21:49:36 +00:00
|
|
|
jsr floats.set_array_float
|
2020-04-03 20:44:10 +00:00
|
|
|
""")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte")
|
2020-11-23 21:14:45 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
2022-02-08 20:38:27 +00:00
|
|
|
val floatConst = allocator.getFloatAsmConst(float)
|
2020-11-23 21:14:45 +00:00
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM")
|
|
|
|
RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK")
|
|
|
|
else -> throw AssemblyError("can only assign float to Fac1 or 2")
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
2022-02-08 20:38:27 +00:00
|
|
|
val floatConst = allocator.getFloatAsmConst(float)
|
2020-09-20 21:49:36 +00:00
|
|
|
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
|
2020-08-25 15:43:35 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-20 23:48:23 +00:00
|
|
|
private fun assignMemoryByte(target: AsmAssignTarget, address: UInt?, identifier: IdentifierReference?) {
|
2020-04-06 16:19:14 +00:00
|
|
|
if (address != null) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2019-08-16 20:49:29 +00:00
|
|
|
asmgen.out("""
|
|
|
|
lda ${address.toHex()}
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
2019-08-16 20:49:29 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" lda ${address.toHex()}")
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-08-23 16:32:53 +00:00
|
|
|
throw AssemblyError("no asm gen for assign memory byte at $address to array ${target.asmVarname}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> asmgen.out(" lda ${address.toHex()}")
|
|
|
|
RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" ldy ${address.toHex()}")
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda ${address.toHex()}")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda ${address.toHex()}")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldy ${address.toHex()}")
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
2020-12-21 22:45:26 +00:00
|
|
|
lda ${address.toHex()}
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 22:45:26 +00:00
|
|
|
lda #0
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda ${address.toHex()}
|
2020-08-25 17:32:31 +00:00
|
|
|
sta P8ESTACK_LO,x
|
2020-08-25 15:43:35 +00:00
|
|
|
dex""")
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-04-06 16:19:14 +00:00
|
|
|
} else if (identifier != null) {
|
2020-08-23 11:56:21 +00:00
|
|
|
when(target.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-08-24 22:59:02 +00:00
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2020-08-24 21:18:46 +00:00
|
|
|
asmgen.out(" sta ${target.asmVarname}")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.MEMORY -> {
|
2021-01-23 17:50:46 +00:00
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2021-01-19 18:25:23 +00:00
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
TargetStorageKind.ARRAY -> {
|
2020-08-24 22:18:33 +00:00
|
|
|
throw AssemblyError("no asm gen for assign memory byte $identifier to array ${target.asmVarname} ")
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
2020-08-23 21:28:25 +00:00
|
|
|
TargetStorageKind.REGISTER -> {
|
2020-08-24 22:59:02 +00:00
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2020-08-23 21:28:25 +00:00
|
|
|
when(target.register!!) {
|
|
|
|
RegisterOrPair.A -> {}
|
|
|
|
RegisterOrPair.X -> asmgen.out(" tax")
|
|
|
|
RegisterOrPair.Y -> asmgen.out(" tay")
|
2020-09-12 00:48:16 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" tax | ldy #0")
|
2020-11-23 21:14:45 +00:00
|
|
|
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> throw AssemblyError("expected typecasted byte to float")
|
2020-12-25 11:36:11 +00:00
|
|
|
in Cx16VirtualRegisters -> {
|
2021-05-05 21:01:04 +00:00
|
|
|
asmgen.out(
|
|
|
|
"""
|
|
|
|
sta cx16.${target.register.toString().lowercase()}
|
2020-12-21 22:45:26 +00:00
|
|
|
lda #0
|
2021-05-05 21:01:04 +00:00
|
|
|
sta cx16.${target.register.toString().lowercase()}+1
|
2020-12-21 22:45:26 +00:00
|
|
|
""")
|
|
|
|
}
|
2020-12-25 11:36:11 +00:00
|
|
|
else -> throw AssemblyError("weird register")
|
2020-08-23 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-25 15:43:35 +00:00
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2020-08-25 17:32:31 +00:00
|
|
|
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
2020-08-25 15:43:35 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-20 23:48:23 +00:00
|
|
|
private fun assignMemoryByteIntoWord(wordtarget: AsmAssignTarget, address: UInt?, identifier: IdentifierReference?) {
|
2020-09-15 01:26:57 +00:00
|
|
|
if (address != null) {
|
|
|
|
when(wordtarget.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" lda ${address.toHex()} | sta ${wordtarget.asmVarname}")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz ${wordtarget.asmVarname}+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta ${wordtarget.asmVarname}+1")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
throw AssemblyError("no asm gen for assign memory byte at $address to array ${wordtarget.asmVarname}")
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> when(wordtarget.register!!) {
|
2020-12-27 17:12:12 +00:00
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda ${address.toHex()}")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda ${address.toHex()}")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldy ${address.toHex()}")
|
2020-09-15 01:26:57 +00:00
|
|
|
else -> throw AssemblyError("word regs can only be pair")
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" lda ${address.toHex()} | sta P8ESTACK_LO,x")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz P8ESTACK_HI,x | dex")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("other types aren't word")
|
|
|
|
}
|
|
|
|
} else if (identifier != null) {
|
|
|
|
when(wordtarget.kind) {
|
|
|
|
TargetStorageKind.VARIABLE -> {
|
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" sta ${wordtarget.asmVarname}")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz ${wordtarget.asmVarname}+1")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta ${wordtarget.asmVarname}+1")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
throw AssemblyError("no asm gen for assign memory byte $identifier to array ${wordtarget.asmVarname} ")
|
|
|
|
}
|
|
|
|
TargetStorageKind.REGISTER -> {
|
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
|
|
|
when(wordtarget.register!!) {
|
|
|
|
RegisterOrPair.AX -> asmgen.out(" ldx #0")
|
|
|
|
RegisterOrPair.AY -> asmgen.out(" ldy #0")
|
|
|
|
RegisterOrPair.XY -> asmgen.out(" tax | ldy #0")
|
|
|
|
else -> throw AssemblyError("word regs can only be pair")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.loadByteFromPointerIntoA(identifier)
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" sta P8ESTACK_LO,x")
|
2021-02-19 17:48:12 +00:00
|
|
|
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
2020-12-06 07:30:13 +00:00
|
|
|
asmgen.out(" stz P8ESTACK_HI,x | dex")
|
|
|
|
else
|
|
|
|
asmgen.out(" lda #0 | sta P8ESTACK_HI,x | dex")
|
2020-09-15 01:26:57 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("other types aren't word")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-19 18:25:23 +00:00
|
|
|
private fun storeRegisterAInMemoryAddress(memoryAddress: DirectMemoryWrite) {
|
2020-08-23 12:36:24 +00:00
|
|
|
val addressExpr = memoryAddress.addressExpression
|
2022-02-10 23:21:40 +00:00
|
|
|
val addressLv = addressExpr as? NumericLiteral
|
2021-01-15 19:46:47 +00:00
|
|
|
|
2021-01-15 20:33:57 +00:00
|
|
|
fun storeViaExprEval() {
|
2021-01-19 18:25:23 +00:00
|
|
|
when(addressExpr) {
|
2022-02-10 23:21:40 +00:00
|
|
|
is NumericLiteral, is IdentifierReference -> {
|
2021-06-12 15:31:09 +00:00
|
|
|
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
2021-12-04 03:43:58 +00:00
|
|
|
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2")
|
2021-01-19 18:25:23 +00:00
|
|
|
}
|
|
|
|
else -> {
|
|
|
|
// same as above but we need to save the A register
|
|
|
|
asmgen.out(" pha")
|
2021-06-12 15:31:09 +00:00
|
|
|
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" pla")
|
2021-12-04 03:43:58 +00:00
|
|
|
asmgen.storeAIntoZpPointerVar("P8ZP_SCRATCH_W2")
|
2021-01-15 20:33:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-23 12:36:24 +00:00
|
|
|
when {
|
|
|
|
addressLv != null -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" sta ${addressLv.number.toHex()}")
|
2020-08-23 12:36:24 +00:00
|
|
|
}
|
|
|
|
addressExpr is IdentifierReference -> {
|
2021-12-04 03:43:58 +00:00
|
|
|
asmgen.storeAIntoPointerVar(addressExpr)
|
2020-08-23 12:36:24 +00:00
|
|
|
}
|
2021-01-15 19:46:47 +00:00
|
|
|
addressExpr is BinaryExpression -> {
|
2021-01-19 18:25:23 +00:00
|
|
|
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true))
|
2021-01-15 19:46:47 +00:00
|
|
|
storeViaExprEval()
|
2020-08-23 12:36:24 +00:00
|
|
|
}
|
2021-01-15 19:46:47 +00:00
|
|
|
else -> storeViaExprEval()
|
2020-08-23 12:36:24 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-15 14:04:23 +00:00
|
|
|
|
2021-11-06 17:48:42 +00:00
|
|
|
internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair, signed: Boolean) {
|
2021-10-31 01:34:17 +00:00
|
|
|
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
2022-07-31 11:38:00 +00:00
|
|
|
val tgt = AsmAssignTarget.fromRegisters(register, signed, null, asmgen)
|
2021-02-19 18:02:29 +00:00
|
|
|
val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position)
|
2020-11-15 14:04:23 +00:00
|
|
|
translateNormalAssignment(assign)
|
|
|
|
}
|
|
|
|
|
|
|
|
internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) {
|
2022-05-03 21:43:38 +00:00
|
|
|
if(expr.inferType(program) istype DataType.FLOAT && dt!=DataType.FLOAT) {
|
|
|
|
throw AssemblyError("can't directly assign a FLOAT expression to an integer variable $expr")
|
|
|
|
} else {
|
|
|
|
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
2022-07-31 11:38:00 +00:00
|
|
|
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, scope, variableAsmName = asmVarName)
|
2022-05-03 21:43:38 +00:00
|
|
|
val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position)
|
|
|
|
translateNormalAssignment(assign)
|
|
|
|
}
|
2020-11-15 14:04:23 +00:00
|
|
|
}
|
2020-11-15 16:44:47 +00:00
|
|
|
|
2021-11-06 17:48:42 +00:00
|
|
|
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean) {
|
2022-07-31 11:38:00 +00:00
|
|
|
val tgt = AsmAssignTarget.fromRegisters(register, signed, null, asmgen)
|
2020-11-15 16:44:47 +00:00
|
|
|
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
|
2021-02-19 18:02:29 +00:00
|
|
|
val assign = AsmAssignment(src, tgt, false, program.memsizer, Position.DUMMY)
|
2020-11-15 16:44:47 +00:00
|
|
|
translateNormalAssignment(assign)
|
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|