2021-02-28 15:29:15 +00:00
|
|
|
package prog8.compiler.target.cpu6502.codegen.assignment
|
2019-08-16 20:49:29 +00:00
|
|
|
|
|
|
|
import prog8.ast.Program
|
|
|
|
import prog8.ast.base.*
|
|
|
|
import prog8.ast.expressions.*
|
2020-08-20 13:18:24 +00:00
|
|
|
import prog8.ast.statements.*
|
2021-02-07 05:21:29 +00:00
|
|
|
import prog8.ast.toHex
|
2021-10-29 03:00:30 +00:00
|
|
|
import prog8.compiler.target.AssemblyError
|
2021-02-28 15:29:15 +00:00
|
|
|
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
2021-10-29 03:00:30 +00:00
|
|
|
import prog8.compilerinterface.BuiltinFunctions
|
2021-10-29 03:28:02 +00:00
|
|
|
import prog8.compilerinterface.CpuType
|
2021-10-29 03:00:30 +00:00
|
|
|
import prog8.compilerinterface.builtinFunctionReturnType
|
2019-10-26 21:27:27 +00:00
|
|
|
|
2020-08-22 21:39:27 +00:00
|
|
|
|
2021-11-08 18:21:55 +00:00
|
|
|
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
2019-08-16 20:49:29 +00:00
|
|
|
|
2021-11-08 18:21:55 +00:00
|
|
|
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen)
|
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)
|
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 -> {
|
|
|
|
asmgen.out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue")
|
|
|
|
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-02-19 17:48:12 +00:00
|
|
|
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-01-15 18:52:53 +00:00
|
|
|
asmgen.out(" lda (P8ZP_SCRATCH_W2)")
|
|
|
|
else
|
|
|
|
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
|
|
|
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) {
|
|
|
|
is NumericLiteralValue -> {
|
2021-11-20 23:48:23 +00:00
|
|
|
val address = (value.addressExpression as NumericLiteralValue).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 -> {
|
2020-10-20 15:52:55 +00:00
|
|
|
when(val value = assign.source.expression!!) {
|
2020-10-11 11:31:45 +00:00
|
|
|
is AddressOf -> {
|
2021-05-15 21:58:48 +00:00
|
|
|
val sourceName = asmgen.asmSymbolName(value.identifier)
|
2020-10-11 11:31:45 +00:00
|
|
|
assignAddressOf(assign.target, sourceName)
|
|
|
|
}
|
2020-08-24 00:56:22 +00:00
|
|
|
is NumericLiteralValue -> 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")
|
2020-11-24 21:26:11 +00:00
|
|
|
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
|
2020-10-06 22:06:42 +00:00
|
|
|
is FunctionCall -> {
|
2021-02-07 17:34:55 +00:00
|
|
|
when (val sub = value.target.targetStatement(program)) {
|
2020-10-27 23:29:34 +00:00
|
|
|
is Subroutine -> {
|
2021-01-05 00:41:32 +00:00
|
|
|
asmgen.saveXbeforeCall(value)
|
2021-11-24 00:41:04 +00:00
|
|
|
asmgen.translateFunctionCall(value, true)
|
2020-12-22 11:44:03 +00:00
|
|
|
val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?:
|
|
|
|
sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null }
|
2020-11-06 22:51:39 +00:00
|
|
|
when (returnValue.first) {
|
|
|
|
DataType.STR -> {
|
2021-01-05 01:44:55 +00:00
|
|
|
asmgen.restoreXafterCall(value)
|
2020-11-06 22:51:39 +00:00
|
|
|
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 -> {
|
|
|
|
// copy the actual string result into the target string variable
|
|
|
|
asmgen.out("""
|
2021-10-31 01:34:17 +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""")
|
2020-11-06 22:51:39 +00:00
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird target dt")
|
2020-10-30 21:22:06 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-06 22:51:39 +00:00
|
|
|
DataType.FLOAT -> {
|
|
|
|
// float result from function sits in FAC1
|
2021-01-05 01:44:55 +00:00
|
|
|
asmgen.restoreXafterCall(value)
|
2020-11-06 22:51:39 +00:00
|
|
|
assignFAC1float(assign.target)
|
|
|
|
}
|
|
|
|
else -> {
|
2021-01-05 01:44:55 +00:00
|
|
|
// do NOT restore X register before assigning the result values first
|
2020-11-06 22:51:39 +00:00
|
|
|
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)
|
|
|
|
RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX)
|
|
|
|
RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY)
|
2020-12-22 11:44:03 +00:00
|
|
|
else -> {
|
|
|
|
val sflag = returnValue.second.statusflag
|
|
|
|
if(sflag!=null)
|
|
|
|
assignStatusFlagByte(assign.target, sflag)
|
|
|
|
else
|
|
|
|
throw AssemblyError("should be just one register byte result value")
|
|
|
|
}
|
2020-11-06 22:51:39 +00:00
|
|
|
}
|
2021-01-05 01:44:55 +00:00
|
|
|
// we've processed the result value in the X register by now, so it's now finally safe to restore it
|
2021-01-05 00:41:32 +00:00
|
|
|
asmgen.restoreXafterCall(value)
|
2020-10-28 22:13:53 +00:00
|
|
|
}
|
2020-10-27 23:29:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is BuiltinFunctionStatementPlaceholder -> {
|
|
|
|
val signature = BuiltinFunctions.getValue(sub.name)
|
2021-01-29 00:52:49 +00:00
|
|
|
asmgen.translateBuiltinFunctionCallExpression(value, signature, false, assign.target.register)
|
|
|
|
if(assign.target.register==null) {
|
|
|
|
// still need to assign the result to the target variable/etc.
|
|
|
|
val returntype = builtinFunctionReturnType(sub.name, value.args, program)
|
|
|
|
if(!returntype.isKnown)
|
|
|
|
throw AssemblyError("unknown dt")
|
2021-10-12 22:21:38 +00:00
|
|
|
when(returntype.getOr(DataType.UNDEFINED)) {
|
2021-01-29 00:52:49 +00:00
|
|
|
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) {
|
|
|
|
DataType.STR -> {
|
|
|
|
asmgen.out("""
|
|
|
|
pha
|
|
|
|
lda #<${assign.target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W1
|
|
|
|
lda #>${assign.target.asmVarname}
|
|
|
|
sta P8ZP_SCRATCH_W1+1
|
|
|
|
pla
|
|
|
|
jsr prog8_lib.strcpy""")
|
|
|
|
}
|
|
|
|
DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
|
|
else -> throw AssemblyError("str return value type mismatch with target")
|
2021-01-02 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-29 00:52:49 +00:00
|
|
|
DataType.FLOAT -> {
|
|
|
|
// float result from function sits in FAC1
|
|
|
|
assignFAC1float(assign.target)
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird result type")
|
2021-01-02 15:46:57 +00:00
|
|
|
}
|
2020-10-27 23:29:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> {
|
|
|
|
throw AssemblyError("weird func call")
|
2020-10-06 22:06:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-06 16:57:00 +00:00
|
|
|
is PrefixExpression -> {
|
|
|
|
// first assign the value to the target then apply the operator in place on the target.
|
|
|
|
translateNormalAssignment(AsmAssignment(
|
|
|
|
AsmAssignSource.fromAstSource(value.expression, program, asmgen),
|
|
|
|
assign.target,
|
|
|
|
false, program.memsizer, assign.position
|
|
|
|
))
|
|
|
|
when(value.operator) {
|
|
|
|
"+" -> {}
|
|
|
|
"-" -> augmentableAsmGen.inplaceNegate(assign.target, assign.target.datatype)
|
|
|
|
"~" -> augmentableAsmGen.inplaceInvert(assign.target, assign.target.datatype)
|
|
|
|
"not" -> augmentableAsmGen.inplaceBooleanNot(assign.target, assign.target.datatype)
|
|
|
|
else -> throw AssemblyError("invalid prefix operator")
|
|
|
|
}
|
|
|
|
}
|
2020-08-24 00:56:22 +00:00
|
|
|
else -> {
|
2020-11-17 23:19:17 +00:00
|
|
|
// Everything else just evaluate via the stack.
|
2021-10-31 01:34:17 +00:00
|
|
|
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
|
2020-11-17 23:19:17 +00:00
|
|
|
// because the code here is the implementation of exactly that...)
|
2021-11-15 00:30:12 +00:00
|
|
|
// TODO DON'T STACK-EVAL THIS... by using a temp var? so that it becomes augmentable assignment expression?
|
2021-11-06 02:28:42 +00:00
|
|
|
asmgen.translateExpression(value)
|
2020-12-31 21:13:24 +00:00
|
|
|
if (assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
|
2020-10-10 23:35:38 +00:00
|
|
|
asmgen.signExtendStackLsb(assign.source.datatype)
|
2021-11-06 13:47:11 +00:00
|
|
|
if(assign.target.kind!=TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype)
|
|
|
|
assignStackValue(assign.target)
|
2020-08-24 00:56:22 +00:00
|
|
|
}
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
SourceStorageKind.REGISTER -> {
|
2021-11-06 02:28:42 +00:00
|
|
|
asmgen.assignRegister(assign.source.register!!, assign.target)
|
2020-08-23 09:07:35 +00:00
|
|
|
}
|
2020-08-23 11:56:21 +00:00
|
|
|
SourceStorageKind.STACK -> {
|
2021-11-06 13:47:11 +00:00
|
|
|
if(assign.target.kind!=TargetStorageKind.STACK || assign.target.datatype != assign.source.datatype)
|
|
|
|
assignStackValue(assign.target)
|
2019-08-16 20:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
if(!valueIDt.isKnown)
|
|
|
|
throw AssemblyError("unknown dt")
|
2021-10-12 22:21:38 +00:00
|
|
|
val valueDt = valueIDt.getOr(DataType.UNDEFINED)
|
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-02-19 17:48:12 +00:00
|
|
|
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-01-19 23:28:54 +00:00
|
|
|
asmgen.out(" lda (P8ZP_SCRATCH_W2)")
|
|
|
|
else
|
|
|
|
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y")
|
|
|
|
assignRegisterByte(target, CpuRegister.A)
|
|
|
|
}
|
|
|
|
|
2021-01-19 18:25:23 +00:00
|
|
|
when (value.addressExpression) {
|
|
|
|
is NumericLiteralValue -> {
|
2021-11-20 23:48:23 +00:00
|
|
|
val address = (value.addressExpression as NumericLiteralValue).number.toUInt()
|
2021-01-19 18:25:23 +00:00
|
|
|
assignMemoryByteIntoWord(target, address, null)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
is IdentifierReference -> {
|
|
|
|
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
|
|
|
|
return
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is NumericLiteralValue -> throw AssemblyError("a cast of a literal value should have been const-folded away")
|
|
|
|
else -> {}
|
|
|
|
}
|
|
|
|
|
2020-11-24 21:26:11 +00:00
|
|
|
|
|
|
|
// special case optimizations
|
2021-02-28 15:29:15 +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
|
|
|
}
|
|
|
|
|
2020-12-31 00:02:36 +00:00
|
|
|
if(origTypeCastExpression.type == DataType.UBYTE) {
|
|
|
|
val parentTc = origTypeCastExpression.parent as? TypecastExpression
|
|
|
|
if(parentTc!=null && parentTc.type==DataType.UWORD) {
|
|
|
|
// typecast something to ubyte and directly back to uword
|
|
|
|
// generate code for lsb(value) here instead of the ubyte typecast
|
|
|
|
return assignCastViaLsbFunc(value, target)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(valueDt==DataType.UBYTE) {
|
|
|
|
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 -> {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
asmgen.out(" jsr floats.FREADUY")
|
|
|
|
}
|
|
|
|
DataType.BYTE -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.A, true)
|
|
|
|
asmgen.out(" jsr floats.FREADSA")
|
|
|
|
}
|
|
|
|
DataType.UWORD -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, false)
|
|
|
|
asmgen.out(" jsr floats.GIVUAYFAY")
|
|
|
|
}
|
|
|
|
DataType.WORD -> {
|
|
|
|
assignExpressionToRegister(value, RegisterOrPair.AY, true)
|
|
|
|
asmgen.out(" jsr floats.GIVAYFAY")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("invalid dt")
|
|
|
|
}
|
|
|
|
if(target.register==RegisterOrPair.FAC2) {
|
|
|
|
asmgen.out(" jsr floats.MOVEF")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// 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) {
|
|
|
|
val lsb = FunctionCall(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position)
|
|
|
|
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) {
|
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
|
|
|
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) {
|
|
|
|
DataType.UBYTE, DataType.BYTE -> {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
DataType.WORD, DataType.UWORD -> {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
DataType.WORD, DataType.UWORD -> {
|
|
|
|
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) {
|
|
|
|
DataType.UBYTE, 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(
|
|
|
|
" 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.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) {
|
|
|
|
DataType.UBYTE, 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 -> {
|
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
|
|
|
}
|
|
|
|
DataType.WORD, DataType.UWORD -> {
|
|
|
|
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
|
|
|
}
|
|
|
|
DataType.WORD, DataType.UWORD -> {
|
|
|
|
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("""
|
|
|
|
lda #<${target.asmVarname}+$scaledIdx
|
|
|
|
ldy #>${target.asmVarname}+$scaledIdx
|
|
|
|
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
|
|
|
|
lda #<${target.asmVarname}+$scaledIdx
|
|
|
|
ldy #>${target.asmVarname}+$scaledIdx
|
|
|
|
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
|
2020-09-20 21:49:36 +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)
|
|
|
|
throw AssemblyError("can't assign Fac1 float to another fac register")
|
|
|
|
}
|
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("""
|
|
|
|
lda $sourceName
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $sourceName+1
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $sourceName+2
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+2
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $sourceName+3
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+3
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $sourceName+4
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+4
|
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 -> {
|
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 +
|
|
|
|
ldx #0
|
|
|
|
+ tax
|
|
|
|
pla""")
|
|
|
|
RegisterOrPair.AY -> asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
pha
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
ldy #0
|
|
|
|
+ tay
|
|
|
|
pla""")
|
|
|
|
RegisterOrPair.XY -> asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
tax
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
ldy #0
|
|
|
|
+ tay""")
|
|
|
|
else -> throw AssemblyError("only reg pairs are words")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TargetStorageKind.STACK -> {
|
|
|
|
asmgen.out("""
|
|
|
|
lda $sourceName
|
|
|
|
sta P8ESTACK_LO,x
|
|
|
|
ora #$7f
|
|
|
|
bmi +
|
|
|
|
lda #0
|
|
|
|
+ sta P8ESTACK_HI,x
|
|
|
|
dex""")
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("target type isn't word")
|
|
|
|
}
|
|
|
|
}
|
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")
|
2020-09-15 01:26:57 +00:00
|
|
|
else -> throw AssemblyError("only reg pairs are words")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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) {
|
2021-09-06 21:22:43 +00:00
|
|
|
// we make an exception in the type check for assigning something to a cx16 virtual register, or a register pair
|
|
|
|
// these will be correctly typecasted from a byte to a word value
|
|
|
|
if(target.register !in Cx16VirtualRegisters &&
|
|
|
|
target.register!=RegisterOrPair.AX && target.register!=RegisterOrPair.AY && target.register!=RegisterOrPair.XY) {
|
2021-10-29 03:00:30 +00:00
|
|
|
if(target.kind== TargetStorageKind.VARIABLE) {
|
2021-03-23 22:44:14 +00:00
|
|
|
val parts = target.asmVarname.split('.')
|
|
|
|
if (parts.size != 2 || parts[0] != "cx16")
|
|
|
|
require(target.datatype in ByteDatatypes)
|
|
|
|
} else {
|
|
|
|
require(target.datatype in ByteDatatypes)
|
|
|
|
}
|
|
|
|
}
|
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) {
|
2021-11-04 22:57:25 +00:00
|
|
|
require(target.datatype in NumericDatatypes || target.datatype in PassByReferenceDatatypes)
|
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 -> {
|
|
|
|
throw AssemblyError("no asm gen for assign word $word to memory ${target.memory}")
|
|
|
|
}
|
|
|
|
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-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" lda #${byte.toHex()}")
|
|
|
|
storeRegisterAInMemoryAddress(target.memory!!)
|
2020-12-22 16:59:47 +00:00
|
|
|
}
|
|
|
|
TargetStorageKind.ARRAY -> {
|
|
|
|
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 -> {
|
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
|
|
|
}
|
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 -> {
|
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)
|
|
|
|
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 -> {
|
|
|
|
val floatConst = asmgen.getFloatAsmConst(float)
|
|
|
|
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 -> {
|
2020-08-25 17:32:31 +00:00
|
|
|
val floatConst = asmgen.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
|
2020-08-25 17:32:31 +00:00
|
|
|
val constFloat = asmgen.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("""
|
|
|
|
lda $constFloat
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $constFloat+1
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+1
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $constFloat+2
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+2
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $constFloat+3
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+3
|
2019-08-16 20:49:29 +00:00
|
|
|
lda $constFloat+4
|
2020-08-23 16:20:57 +00:00
|
|
|
sta ${target.asmVarname}+4
|
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("""
|
|
|
|
lda $constFloat
|
|
|
|
sta $arrayVarName+$indexValue
|
|
|
|
lda $constFloat+1
|
|
|
|
sta $arrayVarName+$indexValue+1
|
|
|
|
lda $constFloat+2
|
|
|
|
sta $arrayVarName+$indexValue+2
|
|
|
|
lda $constFloat+3
|
|
|
|
sta $arrayVarName+$indexValue+3
|
|
|
|
lda $constFloat+4
|
|
|
|
sta $arrayVarName+$indexValue+4
|
|
|
|
""")
|
|
|
|
} 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 -> {
|
|
|
|
val floatConst = asmgen.getFloatAsmConst(float)
|
|
|
|
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 -> {
|
2020-08-25 17:32:31 +00:00
|
|
|
val floatConst = asmgen.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
|
|
|
|
val addressLv = addressExpr as? NumericLiteralValue
|
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) {
|
|
|
|
is NumericLiteralValue, is IdentifierReference -> {
|
2021-06-12 15:31:09 +00:00
|
|
|
assignExpressionToVariable(addressExpr, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
2021-02-19 17:48:12 +00:00
|
|
|
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" sta (P8ZP_SCRATCH_W2)")
|
|
|
|
else
|
|
|
|
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
|
|
|
|
}
|
|
|
|
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-02-19 17:48:12 +00:00
|
|
|
if (asmgen.isTargetCpu(CpuType.CPU65c02))
|
2021-01-19 18:25:23 +00:00
|
|
|
asmgen.out(" sta (P8ZP_SCRATCH_W2)")
|
|
|
|
else
|
|
|
|
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
|
2021-01-15 20:33:57 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-15 19:46:47 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 18:25:23 +00:00
|
|
|
fun storeAIntoPointerVar(pointervar: IdentifierReference) {
|
|
|
|
val sourceName = asmgen.asmVariableName(pointervar)
|
2021-02-07 17:34:55 +00:00
|
|
|
val vardecl = pointervar.targetVarDecl(program)!!
|
2021-11-26 19:56:30 +00:00
|
|
|
val scopedName = vardecl.scopedName.joinToString(".")
|
2021-02-19 17:48:12 +00:00
|
|
|
if (asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
2021-01-19 18:25:23 +00:00
|
|
|
if (asmgen.isZpVar(scopedName)) {
|
|
|
|
// pointervar is already in the zero page, no need to copy
|
|
|
|
asmgen.out(" sta ($sourceName)")
|
|
|
|
} else {
|
|
|
|
asmgen.out("""
|
|
|
|
ldy $sourceName
|
|
|
|
sty P8ZP_SCRATCH_W2
|
|
|
|
ldy $sourceName+1
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
sta (P8ZP_SCRATCH_W2)""")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (asmgen.isZpVar(scopedName)) {
|
|
|
|
// pointervar is already in the zero page, no need to copy
|
|
|
|
asmgen.out(" ldy #0 | sta ($sourceName),y")
|
|
|
|
} else {
|
|
|
|
asmgen.out("""
|
|
|
|
ldy $sourceName
|
|
|
|
sty P8ZP_SCRATCH_W2
|
|
|
|
ldy $sourceName+1
|
|
|
|
sty P8ZP_SCRATCH_W2+1
|
|
|
|
ldy #0
|
|
|
|
sta (P8ZP_SCRATCH_W2),y""")
|
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-01-19 18:25:23 +00:00
|
|
|
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)
|
2021-11-06 17:48:42 +00:00
|
|
|
val tgt = AsmAssignTarget.fromRegisters(register, signed, null, program, 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?) {
|
2021-10-31 01:34:17 +00:00
|
|
|
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
|
2020-11-15 14:04:23 +00:00
|
|
|
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, scope, variableAsmName = asmVarName)
|
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)
|
|
|
|
}
|
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) {
|
|
|
|
val tgt = AsmAssignTarget.fromRegisters(register, signed, null, program, 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
|
|
|
}
|