2022-01-27 23:32:09 +00:00
package prog8.codegen.cpu6502.assignment
2019-08-16 20:49:29 +00:00
2023-12-11 21:51:33 +00:00
import prog8.code.StMemVar
import prog8.code.StStaticVariable
2023-01-04 21:55:05 +00:00
import prog8.code.ast.*
2022-03-10 21:38:16 +00:00
import prog8.code.core.*
2023-02-28 20:41:21 +00:00
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.codegen.cpu6502.VariableAllocator
import prog8.codegen.cpu6502.returnsWhatWhere
2019-10-26 21:27:27 +00:00
2020-08-22 21:39:27 +00:00
2023-01-04 21:55:05 +00:00
internal class AssignmentAsmGen ( private val program : PtProgram ,
2023-02-12 22:49:48 +00:00
private val asmgen : AsmGen6502Internal ,
2023-07-17 23:24:27 +00:00
private val anyExprGen : AnyExprAsmGen ,
2022-02-08 20:38:27 +00:00
private val allocator : VariableAllocator ) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen ( program , this , asmgen , allocator )
2020-08-20 16:07:48 +00:00
2023-01-04 21:55:05 +00:00
fun translate ( assignment : PtAssignment ) {
2023-02-15 21:50:35 +00:00
val target = AsmAssignTarget . fromAstAssignment ( assignment . target , assignment . definingISub ( ) , asmgen )
2021-10-31 01:34:17 +00:00
val source = AsmAssignSource . fromAstSource ( assignment . value , program , asmgen ) . adjustSignedUnsigned ( target )
2023-08-11 21:41:19 +00:00
val pos = if ( assignment . position !== Position . DUMMY ) assignment . position else if ( assignment . target . position !== Position . DUMMY ) assignment . target . position else assignment . value . position
val assign = AsmAssignment ( source , target , program . memsizer , pos )
2023-03-18 23:24:05 +00:00
translateNormalAssignment ( assign , assignment . definingISub ( ) )
2023-02-15 21:50:35 +00:00
}
2020-08-23 11:31:14 +00:00
2023-02-15 21:50:35 +00:00
fun translate ( augmentedAssign : PtAugmentedAssign ) {
val target = AsmAssignTarget . fromAstAssignment ( augmentedAssign . target , augmentedAssign . definingISub ( ) , asmgen )
val source = AsmAssignSource . fromAstSource ( augmentedAssign . value , program , asmgen ) . adjustSignedUnsigned ( target )
2023-08-11 21:41:19 +00:00
val pos = if ( augmentedAssign . position !== Position . DUMMY ) augmentedAssign . position else if ( augmentedAssign . target . position !== Position . DUMMY ) augmentedAssign . target . position else augmentedAssign . value . position
val assign = AsmAugmentedAssignment ( source , augmentedAssign . operator , target , program . memsizer , pos )
2023-03-18 23:24:05 +00:00
augmentableAsmGen . translate ( assign , augmentedAssign . definingISub ( ) )
2020-08-23 14:08:31 +00:00
}
2023-03-18 23:24:05 +00:00
fun translateNormalAssignment ( assign : AsmAssignment , scope : IPtSubroutine ? ) {
2020-08-23 14:08:31 +00:00
when ( assign . source . kind ) {
2024-02-05 22:31:55 +00:00
SourceStorageKind . LITERALBOOLEAN -> {
2024-02-12 20:29:02 +00:00
// simple case: assign a constant boolean (0 or 1)
2024-02-05 22:31:55 +00:00
val num = assign . source . boolean !! . asInt ( )
when ( assign . target . datatype ) {
DataType . BOOL , DataType . UBYTE , DataType . BYTE -> assignConstantByte ( assign . target , num )
DataType . UWORD , DataType . WORD -> assignConstantWord ( assign . target , num )
DataType . FLOAT -> assignConstantFloat ( assign . target , num . toDouble ( ) )
else -> throw AssemblyError ( " weird numval type " )
}
}
2020-08-23 14:08:31 +00:00
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 ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> assignConstantByte ( assign . target , if ( num == 0.0 ) 0 else 1 )
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 ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> {
if ( assign . source . datatype == DataType . BOOL ) assignVariableByte ( assign . target , variable )
else throw AssemblyError ( " assigning non-bool variable to boolean, should have been typecasted " )
}
2020-08-23 12:36:24 +00:00
DataType . UBYTE , DataType . BYTE -> assignVariableByte ( assign . target , variable )
2023-07-16 19:52:28 +00:00
DataType . WORD -> assignVariableWord ( assign . target , variable , assign . source . datatype )
2020-11-09 23:35:24 +00:00
DataType . UWORD -> {
if ( assign . source . datatype in PassByReferenceDatatypes )
2023-09-17 16:30:57 +00:00
assignAddressOf ( assign . target , variable , null , null )
2020-11-09 23:35:24 +00:00
else
2023-07-16 19:52:28 +00:00
assignVariableWord ( assign . target , variable , assign . source . datatype )
2020-11-09 23:35:24 +00:00
}
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
2023-01-04 21:55:05 +00:00
val arrayVarName = asmgen . asmVariableName ( value . variable )
val constIndex = value . index . asConstInteger ( )
2023-05-27 12:43:09 +00:00
if ( value . splitWords ) {
require ( elementDt in WordDatatypes )
if ( constIndex != null ) {
asmgen . out ( " lda ${arrayVarName} _lsb+ $constIndex | ldy ${arrayVarName} _msb+ $constIndex " )
assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
} else {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( value , CpuRegister . Y )
2023-10-14 05:18:37 +00:00
asmgen . out ( " lda ${arrayVarName} _lsb,y | ldx ${arrayVarName} _msb,y " )
assignRegisterpairWord ( assign . target , RegisterOrPair . AX )
2023-05-27 12:43:09 +00:00
}
return
}
2021-03-22 18:33:57 +00:00
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 ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> {
2020-11-22 16:16:07 +00:00
asmgen . out ( " lda $arrayVarName + $indexValue " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , elementDt in SignedDatatypes , false )
2020-11-22 16:16:07 +00:00
}
in WordDatatypes -> {
asmgen . out ( " lda $arrayVarName + $indexValue | ldy $arrayVarName + $indexValue +1 " )
assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
}
DataType . FLOAT -> {
2022-01-09 15:18:13 +00:00
asmgen . out ( " lda #<( $arrayVarName + $indexValue ) | ldy #>( $arrayVarName + $indexValue ) " )
2020-11-22 16:16:07 +00:00
assignFloatFromAY ( assign . target )
}
2019-08-16 20:49:29 +00:00
else ->
throw AssemblyError ( " weird array type " )
}
} else {
2020-08-23 18:25:00 +00:00
when ( elementDt ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( value , CpuRegister . Y )
2020-11-22 16:16:07 +00:00
asmgen . out ( " lda $arrayVarName ,y " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , elementDt in SignedDatatypes , true )
2020-08-23 18:25:00 +00:00
}
in WordDatatypes -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( value , CpuRegister . Y )
2023-10-14 05:18:37 +00:00
asmgen . out ( " lda $arrayVarName ,y | ldx $arrayVarName +1,y " )
assignRegisterpairWord ( assign . target , RegisterOrPair . AX )
2020-08-23 18:25:00 +00:00
}
DataType . FLOAT -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( value , CpuRegister . A )
2020-08-23 18:25:00 +00:00
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 -> {
2023-01-04 21:55:05 +00:00
fun assignViaExprEval ( expression : PtExpression ) {
2023-03-18 23:58:45 +00:00
assignExpressionToVariable ( expression , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2024-02-07 21:09:04 +00:00
asmgen . loadAFromZpPointerVar ( " P8ZP_SCRATCH_W2 " , false )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , true )
2021-01-15 18:52:53 +00:00
}
2020-08-23 11:56:21 +00:00
val value = assign . source . memory !!
2023-01-04 21:55:05 +00:00
when ( value . address ) {
is PtNumber -> {
val address = ( value . address as PtNumber ) . number . toUInt ( )
2020-08-23 12:36:24 +00:00
assignMemoryByte ( assign . target , address , null )
2020-08-23 09:07:35 +00:00
}
2023-01-04 21:55:05 +00:00
is PtIdentifier -> {
assignMemoryByte ( assign . target , null , value . address as PtIdentifier )
2020-08-23 09:07:35 +00:00
}
2023-03-16 01:27:30 +00:00
is PtBinaryExpression -> {
2023-03-17 23:16:18 +00:00
val addrExpr = value . address as PtBinaryExpression
2024-02-03 16:36:42 +00:00
if ( asmgen . tryOptimizedPointerAccessWithA ( addrExpr , false ) ) {
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , true )
2021-01-19 18:25:23 +00:00
} else {
2023-01-04 21:55:05 +00:00
assignViaExprEval ( value . address )
2021-01-19 18:25:23 +00:00
}
2020-08-23 09:07:35 +00:00
}
2023-01-04 21:55:05 +00:00
else -> assignViaExprEval ( value . address )
2020-08-23 09:07:35 +00:00
}
}
2020-08-23 11:56:21 +00:00
SourceStorageKind . EXPRESSION -> {
2023-03-18 23:24:05 +00:00
assignExpression ( assign , scope )
2022-02-20 17:34:30 +00:00
}
SourceStorageKind . REGISTER -> {
asmgen . assignRegister ( assign . source . register !! , assign . target )
}
}
}
2023-03-18 23:24:05 +00:00
private fun assignExpression ( assign : AsmAssignment , scope : IPtSubroutine ? ) {
2022-02-20 17:34:30 +00:00
when ( val value = assign . source . expression !! ) {
2023-01-04 21:55:05 +00:00
is PtAddressOf -> {
2022-02-20 17:34:30 +00:00
val sourceName = asmgen . asmSymbolName ( value . identifier )
2023-09-17 16:30:57 +00:00
val arrayDt = value . identifier . type
assignAddressOf ( assign . target , sourceName , arrayDt , value . arrayIndexExpr )
2022-02-20 17:34:30 +00:00
}
2024-02-12 20:29:02 +00:00
is PtBool -> throw AssemblyError ( " source kind should have been literalboolean " )
2023-01-04 21:55:05 +00:00
is PtNumber -> throw AssemblyError ( " source kind should have been literalnumber " )
is PtIdentifier -> throw AssemblyError ( " source kind should have been variable " )
is PtArrayIndexer -> throw AssemblyError ( " source kind should have been array " )
is PtMemoryByte -> throw AssemblyError ( " source kind should have been memory " )
is PtTypeCast -> assignTypeCastedValue ( assign . target , value . type , value . value , value )
is PtFunctionCall -> {
2023-02-03 23:02:50 +00:00
val symbol = asmgen . symbolTable . lookup ( value . name )
val sub = symbol !! . astNode as IPtSubroutine
2023-02-09 00:46:23 +00:00
asmgen . translateFunctionCall ( value )
2023-02-09 02:13:52 +00:00
val returnValue = sub . returnsWhatWhere ( ) . singleOrNull { it . first . registerOrPair != null } ?: sub . returnsWhatWhere ( ) . single { it . first . statusflag != null }
when ( returnValue . second ) {
2022-02-20 17:34:30 +00:00
DataType . STR -> {
when ( assign . target . datatype ) {
DataType . UWORD -> {
// assign the address of the string result value
assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
}
DataType . STR , DataType . ARRAY _UB , DataType . ARRAY _B -> {
2022-04-23 00:15:51 +00:00
throw AssemblyError ( " stringvalue assignment should have been replaced by a call to strcpy " )
2022-02-20 01:01:48 +00:00
}
2022-02-20 17:34:30 +00:00
else -> throw AssemblyError ( " weird target dt " )
}
}
DataType . FLOAT -> {
// float result from function sits in FAC1
assignFAC1float ( assign . target )
}
else -> {
// do NOT restore X register before assigning the result values first
2023-02-09 02:13:52 +00:00
when ( returnValue . first . registerOrPair ) {
2023-11-01 23:31:27 +00:00
RegisterOrPair . A -> assignRegisterByte ( assign . target , CpuRegister . A , returnValue . second in SignedDatatypes , true )
RegisterOrPair . X -> assignRegisterByte ( assign . target , CpuRegister . X , returnValue . second in SignedDatatypes , true )
RegisterOrPair . Y -> assignRegisterByte ( assign . target , CpuRegister . Y , returnValue . second in SignedDatatypes , true )
2022-08-09 21:38:29 +00:00
RegisterOrPair . AX -> assignVirtualRegister ( assign . target , RegisterOrPair . AX )
RegisterOrPair . AY -> assignVirtualRegister ( assign . target , RegisterOrPair . AY )
RegisterOrPair . XY -> assignVirtualRegister ( assign . target , RegisterOrPair . XY )
RegisterOrPair . R0 -> assignVirtualRegister ( assign . target , RegisterOrPair . R0 )
RegisterOrPair . R1 -> assignVirtualRegister ( assign . target , RegisterOrPair . R1 )
RegisterOrPair . R2 -> assignVirtualRegister ( assign . target , RegisterOrPair . R2 )
RegisterOrPair . R3 -> assignVirtualRegister ( assign . target , RegisterOrPair . R3 )
RegisterOrPair . R4 -> assignVirtualRegister ( assign . target , RegisterOrPair . R4 )
RegisterOrPair . R5 -> assignVirtualRegister ( assign . target , RegisterOrPair . R5 )
RegisterOrPair . R6 -> assignVirtualRegister ( assign . target , RegisterOrPair . R6 )
RegisterOrPair . R7 -> assignVirtualRegister ( assign . target , RegisterOrPair . R7 )
RegisterOrPair . R8 -> assignVirtualRegister ( assign . target , RegisterOrPair . R8 )
RegisterOrPair . R9 -> assignVirtualRegister ( assign . target , RegisterOrPair . R9 )
RegisterOrPair . R10 -> assignVirtualRegister ( assign . target , RegisterOrPair . R10 )
RegisterOrPair . R11 -> assignVirtualRegister ( assign . target , RegisterOrPair . R11 )
RegisterOrPair . R12 -> assignVirtualRegister ( assign . target , RegisterOrPair . R12 )
RegisterOrPair . R13 -> assignVirtualRegister ( assign . target , RegisterOrPair . R13 )
RegisterOrPair . R14 -> assignVirtualRegister ( assign . target , RegisterOrPair . R14 )
RegisterOrPair . R15 -> assignVirtualRegister ( assign . target , RegisterOrPair . R15 )
2022-02-20 01:01:48 +00:00
else -> {
2023-02-09 02:13:52 +00:00
val sflag = returnValue . first . statusflag
2022-02-20 17:34:30 +00:00
if ( sflag != null )
assignStatusFlagByte ( assign . target , sflag )
else
throw AssemblyError ( " should be just one register byte result value " )
2020-10-27 23:29:34 +00:00
}
2022-02-20 01:01:48 +00:00
}
}
2022-02-20 17:34:30 +00:00
}
}
2023-01-04 21:55:05 +00:00
is PtBuiltinFunctionCall -> {
2023-07-15 09:37:36 +00:00
val returnDt = asmgen . translateBuiltinFunctionCallExpression ( value , assign . target . register )
2022-02-20 17:34:30 +00:00
if ( assign . target . register == null ) {
// still need to assign the result to the target variable/etc.
2023-01-07 14:25:33 +00:00
when ( returnDt ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> assignRegisterByte ( assign . target , CpuRegister . A , returnDt in SignedDatatypes , false ) // function's byte result is in A
2022-02-20 17:34:30 +00:00
in WordDatatypes -> assignRegisterpairWord ( assign . target , RegisterOrPair . AY ) // function's word result is in AY
DataType . STR -> {
when ( assign . target . datatype ) {
2022-02-20 01:01:48 +00:00
DataType . STR -> {
2022-02-20 17:34:30 +00:00
asmgen . out ( """
2023-09-01 18:27:39 +00:00
tax
lda # < $ { assign . target . asmVarname }
sta P8ZP _SCRATCH _W1
lda # > $ { assign . target . asmVarname }
sta P8ZP _SCRATCH _W1 + 1
txa
jsr prog8 _lib . strcpy """ )
2022-02-20 01:01:48 +00:00
}
2022-02-20 17:34:30 +00:00
DataType . UWORD -> assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
else -> throw AssemblyError ( " str return value type mismatch with target " )
2020-10-06 22:06:42 +00:00
}
}
2022-02-20 17:34:30 +00:00
DataType . FLOAT -> {
// float result from function sits in FAC1
assignFAC1float ( assign . target )
2022-01-09 17:49:44 +00:00
}
2022-02-20 17:34:30 +00:00
else -> throw AssemblyError ( " weird result type " )
2022-01-09 17:49:44 +00:00
}
2019-08-16 20:49:29 +00:00
}
}
2023-01-04 21:55:05 +00:00
is PtPrefix -> {
2022-10-27 19:58:37 +00:00
if ( assign . target . array == null ) {
2023-07-16 19:52:28 +00:00
if ( assign . source . datatype == assign . target . datatype ) {
2024-02-12 20:29:02 +00:00
if ( assign . source . datatype in IntegerDatatypesWithBoolean ) {
2023-07-24 21:28:32 +00:00
val signed = assign . source . datatype in SignedDatatypes
2024-02-12 20:29:02 +00:00
if ( assign . source . datatype in ByteDatatypesWithBoolean ) {
2023-07-24 21:28:32 +00:00
assignExpressionToRegister ( value . value , RegisterOrPair . A , signed )
when ( value . operator ) {
" + " -> { }
" - " -> {
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " eor #255 | ina " )
else
asmgen . out ( " eor #255 | clc | adc #1 " )
}
" ~ " -> asmgen . out ( " eor #255 " )
2024-02-12 20:29:02 +00:00
" not " -> asmgen . out ( " eor #1 " )
2023-07-24 21:28:32 +00:00
else -> throw AssemblyError ( " invalid prefix operator " )
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , signed , false )
2023-07-24 21:28:32 +00:00
} else {
assignExpressionToRegister ( value . value , RegisterOrPair . AY , signed )
when ( value . operator ) {
" + " -> { }
" - " -> {
asmgen . out ( """
sec
eor # 255
adc # 0
2023-09-01 18:27:39 +00:00
tax
2023-07-24 21:28:32 +00:00
tya
eor # 255
adc # 0
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-24 21:28:32 +00:00
}
2023-09-01 18:27:39 +00:00
" ~ " -> asmgen . out ( " tax | tya | eor #255 | tay | txa | eor #255 " )
2024-02-12 20:29:02 +00:00
" not " -> throw AssemblyError ( " not shouldn't exist for an integer " )
2023-07-24 21:28:32 +00:00
else -> throw AssemblyError ( " invalid prefix operator " )
}
assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
}
} else {
// First assign the value to the target then apply the operator in place on the target.
// This saves a temporary variable
translateNormalAssignment (
AsmAssignment (
AsmAssignSource . fromAstSource ( value . value , program , asmgen ) ,
assign . target , program . memsizer , assign . position
) , scope
)
when ( value . operator ) {
" + " -> { }
" - " -> inplaceNegate ( assign , true , scope )
" ~ " -> inplaceInvert ( assign , scope )
2024-02-12 20:29:02 +00:00
" not " -> inplaceInvert ( assign , scope )
2023-07-24 21:28:32 +00:00
else -> throw AssemblyError ( " invalid prefix operator " )
}
2023-07-16 19:52:28 +00:00
}
} else {
// use a temporary variable
2024-02-13 20:56:22 +00:00
val tempvar = if ( value . type in ByteDatatypesWithBoolean ) " P8ZP_SCRATCH_B1 " else " P8ZP_SCRATCH_W1 "
2023-07-16 19:52:28 +00:00
assignExpressionToVariable ( value . value , tempvar , value . type )
when ( value . operator ) {
" + " -> { }
" - " , " ~ " -> {
val assignTempvar = AsmAssignment (
AsmAssignSource ( SourceStorageKind . VARIABLE , program , asmgen , value . type , variableAsmName = tempvar ) ,
AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , value . type , scope , assign . position , variableAsmName = tempvar ) ,
program . memsizer , assign . position )
if ( value . operator == " - " )
inplaceNegate ( assignTempvar , true , scope )
else
inplaceInvert ( assignTempvar , scope )
}
2024-02-12 20:29:02 +00:00
" not " -> {
val assignTempvar = AsmAssignment (
AsmAssignSource ( SourceStorageKind . VARIABLE , program , asmgen , value . type , variableAsmName = tempvar ) ,
AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , value . type , scope , assign . position , variableAsmName = tempvar ) ,
program . memsizer , assign . position )
inplaceInvert ( assignTempvar , scope )
}
2023-07-16 19:52:28 +00:00
else -> throw AssemblyError ( " invalid prefix operator " )
}
2024-02-12 20:29:02 +00:00
if ( value . type in ByteDatatypesWithBoolean )
2023-07-16 19:52:28 +00:00
assignVariableByte ( assign . target , tempvar )
else
assignVariableWord ( assign . target , tempvar , value . type )
2022-10-27 19:58:37 +00:00
}
} else {
2023-03-18 23:24:05 +00:00
assignPrefixedExpressionToArrayElt ( assign , scope )
2022-02-20 17:34:30 +00:00
}
2020-08-23 09:07:35 +00:00
}
2023-01-04 21:55:05 +00:00
is PtContainmentCheck -> {
2022-02-20 17:34:30 +00:00
containmentCheckIntoA ( value )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , true )
2022-02-20 17:34:30 +00:00
}
2023-03-16 01:27:30 +00:00
is PtBinaryExpression -> {
2022-06-12 20:55:23 +00:00
if ( ! attemptAssignOptimizedBinexpr ( value , assign ) ) {
2023-07-15 09:05:25 +00:00
// TOO BAD: the expression was too complex to translate into assembly.
2023-08-11 21:41:19 +00:00
val pos = if ( value . position !== Position . DUMMY ) value . position else assign . position
throw AssemblyError ( " Expression is too complex to translate into assembly. Split it up into several separate statements, introduce a temporary variable, or otherwise rewrite it. Location: $pos " )
2022-02-20 17:34:30 +00:00
}
2019-08-16 20:49:29 +00:00
}
2022-02-20 17:34:30 +00:00
else -> throw AssemblyError ( " weird assignment value type $value " )
2019-08-16 20:49:29 +00:00
}
2022-10-27 21:08:40 +00:00
}
2023-03-18 23:24:05 +00:00
private fun assignPrefixedExpressionToArrayElt ( assign : AsmAssignment , scope : IPtSubroutine ? ) {
2023-01-04 21:55:05 +00:00
require ( assign . source . expression is PtPrefix )
2022-11-03 19:08:46 +00:00
if ( assign . source . datatype == DataType . FLOAT ) {
// floatarray[x] = -value ... just use FAC1 to calculate the expression into and then store that back into the array.
assignExpressionToRegister ( assign . source . expression , RegisterOrPair . FAC1 , true )
assignFAC1float ( assign . target )
} else {
2024-02-13 20:56:22 +00:00
val register = if ( assign . source . datatype in ByteDatatypesWithBoolean ) RegisterOrPair . A else RegisterOrPair . AY
val assignToRegister = AsmAssignment ( assign . source ,
AsmAssignTarget ( TargetStorageKind . REGISTER , asmgen , assign . target . datatype , assign . target . scope , assign . target . position ,
register = register , origAstTarget = assign . target . origAstTarget ) , program . memsizer , assign . position )
asmgen . translateNormalAssignment ( assignToRegister , scope )
val signed = assign . target . datatype in SignedDatatypes
2022-11-03 19:08:46 +00:00
when ( assign . target . datatype ) {
2024-02-13 20:56:22 +00:00
in ByteDatatypesWithBoolean -> assignRegisterByte ( assign . target , CpuRegister . A , signed , false )
in WordDatatypes -> assignRegisterpairWord ( assign . target , RegisterOrPair . AY )
2022-11-03 19:08:46 +00:00
else -> throw AssemblyError ( " weird dt " )
}
2022-10-27 21:08:40 +00:00
}
2019-08-16 20:49:29 +00:00
}
2022-08-09 21:38:29 +00:00
private fun assignVirtualRegister ( target : AsmAssignTarget , register : RegisterOrPair ) {
when ( target . datatype ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> {
if ( register in Cx16VirtualRegisters ) {
asmgen . out ( " lda cx16. ${register.toString().lowercase()} L " )
} else {
TODO ( " LDA byte from $register " )
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , false )
2022-08-09 21:38:29 +00:00
}
in WordDatatypes -> assignRegisterpairWord ( target , register )
else -> throw AssemblyError ( " expected byte or word " )
}
}
2023-03-16 01:27:30 +00:00
private fun attemptAssignOptimizedBinexpr ( expr : PtBinaryExpression , assign : AsmAssignment ) : Boolean {
2023-08-11 21:41:19 +00:00
val translatedOk = when ( expr . operator ) {
in ComparisonOperators -> optimizedComparison ( expr , assign )
2024-02-12 20:29:02 +00:00
in BitwiseOperators -> optimizedBitwiseExpr ( expr , assign . target )
in LogicalOperators -> optimizedLogicalExpr ( expr , assign . target )
2023-08-11 21:41:19 +00:00
" + " , " - " -> optimizedPlusMinExpr ( expr , assign . target )
" << " , " >> " -> optimizedBitshiftExpr ( expr , assign . target )
" * " -> optimizedMultiplyExpr ( expr , assign . target )
" / " -> optimizedDivideExpr ( expr , assign . target )
" % " -> optimizedRemainderExpr ( expr , assign . target )
else -> false
}
return if ( translatedOk )
true
else
anyExprGen . assignAnyExpressionUsingStack ( expr , assign )
}
private fun optimizedComparison ( expr : PtBinaryExpression , assign : AsmAssignment ) : Boolean {
if ( expr . right . asConstInteger ( ) == 0 ) {
if ( expr . operator == " == " || expr . operator == " != " ) {
when ( assign . target . datatype ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> if ( attemptAssignToByteCompareZero ( expr , assign ) ) return true
2023-08-11 21:41:19 +00:00
else -> {
// do nothing, this is handled by a type cast.
2022-07-04 21:42:49 +00:00
}
}
}
2023-08-11 21:41:19 +00:00
}
2023-05-07 11:29:45 +00:00
2024-03-01 18:45:16 +00:00
// b = v > 99 --> b=false , if v>99 b=true
val targetReg = assign . target . register
if ( targetReg != null ) {
// a register as target should be handled slightly differently to avoid overwriting the value
val ifPart = PtNodeGroup ( )
val elsePart = PtNodeGroup ( )
val reg = when ( targetReg ) {
RegisterOrPair . A -> " a "
RegisterOrPair . X -> " x "
RegisterOrPair . Y -> " y "
else -> TODO ( " comparison to word register " )
}
val assignTrue = PtInlineAssembly ( " ld ${reg} #1 " , false , assign . target . position )
val assignFalse = PtInlineAssembly ( " ld ${reg} #0 " , false , assign . target . position )
ifPart . add ( assignTrue )
elsePart . add ( assignFalse )
2023-08-11 21:41:19 +00:00
val ifelse = PtIfElse ( assign . position )
2024-03-02 16:01:31 +00:00
val exprClone : PtBinaryExpression
if ( ! asmgen . isTargetCpu ( CpuType . VIRTUAL )
&& ( expr . operator == " > " || expr . operator == " <= " )
&& expr . right . type in WordDatatypes ) {
// word X>Y -> X<Y, X<=Y -> Y>=X , easier to do in 6502 (codegen also expects these to no longe exist!)
exprClone = PtBinaryExpression ( if ( expr . operator == " > " ) " < " else " >= " , expr . type , expr . position )
exprClone . children . add ( expr . children [ 1 ] ) // doesn't seem to need a deep clone
exprClone . children . add ( expr . children [ 0 ] ) // doesn't seem to need a deep clone
} else {
exprClone = PtBinaryExpression ( expr . operator , expr . type , expr . position )
exprClone . children . add ( expr . children [ 0 ] ) // doesn't seem to need a deep clone
exprClone . children . add ( expr . children [ 1 ] ) // doesn't seem to need a deep clone
}
2023-08-11 21:41:19 +00:00
ifelse . add ( exprClone )
2024-03-01 18:45:16 +00:00
ifelse . add ( ifPart )
ifelse . add ( elsePart )
2023-08-11 21:41:19 +00:00
ifelse . parent = expr . parent
asmgen . translate ( ifelse )
return true
}
2024-03-01 18:45:16 +00:00
val target = assign . target . origAstTarget
assignConstantByte ( assign . target , 0 )
val ifPart = PtNodeGroup ( )
val assignTrue : PtNode
if ( target != null ) {
// set target to true
assignTrue = PtAssignment ( assign . position )
assignTrue . add ( target )
assignTrue . add ( PtNumber . fromBoolean ( true , assign . position ) )
} else {
require ( assign . target . datatype in ByteDatatypes )
when ( assign . target . kind ) {
TargetStorageKind . VARIABLE -> {
if ( assign . target . datatype in WordDatatypes ) {
assignTrue = if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) ) {
PtInlineAssembly ( """
lda # 1
sta $ { assign . target . asmVarname }
stz $ { assign . target . asmVarname } + 1 """ , false, assign.target.position)
} else {
PtInlineAssembly ( """
lda # 1
sta $ { assign . target . asmVarname }
lda # 0
sta $ { assign . target . asmVarname } + 1 """ , false, assign.target.position)
}
} else {
assignTrue = PtInlineAssembly ( " lda #1 \n sta ${assign.target.asmVarname} " , false , assign . target . position )
}
}
TargetStorageKind . MEMORY -> {
val tgt = PtAssignTarget ( assign . target . position )
val targetmem = assign . target . memory !!
val mem = PtMemoryByte ( targetmem . position )
mem . add ( targetmem . address )
tgt . add ( mem )
assignTrue = PtAssignment ( assign . position )
assignTrue . add ( tgt )
assignTrue . add ( PtNumber . fromBoolean ( true , assign . position ) )
}
TargetStorageKind . ARRAY -> {
val tgt = PtAssignTarget ( assign . target . position )
val targetarray = assign . target . array !!
val array = PtArrayIndexer ( assign . target . datatype , targetarray . position )
array . add ( targetarray . variable )
array . add ( targetarray . index )
tgt . add ( array )
assignTrue = PtAssignment ( assign . position )
assignTrue . add ( tgt )
assignTrue . add ( PtNumber . fromBoolean ( true , assign . position ) )
}
TargetStorageKind . REGISTER -> { /* handled earlier */ return true }
}
}
ifPart . add ( assignTrue )
val ifelse = PtIfElse ( assign . position )
2024-03-02 16:01:31 +00:00
val exprClone : PtBinaryExpression
if ( ! asmgen . isTargetCpu ( CpuType . VIRTUAL )
&& ( expr . operator == " > " || expr . operator == " <= " )
&& expr . right . type in WordDatatypes ) {
// word X>Y -> X<Y, X<=Y -> Y>=X , easier to do in 6502 (codegen also expects these to no longe exist!)
exprClone = PtBinaryExpression ( if ( expr . operator == " > " ) " < " else " >= " , expr . type , expr . position )
exprClone . children . add ( expr . children [ 1 ] ) // doesn't seem to need a deep clone
exprClone . children . add ( expr . children [ 0 ] ) // doesn't seem to need a deep clone
} else {
exprClone = PtBinaryExpression ( expr . operator , expr . type , expr . position )
exprClone . children . add ( expr . children [ 0 ] ) // doesn't seem to need a deep clone
exprClone . children . add ( expr . children [ 1 ] ) // doesn't seem to need a deep clone
}
2024-03-01 18:45:16 +00:00
ifelse . add ( exprClone )
ifelse . add ( ifPart )
ifelse . add ( PtNodeGroup ( ) )
ifelse . parent = expr . parent
asmgen . translate ( ifelse )
return true
2023-07-15 14:36:53 +00:00
}
2024-01-05 23:04:15 +00:00
private fun directIntoY ( expr : PtExpression ) : Boolean {
return when ( expr ) {
is PtIdentifier -> true
is PtMachineRegister -> true
is PtNumber -> true
is PtBuiltinFunctionCall -> expr . name in arrayOf ( " lsb " , " msb " )
else -> false
}
}
2023-07-15 14:36:53 +00:00
private fun optimizedRemainderExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
when ( expr . type ) {
DataType . UBYTE -> {
2022-12-06 19:01:50 +00:00
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pha " )
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . right , RegisterOrPair . Y , false )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pla " )
asmgen . out ( " jsr math.divmod_ub_asm " )
2023-07-15 14:36:53 +00:00
if ( target . register == RegisterOrPair . A )
asmgen . out ( " cmp #0 " ) // fix the status register
else
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2023-05-07 11:29:45 +00:00
return true
2022-12-06 19:01:50 +00:00
}
2023-07-15 14:36:53 +00:00
DataType . UWORD -> {
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " P8ZP_SCRATCH_W1 " )
asmgen . out ( " jsr math.divmod_uw_asm " )
2023-07-16 21:31:07 +00:00
assignVariableWord ( target , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2023-07-15 14:36:53 +00:00
return true
}
else -> return false
}
}
private fun optimizedDivideExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
when ( expr . type ) {
DataType . UBYTE -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pha " )
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . right , RegisterOrPair . Y , false )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pla " )
asmgen . out ( " jsr math.divmod_ub_asm " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . Y , false , true )
2023-07-15 14:36:53 +00:00
return true
}
DataType . BYTE -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , true )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pha " )
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . right , RegisterOrPair . Y , true )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pla " )
asmgen . out ( " jsr math.divmod_b_asm " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . Y , true , true )
2023-07-15 14:36:53 +00:00
return true
}
DataType . UWORD -> {
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " P8ZP_SCRATCH_W1 " )
asmgen . out ( " jsr math.divmod_uw_asm " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
DataType . WORD -> {
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " P8ZP_SCRATCH_W1 " )
asmgen . out ( " jsr math.divmod_w_asm " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
else -> return false
}
}
private fun optimizedMultiplyExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
val value = expr . right . asConstInteger ( )
if ( value == null ) {
when ( expr . type ) {
in ByteDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , expr . type in SignedDatatypes )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pha " )
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . right , RegisterOrPair . Y , expr . type in SignedDatatypes )
2024-01-05 23:04:15 +00:00
if ( ! directIntoY ( expr . right ) ) asmgen . out ( " pla " )
asmgen . out ( " jsr math.multiply_bytes " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2023-07-15 14:36:53 +00:00
return true
}
in WordDatatypes -> {
2023-12-26 21:01:49 +00:00
if ( expr . definingBlock ( ) !! . options . veraFxMuls ) {
2023-10-05 19:52:48 +00:00
// cx16 verafx hardware mul
if ( expr . right . isSimple ( ) ) {
asmgen . assignExpressionToRegister ( expr . left , RegisterOrPair . R0 , expr . left . type in SignedDatatypes )
asmgen . assignExpressionToRegister ( expr . right , RegisterOrPair . R1 , expr . left . type in SignedDatatypes )
} else {
asmgen . assignExpressionToRegister ( expr . left , RegisterOrPair . AY , expr . left . type in SignedDatatypes )
2024-01-04 19:44:46 +00:00
asmgen . out ( " pha " )
2023-10-05 19:52:48 +00:00
asmgen . saveRegisterStack ( CpuRegister . Y , false )
asmgen . assignExpressionToRegister ( expr . right , RegisterOrPair . R1 , expr . left . type in SignedDatatypes )
asmgen . restoreRegisterStack ( CpuRegister . Y , false )
2024-01-04 19:44:46 +00:00
asmgen . out ( " pla " )
2023-10-05 19:52:48 +00:00
asmgen . out ( " sta cx16.r0 | sty cx16.r0+1 " )
}
asmgen . out ( " jsr verafx.muls " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
} else {
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " math.multiply_words.multiplier " )
asmgen . out ( " jsr math.multiply_words " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
}
2023-10-02 19:06:14 +00:00
return true
2023-07-15 14:36:53 +00:00
}
else -> return false
}
} else {
when ( expr . type ) {
in ByteDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , expr . type in SignedDatatypes )
if ( value in asmgen . optimizedByteMultiplications )
asmgen . out ( " jsr math.mul_byte_ ${value} " )
else
asmgen . out ( " ldy # $value | jsr math.multiply_bytes " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2023-07-15 14:36:53 +00:00
return true
}
in WordDatatypes -> {
if ( value in asmgen . optimizedWordMultiplications ) {
assignExpressionToRegister ( expr . left , RegisterOrPair . AY , expr . type in SignedDatatypes )
asmgen . out ( " jsr math.mul_word_ ${value} " )
2023-05-07 11:29:45 +00:00
}
2023-07-15 14:36:53 +00:00
else {
2023-12-26 21:01:49 +00:00
if ( expr . definingBlock ( ) !! . options . veraFxMuls ) {
2023-10-05 19:52:48 +00:00
// cx16 verafx hardware mul
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " cx16.r1 " )
asmgen . out ( """
sta cx16 . r0
sty cx16 . r0 + 1
jsr verafx . muls """ )
} else {
asmgen . assignWordOperandsToAYAndVar ( expr . right , expr . left , " math.multiply_words.multiplier " )
asmgen . out ( " jsr math.multiply_words " )
}
2023-05-07 11:29:45 +00:00
}
2023-07-15 14:36:53 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
2023-05-07 11:29:45 +00:00
}
2023-07-15 14:36:53 +00:00
else -> return false
2022-07-31 11:38:00 +00:00
}
}
2023-07-15 14:36:53 +00:00
}
2022-06-06 20:54:54 +00:00
2023-07-15 14:36:53 +00:00
private fun optimizedBitshiftExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
2023-07-16 15:39:30 +00:00
val signed = expr . left . type in SignedDatatypes
2023-07-15 14:36:53 +00:00
val shifts = expr . right . asConstInteger ( )
2023-07-16 15:39:30 +00:00
val dt = expr . left . type
if ( shifts == null ) {
// bit shifts with variable shifts
when ( expr . right . type ) {
in ByteDatatypes -> {
assignExpressionToRegister ( expr . right , RegisterOrPair . A , false )
}
in WordDatatypes -> {
assignExpressionToRegister ( expr . right , RegisterOrPair . AY , false )
asmgen . out ( """
cpy # 0
beq +
lda # 127
+ """ )
}
else -> throw AssemblyError ( " weird shift value type " )
}
asmgen . out ( " pha " )
2023-07-15 16:02:23 +00:00
if ( dt in ByteDatatypes ) {
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . left , RegisterOrPair . A , signed )
2023-08-14 19:58:26 +00:00
asmgen . restoreRegisterStack ( CpuRegister . Y , true )
2023-07-16 15:39:30 +00:00
if ( expr . operator == " >> " )
if ( signed )
asmgen . out ( " jsr math.lsr_byte_A " )
else
asmgen . out ( " jsr math.lsr_ubyte_A " )
else
asmgen . out ( " jsr math.asl_byte_A " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , signed , true )
2023-07-16 15:39:30 +00:00
return true
} else {
assignExpressionToRegister ( expr . left , RegisterOrPair . AY , signed )
2023-08-14 19:58:26 +00:00
asmgen . restoreRegisterStack ( CpuRegister . X , true )
2023-07-16 15:39:30 +00:00
if ( expr . operator == " >> " )
if ( signed )
asmgen . out ( " jsr math.lsr_word_AY " )
else
asmgen . out ( " jsr math.lsr_uword_AY " )
else
asmgen . out ( " jsr math.asl_word_AY " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
}
else {
// bit shift with constant value
if ( dt in ByteDatatypes ) {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , signed )
when ( shifts ) {
in 0. . 7 -> {
if ( expr . operator == " << " ) {
2023-07-15 16:02:23 +00:00
repeat ( shifts ) {
2023-07-16 15:39:30 +00:00
asmgen . out ( " asl a " )
}
} else {
if ( signed && shifts > 0 ) {
asmgen . out ( " ldy # $shifts | jsr math.lsr_byte_A " )
} else {
repeat ( shifts ) {
asmgen . out ( " lsr a " )
}
2023-07-15 16:02:23 +00:00
}
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , signed , true )
2023-07-16 15:39:30 +00:00
return true
2023-07-15 14:36:53 +00:00
}
2023-07-16 15:39:30 +00:00
else -> {
if ( signed && expr . operator == " >> " ) {
2023-07-22 21:08:22 +00:00
asmgen . out ( " ldy # $shifts | jsr math.lsr_byte_A " )
2023-07-16 15:39:30 +00:00
} else {
asmgen . out ( " lda #0 " )
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , signed , true )
2023-07-16 15:39:30 +00:00
return true
2023-07-15 14:36:53 +00:00
}
2022-06-06 20:54:54 +00:00
}
2023-07-15 16:02:23 +00:00
} else if ( dt in WordDatatypes ) {
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . left , RegisterOrPair . AY , signed )
2023-07-16 15:39:30 +00:00
when ( shifts ) {
in 0. . 7 -> {
if ( expr . operator == " << " ) {
2023-07-15 16:02:23 +00:00
if ( shifts > 0 ) {
asmgen . out ( " sty P8ZP_SCRATCH_B1 " )
repeat ( shifts ) {
2023-07-16 15:39:30 +00:00
asmgen . out ( " asl a | rol P8ZP_SCRATCH_B1 " )
2023-07-15 16:02:23 +00:00
}
asmgen . out ( " ldy P8ZP_SCRATCH_B1 " )
}
2023-07-16 15:39:30 +00:00
} else {
if ( signed && shifts > 0 ) {
asmgen . out ( " ldx # $shifts | jsr math.lsr_word_AY " )
} else {
if ( shifts > 0 ) {
asmgen . out ( " sty P8ZP_SCRATCH_B1 " )
repeat ( shifts ) {
asmgen . out ( " lsr P8ZP_SCRATCH_B1 | ror a " )
}
asmgen . out ( " ldy P8ZP_SCRATCH_B1 " )
}
}
2023-07-15 16:02:23 +00:00
}
2023-07-16 15:39:30 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
2023-07-15 16:02:23 +00:00
}
2023-07-16 15:39:30 +00:00
in 8. . 15 -> {
if ( expr . operator == " << " ) {
// msb = lsb << (shifts-8), lsb = 0
repeat ( shifts - 8 ) {
asmgen . out ( " asl a " )
}
asmgen . out ( " tay | lda #0 " )
} else {
2023-12-29 04:04:38 +00:00
asmgen . out ( " ldx # $shifts " )
if ( signed )
asmgen . out ( " jsr math.lsr_word_AY " )
else
asmgen . out ( " jsr math.lsr_uword_AY " )
2023-07-15 16:02:23 +00:00
}
2023-07-16 15:39:30 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
2023-07-15 14:36:53 +00:00
}
2023-07-16 15:39:30 +00:00
else -> {
if ( signed && expr . operator == " >> " ) {
2023-07-22 21:08:22 +00:00
asmgen . out ( " ldx # $shifts | jsr math.lsr_word_AY " )
2023-07-16 15:39:30 +00:00
} else {
asmgen . out ( " lda #0 | ldy #0 " )
}
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
2023-07-15 16:02:23 +00:00
}
2022-06-06 20:54:54 +00:00
}
}
2022-07-31 11:38:00 +00:00
}
2023-07-15 14:36:53 +00:00
return false
}
2023-05-08 01:30:14 +00:00
2023-07-15 14:36:53 +00:00
private fun optimizedPlusMinExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
val dt = expr . type
val left = expr . left
val right = expr . right
if ( dt in ByteDatatypes ) {
when ( right ) {
is PtIdentifier -> {
assignExpressionToRegister ( left , RegisterOrPair . A , dt == DataType . BYTE )
val symname = asmgen . asmVariableName ( right )
2023-05-08 01:30:14 +00:00
if ( expr . operator == " + " )
2023-07-15 14:36:53 +00:00
asmgen . out ( " clc | adc $symname " )
else
asmgen . out ( " sec | sbc $symname " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
2023-07-15 14:36:53 +00:00
return true
}
is PtNumber -> {
assignExpressionToRegister ( left , RegisterOrPair . A , dt == DataType . BYTE )
if ( expr . operator == " + " )
asmgen . out ( " clc | adc # ${right.number.toHex()} " )
else
asmgen . out ( " sec | sbc # ${right.number.toHex()} " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
2023-07-15 14:36:53 +00:00
return true
}
else -> {
2024-02-03 16:36:42 +00:00
val leftMemByte = expr . left as ? PtMemoryByte
val rightMemByte = expr . right as ? PtMemoryByte
val leftArrayIndexer = expr . left as ? PtArrayIndexer
2023-09-04 19:07:49 +00:00
val rightArrayIndexer = expr . right as ? PtArrayIndexer
2024-02-03 16:36:42 +00:00
if ( expr . operator == " + " && leftArrayIndexer != null && leftArrayIndexer . type in ByteDatatypes && right . type in ByteDatatypes ) {
// special optimization for bytearray[y] + bytevalue : no need to use a tempvar, just use adc array,y
assignExpressionToRegister ( right , RegisterOrPair . A , right . type == DataType . BYTE )
if ( ! leftArrayIndexer . index . isSimple ( ) ) asmgen . out ( " pha " )
asmgen . assignExpressionToRegister ( leftArrayIndexer . index , RegisterOrPair . Y , false )
if ( ! leftArrayIndexer . index . isSimple ( ) ) asmgen . out ( " pla " )
val arrayvarname = asmgen . asmSymbolName ( leftArrayIndexer . variable )
asmgen . out ( " clc | adc $arrayvarname ,y " )
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
} else if ( rightArrayIndexer != null && rightArrayIndexer . type in ByteDatatypes && left . type in ByteDatatypes ) {
// special optimization for bytevalue +/- bytearray[y] : no need to use a tempvar, just use adc array,y or sbc array,y
2023-09-04 19:07:49 +00:00
assignExpressionToRegister ( left , RegisterOrPair . A , left . type == DataType . BYTE )
2023-09-07 20:17:46 +00:00
if ( ! rightArrayIndexer . index . isSimple ( ) ) asmgen . out ( " pha " )
2023-09-04 19:07:49 +00:00
asmgen . assignExpressionToRegister ( rightArrayIndexer . index , RegisterOrPair . Y , false )
2023-09-07 20:17:46 +00:00
if ( ! rightArrayIndexer . index . isSimple ( ) ) asmgen . out ( " pla " )
2024-02-03 00:57:17 +00:00
val arrayvarname = asmgen . asmSymbolName ( rightArrayIndexer . variable )
if ( expr . operator == " + " )
asmgen . out ( " clc | adc $arrayvarname ,y " )
else
asmgen . out ( " sec | sbc $arrayvarname ,y " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
2024-02-03 22:11:53 +00:00
} else if ( expr . operator == " + " && leftMemByte != null && right . type in ByteDatatypes && optimizedPointerIndexPlusMinusByteIntoA ( right , " + " , leftMemByte ) ) {
2024-02-03 16:36:42 +00:00
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
return true
} else if ( rightMemByte != null && left . type in ByteDatatypes && optimizedPointerIndexPlusMinusByteIntoA ( left , expr . operator , rightMemByte ) ) {
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
return true
2023-09-04 19:07:49 +00:00
} else {
assignExpressionToRegister ( left , RegisterOrPair . A , left . type == DataType . BYTE )
2024-01-05 23:04:15 +00:00
if ( directIntoY ( right ) ) {
assignExpressionToRegister ( right , RegisterOrPair . Y , left . type == DataType . BYTE )
asmgen . out ( " sty P8ZP_SCRATCH_B1 " )
} else {
asmgen . out ( " pha " )
assignExpressionToVariable ( right , " P8ZP_SCRATCH_B1 " , right . type )
asmgen . out ( " pla " )
}
2023-09-04 19:07:49 +00:00
if ( expr . operator == " + " )
asmgen . out ( " clc | adc P8ZP_SCRATCH_B1 " )
else
asmgen . out ( " sec | sbc P8ZP_SCRATCH_B1 " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , dt in SignedDatatypes , true )
2023-09-04 19:07:49 +00:00
}
2023-07-15 14:36:53 +00:00
return true
}
}
} else if ( dt in WordDatatypes ) {
fun doAddOrSubWordExpr ( ) {
asmgen . assignWordOperandsToAYAndVar ( expr . left , expr . right , " P8ZP_SCRATCH_W1 " )
if ( expr . operator == " + " )
asmgen . out ( """
2023-05-08 01:30:14 +00:00
clc
2023-05-08 19:51:55 +00:00
adc P8ZP _SCRATCH _W1
2023-09-01 18:27:39 +00:00
tax
2023-05-08 01:30:14 +00:00
tya
2023-05-08 19:51:55 +00:00
adc P8ZP _SCRATCH _W1 + 1
2023-05-08 01:30:14 +00:00
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-15 14:36:53 +00:00
else
asmgen . out ( """
2023-05-08 01:30:14 +00:00
sec
2023-05-08 19:51:55 +00:00
sbc P8ZP _SCRATCH _W1
2023-09-01 18:27:39 +00:00
tax
2023-05-08 01:30:14 +00:00
tya
2023-05-08 19:51:55 +00:00
sbc P8ZP _SCRATCH _W1 + 1
2023-05-08 01:30:14 +00:00
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-15 14:36:53 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
}
2023-05-08 01:30:14 +00:00
2023-07-15 14:36:53 +00:00
when ( right ) {
is PtAddressOf -> {
val symbol = asmgen . asmVariableName ( right . identifier )
2023-09-17 16:30:57 +00:00
if ( right . isFromArrayElement ) {
TODO ( " address-of array element $symbol at ${right.position} " )
} else {
assignExpressionToRegister ( left , RegisterOrPair . AY , dt == DataType . WORD )
if ( expr . operator == " + " )
asmgen . out ( """
clc
adc # < $ symbol
tax
tya
adc # > $ symbol
tay
txa """ )
else
asmgen . out ( """
sec
sbc # < $ symbol
tax
tya
sbc # > $ symbol
tay
txa """ )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
2023-07-15 14:36:53 +00:00
}
is PtIdentifier -> {
val symname = asmgen . asmVariableName ( right )
assignExpressionToRegister ( left , RegisterOrPair . AY , dt == DataType . WORD )
if ( expr . operator == " + " )
asmgen . out ( """
2022-07-31 11:38:00 +00:00
clc
adc $ symname
2023-09-01 18:27:39 +00:00
tax
2022-07-31 11:38:00 +00:00
tya
adc $ symname + 1
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-15 14:36:53 +00:00
else
asmgen . out ( """
2022-07-31 11:38:00 +00:00
sec
sbc $ symname
2023-09-01 18:27:39 +00:00
tax
2022-07-31 11:38:00 +00:00
tya
sbc $ symname + 1
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-15 14:36:53 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
is PtNumber -> {
assignExpressionToRegister ( left , RegisterOrPair . AY , dt == DataType . WORD )
if ( expr . operator == " + " ) {
asmgen . out ( """
2022-07-31 11:38:00 +00:00
clc
adc # < $ { right . number . toHex ( ) }
2023-09-01 18:27:39 +00:00
tax
2022-07-31 11:38:00 +00:00
tya
adc # > $ { right . number . toHex ( ) }
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-07-15 14:36:53 +00:00
} else if ( expr . operator == " - " ) {
asmgen . out ( """
2022-07-31 11:38:00 +00:00
sec
sbc # < $ { right . number . toHex ( ) }
2023-09-01 18:27:39 +00:00
tax
2022-07-31 11:38:00 +00:00
tya
sbc # > $ { right . number . toHex ( ) }
tay
2023-09-01 18:27:39 +00:00
txa """ )
2022-07-31 11:38:00 +00:00
}
2023-07-15 14:36:53 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
is PtTypeCast -> {
val castedValue = right . value
if ( right . type in WordDatatypes && castedValue . type in ByteDatatypes && castedValue is PtIdentifier ) {
2023-10-17 00:34:56 +00:00
if ( right . type in SignedDatatypes ) {
// we need to sign extend, do this via temporary word variable
asmgen . assignExpressionToVariable ( right , " P8ZP_SCRATCH_W1 " , DataType . WORD )
assignExpressionToRegister ( left , RegisterOrPair . AY , dt == DataType . WORD )
if ( expr . operator == " + " ) {
asmgen . out ( """
clc
adc P8ZP _SCRATCH _W1
tax
tya
adc P8ZP _SCRATCH _W1 + 1
tay
txa """ )
} else if ( expr . operator == " - " ) {
asmgen . out ( """
sec
sbc P8ZP _SCRATCH _W1
tax
tya
sbc P8ZP _SCRATCH _W1 + 1
tay
txa """ )
}
} else {
assignExpressionToRegister ( left , RegisterOrPair . AY , dt == DataType . WORD )
val castedSymname = asmgen . asmVariableName ( castedValue )
if ( expr . operator == " + " )
asmgen . out (
2023-07-15 14:36:53 +00:00
"""
2023-05-08 01:30:14 +00:00
clc
adc $ castedSymname
bcc +
iny
+ """
2023-07-15 14:36:53 +00:00
)
2023-10-17 00:34:56 +00:00
else
asmgen . out (
2023-07-15 14:36:53 +00:00
"""
2023-05-08 01:30:14 +00:00
sec
sbc $ castedSymname
bcs +
dey
+ """
2023-07-15 14:36:53 +00:00
)
2023-10-17 00:34:56 +00:00
}
2023-07-15 14:36:53 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
2023-05-08 01:30:14 +00:00
return true
2022-06-06 20:54:54 +00:00
}
2023-07-15 14:36:53 +00:00
doAddOrSubWordExpr ( )
2022-11-15 01:45:51 +00:00
return true
2023-07-15 14:36:53 +00:00
}
else -> {
doAddOrSubWordExpr ( )
2022-11-15 01:45:51 +00:00
return true
}
}
}
2023-07-15 14:36:53 +00:00
return false
}
2024-02-03 16:36:42 +00:00
private fun optimizedPointerIndexPlusMinusByteIntoA ( value : PtExpression , operator : String , mem : PtMemoryByte ) : Boolean {
// special optimization for bytevalue +/- pointervar[y] (actually: bytevalue +/- @(address) )
val address = mem . address as ? PtBinaryExpression
if ( address is PtBinaryExpression ) {
2024-02-03 22:11:53 +00:00
val ptrVar = address . left as ? PtIdentifier
if ( ptrVar != null && asmgen . isZpVar ( ptrVar ) ) {
assignExpressionToRegister ( value , RegisterOrPair . A , false )
val pointername = asmgen . asmVariableName ( ptrVar )
val constOffset = address . right . asConstInteger ( )
if ( constOffset != null && constOffset < 256 ) {
// we have value + @(zpptr + 255), or value - @(zpptr+255)
asmgen . out ( " ldy # $constOffset " )
if ( operator == " + " )
asmgen . out ( " clc | adc ( $pointername ),y " )
else
asmgen . out ( " sec | sbc ( $pointername ),y " )
} else if ( address . right . type in ByteDatatypes ) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
asmgen . out ( " pha " )
assignExpressionToRegister ( address . right , RegisterOrPair . Y , false )
asmgen . out ( " pla " )
if ( operator == " + " )
asmgen . out ( " clc | adc ( $pointername ),y " )
else
asmgen . out ( " sec | sbc ( $pointername ),y " )
} else if ( ( address . right as ? PtTypeCast ) ?. value ?. type in ByteDatatypes ) {
// we have @(ptr + bytevar as uword) ++ , or @(ptr+bytevar as uword)--
asmgen . out ( " pha " )
assignExpressionToRegister ( ( address . right as PtTypeCast ) . value , RegisterOrPair . Y , false )
asmgen . out ( " pla " )
if ( operator == " + " )
asmgen . out ( " clc | adc ( $pointername ),y " )
else
asmgen . out ( " sec | sbc ( $pointername ),y " )
}
return true
2024-02-03 16:36:42 +00:00
}
}
return false
}
2023-11-15 22:10:20 +00:00
private fun optimizedBitwiseExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
2023-07-15 14:36:53 +00:00
if ( expr . left . type in ByteDatatypes && expr . right . type in ByteDatatypes ) {
if ( expr . right . isSimple ( ) ) {
if ( expr . right is PtNumber || expr . right is PtIdentifier ) {
2023-11-15 22:10:20 +00:00
assignBitwiseWithSimpleRightOperandByte ( target , expr . left , expr . operator , expr . right )
2023-05-07 23:03:54 +00:00
return true
}
2023-07-15 14:36:53 +00:00
else if ( expr . left is PtNumber || expr . left is PtIdentifier ) {
2023-11-15 22:10:20 +00:00
assignBitwiseWithSimpleRightOperandByte ( target , expr . right , expr . operator , expr . left )
2023-05-07 23:03:54 +00:00
return true
}
}
2024-02-13 20:56:22 +00:00
val rightArray = expr . right as ? PtArrayIndexer
if ( rightArray != null ) {
val constIndex = rightArray . index . asConstInteger ( )
if ( constIndex != null ) {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
val valueVarname = " ${asmgen.asmSymbolName(rightArray.variable)} + ${constIndex*program.memsizer.memorySize(rightArray.type)} "
when ( expr . operator ) {
" & " -> asmgen . out ( " and $valueVarname " )
" | " -> asmgen . out ( " ora $valueVarname " )
" ^ " -> asmgen . out ( " eor $valueVarname " )
else -> throw AssemblyError ( " invalid logical operator " )
}
assignRegisterByte ( target , CpuRegister . A , false , true )
return true
}
}
2023-07-15 14:36:53 +00:00
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
2024-01-05 23:04:15 +00:00
if ( directIntoY ( expr . right ) ) {
assignExpressionToRegister ( expr . right , RegisterOrPair . Y , false )
asmgen . out ( " sty P8ZP_SCRATCH_B1 " )
} else {
asmgen . out ( " pha " )
assignExpressionToVariable ( expr . right , " P8ZP_SCRATCH_B1 " , DataType . UBYTE )
asmgen . out ( " pla " )
}
2023-07-15 14:36:53 +00:00
when ( expr . operator ) {
2023-11-15 22:10:20 +00:00
" & " -> asmgen . out ( " and P8ZP_SCRATCH_B1 " )
" | " -> asmgen . out ( " ora P8ZP_SCRATCH_B1 " )
2024-02-13 20:56:22 +00:00
" ^ " -> asmgen . out ( " eor P8ZP_SCRATCH_B1 " )
2023-11-15 22:10:20 +00:00
else -> throw AssemblyError ( " invalid bitwise operator " )
2023-07-15 14:36:53 +00:00
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2023-07-15 14:36:53 +00:00
return true
2023-05-07 23:03:54 +00:00
}
2023-07-15 14:36:53 +00:00
else if ( expr . left . type in WordDatatypes && expr . right . type in WordDatatypes ) {
if ( expr . right . isSimple ( ) ) {
if ( expr . right is PtNumber || expr . right is PtIdentifier ) {
2023-11-15 22:10:20 +00:00
assignBitwiseWithSimpleRightOperandWord ( target , expr . left , expr . operator , expr . right )
2023-05-07 23:03:54 +00:00
return true
}
2023-07-15 14:36:53 +00:00
else if ( expr . left is PtNumber || expr . left is PtIdentifier ) {
2023-11-15 22:10:20 +00:00
assignBitwiseWithSimpleRightOperandWord ( target , expr . right , expr . operator , expr . left )
2023-05-07 23:03:54 +00:00
return true
}
}
2023-07-15 14:36:53 +00:00
asmgen . assignWordOperandsToAYAndVar ( expr . left , expr . right , " P8ZP_SCRATCH_W1 " )
when ( expr . operator ) {
2023-11-15 22:10:20 +00:00
" & " -> asmgen . out ( " and P8ZP_SCRATCH_W1 | tax | tya | and P8ZP_SCRATCH_W1+1 | tay | txa " )
" | " -> asmgen . out ( " ora P8ZP_SCRATCH_W1 | tax | tya | ora P8ZP_SCRATCH_W1+1 | tay | txa " )
2024-02-13 20:56:22 +00:00
" ^ " -> asmgen . out ( " eor P8ZP_SCRATCH_W1 | tax | tya | eor P8ZP_SCRATCH_W1+1 | tay | txa " )
2023-11-15 22:10:20 +00:00
else -> throw AssemblyError ( " invalid bitwise operator " )
}
assignRegisterpairWord ( target , RegisterOrPair . AY )
return true
}
return false
}
2024-02-12 20:29:02 +00:00
private fun optimizedLogicalExpr ( expr : PtBinaryExpression , target : AsmAssignTarget ) : Boolean {
2023-11-15 22:10:20 +00:00
2024-02-13 20:56:22 +00:00
fun swapOperands ( ) : Boolean =
if ( expr . right is PtIdentifier || expr . right is PtMemoryByte )
false
else
expr . left is PtIdentifier || expr . left is PtMemoryByte
fun assignResultIntoA ( left : PtExpression , operator : String , right : PtExpression ) {
// non short-circuit evaluation it is *likely* shorter and faster because of the simple operands.
fun assignViaScratch ( ) {
if ( directIntoY ( right ) ) {
assignExpressionToRegister ( right , RegisterOrPair . Y , false )
2024-01-05 23:04:15 +00:00
asmgen . out ( " sty P8ZP_SCRATCH_B1 " )
} else {
asmgen . out ( " pha " )
2024-02-13 20:56:22 +00:00
assignExpressionToVariable ( right , " P8ZP_SCRATCH_B1 " , DataType . UBYTE )
2024-01-05 23:04:15 +00:00
asmgen . out ( " pla " )
}
2024-02-13 20:56:22 +00:00
when ( operator ) {
2023-12-30 01:18:56 +00:00
" and " -> asmgen . out ( " and P8ZP_SCRATCH_B1 " )
" or " -> asmgen . out ( " ora P8ZP_SCRATCH_B1 " )
2024-02-12 20:29:02 +00:00
" xor " -> asmgen . out ( " eor P8ZP_SCRATCH_B1 " )
2023-12-30 01:18:56 +00:00
else -> throw AssemblyError ( " invalid logical operator " )
}
2023-11-15 22:10:20 +00:00
}
2024-02-13 20:56:22 +00:00
assignExpressionToRegister ( left , RegisterOrPair . A , false )
when ( right ) {
is PtBool -> throw AssemblyError ( " bool literal in logical expr should have been optimized away " )
is PtIdentifier -> {
val varname = asmgen . asmVariableName ( right )
when ( operator ) {
" and " -> asmgen . out ( " and $varname " )
" or " -> asmgen . out ( " ora $varname " )
" xor " -> asmgen . out ( " eor $varname " )
else -> throw AssemblyError ( " invalid logical operator " )
}
}
is PtMemoryByte -> {
val constAddress = right . address . asConstInteger ( )
if ( constAddress != null ) {
when ( operator ) {
" and " -> asmgen . out ( " and ${constAddress.toHex()} " )
" or " -> asmgen . out ( " ora ${constAddress.toHex()} " )
" xor " -> asmgen . out ( " eor ${constAddress.toHex()} " )
else -> throw AssemblyError ( " invalid logical operator " )
}
}
else assignViaScratch ( )
}
is PtArrayIndexer -> {
val constIndex = right . index . asConstInteger ( )
if ( constIndex != null ) {
val valueVarname = " ${asmgen.asmSymbolName(right.variable)} + ${constIndex*program.memsizer.memorySize(right.type)} "
when ( operator ) {
" and " -> asmgen . out ( " and $valueVarname " )
" or " -> asmgen . out ( " ora $valueVarname " )
" xor " -> asmgen . out ( " eor $valueVarname " )
else -> throw AssemblyError ( " invalid logical operator " )
}
}
else assignViaScratch ( )
}
else -> assignViaScratch ( )
}
2023-11-15 22:10:20 +00:00
}
2024-02-13 20:56:22 +00:00
if ( ! expr . right . isSimple ( ) && expr . operator != " xor " ) {
// shortcircuit evaluation into A
val shortcutLabel = asmgen . makeLabel ( " shortcut " )
when ( expr . operator ) {
" and " -> {
// short-circuit LEFT and RIGHT --> if LEFT then RIGHT else LEFT (== if !LEFT then LEFT else RIGHT)
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
asmgen . out ( " beq $shortcutLabel " )
assignExpressionToRegister ( expr . right , RegisterOrPair . A , false )
asmgen . out ( shortcutLabel )
}
" or " -> {
// short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT
assignExpressionToRegister ( expr . left , RegisterOrPair . A , false )
asmgen . out ( " bne $shortcutLabel " )
assignExpressionToRegister ( expr . right , RegisterOrPair . A , false )
asmgen . out ( shortcutLabel )
}
else -> throw AssemblyError ( " invalid logical operator " )
}
} else if ( swapOperands ( ) ) {
// non short-circuit evaluation is *likely* shorter and faster because of the simple operands.
assignResultIntoA ( expr . right , expr . operator , expr . left )
} else {
assignResultIntoA ( expr . left , expr . operator , expr . right )
2023-05-07 23:03:54 +00:00
}
2024-02-13 20:56:22 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
return true
2022-06-06 20:54:54 +00:00
}
2023-11-15 22:10:20 +00:00
private fun assignBitwiseWithSimpleRightOperandByte ( target : AsmAssignTarget , left : PtExpression , operator : String , right : PtExpression ) {
2022-08-11 22:46:38 +00:00
assignExpressionToRegister ( left , RegisterOrPair . A , false )
val operand = when ( right ) {
2023-01-04 21:55:05 +00:00
is PtNumber -> " # ${right.number.toHex()} "
is PtIdentifier -> asmgen . asmSymbolName ( right )
2022-08-11 22:46:38 +00:00
else -> throw AssemblyError ( " wrong right operand type " )
}
when ( operator ) {
2023-11-15 22:10:20 +00:00
" & " -> asmgen . out ( " and $operand " )
" | " -> asmgen . out ( " ora $operand " )
2024-02-12 20:29:02 +00:00
" ^ " -> asmgen . out ( " eor $operand " )
2022-08-11 22:46:38 +00:00
else -> throw AssemblyError ( " invalid operator " )
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2022-08-11 22:46:38 +00:00
}
2023-11-15 22:10:20 +00:00
private fun assignBitwiseWithSimpleRightOperandWord ( target : AsmAssignTarget , left : PtExpression , operator : String , right : PtExpression ) {
2022-08-11 22:46:38 +00:00
assignExpressionToRegister ( left , RegisterOrPair . AY , false )
when ( right ) {
2023-01-04 21:55:05 +00:00
is PtNumber -> {
2022-08-11 22:46:38 +00:00
val number = right . number . toHex ( )
when ( operator ) {
2023-11-15 22:10:20 +00:00
" & " -> asmgen . out ( " and #< $number | tax | tya | and #> $number | tay | txa " )
" | " -> asmgen . out ( " ora #< $number | tax | tya | ora #> $number | tay | txa " )
2024-02-12 20:29:02 +00:00
" ^ " -> asmgen . out ( " eor #< $number | tax | tya | eor #> $number | tay | txa " )
2023-11-15 22:10:20 +00:00
else -> throw AssemblyError ( " invalid bitwise operator " )
2022-08-11 22:46:38 +00:00
}
}
2023-01-04 21:55:05 +00:00
is PtIdentifier -> {
2022-08-11 22:46:38 +00:00
val name = asmgen . asmSymbolName ( right )
when ( operator ) {
2023-11-15 22:10:20 +00:00
" & " -> asmgen . out ( " and $name | tax | tya | and $name +1 | tay | txa " )
" | " -> asmgen . out ( " ora $name | tax | tya | ora $name +1 | tay | txa " )
2024-02-12 20:29:02 +00:00
" ^ " -> asmgen . out ( " eor $name | tax | tya | eor $name +1 | tay | txa " )
2023-11-15 22:10:20 +00:00
else -> throw AssemblyError ( " invalid bitwise operator " )
2022-08-11 22:46:38 +00:00
}
}
else -> throw AssemblyError ( " wrong right operand type " )
}
assignRegisterpairWord ( target , RegisterOrPair . AY )
}
2023-03-16 01:27:30 +00:00
private fun attemptAssignToByteCompareZero ( expr : PtBinaryExpression , assign : AsmAssignment ) : Boolean {
2022-07-04 21:42:49 +00:00
when ( expr . operator ) {
" == " -> {
2023-01-04 21:55:05 +00:00
when ( val dt = expr . left . type ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> TODO ( " compare bool to 0 " )
2022-07-04 21:42:49 +00:00
in ByteDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , dt == DataType . BYTE )
asmgen . out ( """
beq +
2023-08-31 23:50:28 +00:00
lda # 1
+ eor # 1 """ )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , false )
2022-07-04 21:42:49 +00:00
return true
}
in WordDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . AY , dt == DataType . WORD )
asmgen . out ( """
sty P8ZP _SCRATCH _B1
ora P8ZP _SCRATCH _B1
beq +
2023-08-31 23:50:28 +00:00
lda # 1
+ eor # 1 """ )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , false )
2022-07-04 21:42:49 +00:00
return true
}
DataType . FLOAT -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . FAC1 , true )
asmgen . out ( " jsr floats.SIGN | and #1 | eor #1 " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , false )
2022-07-04 21:42:49 +00:00
return true
}
else -> {
return false
}
}
}
" != " -> {
2023-01-04 21:55:05 +00:00
when ( val dt = expr . left . type ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> TODO ( " compare bool to 0 " )
2022-07-04 21:42:49 +00:00
in ByteDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . A , dt == DataType . BYTE )
asmgen . out ( " beq + | lda #1 " )
asmgen . out ( " + " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , false )
2022-07-04 21:42:49 +00:00
return true
}
in WordDatatypes -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . AY , dt == DataType . WORD )
asmgen . out ( " sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1 " )
asmgen . out ( " beq + | lda #1 " )
asmgen . out ( " + " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , false , false )
2022-07-04 21:42:49 +00:00
return true
}
DataType . FLOAT -> {
assignExpressionToRegister ( expr . left , RegisterOrPair . FAC1 , true )
asmgen . out ( " jsr floats.SIGN " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( assign . target , CpuRegister . A , true , false )
2022-07-04 21:42:49 +00:00
return true
}
else -> {
return false
}
}
}
else -> return false
}
}
2023-01-04 21:55:05 +00:00
private fun containmentCheckIntoA ( containment : PtContainmentCheck ) {
val elementDt = containment . element . type
2023-12-11 21:51:33 +00:00
val symbol = asmgen . symbolTable . lookup ( containment . iterable . name ) !!
val symbolName = asmgen . asmVariableName ( symbol , containment . definingSub ( ) )
val ( dt , numElements ) = when ( symbol ) {
is StStaticVariable -> symbol . dt to symbol . length !!
is StMemVar -> symbol . dt to symbol . length !!
else -> DataType . UNDEFINED to 0
2023-02-12 16:04:58 +00:00
}
2023-12-11 21:51:33 +00:00
when ( dt ) {
2022-03-27 13:23:32 +00:00
DataType . STR -> {
2023-01-04 21:55:05 +00:00
assignExpressionToRegister ( containment . element , RegisterOrPair . A , elementDt == DataType . BYTE )
2024-01-05 19:46:26 +00:00
asmgen . out ( " pha " ) // need to keep the scratch var safe so we have to do it in this order
2023-12-11 21:51:33 +00:00
assignAddressOf ( AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , DataType . UWORD , containment . definingISub ( ) , containment . position , " P8ZP_SCRATCH_W1 " ) , symbolName , null , null )
2024-01-04 19:44:46 +00:00
asmgen . out ( " pla " )
2023-12-11 21:51:33 +00:00
asmgen . out ( " ldy # ${numElements-1} " )
2022-03-27 13:23:32 +00:00
asmgen . out ( " jsr prog8_lib.containment_bytearray " )
2021-12-29 15:21:37 +00:00
}
2022-05-04 18:47:48 +00:00
DataType . ARRAY _F -> {
2024-01-14 12:20:12 +00:00
assignExpressionToRegister ( containment . element , RegisterOrPair . FAC1 , true )
assignAddressOf ( AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , DataType . UWORD , containment . definingISub ( ) , containment . position , " P8ZP_SCRATCH_W1 " ) , symbolName , null , null )
asmgen . out ( " ldy # $numElements " )
asmgen . out ( " jsr floats.containment_floatarray " )
2022-05-04 18:47:48 +00:00
}
2022-03-27 13:23:32 +00:00
DataType . ARRAY _B , DataType . ARRAY _UB -> {
2023-01-04 21:55:05 +00:00
assignExpressionToRegister ( containment . element , RegisterOrPair . A , elementDt == DataType . BYTE )
2024-01-05 19:46:26 +00:00
asmgen . out ( " pha " ) // need to keep the scratch var safe so we have to do it in this order
2023-12-11 21:51:33 +00:00
assignAddressOf ( AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , DataType . UWORD , containment . definingISub ( ) , containment . position , " P8ZP_SCRATCH_W1 " ) , symbolName , null , null )
2024-01-04 19:44:46 +00:00
asmgen . out ( " pla " )
2022-12-23 12:38:34 +00:00
asmgen . out ( " ldy # $numElements " )
2022-03-27 13:23:32 +00:00
asmgen . out ( " jsr prog8_lib.containment_bytearray " )
}
DataType . ARRAY _W , DataType . ARRAY _UW -> {
2023-03-18 23:58:45 +00:00
assignExpressionToVariable ( containment . element , " P8ZP_SCRATCH_W1 " , elementDt )
2023-12-11 21:51:33 +00:00
assignAddressOf ( AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , DataType . UWORD , containment . definingISub ( ) , containment . position , " P8ZP_SCRATCH_W2 " ) , symbolName , null , null )
2022-12-23 12:38:34 +00:00
asmgen . out ( " ldy # $numElements " )
2022-03-27 13:23:32 +00:00
asmgen . out ( " jsr prog8_lib.containment_wordarray " )
2021-12-29 15:21:37 +00:00
}
else -> throw AssemblyError ( " invalid dt " )
}
}
2020-12-22 11:44:03 +00:00
private fun assignStatusFlagByte ( target : AsmAssignTarget , statusflag : Statusflag ) {
when ( statusflag ) {
Statusflag . Pc -> {
asmgen . out ( " lda #0 | rol a " )
}
Statusflag . Pv -> {
asmgen . out ( """
bvs +
lda # 0
beq ++
+ lda # 1
+ """ )
}
2023-12-12 23:53:01 +00:00
Statusflag . Pz -> {
asmgen . out ( """
beq +
lda # 0
beq ++
+ lda # 1
+ """ )
}
Statusflag . Pn -> {
asmgen . out ( """
bmi +
lda # 0
beq ++
+ lda # 1
+ """ )
}
2020-12-22 11:44:03 +00:00
}
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
2020-12-22 11:44:03 +00:00
}
2023-01-04 21:55:05 +00:00
private fun assignTypeCastedValue ( target : AsmAssignTarget , targetDt : DataType , value : PtExpression , origTypeCastExpression : PtTypeCast ) {
val valueDt = value . type
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 ) {
2023-01-04 21:55:05 +00:00
is PtIdentifier -> {
2020-10-10 13:39:48 +00:00
if ( targetDt in WordDatatypes ) {
2024-02-12 20:29:02 +00:00
if ( valueDt == DataType . UBYTE || valueDt == DataType . BOOL ) {
2020-10-10 13:39:48 +00:00
assignVariableUByteIntoWord ( target , value )
return
}
if ( valueDt == DataType . BYTE ) {
assignVariableByteIntoWord ( target , value )
2020-09-15 01:26:57 +00:00
return
}
}
}
2023-01-04 21:55:05 +00:00
is PtMemoryByte -> {
2020-09-15 01:26:57 +00:00
if ( targetDt in WordDatatypes ) {
2021-01-19 23:28:54 +00:00
2023-01-04 21:55:05 +00:00
fun assignViaExprEval ( addressExpression : PtExpression ) {
2023-03-18 23:58:45 +00:00
asmgen . assignExpressionToVariable ( addressExpression , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2024-02-07 21:09:04 +00:00
asmgen . loadAFromZpPointerVar ( " P8ZP_SCRATCH_W2 " , false )
2022-10-23 09:57:23 +00:00
asmgen . out ( " ldy #0 " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
2021-01-19 23:28:54 +00:00
}
2023-01-04 21:55:05 +00:00
when ( value . address ) {
is PtNumber -> {
val address = ( value . address as PtNumber ) . number . toUInt ( )
2021-01-19 18:25:23 +00:00
assignMemoryByteIntoWord ( target , address , null )
}
2023-01-04 21:55:05 +00:00
is PtIdentifier -> {
assignMemoryByteIntoWord ( target , null , value . address as PtIdentifier )
2021-01-19 18:25:23 +00:00
}
2023-03-16 01:27:30 +00:00
is PtBinaryExpression -> {
2023-03-17 23:16:18 +00:00
val addrExpr = value . address as PtBinaryExpression
2024-02-03 16:36:42 +00:00
if ( asmgen . tryOptimizedPointerAccessWithA ( addrExpr , false ) ) {
2021-01-19 23:28:54 +00:00
asmgen . out ( " ldy #0 " )
assignRegisterpairWord ( target , RegisterOrPair . AY )
} else {
2023-01-04 21:55:05 +00:00
assignViaExprEval ( value . address )
2021-01-19 23:28:54 +00:00
}
}
2021-01-19 18:25:23 +00:00
else -> {
2023-01-04 21:55:05 +00:00
assignViaExprEval ( value . address )
2021-01-19 18:25:23 +00:00
}
2020-09-15 01:26:57 +00:00
}
2022-12-04 11:22:05 +00:00
return
2020-09-15 01:26:57 +00:00
}
}
2024-02-12 20:29:02 +00:00
is PtNumber , is PtBool -> throw AssemblyError ( " a cast of a literal value should have been const-folded away " )
2023-11-03 23:33:50 +00:00
is PtArrayIndexer -> {
if ( targetDt in ByteDatatypes && valueDt in WordDatatypes ) {
// just assign the lsb from the array value
return assignCastViaLsbFunc ( value , target )
}
}
2020-09-15 01:26:57 +00:00
else -> { }
}
2020-11-24 21:26:11 +00:00
// special case optimizations
2022-12-04 11:22:05 +00:00
if ( target . kind == TargetStorageKind . VARIABLE ) {
2023-01-04 21:55:05 +00:00
if ( value is PtIdentifier && valueDt != DataType . UNDEFINED )
2020-11-24 23:17:42 +00:00
return assignTypeCastedIdentifier ( target . asmVarname , targetDt , asmgen . asmVariableName ( value ) , valueDt )
when ( valueDt ) {
2024-02-12 20:29:02 +00:00
in ByteDatatypesWithBoolean -> {
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)
2023-03-18 23:58:45 +00:00
assignExpressionToVariable ( value , target . asmVarname , targetDt )
2020-11-24 23:17:42 +00:00
}
else -> throw AssemblyError ( " strange dt in typecast assign to var: $valueDt --> $targetDt " )
2020-09-15 01:26:57 +00:00
}
2020-11-26 18:21:07 +00:00
return
2020-09-15 01:26:57 +00:00
}
2022-07-13 20:24:31 +00:00
if ( valueDt in WordDatatypes && origTypeCastExpression . type == DataType . UBYTE ) {
2023-01-04 21:55:05 +00:00
val parentTc = origTypeCastExpression . parent as ? PtTypeCast
2020-12-31 00:02:36 +00:00
if ( parentTc != null && parentTc . type == DataType . UWORD ) {
2022-07-13 20:24:31 +00:00
// typecast a word value to ubyte and directly back to uword
2020-12-31 00:02:36 +00:00
// generate code for lsb(value) here instead of the ubyte typecast
return assignCastViaLsbFunc ( value , target )
}
}
2024-02-13 20:56:22 +00:00
if ( valueDt in ByteDatatypesWithBoolean ) {
2020-12-31 00:02:36 +00:00
when ( target . register ) {
RegisterOrPair . A ,
RegisterOrPair . X ,
RegisterOrPair . Y -> {
2021-10-10 21:35:02 +00:00
// 'cast' an ubyte value to a byte register; no cast needed at all
2024-01-06 23:01:00 +00:00
return assignExpressionToRegister ( value , target . register , valueDt in SignedDatatypes )
2020-12-31 00:02:36 +00:00
}
RegisterOrPair . AX ,
RegisterOrPair . AY ,
RegisterOrPair . XY ,
in Cx16VirtualRegisters -> {
2023-10-17 20:51:49 +00:00
assignExpressionToRegister ( value , RegisterOrPair . A , false )
2024-01-06 23:01:00 +00:00
assignRegisterByte ( target , CpuRegister . A , valueDt in SignedDatatypes , true )
2023-10-17 20:51:49 +00:00
return
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
2024-01-06 23:01:00 +00:00
return assignExpressionToRegister ( value , target . register !! , targetDt in SignedDatatypes )
2020-12-31 00:02:36 +00:00
}
else -> { }
}
}
2022-01-23 18:02:51 +00:00
if ( target . kind == TargetStorageKind . REGISTER ) {
2022-05-03 21:43:38 +00:00
if ( valueDt == DataType . FLOAT && target . datatype != DataType . FLOAT ) {
// have to typecast the float number on the fly down to an integer
assignExpressionToRegister ( value , RegisterOrPair . FAC1 , target . datatype in SignedDatatypes )
assignTypeCastedFloatFAC1 ( " P8ZP_SCRATCH_W1 " , target . datatype )
2023-03-18 23:24:05 +00:00
assignVariableToRegister ( " P8ZP_SCRATCH_W1 " , target . register !! , target . datatype in SignedDatatypes , origTypeCastExpression . definingISub ( ) , target . position )
2022-12-04 11:22:05 +00:00
return
2022-05-03 21:43:38 +00:00
} else {
2022-07-05 22:28:43 +00:00
if ( ! ( valueDt isAssignableTo targetDt ) ) {
2022-12-04 11:22:05 +00:00
return if ( valueDt in WordDatatypes && targetDt in ByteDatatypes ) {
2022-07-05 22:28:43 +00:00
// word to byte, just take the lsb
2022-12-04 11:22:05 +00:00
assignCastViaLsbFunc ( value , target )
2022-07-05 22:28:43 +00:00
} else if ( valueDt in WordDatatypes && targetDt in WordDatatypes ) {
// word to word, just assign
2023-10-17 00:34:56 +00:00
assignExpressionToRegister ( value , target . register !! , valueDt in SignedDatatypes )
2024-02-12 20:29:02 +00:00
} else if ( valueDt in ByteDatatypesWithBoolean && targetDt in ByteDatatypes ) {
2022-07-05 22:28:43 +00:00
// byte to byte, just assign
2023-10-17 00:34:56 +00:00
assignExpressionToRegister ( value , target . register !! , valueDt in SignedDatatypes )
2024-02-12 20:29:02 +00:00
} else if ( valueDt in ByteDatatypesWithBoolean && targetDt in WordDatatypes ) {
2022-09-22 11:00:47 +00:00
// byte to word, just assign
2023-10-17 00:34:56 +00:00
assignExpressionToRegister ( value , target . register !! , valueDt == DataType . WORD )
2022-12-04 11:22:05 +00:00
} else
2022-07-05 22:28:43 +00:00
throw AssemblyError ( " can't cast $valueDt to $targetDt , this should have been checked in the astchecker " )
}
2022-05-03 21:43:38 +00:00
}
2022-12-04 11:22:05 +00:00
}
2024-02-12 20:29:02 +00:00
if ( targetDt in IntegerDatatypes && valueDt in IntegerDatatypesWithBoolean && valueDt . isAssignableTo ( targetDt ) ) {
require ( targetDt in WordDatatypes && valueDt in ByteDatatypesWithBoolean ) {
2022-12-23 12:38:34 +00:00
" should be byte to word assignment ${origTypeCastExpression.position} "
}
2022-12-04 11:22:05 +00:00
when ( target . kind ) {
// TargetStorageKind.VARIABLE -> {
// This has been handled already earlier on line 961.
// // byte to word, just assign to registers first, then assign to variable
// assignExpressionToRegister(value, RegisterOrPair.AY, targetDt==DataType.WORD)
// assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, targetDt)
// return
// }
TargetStorageKind . ARRAY -> {
// byte to word, just assign to registers first, then assign into array
assignExpressionToRegister ( value , RegisterOrPair . AY , targetDt == DataType . WORD )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return
}
TargetStorageKind . REGISTER -> {
// byte to word, just assign to registers
assignExpressionToRegister ( value , target . register !! , targetDt == DataType . WORD )
return
}
else -> throw AssemblyError ( " weird target " )
}
2022-01-23 18:02:51 +00:00
}
2021-11-09 18:31:19 +00:00
if ( targetDt == DataType . FLOAT && ( target . register == RegisterOrPair . FAC1 || target . register == RegisterOrPair . FAC2 ) ) {
2023-07-17 23:24:27 +00:00
if ( target . register == RegisterOrPair . FAC2 )
asmgen . pushFAC1 ( )
2021-11-09 18:31:19 +00:00
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 ) {
2023-07-17 23:24:27 +00:00
asmgen . out ( " jsr floats.MOVEF " )
asmgen . popFAC1 ( )
2021-11-09 18:31:19 +00:00
}
2022-12-04 11:22:05 +00:00
return
2021-11-09 18:31:19 +00:00
}
2022-12-23 12:38:34 +00:00
2023-09-04 19:07:49 +00:00
// No more special optimized cases yet. Do the rest via more complex evaluation
2022-12-23 12:38:34 +00:00
// 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
}
2023-01-04 21:55:05 +00:00
private fun assignCastViaLsbFunc ( value : PtExpression , target : AsmAssignTarget ) {
val lsb = PtBuiltinFunctionCall ( " lsb " , false , true , DataType . UBYTE , value . position )
2023-01-30 22:13:36 +00:00
lsb . parent = value . parent
2023-01-04 21:55:05 +00:00
lsb . add ( value )
2020-12-31 00:02:36 +00:00
val src = AsmAssignSource ( SourceStorageKind . EXPRESSION , program , asmgen , DataType . UBYTE , expression = lsb )
2023-02-15 21:50:35 +00:00
val assign = AsmAssignment ( src , target , program . memsizer , value . position )
2023-03-18 23:24:05 +00:00
translateNormalAssignment ( assign , value . definingISub ( ) )
2020-12-31 00:02:36 +00:00
}
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
2023-01-04 21:55:05 +00:00
// also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast)
2020-11-19 21:58:38 +00:00
when ( sourceDt ) {
2024-02-12 20:29:02 +00:00
DataType . UBYTE , DataType . BOOL -> {
2020-11-19 21:58:38 +00:00
when ( targetDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> {
asmgen . out ( """
lda $ sourceAsmVarName
beq +
lda # 1
+ sta $ targetAsmVarName """ )
}
DataType . UBYTE , DataType . BYTE -> {
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName " )
}
DataType . UWORD , DataType . WORD -> {
2021-02-19 17:48:12 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName +1 " )
else
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName +1 " )
}
DataType . FLOAT -> {
asmgen . out ( """
lda # < $ targetAsmVarName
ldy # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2
sty P8ZP _SCRATCH _W2 + 1
ldy $ sourceAsmVarName
jsr floats . cast _from _ub """ )
}
2024-02-12 20:29:02 +00:00
else -> throw AssemblyError ( " weird type $targetDt " )
2020-11-19 21:58:38 +00:00
}
}
DataType . BYTE -> {
when ( targetDt ) {
2022-06-12 14:15:08 +00:00
DataType . UBYTE -> {
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName " )
}
2020-11-24 23:18:07 +00:00
DataType . UWORD -> {
2021-02-19 17:48:12 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
2020-11-24 23:18:07 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | stz $targetAsmVarName +1 " )
else
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName +1 " )
}
DataType . WORD -> {
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName " )
asmgen . signExtendVariableLsb ( targetAsmVarName , DataType . BYTE )
}
DataType . FLOAT -> {
asmgen . out ( """
lda # < $ targetAsmVarName
ldy # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2
sty P8ZP _SCRATCH _W2 + 1
lda $ sourceAsmVarName
jsr floats . cast _from _b """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . UWORD -> {
when ( targetDt ) {
DataType . BYTE , DataType . UBYTE -> {
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName " )
}
2022-06-12 14:15:08 +00:00
DataType . WORD -> {
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName +1 | sta $targetAsmVarName +1 " )
}
DataType . FLOAT -> {
asmgen . out ( """
lda # < $ targetAsmVarName
ldy # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2
sty P8ZP _SCRATCH _W2 + 1
lda $ sourceAsmVarName
ldy $ sourceAsmVarName + 1
jsr floats . cast _from _uw """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . WORD -> {
when ( targetDt ) {
DataType . BYTE , DataType . UBYTE -> {
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName " )
}
2022-06-12 14:15:08 +00:00
DataType . UWORD -> {
2020-11-19 21:58:38 +00:00
asmgen . out ( " lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName +1 | sta $targetAsmVarName +1 " )
}
DataType . FLOAT -> {
asmgen . out ( """
lda # < $ targetAsmVarName
ldy # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2
sty P8ZP _SCRATCH _W2 + 1
lda $ sourceAsmVarName
ldy $ sourceAsmVarName + 1
jsr floats . cast _from _w """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . FLOAT -> {
2020-11-26 00:39:27 +00:00
asmgen . out ( " lda #< $sourceAsmVarName | ldy #> $sourceAsmVarName " )
2020-11-19 21:58:38 +00:00
when ( targetDt ) {
DataType . UBYTE -> asmgen . out ( " jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName " )
DataType . BYTE -> asmgen . out ( " jsr floats.cast_as_w_into_ay | sta $targetAsmVarName " )
DataType . UWORD -> asmgen . out ( " jsr floats.cast_as_uw_into_ya | sty $targetAsmVarName | sta $targetAsmVarName +1 " )
DataType . WORD -> asmgen . out ( " jsr floats.cast_as_w_into_ay | sta $targetAsmVarName | sty $targetAsmVarName +1 " )
else -> throw AssemblyError ( " weird type " )
}
}
2021-03-24 20:49:33 +00:00
DataType . STR -> throw AssemblyError ( " cannot typecast a string value " )
2020-11-19 21:58:38 +00:00
else -> throw AssemblyError ( " weird type " )
}
}
2020-11-26 00:11:31 +00:00
private fun assignTypeCastedRegisters ( targetAsmVarName : String , targetDt : DataType ,
regs : RegisterOrPair , sourceDt : DataType ) {
if ( sourceDt == targetDt )
2020-11-26 00:39:27 +00:00
throw AssemblyError ( " typecast to identical type " )
2020-11-26 00:11:31 +00:00
2023-01-04 21:55:05 +00:00
// also see: PtExpressionAsmGen, fun translateExpression(typecast: PtTypeCast)
2020-11-26 00:11:31 +00:00
when ( sourceDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> {
when ( targetDt ) {
in ByteDatatypesWithBoolean -> asmgen . out ( " st ${regs.toString().lowercase()} $targetAsmVarName " )
else -> throw AssemblyError ( " assign bool to non-byte variable " )
}
}
2020-11-26 00:11:31 +00:00
DataType . UBYTE -> {
when ( targetDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> {
asmgen . out ( """
cp $ { regs . toString ( ) . lowercase ( ) } # 0
beq +
ld $ { regs . toString ( ) . lowercase ( ) } # 1
+ st $ { regs . toString ( ) . lowercase ( ) } $ targetAsmVarName """ )
}
2022-06-12 14:15:08 +00:00
DataType . BYTE -> {
2021-05-05 21:01:04 +00:00
asmgen . out ( " st ${regs.toString().lowercase()} $targetAsmVarName " )
2020-11-26 00:11:31 +00:00
}
DataType . UWORD , DataType . WORD -> {
2021-02-19 17:48:12 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
2021-05-05 21:01:04 +00:00
asmgen . out (
2022-12-04 11:22:05 +00:00
" st ${regs.toString().lowercase()} $targetAsmVarName | stz $targetAsmVarName +1 " )
2020-11-26 00:11:31 +00:00
else
2021-05-05 21:01:04 +00:00
asmgen . out (
2022-12-04 11:22:05 +00:00
" st ${regs.toString().lowercase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName +1 " )
2020-11-26 00:11:31 +00:00
}
DataType . FLOAT -> {
when ( regs ) {
RegisterOrPair . A -> asmgen . out ( " tay " )
RegisterOrPair . X -> asmgen . out ( " txa | tay " )
RegisterOrPair . Y -> { }
else -> throw AssemblyError ( " non-byte regs " )
}
asmgen . out ( """
lda # < $ targetAsmVarName
sta P8ZP _SCRATCH _W2
lda # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2 + 1
jsr floats . cast _from _ub """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . BYTE -> {
when ( targetDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> TODO ( " assign byte to bool " )
2022-06-12 14:15:08 +00:00
DataType . UBYTE -> {
2021-05-05 21:01:04 +00:00
asmgen . out ( " st ${regs.toString().lowercase()} $targetAsmVarName " )
2020-11-26 00:11:31 +00:00
}
DataType . UWORD -> {
2021-02-19 17:48:12 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
2021-05-05 21:01:04 +00:00
asmgen . out (
" st $ {
regs . toString ( ) . lowercase ( )
} $ targetAsmVarName | stz $ targetAsmVarName + 1 " )
2020-11-26 00:11:31 +00:00
else
2021-05-05 21:01:04 +00:00
asmgen . out (
" st $ {
regs . toString ( ) . lowercase ( )
} $ targetAsmVarName | lda # 0 | sta $ targetAsmVarName + 1 " )
2020-11-26 00:11:31 +00:00
}
DataType . WORD -> {
when ( regs ) {
RegisterOrPair . A -> { }
RegisterOrPair . X -> asmgen . out ( " txa " )
RegisterOrPair . Y -> asmgen . out ( " tya " )
else -> throw AssemblyError ( " non-byte regs " )
}
asmgen . signExtendAYlsb ( sourceDt )
asmgen . out ( " sta $targetAsmVarName | sty $targetAsmVarName +1 " )
}
DataType . FLOAT -> {
when ( regs ) {
RegisterOrPair . A -> { }
RegisterOrPair . X -> asmgen . out ( " txa " )
RegisterOrPair . Y -> asmgen . out ( " tya " )
else -> throw AssemblyError ( " non-byte regs " )
}
asmgen . out ( """
ldy # < $ targetAsmVarName
sty P8ZP _SCRATCH _W2
ldy # > $ targetAsmVarName
sty P8ZP _SCRATCH _W2 + 1
jsr floats . cast _from _b """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . UWORD -> {
when ( targetDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> TODO ( " assign uword to bool " )
2020-11-26 00:11:31 +00:00
DataType . BYTE , DataType . UBYTE -> {
2021-05-05 21:01:04 +00:00
asmgen . out ( " st ${regs.toString().lowercase().first()} $targetAsmVarName " )
2020-11-26 00:11:31 +00:00
}
2022-06-12 14:15:08 +00:00
DataType . WORD -> {
2020-11-26 00:11:31 +00:00
when ( regs ) {
RegisterOrPair . AX -> asmgen . out ( " sta $targetAsmVarName | stx $targetAsmVarName +1 " )
RegisterOrPair . AY -> asmgen . out ( " sta $targetAsmVarName | sty $targetAsmVarName +1 " )
RegisterOrPair . XY -> asmgen . out ( " stx $targetAsmVarName | sty $targetAsmVarName +1 " )
else -> throw AssemblyError ( " non-word regs " )
}
}
DataType . FLOAT -> {
if ( regs != RegisterOrPair . AY )
throw AssemblyError ( " only supports AY here " )
asmgen . out ( """
2023-09-01 18:27:39 +00:00
tax
2020-11-26 00:11:31 +00:00
lda # < $ targetAsmVarName
sta P8ZP _SCRATCH _W2
lda # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2 + 1
2023-09-01 18:27:39 +00:00
txa
2020-11-26 00:11:31 +00:00
jsr floats . cast _from _uw """ )
}
else -> throw AssemblyError ( " weird type " )
}
}
DataType . WORD -> {
when ( targetDt ) {
2024-02-12 20:29:02 +00:00
DataType . BOOL -> TODO ( " assign word to bool " )
2020-11-26 00:11:31 +00:00
DataType . BYTE , DataType . UBYTE -> {
2021-05-05 21:01:04 +00:00
asmgen . out ( " st ${regs.toString().lowercase().first()} $targetAsmVarName " )
2020-11-26 00:11:31 +00:00
}
2022-06-12 14:15:08 +00:00
DataType . UWORD -> {
2020-11-26 00:11:31 +00:00
when ( regs ) {
RegisterOrPair . AX -> asmgen . out ( " sta $targetAsmVarName | stx $targetAsmVarName +1 " )
RegisterOrPair . AY -> asmgen . out ( " sta $targetAsmVarName | sty $targetAsmVarName +1 " )
RegisterOrPair . XY -> asmgen . out ( " stx $targetAsmVarName | sty $targetAsmVarName +1 " )
else -> throw AssemblyError ( " non-word regs " )
}
}
DataType . FLOAT -> {
if ( regs != RegisterOrPair . AY )
throw AssemblyError ( " only supports AY here " )
asmgen . out ( """
2023-09-01 18:27:39 +00:00
tax
2020-11-26 00:11:31 +00:00
lda # < $ targetAsmVarName
sta P8ZP _SCRATCH _W2
lda # > $ targetAsmVarName
sta P8ZP _SCRATCH _W2 + 1
2023-09-01 18:27:39 +00:00
txa
2020-11-26 00:11:31 +00:00
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 " )
}
}
2023-09-17 16:30:57 +00:00
private fun assignAddressOf ( target : AsmAssignTarget , sourceName : String , arrayDt : DataType ? , arrayIndexExpr : PtExpression ? ) {
2024-02-08 21:45:36 +00:00
if ( arrayIndexExpr != null ) {
require ( arrayDt !in SplitWordArrayTypes )
2023-09-17 16:30:57 +00:00
val constIndex = arrayIndexExpr . asConstInteger ( )
if ( constIndex != null ) {
2024-02-08 21:45:36 +00:00
if ( arrayDt == DataType . UWORD ) {
assignVariableToRegister ( sourceName , RegisterOrPair . AY , false , arrayIndexExpr . definingISub ( ) , arrayIndexExpr . position )
if ( constIndex > 0 )
asmgen . out ( """
clc
adc # $ constIndex
bne +
iny
+ """ )
}
else {
if ( constIndex > 0 ) {
val offset = program . memsizer . memorySize ( arrayDt !! , constIndex ) // add arrayIndexExpr * elementsize to the address of the array variable.
asmgen . out ( " lda #<( $sourceName + $offset ) | ldy #>( $sourceName + $offset ) " )
} else {
asmgen . out ( " lda #< $sourceName | ldy #> $sourceName " )
2023-10-14 05:57:36 +00:00
}
}
2024-02-08 21:45:36 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return
} else {
if ( arrayDt == DataType . UWORD ) {
assignVariableToRegister ( sourceName , RegisterOrPair . AY , false , arrayIndexExpr . definingISub ( ) , arrayIndexExpr . position )
asmgen . saveRegisterStack ( CpuRegister . A , false )
asmgen . saveRegisterStack ( CpuRegister . Y , false )
assignExpressionToVariable ( arrayIndexExpr , " P8ZP_SCRATCH_REG " , DataType . UBYTE )
asmgen . restoreRegisterStack ( CpuRegister . Y , false )
asmgen . restoreRegisterStack ( CpuRegister . A , false )
asmgen . out ( """
clc
adc P8ZP _SCRATCH _REG
bne +
iny
+ """ )
}
else {
assignExpressionToRegister ( arrayIndexExpr , RegisterOrPair . A , false )
asmgen . out ( """
ldy # > $ sourceName
clc
adc # < $ sourceName
bne +
iny
+ """ )
}
2023-10-14 05:57:36 +00:00
assignRegisterpairWord ( target , RegisterOrPair . AY )
return
2023-09-17 16:30:57 +00:00
}
2024-02-08 21:45:36 +00:00
}
2023-09-17 16:30:57 +00:00
2024-02-08 21:45:36 +00:00
// address of a normal variable
2020-08-23 11:56:21 +00:00
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
2019-08-16 20:49:29 +00:00
asmgen . out ( """
2024-02-08 21:45:36 +00:00
lda # < $ sourceName
ldy # > $ sourceName
2020-08-23 16:20:57 +00:00
sta $ { target . asmVarname }
2024-02-08 21:45:36 +00:00
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 -> {
2024-02-08 21:45:36 +00:00
asmgen . out ( " lda #< $sourceName | ldy #> $sourceName " )
2020-12-08 21:27:42 +00:00
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 !! ) {
2024-02-08 21:45:36 +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 -> {
2024-02-08 21:45:36 +00:00
asmgen . out ( """
lda # < $ sourceName
ldy # > $ sourceName
2021-05-05 21:01:04 +00:00
sta cx16 . $ { target . register . toString ( ) . lowercase ( ) }
2024-02-08 21:45:36 +00:00
sty 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 " )
}
}
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 " )
}
}
else -> throw AssemblyError ( " string-assign to weird target " )
}
}
2023-07-16 19:52:28 +00:00
private fun assignVariableWord ( target : AsmAssignTarget , sourceName : String , sourceDt : DataType ) {
2023-10-17 00:34:56 +00:00
if ( sourceDt == DataType . BYTE ) {
// need to sign extend
asmgen . out ( " lda $sourceName " )
asmgen . signExtendAYlsb ( DataType . BYTE )
assignRegisterpairWord ( target , RegisterOrPair . AY )
return
}
2024-02-12 20:29:02 +00:00
require ( sourceDt in WordDatatypes || sourceDt == DataType . UBYTE || sourceDt == DataType . BOOL ) { " weird source dt for word variable " }
2020-08-23 11:56:21 +00:00
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
2024-02-12 20:29:02 +00:00
if ( sourceDt == DataType . UBYTE || sourceDt == DataType . BOOL ) {
2023-07-16 19:52:28 +00:00
asmgen . out ( " lda $sourceName | sta ${target.asmVarname} " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
2023-10-14 05:57:36 +00:00
asmgen . out ( " stz ${target.asmVarname} +1 " )
2023-07-16 19:52:28 +00:00
else
2023-10-14 05:57:36 +00:00
asmgen . out ( " lda #0 | sta ${target.asmVarname} +1 " )
2023-07-16 19:52:28 +00:00
}
else
asmgen . out ( """
lda $ sourceName
ldy $ sourceName + 1
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 -> {
2023-03-11 13:55:13 +00:00
throw AssemblyError ( " assign word to memory ${target.memory} should have gotten a typecast " )
2019-08-16 20:49:29 +00:00
}
2020-08-23 11:56:21 +00:00
TargetStorageKind . ARRAY -> {
2023-07-16 19:52:28 +00:00
if ( sourceDt == DataType . UBYTE ) TODO ( " assign byte to word 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 -> {
2023-05-28 12:53:53 +00:00
if ( target . array . splitWords )
asmgen . out ( """
lda $ sourceName
sta $ { target . asmVarname } _lsb + $ { target . constArrayIndexValue }
lda $ sourceName + 1
sta $ { target . asmVarname } _msb + $ { target . constArrayIndexValue } """ )
else
asmgen . out ( """
lda $ sourceName
sta $ { target . asmVarname } + $ scaledIdx
lda $ sourceName + 1
sta $ { target . asmVarname } + $ scaledIdx + 1 """ )
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 -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2020-10-17 14:00:49 +00:00
asmgen . out ( " lda $sourceName | sta ${target.asmVarname} ,y " )
}
DataType . UWORD , DataType . WORD -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
if ( target . array . splitWords )
asmgen . out ( """
lda $ sourceName
sta $ { target . asmVarname } _lsb , y
lda $ sourceName + 1
sta $ { target . asmVarname } _msb , y """ )
else
asmgen . out ( """
lda $ sourceName
sta $ { target . asmVarname } , y
lda $ sourceName + 1
sta $ { target . asmVarname } + 1 , y """ )
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 -> {
2023-07-16 19:52:28 +00:00
if ( sourceDt == DataType . UBYTE ) {
when ( target . register !! ) {
RegisterOrPair . AX -> asmgen . out ( " ldx #0 | lda $sourceName " )
RegisterOrPair . AY -> asmgen . out ( " ldy #0 | lda $sourceName " )
RegisterOrPair . XY -> asmgen . out ( " ldy #0 | ldx $sourceName " )
in Cx16VirtualRegisters -> {
asmgen . out ( " lda $sourceName | sta cx16. ${target.register.toString().lowercase()} " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz cx16. ${target.register.toString().lowercase()} +1 " )
else
asmgen . out ( " lda #0 | sta cx16. ${target.register.toString().lowercase()} +1 " )
}
else -> throw AssemblyError ( " can't load word in a single 8-bit register " )
}
} else {
when ( target . register !! ) {
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 " )
in Cx16VirtualRegisters -> {
asmgen . out (
"""
lda $ sourceName
sta cx16 . $ { target . register . toString ( ) . lowercase ( ) }
lda $ sourceName + 1
sta cx16 . $ { target . register . toString ( ) . lowercase ( ) } + 1
""" )
}
else -> throw AssemblyError ( " can't load word in a single 8-bit register " )
2020-12-21 19:38:00 +00:00
}
2020-08-23 21:28:25 +00:00
}
}
2019-08-16 20:49:29 +00:00
}
}
2021-11-26 20:34:00 +00:00
internal fun assignFAC2float ( target : AsmAssignTarget ) {
2023-07-17 23:24:27 +00:00
asmgen . out ( " jsr floats.MOVFA " )
if ( target . register != RegisterOrPair . FAC1 )
assignFAC1float ( target )
2021-11-26 20:34:00 +00:00
}
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 ( """
ldx # < $ { target . asmVarname }
ldy # > $ { target . asmVarname }
jsr floats . MOVMF
""" )
}
TargetStorageKind . ARRAY -> {
2023-11-27 19:54:49 +00:00
asmgen . assignExpressionToRegister ( target . array !! . index , RegisterOrPair . A , false )
2020-10-30 22:02:20 +00:00
asmgen . out ( """
2023-11-27 19:54:49 +00:00
ldy # < $ { target . asmVarname }
sty P8ZP _SCRATCH _W1
2020-10-30 22:02:20 +00:00
ldy # > $ { target . asmVarname }
2023-11-27 19:54:49 +00:00
sty P8ZP _SCRATCH _W1 + 1
jsr floats . set _array _float _from _fac1 """ )
2020-10-30 22:02:20 +00:00
}
TargetStorageKind . MEMORY -> throw AssemblyError ( " can't assign float to mem byte " )
2020-11-24 00:09:24 +00:00
TargetStorageKind . REGISTER -> {
2023-07-17 23:24:27 +00:00
if ( target . register == RegisterOrPair . FAC2 )
asmgen . out ( " jsr floats.MOVAF " )
else if ( target . register !! != RegisterOrPair . FAC1 )
2022-04-13 22:38:31 +00:00
throw AssemblyError ( " can't assign Fac1 float to another register " )
2020-11-24 00:09:24 +00:00
}
2020-10-30 22:02:20 +00:00
}
}
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 -> {
2024-01-04 19:44:46 +00:00
asmgen . out ( " pha " )
2023-11-27 19:54:49 +00:00
asmgen . saveRegisterStack ( CpuRegister . Y , false )
asmgen . assignExpressionToRegister ( target . array !! . index , RegisterOrPair . A , false )
asmgen . restoreRegisterStack ( CpuRegister . Y , false )
2024-01-04 19:44:46 +00:00
asmgen . out ( " pla " )
2020-11-22 16:16:07 +00:00
asmgen . out ( """
sta P8ZP _SCRATCH _W1
sty P8ZP _SCRATCH _W1 + 1
lda # < $ { target . asmVarname }
ldy # > $ { target . asmVarname }
sta P8ZP _SCRATCH _W2
2023-11-27 19:54:49 +00:00
sty P8ZP _SCRATCH _W2 + 1
jsr floats . set _array _float """ )
2020-11-22 16:16:07 +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 ( " 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
}
}
2020-10-11 11:31:45 +00:00
private fun assignVariableFloat ( target : AsmAssignTarget , sourceName : String ) {
2020-08-23 11:56:21 +00:00
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
2019-08-16 20:49:29 +00:00
asmgen . out ( """
2022-01-09 15:18:13 +00:00
lda # < $ sourceName
ldy # > $ sourceName
sta P8ZP _SCRATCH _W1
sty P8ZP _SCRATCH _W1 + 1
lda # < $ { target . asmVarname }
ldy # > $ { target . asmVarname }
jsr floats . copy _float """ )
2019-08-16 20:49:29 +00:00
}
2020-08-23 11:56:21 +00:00
TargetStorageKind . ARRAY -> {
2023-11-27 19:54:49 +00:00
asmgen . assignExpressionToRegister ( target . array !! . index , RegisterOrPair . A , false )
2020-10-19 21:57:00 +00:00
asmgen . out ( """
2023-11-27 19:54:49 +00:00
ldy # < $ sourceName
sty P8ZP _SCRATCH _W1
2020-10-19 21:57:00 +00:00
ldy # > $ sourceName
sty P8ZP _SCRATCH _W1 + 1
2023-11-27 19:54:49 +00:00
ldy # < $ { target . asmVarname }
sty P8ZP _SCRATCH _W2
2020-10-19 21:57:00 +00:00
ldy # > $ { target . asmVarname }
2023-11-27 19:54:49 +00:00
sty P8ZP _SCRATCH _W2 + 1
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 " )
}
}
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 -> {
2023-05-28 12:53:53 +00:00
if ( target . array !! . splitWords )
TODO ( " assign into split words ${target.position} " )
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 {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2020-10-17 14:00:49 +00:00
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
}
}
2019-08-16 20:49:29 +00:00
}
}
2023-01-04 21:55:05 +00:00
private fun assignVariableByteIntoWord ( wordtarget : AsmAssignTarget , bytevar : PtIdentifier ) {
2020-10-10 13:39:48 +00:00
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 -> {
2023-05-27 12:43:09 +00:00
if ( wordtarget . array !! . splitWords )
TODO ( " assign byte into split words ${wordtarget.position} " )
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 {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( wordtarget . array , CpuRegister . X )
2021-04-06 20:46:52 +00:00
asmgen . out ( " lda $sourceName " )
asmgen . signExtendAYlsb ( DataType . BYTE )
asmgen . out ( " sta ${wordtarget.asmVarname} ,x | inx | tya | sta ${wordtarget.asmVarname} ,x " )
}
2020-10-10 13:39:48 +00:00
}
TargetStorageKind . REGISTER -> {
when ( wordtarget . register !! ) {
RegisterOrPair . AX -> asmgen . out ( """
lda $ sourceName
pha
ora # $ 7f
bmi +
2022-01-27 17:05:25 +00:00
lda # 0
2020-10-10 13:39:48 +00:00
+ tax
pla """ )
RegisterOrPair . AY -> asmgen . out ( """
lda $ sourceName
2023-09-01 18:27:39 +00:00
tax
2020-10-10 13:39:48 +00:00
ora # $ 7f
bmi +
2022-01-27 17:05:25 +00:00
lda # 0
2020-10-10 13:39:48 +00:00
+ tay
2023-09-01 18:27:39 +00:00
txa """ )
2020-10-10 13:39:48 +00:00
RegisterOrPair . XY -> asmgen . out ( """
lda $ sourceName
tax
ora # $ 7f
bmi +
2022-01-27 17:05:25 +00:00
lda # 0
2020-10-10 13:39:48 +00:00
+ tay """ )
2022-01-27 17:05:25 +00:00
in Cx16VirtualRegisters -> {
val regname = wordtarget . register . name . lowercase ( )
asmgen . out ( """
lda $ sourceName
sta cx16 . $ regname
ora # $ 7f
bmi +
lda # 0
+ sta cx16 . $ regname + 1 """ )
}
else -> throw AssemblyError ( " only reg pairs allowed as word target ${wordtarget.register} " )
2020-10-10 13:39:48 +00:00
}
}
else -> throw AssemblyError ( " target type isn't word " )
}
}
2020-09-15 01:26:57 +00:00
2023-01-04 21:55:05 +00:00
private fun assignVariableUByteIntoWord ( wordtarget : AsmAssignTarget , bytevar : PtIdentifier ) {
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 -> {
2023-05-28 12:53:53 +00:00
if ( wordtarget . array !! . splitWords ) {
if ( wordtarget . constArrayIndexValue != null ) {
val scaledIdx = wordtarget . constArrayIndexValue !!
asmgen . out ( " lda $sourceName | sta ${wordtarget.asmVarname} _lsb+ $scaledIdx " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz ${wordtarget.asmVarname} _msb+ $scaledIdx " )
else
asmgen . out ( " lda #0 | sta ${wordtarget.asmVarname} _msb+ $scaledIdx " )
}
else {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( wordtarget . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
asmgen . out ( """
lda $ sourceName
sta $ { wordtarget . asmVarname } _lsb , y
lda # 0
sta $ { wordtarget . asmVarname } _msb , y """ )
}
} else {
if ( wordtarget . constArrayIndexValue != null ) {
val scaledIdx = wordtarget . constArrayIndexValue !! * 2u
asmgen . out ( " lda $sourceName | sta ${wordtarget.asmVarname} + $scaledIdx " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz ${wordtarget.asmVarname} + $scaledIdx +1 " )
else
asmgen . out ( " lda #0 | sta ${wordtarget.asmVarname} + $scaledIdx +1 " )
}
else {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( wordtarget . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
asmgen . out ( """
lda $ sourceName
sta $ { wordtarget . asmVarname } , y
iny
lda # 0
sta $ { wordtarget . asmVarname } , y """ )
}
2020-09-15 01:26:57 +00:00
}
}
TargetStorageKind . REGISTER -> {
when ( wordtarget . register !! ) {
2020-12-27 17:12:12 +00:00
RegisterOrPair . AX -> asmgen . out ( " ldx #0 | lda $sourceName " )
RegisterOrPair . AY -> asmgen . out ( " ldy #0 | lda $sourceName " )
RegisterOrPair . XY -> asmgen . out ( " ldy #0 | ldx $sourceName " )
2022-01-27 17:05:25 +00:00
in Cx16VirtualRegisters -> {
val regname = wordtarget . register . name . lowercase ( )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " lda $sourceName | sta cx16. $regname | stz cx16. $regname +1 " )
else
asmgen . out ( " lda $sourceName | sta cx16. $regname | lda #0 | sta cx16. $regname +1 " )
}
else -> throw AssemblyError ( " only reg pairs allowed as word target " )
2020-09-15 01:26:57 +00:00
}
}
2020-10-10 13:39:48 +00:00
else -> throw AssemblyError ( " target type isn't word " )
2020-09-15 01:26:57 +00:00
}
}
2023-11-01 23:31:27 +00:00
private fun extendToMSBofVirtualReg ( cpuRegister : CpuRegister , vreg : String , signed : Boolean ) {
if ( signed ) {
when ( cpuRegister ) {
CpuRegister . A -> { }
CpuRegister . X -> asmgen . out ( " txa " )
CpuRegister . Y -> asmgen . out ( " tya " )
}
asmgen . out ( """
ora # $ 7f
bmi +
lda # 0
+ sta $ vreg + 1 """ )
} else {
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz $vreg +1 " )
else
asmgen . out ( " lda #0 | sta $vreg +1 " )
}
}
internal fun assignRegisterByte ( target : AsmAssignTarget , register : CpuRegister , signed : Boolean , extendWord : Boolean ) {
2023-05-08 21:02:48 +00:00
val assignAsWord = target . datatype in WordDatatypes
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} " )
2023-11-01 23:31:27 +00:00
if ( assignAsWord && extendWord ) {
2023-05-08 21:02:48 +00:00
if ( target . datatype in SignedDatatypes ) {
if ( register != CpuRegister . A )
asmgen . out ( " t ${register.name.lowercase()} a " )
asmgen . signExtendAYlsb ( if ( target . datatype in SignedDatatypes ) DataType . BYTE else DataType . UBYTE )
asmgen . out ( " sty ${target.asmVarname} +1 " )
} else {
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz ${target.asmVarname} +1 " )
else
asmgen . out ( " lda #0 | sta ${target.asmVarname} +1 " )
}
}
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 -> {
2023-12-02 20:10:51 +00:00
if ( assignAsWord ) {
when ( register ) {
CpuRegister . A -> { }
CpuRegister . X -> asmgen . out ( " txa " )
CpuRegister . Y -> asmgen . out ( " tya " )
}
if ( extendWord ) {
asmgen . signExtendAYlsb ( if ( target . datatype in SignedDatatypes ) DataType . BYTE else DataType . UBYTE )
} else {
asmgen . out ( " ldy #0 " )
}
assignRegisterpairWord ( target , RegisterOrPair . AY )
} else {
assignRegisterByteToByteArray ( target , register )
}
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 " ) }
2023-04-29 15:14:50 +00:00
RegisterOrPair . AY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord ) {
" no extend "
}
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
ldy # 0
cmp # $ { '$' } 80
bcc +
dey
+ """ )
else
asmgen . out ( " ldy #0 " )
}
RegisterOrPair . AX -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
ldx # 0
cmp # $ { '$' } 80
bcc +
dex
+ """ )
else
asmgen . out ( " ldx #0 " )
}
RegisterOrPair . XY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
tax
ldy # 0
cpx # $ { '$' } 80
bcc +
dey
+ """ )
else
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 -> {
2023-11-01 23:31:27 +00:00
val reg = " cx16. ${target.register.toString().lowercase()} "
asmgen . out ( " sta $reg " )
if ( extendWord )
extendToMSBofVirtualReg ( CpuRegister . A , reg , signed )
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 -> { }
2023-12-29 02:27:35 +00:00
RegisterOrPair . Y -> { asmgen . out ( " stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG " ) }
2023-04-29 15:14:50 +00:00
RegisterOrPair . AY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
txa
ldy # 0
cmp # $ { '$' } 80
bcc +
dey
+ """ )
else
asmgen . out ( " txa | ldy #0 " )
}
RegisterOrPair . AX -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
txa
ldx # 0
cmp # $ { '$' } 80
bcc +
dex
+ """ )
else
asmgen . out ( " txa | ldx #0 " )
}
RegisterOrPair . XY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
ldy # 0
cpx # $ { '$' } 80
bcc +
dey
+ """ )
else
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 -> {
2023-11-01 23:31:27 +00:00
val reg = " cx16. ${target.register.toString().lowercase()} "
asmgen . out ( " stx $reg " )
if ( extendWord )
extendToMSBofVirtualReg ( CpuRegister . X , reg , signed )
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 " ) }
2023-12-29 02:27:35 +00:00
RegisterOrPair . X -> { asmgen . out ( " sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG " ) }
2020-08-23 21:28:25 +00:00
RegisterOrPair . Y -> { }
2023-04-29 15:14:50 +00:00
RegisterOrPair . AY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
tya
ldy # 0
cmp # $ { '$' } 80
bcc +
dey
+ """ )
else
asmgen . out ( " tya | ldy #0 " )
}
RegisterOrPair . AX -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
tya
ldx # 0
cmp # $ { '$' } 80
bcc +
dex
+ """ )
else
asmgen . out ( " tya | ldx #0 " )
}
RegisterOrPair . XY -> {
2023-11-01 23:31:27 +00:00
require ( extendWord )
2023-04-29 15:14:50 +00:00
if ( signed )
asmgen . out ( """
tya
tax
ldy # 0
cpx # $ { '$' } 80
bcc +
dey
+ """ )
else
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 -> {
2023-11-01 23:31:27 +00:00
val reg = " cx16. ${target.register.toString().lowercase()} "
asmgen . out ( " sty $reg " )
if ( extendWord )
extendToMSBofVirtualReg ( CpuRegister . Y , reg , signed )
2020-12-25 11:36:11 +00:00
}
else -> throw AssemblyError ( " weird register " )
2020-08-23 21:28:25 +00:00
}
}
}
2019-08-16 20:49:29 +00:00
}
}
2023-11-01 23:31:27 +00:00
private fun assignRegisterByteToByteArray ( target : AsmAssignTarget , register : CpuRegister ) {
2023-09-17 01:48:16 +00:00
if ( target . array !! . splitWords )
throw AssemblyError ( " cannot assign byte to split word array here ${target.position} " )
2024-02-03 00:57:17 +00:00
// assign regular array indexing
if ( target . constArrayIndexValue != null ) {
when ( register ) {
CpuRegister . A -> { }
CpuRegister . X -> asmgen . out ( " txa " )
CpuRegister . Y -> asmgen . out ( " tya " )
2023-09-17 01:48:16 +00:00
}
2024-02-03 00:57:17 +00:00
asmgen . out ( " sta ${target.asmVarname} + ${target.constArrayIndexValue} " )
}
else {
when ( register ) {
CpuRegister . A -> { }
CpuRegister . X -> asmgen . out ( " txa " )
CpuRegister . Y -> asmgen . out ( " tya " )
}
val indexVar = target . array . index as ? PtIdentifier
if ( indexVar != null ) {
asmgen . out ( " ldy ${asmgen.asmVariableName(indexVar)} | sta ${target.asmVarname} ,y " )
} else {
2024-02-13 20:56:22 +00:00
require ( target . array . index . type in ByteDatatypesWithBoolean )
2024-02-03 00:57:17 +00:00
asmgen . saveRegisterStack ( register , false )
asmgen . assignExpressionToRegister ( target . array . index , RegisterOrPair . Y , false )
asmgen . out ( " pla | sta ${target.asmVarname} ,y " )
2023-09-17 01:48:16 +00:00
}
}
}
2020-11-27 23:44:38 +00:00
internal fun assignRegisterpairWord ( target : AsmAssignTarget , regs : RegisterOrPair ) {
2022-12-03 18:56:54 +00:00
require ( target . datatype in NumericDatatypes || target . datatype in PassByReferenceDatatypes ) {
2023-03-10 00:02:25 +00:00
" assign target must be word type ${target.position} "
2022-12-03 18:56:54 +00:00
}
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 -> {
2023-05-28 12:53:53 +00:00
if ( target . array !! . splitWords ) {
// assign to split lsb/msb word array
if ( target . constArrayIndexValue != null ) {
val idx = target . constArrayIndexValue !!
when ( regs ) {
RegisterOrPair . AX -> asmgen . out ( " sta ${target.asmVarname} _lsb+ $idx | stx ${target.asmVarname} _msb+ $idx " )
RegisterOrPair . AY -> asmgen . out ( " sta ${target.asmVarname} _lsb+ $idx | sty ${target.asmVarname} _msb+ $idx " )
RegisterOrPair . XY -> asmgen . out ( " stx ${target.asmVarname} _lsb+ $idx | sty ${target.asmVarname} _msb+ $idx " )
in Cx16VirtualRegisters -> {
val srcReg = asmgen . asmSymbolName ( regs )
asmgen . out ( """
lda $ srcReg
sta $ { target . asmVarname } _lsb + $ idx
lda $ srcReg + 1
sta $ { target . asmVarname } _msb + $ idx """ )
}
else -> throw AssemblyError ( " expected reg pair or cx16 virtual 16-bit register " )
}
}
else {
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 " )
}
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
asmgen . out ( """
pla
2023-05-28 20:49:33 +00:00
sta $ { target . asmVarname } _msb , y
2023-05-28 12:53:53 +00:00
pla
2023-05-28 20:49:33 +00:00
sta $ { target . asmVarname } _lsb , y """ )
2023-05-28 12:53:53 +00:00
} else {
2021-02-06 12:01:45 +00:00
val srcReg = asmgen . asmSymbolName ( regs )
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2021-02-06 12:01:45 +00:00
asmgen . out ( """
lda $ srcReg
2023-05-28 12:53:53 +00:00
sta $ { target . asmVarname } _lsb , y
2021-02-06 12:01:45 +00:00
lda $ srcReg + 1
2023-05-28 12:53:53 +00:00
sta $ { target . asmVarname } _msb , y """ )
2021-02-06 12:01:45 +00:00
}
2020-12-08 21:54:20 +00:00
}
2023-05-28 12:53:53 +00:00
} else {
// assign to normal word array
if ( target . constArrayIndexValue != null ) {
val idx = target . constArrayIndexValue !! * 2u
2021-02-06 12:01:45 +00:00
when ( regs ) {
2023-05-28 12:53:53 +00:00
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 " )
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 " )
}
}
else {
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 " )
}
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
asmgen . out ( """
2023-05-28 20:49:33 +00:00
iny
2023-05-28 12:53:53 +00:00
pla
sta $ { target . asmVarname } , y
dey
pla
sta $ { target . asmVarname } , y """ )
} else {
val srcReg = asmgen . asmSymbolName ( regs )
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2023-05-28 12:53:53 +00:00
asmgen . out ( """
2023-05-28 20:49:33 +00:00
iny
2023-05-28 12:53:53 +00:00
lda $ srcReg + 1
sta $ { target . asmVarname } , y
dey
lda $ srcReg
sta $ { target . asmVarname } , y """ )
2021-02-06 12:01:45 +00:00
}
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 . MEMORY -> throw AssemblyError ( " can't store word into memory byte " )
}
}
2020-08-23 12:36:24 +00:00
private fun assignConstantWord ( target : AsmAssignTarget , word : Int ) {
2021-02-19 17:48:12 +00:00
if ( word == 0 && asmgen . isTargetCpu ( CpuType . CPU65c02 ) ) {
2020-12-22 16:59:47 +00:00
// optimize setting zero value for this processor
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
asmgen . out ( " stz ${target.asmVarname} | stz ${target.asmVarname} +1 " )
}
TargetStorageKind . MEMORY -> {
2021-12-04 00:03:51 +00:00
throw AssemblyError ( " memory is bytes not words " )
2020-12-22 16:59:47 +00:00
}
TargetStorageKind . ARRAY -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array !! , CpuRegister . Y )
2023-05-27 12:43:09 +00:00
if ( target . array . splitWords )
asmgen . out ( """
lda # 0
sta $ { target . asmVarname } _lsb , y
sta $ { target . asmVarname } _msb , y """ )
else
asmgen . out ( """
lda # 0
sta $ { target . asmVarname } , y
sta $ { target . asmVarname } + 1 , y """ )
2020-12-22 16:59:47 +00:00
}
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 " )
}
}
}
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 -> {
2023-03-11 13:55:13 +00:00
throw AssemblyError ( " assign word to memory ${target.memory} should have gotten a typecast " )
2019-08-16 20:49:29 +00:00
}
2020-08-23 11:56:21 +00:00
TargetStorageKind . ARRAY -> {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array !! , CpuRegister . Y )
2023-05-27 12:43:09 +00:00
if ( target . array . splitWords )
asmgen . out ( """
lda # < $ { word . toHex ( ) }
sta $ { target . asmVarname } _lsb , y
lda # > $ { word . toHex ( ) }
sta $ { target . asmVarname } _msb , y """ )
else
asmgen . out ( """
lda # < $ { word . toHex ( ) }
sta $ { target . asmVarname } , y
lda # > $ { word . toHex ( ) }
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
}
}
2019-08-16 20:49:29 +00:00
}
}
2023-09-17 01:48:16 +00:00
internal fun assignConstantByte ( target : AsmAssignTarget , byte : Int ) {
2021-11-20 23:48:23 +00:00
if ( byte == 0 && asmgen . isTargetCpu ( CpuType . CPU65c02 ) ) {
2020-12-22 16:59:47 +00:00
// optimize setting zero value for this cpu
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
asmgen . out ( " stz ${target.asmVarname} " )
}
TargetStorageKind . MEMORY -> {
2021-12-04 00:03:51 +00:00
asmgen . out ( " lda #0 " )
2021-01-19 18:25:23 +00:00
storeRegisterAInMemoryAddress ( target . memory !! )
2020-12-22 16:59:47 +00:00
}
TargetStorageKind . ARRAY -> {
2023-05-28 12:53:53 +00:00
if ( target . array !! . splitWords )
2023-09-17 01:48:16 +00:00
throw AssemblyError ( " cannot assign byte to split word array here ${target.position} " )
2020-12-22 16:59:47 +00:00
if ( target . constArrayIndexValue != null ) {
val indexValue = target . constArrayIndexValue !!
asmgen . out ( " stz ${target.asmVarname} + $indexValue " )
}
else {
2023-09-17 01:48:16 +00:00
asmgen . assignExpressionToRegister ( target . array . index , RegisterOrPair . X , false )
asmgen . out ( " stz ${target.asmVarname} ,x " )
2020-12-22 16:59:47 +00:00
}
}
TargetStorageKind . REGISTER -> when ( target . register !! ) {
RegisterOrPair . A -> asmgen . out ( " lda #0 " )
RegisterOrPair . X -> asmgen . out ( " ldx #0 " )
RegisterOrPair . Y -> asmgen . out ( " ldy #0 " )
RegisterOrPair . AX -> asmgen . out ( " lda #0 | tax " )
RegisterOrPair . AY -> asmgen . out ( " lda #0 | tay " )
RegisterOrPair . XY -> asmgen . out ( " ldx #0 | ldy #0 " )
RegisterOrPair . FAC1 , RegisterOrPair . FAC2 -> throw AssemblyError ( " expected typecasted byte to float " )
2020-12-25 11:36:11 +00:00
in Cx16VirtualRegisters -> {
2022-06-27 20:26:40 +00:00
asmgen . out ( " stz cx16. ${target.register.toString().lowercase()} | stz cx16. ${target.register.toString().lowercase()} +1 " )
2020-12-22 16:59:47 +00:00
}
2020-12-25 11:36:11 +00:00
else -> throw AssemblyError ( " weird register " )
2020-12-22 16:59:47 +00:00
}
}
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 -> {
2023-05-28 12:53:53 +00:00
if ( target . array !! . splitWords )
TODO ( " assign into split words ${target.position} " )
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 {
2024-01-15 02:25:50 +00:00
asmgen . loadScaledArrayIndexIntoRegister ( target . array , CpuRegister . Y )
2022-06-06 16:30:19 +00:00
asmgen . out ( " lda # ${byte.toHex()} | sta ${target.asmVarname} ,y " )
2020-08-23 20:36:49 +00:00
}
2019-08-16 20:49:29 +00:00
}
2020-08-23 21:28:25 +00:00
TargetStorageKind . REGISTER -> when ( target . register !! ) {
RegisterOrPair . A -> asmgen . out ( " lda # ${byte.toHex()} " )
RegisterOrPair . X -> asmgen . out ( " ldx # ${byte.toHex()} " )
RegisterOrPair . Y -> asmgen . out ( " ldy # ${byte.toHex()} " )
2020-12-27 17:12:12 +00:00
RegisterOrPair . AX -> asmgen . out ( " ldx #0 | lda # ${byte.toHex()} " )
RegisterOrPair . AY -> asmgen . out ( " ldy #0 | lda # ${byte.toHex()} " )
RegisterOrPair . XY -> asmgen . out ( " ldy #0 | ldx # ${byte.toHex()} " )
2020-11-23 21:14:45 +00:00
RegisterOrPair . FAC1 , RegisterOrPair . FAC2 -> throw AssemblyError ( " expected typecasted byte to float " )
2020-12-25 11:36:11 +00:00
in Cx16VirtualRegisters -> {
2023-09-17 01:48:16 +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
2023-09-17 01:48:16 +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
}
2019-08-16 20:49:29 +00:00
}
}
2023-03-26 02:49:23 +00:00
internal 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 -> {
2023-11-27 19:54:49 +00:00
asmgen . assignExpressionToRegister ( target . array !! . index , RegisterOrPair . A , false )
asmgen . out ( """
ldy # < $ { target . asmVarname }
sty P8ZP _SCRATCH _W1
ldy # > $ { target . asmVarname }
sty P8ZP _SCRATCH _W1 + 1
jsr floats . set _0 _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 memory byte " )
2020-11-23 21:14:45 +00:00
TargetStorageKind . REGISTER -> {
2022-02-08 20:38:27 +00:00
val floatConst = allocator . getFloatAsmConst ( float )
2020-11-23 21:14:45 +00:00
when ( target . register !! ) {
RegisterOrPair . FAC1 -> asmgen . out ( " lda #< $floatConst | ldy #> $floatConst | jsr floats.MOVFM " )
RegisterOrPair . FAC2 -> asmgen . out ( " lda #< $floatConst | ldy #> $floatConst | jsr floats.CONUPK " )
else -> throw AssemblyError ( " can only assign float to Fac1 or 2 " )
}
}
2019-08-16 20:49:29 +00:00
}
} else {
// non-zero value
2022-02-08 20:38:27 +00:00
val constFloat = allocator . getFloatAsmConst ( float )
2020-08-23 11:56:21 +00:00
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
2019-08-16 20:49:29 +00:00
asmgen . out ( """
2022-01-09 15:18:13 +00:00
lda # < $ constFloat
ldy # > $ constFloat
sta P8ZP _SCRATCH _W1
sty P8ZP _SCRATCH _W1 + 1
lda # < $ { target . asmVarname }
ldy # > $ { target . asmVarname }
jsr floats . copy _float """ )
2019-08-16 20:49:29 +00:00
}
2020-08-23 11:56:21 +00:00
TargetStorageKind . ARRAY -> {
2023-11-27 19:54:49 +00:00
asmgen . assignExpressionToRegister ( target . array !! . index , RegisterOrPair . A , false )
asmgen . out ( """
ldy # < $ { constFloat }
sty P8ZP _SCRATCH _W1
ldy # > $ { constFloat }
sty P8ZP _SCRATCH _W1 + 1
ldy # < $ { target . asmVarname }
sty P8ZP _SCRATCH _W2
ldy # > $ { target . asmVarname }
sty P8ZP _SCRATCH _W2 + 1
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 memory byte " )
2020-11-23 21:14:45 +00:00
TargetStorageKind . REGISTER -> {
2022-02-08 20:38:27 +00:00
val floatConst = allocator . getFloatAsmConst ( float )
2020-11-23 21:14:45 +00:00
when ( target . register !! ) {
RegisterOrPair . FAC1 -> asmgen . out ( " lda #< $floatConst | ldy #> $floatConst | jsr floats.MOVFM " )
RegisterOrPair . FAC2 -> asmgen . out ( " lda #< $floatConst | ldy #> $floatConst | jsr floats.CONUPK " )
else -> throw AssemblyError ( " can only assign float to Fac1 or 2 " )
}
}
2019-08-16 20:49:29 +00:00
}
}
}
2023-01-04 21:55:05 +00:00
private fun assignMemoryByte ( target : AsmAssignTarget , address : UInt ? , identifier : PtIdentifier ? ) {
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 -> {
2023-03-11 14:19:41 +00:00
asmgen . out ( " lda ${address.toHex()} " )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
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
}
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 -> {
2023-03-11 14:19:41 +00:00
asmgen . loadByteFromPointerIntoA ( identifier )
2023-11-01 23:31:27 +00:00
assignRegisterByte ( target , CpuRegister . A , false , true )
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
}
}
2019-08-16 20:49:29 +00:00
}
}
}
2023-01-04 21:55:05 +00:00
private fun assignMemoryByteIntoWord ( wordtarget : AsmAssignTarget , address : UInt ? , identifier : PtIdentifier ? ) {
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 -> {
2023-03-11 14:19:41 +00:00
asmgen . out ( " lda ${address.toHex()} | ldy #0 " )
assignRegisterpairWord ( wordtarget , RegisterOrPair . AY )
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 ${address.toHex()} " )
RegisterOrPair . AY -> asmgen . out ( " ldy #0 | lda ${address.toHex()} " )
RegisterOrPair . XY -> asmgen . out ( " ldy #0 | ldy ${address.toHex()} " )
2023-06-14 19:10:01 +00:00
in Cx16VirtualRegisters -> {
asmgen . out ( " lda ${address.toHex()} | sta cx16. ${wordtarget.register.toString().lowercase()} " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz cx16. ${wordtarget.register.toString().lowercase()} +1 " )
else
asmgen . out ( " lda #0 | sta cx16. ${wordtarget.register.toString().lowercase()} +1 " )
}
2020-09-15 01:26:57 +00:00
else -> throw AssemblyError ( " word regs can only be pair " )
}
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 -> {
2023-03-11 14:19:41 +00:00
asmgen . loadByteFromPointerIntoA ( identifier )
asmgen . out ( " ldy #0 " )
assignRegisterpairWord ( wordtarget , RegisterOrPair . AY )
2020-09-15 01:26:57 +00:00
}
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 " )
2023-06-14 19:10:01 +00:00
in Cx16VirtualRegisters -> {
asmgen . out ( " sta cx16. ${wordtarget.register.toString().lowercase()} " )
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " stz cx16. ${wordtarget.register.toString().lowercase()} +1 " )
else
asmgen . out ( " lda #0 | sta cx16. ${wordtarget.register.toString().lowercase()} +1 " )
}
2020-09-15 01:26:57 +00:00
else -> throw AssemblyError ( " word regs can only be pair " )
}
}
else -> throw AssemblyError ( " other types aren't word " )
}
}
}
2023-09-15 21:05:42 +00:00
internal fun storeRegisterAInMemoryAddress ( memoryAddress : PtMemoryByte ) {
2023-01-04 21:55:05 +00:00
val addressExpr = memoryAddress . address
val addressLv = addressExpr as ? PtNumber
2023-09-14 21:04:23 +00:00
val addressOf = addressExpr as ? PtAddressOf
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 ) {
2023-01-04 21:55:05 +00:00
is PtNumber , is PtIdentifier -> {
2023-03-18 23:58:45 +00:00
assignExpressionToVariable ( addressExpr , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2024-02-07 21:09:04 +00:00
asmgen . storeAIntoZpPointerVar ( " P8ZP_SCRATCH_W2 " , false )
2021-01-19 18:25:23 +00:00
}
else -> {
// same as above but we need to save the A register
asmgen . out ( " pha " )
2023-03-18 23:58:45 +00:00
assignExpressionToVariable ( addressExpr , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2021-01-19 18:25:23 +00:00
asmgen . out ( " pla " )
2024-02-07 21:09:04 +00:00
asmgen . storeAIntoZpPointerVar ( " P8ZP_SCRATCH_W2 " , false )
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
}
2023-09-14 21:04:23 +00:00
addressOf != null -> {
2023-09-17 16:30:57 +00:00
if ( addressOf . isFromArrayElement ) {
TODO ( " address-of array element $addressOf " )
} else {
asmgen . out ( " sta ${asmgen.asmSymbolName(addressOf.identifier)} " )
}
2023-09-14 21:04:23 +00:00
}
2023-01-04 21:55:05 +00:00
addressExpr is PtIdentifier -> {
2021-12-04 03:43:58 +00:00
asmgen . storeAIntoPointerVar ( addressExpr )
2020-08-23 12:36:24 +00:00
}
2023-03-16 01:27:30 +00:00
addressExpr is PtBinaryExpression -> {
2023-09-14 21:04:23 +00:00
if ( addressExpr . operator == " + " || addressExpr . operator == " - " ) {
val addrOf = addressExpr . left as ? PtAddressOf
val offset = ( addressExpr . right as ? PtNumber ) ?. number ?. toInt ( )
if ( addrOf != null && offset != null ) {
2023-09-17 16:30:57 +00:00
if ( addrOf . isFromArrayElement ) {
TODO ( " address-of array element $addrOf " )
} else {
asmgen . out ( " sta ${asmgen.asmSymbolName(addrOf.identifier)} ${addressExpr.operator} ${offset} " )
return
}
2023-09-14 21:04:23 +00:00
}
}
2024-02-03 16:36:42 +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
2023-01-04 21:55:05 +00:00
internal fun assignExpressionToRegister ( expr : PtExpression , register : RegisterOrPair , signed : Boolean ) {
2021-10-31 01:34:17 +00:00
val src = AsmAssignSource . fromAstSource ( expr , program , asmgen )
2023-03-10 00:02:25 +00:00
val tgt = AsmAssignTarget . fromRegisters ( register , signed , expr . position , null , asmgen )
2023-02-15 21:50:35 +00:00
val assign = AsmAssignment ( src , tgt , program . memsizer , expr . position )
2023-03-18 23:24:05 +00:00
translateNormalAssignment ( assign , expr . definingISub ( ) )
2020-11-15 14:04:23 +00:00
}
2023-03-18 23:58:45 +00:00
internal fun assignExpressionToVariable ( expr : PtExpression , asmVarName : String , dt : DataType ) {
2023-01-04 21:55:05 +00:00
if ( expr . type == DataType . FLOAT && dt != DataType . FLOAT ) {
2022-05-03 21:43:38 +00:00
throw AssemblyError ( " can't directly assign a FLOAT expression to an integer variable $expr " )
} else {
val src = AsmAssignSource . fromAstSource ( expr , program , asmgen )
2023-03-18 23:58:45 +00:00
val tgt = AsmAssignTarget ( TargetStorageKind . VARIABLE , asmgen , dt , expr . definingISub ( ) , expr . position , variableAsmName = asmVarName )
2023-02-15 21:50:35 +00:00
val assign = AsmAssignment ( src , tgt , program . memsizer , expr . position )
2023-03-18 23:24:05 +00:00
translateNormalAssignment ( assign , expr . definingISub ( ) )
2022-05-03 21:43:38 +00:00
}
2020-11-15 14:04:23 +00:00
}
2020-11-15 16:44:47 +00:00
2023-03-18 23:24:05 +00:00
internal fun assignVariableToRegister ( asmVarName : String , register : RegisterOrPair , signed : Boolean , scope : IPtSubroutine ? , pos : Position ) {
2023-03-10 00:02:25 +00:00
val tgt = AsmAssignTarget . fromRegisters ( register , signed , pos , null , asmgen )
2020-11-15 16:44:47 +00:00
val src = AsmAssignSource ( SourceStorageKind . VARIABLE , program , asmgen , tgt . datatype , variableAsmName = asmVarName )
2023-02-15 21:50:35 +00:00
val assign = AsmAssignment ( src , tgt , program . memsizer , Position . DUMMY )
2023-03-18 23:24:05 +00:00
translateNormalAssignment ( assign , scope )
2020-11-15 16:44:47 +00:00
}
2023-02-15 21:50:35 +00:00
2023-03-18 23:24:05 +00:00
internal fun inplaceInvert ( assign : AsmAssignment , scope : IPtSubroutine ? ) {
2023-02-15 21:50:35 +00:00
val target = assign . target
when ( assign . target . datatype ) {
2024-02-12 20:29:02 +00:00
DataType . UBYTE , DataType . BOOL -> {
val eorValue = if ( assign . target . datatype == DataType . BOOL ) 1 else 255
2023-02-15 21:50:35 +00:00
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
asmgen . out ( """
lda $ { target . asmVarname }
2024-02-12 20:29:02 +00:00
eor # $ eorValue
2023-02-15 21:50:35 +00:00
sta $ { target . asmVarname } """ )
}
TargetStorageKind . MEMORY -> {
val memory = target . memory !!
when ( memory . address ) {
is PtNumber -> {
val addr = ( memory . address as PtNumber ) . number . toHex ( )
asmgen . out ( """
lda $ addr
2024-02-12 20:29:02 +00:00
eor # $ eorValue
2023-02-15 21:50:35 +00:00
sta $ addr """ )
}
is PtIdentifier -> {
2024-01-31 22:54:22 +00:00
asmgen . loadByteFromPointerIntoA ( memory . address as PtIdentifier )
2024-02-12 20:29:02 +00:00
asmgen . out ( " eor # $eorValue " )
2024-01-31 22:54:22 +00:00
asmgen . storeAIntoPointerVar ( memory . address as PtIdentifier )
2023-02-15 21:50:35 +00:00
}
else -> {
2023-03-18 23:58:45 +00:00
asmgen . assignExpressionToVariable ( memory . address , " P8ZP_SCRATCH_W2 " , DataType . UWORD )
2023-10-31 20:26:55 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) ) {
asmgen . out ( """
lda ( P8ZP _SCRATCH _W2 )
2024-02-12 20:29:02 +00:00
eor # $ eorValue """ )
2023-10-31 20:26:55 +00:00
} else {
asmgen . out ( """
ldy # 0
lda ( P8ZP _SCRATCH _W2 ) , y
2024-02-12 20:29:02 +00:00
eor # $ eorValue """ )
2023-10-31 20:26:55 +00:00
}
2024-02-07 21:09:04 +00:00
asmgen . storeAIntoZpPointerVar ( " P8ZP_SCRATCH_W2 " , false )
2023-02-15 21:50:35 +00:00
}
}
}
TargetStorageKind . REGISTER -> {
when ( target . register !! ) {
2024-02-12 20:29:02 +00:00
RegisterOrPair . A -> asmgen . out ( " eor # $eorValue " )
RegisterOrPair . X -> asmgen . out ( " txa | eor # $eorValue | tax " )
RegisterOrPair . Y -> asmgen . out ( " tya | eor # $eorValue | tay " )
2023-02-15 21:50:35 +00:00
else -> throw AssemblyError ( " invalid reg dt for byte invert " )
}
}
2024-02-13 20:56:22 +00:00
TargetStorageKind . ARRAY -> {
val invertOperator = if ( assign . target . datatype == DataType . BOOL ) " not " else " ~ "
assignPrefixedExpressionToArrayElt ( makePrefixedExprFromArrayExprAssign ( invertOperator , assign ) , scope )
}
2023-02-15 21:50:35 +00:00
}
}
DataType . UWORD -> {
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
asmgen . out ( """
lda $ { target . asmVarname }
eor # 255
sta $ { target . asmVarname }
lda $ { target . asmVarname } + 1
eor # 255
sta $ { target . asmVarname } + 1 """ )
}
TargetStorageKind . REGISTER -> {
when ( target . register !! ) {
RegisterOrPair . AX -> asmgen . out ( " pha | txa | eor #255 | tax | pla | eor #255 " )
RegisterOrPair . AY -> asmgen . out ( " pha | tya | eor #255 | tay | pla | eor #255 " )
RegisterOrPair . XY -> asmgen . out ( " txa | eor #255 | tax | tya | eor #255 | tay " )
in Cx16VirtualRegisters -> throw AssemblyError ( " cx16 virtual regs should be variables, not real registers " )
else -> throw AssemblyError ( " invalid reg dt for word invert " )
}
}
2023-03-18 23:24:05 +00:00
TargetStorageKind . ARRAY -> assignPrefixedExpressionToArrayElt ( makePrefixedExprFromArrayExprAssign ( " ~ " , assign ) , scope )
2023-02-15 21:50:35 +00:00
else -> throw AssemblyError ( " weird target " )
}
}
else -> throw AssemblyError ( " invert of invalid type " )
}
}
2023-03-18 23:24:05 +00:00
internal fun inplaceNegate ( assign : AsmAssignment , ignoreDatatype : Boolean , scope : IPtSubroutine ? ) {
2023-02-15 21:50:35 +00:00
val target = assign . target
val datatype = if ( ignoreDatatype ) {
when ( target . datatype ) {
DataType . UBYTE , DataType . BYTE -> DataType . BYTE
DataType . UWORD , DataType . WORD -> DataType . WORD
else -> target . datatype
}
} else target . datatype
when ( datatype ) {
DataType . BYTE -> {
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
2023-07-24 21:28:32 +00:00
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( """
lda $ { target . asmVarname }
eor # 255
ina
sta $ { target . asmVarname } """ )
else
asmgen . out ( """
lda # 0
sec
sbc $ { target . asmVarname }
sta $ { target . asmVarname } """ )
2023-02-15 21:50:35 +00:00
}
TargetStorageKind . REGISTER -> {
when ( target . register !! ) {
RegisterOrPair . A -> {
if ( asmgen . isTargetCpu ( CpuType . CPU65c02 ) )
asmgen . out ( " eor #255 | ina " )
else
asmgen . out ( " eor #255 | clc | adc #1 " )
}
RegisterOrPair . X -> asmgen . out ( " txa | eor #255 | tax | inx " )
RegisterOrPair . Y -> asmgen . out ( " tya | eor #255 | tay | iny " )
else -> throw AssemblyError ( " invalid reg dt for byte negate " )
}
}
TargetStorageKind . MEMORY -> throw AssemblyError ( " memory is ubyte, can't negate that " )
2023-03-18 23:24:05 +00:00
TargetStorageKind . ARRAY -> assignPrefixedExpressionToArrayElt ( makePrefixedExprFromArrayExprAssign ( " - " , assign ) , scope )
2023-02-15 21:50:35 +00:00
}
}
DataType . WORD -> {
when ( target . kind ) {
TargetStorageKind . VARIABLE -> {
asmgen . out ( """
lda # 0
sec
sbc $ { target . asmVarname }
sta $ { target . asmVarname }
lda # 0
sbc $ { target . asmVarname } + 1
sta $ { target . asmVarname } + 1 """ )
}
TargetStorageKind . REGISTER -> {
when ( target . register !! ) { //P8ZP_SCRATCH_REG
RegisterOrPair . AX -> {
asmgen . out ( """
sec
eor # 255
adc # 0
pha
txa
eor # 255
adc # 0
tax
pla """ )
}
RegisterOrPair . AY -> {
asmgen . out ( """
sec
eor # 255
adc # 0
2023-09-01 18:27:39 +00:00
tax
2023-02-15 21:50:35 +00:00
tya
eor # 255
adc # 0
tay
2023-09-01 18:27:39 +00:00
txa """ )
2023-02-15 21:50:35 +00:00
}
RegisterOrPair . XY -> {
asmgen . out ( """
sec
txa
eor # 255
adc # 0
tax
tya
eor # 255
adc # 0
tay """ )
}
in Cx16VirtualRegisters -> throw AssemblyError ( " cx16 virtual regs should be variables, not real registers " )
else -> throw AssemblyError ( " invalid reg dt for word neg " )
}
}
TargetStorageKind . MEMORY -> throw AssemblyError ( " memory is ubyte, can't negate that " )
2023-03-18 23:24:05 +00:00
TargetStorageKind . ARRAY -> assignPrefixedExpressionToArrayElt ( makePrefixedExprFromArrayExprAssign ( " - " , assign ) , scope )
2023-02-15 21:50:35 +00:00
}
}
DataType . FLOAT -> {
when ( target . kind ) {
TargetStorageKind . REGISTER -> {
when ( target . register !! ) {
RegisterOrPair . FAC1 -> asmgen . out ( " jsr floats.NEGOP " )
RegisterOrPair . FAC2 -> asmgen . out ( " jsr floats.MOVFA | jsr floats.NEGOP | jsr floats.MOVEF " )
else -> throw AssemblyError ( " invalid float register " )
}
}
TargetStorageKind . VARIABLE -> {
// simply flip the sign bit in the float
asmgen . out ( """
lda $ { target . asmVarname } + 1
eor # $ 80
sta $ { target . asmVarname } + 1
""" )
}
2023-03-18 23:24:05 +00:00
TargetStorageKind . ARRAY -> assignPrefixedExpressionToArrayElt ( makePrefixedExprFromArrayExprAssign ( " - " , assign ) , scope )
2023-02-15 21:50:35 +00:00
else -> throw AssemblyError ( " weird target for in-place float negation " )
}
}
else -> throw AssemblyError ( " negate of invalid type " )
}
}
private fun makePrefixedExprFromArrayExprAssign ( operator : String , assign : AsmAssignment ) : AsmAssignment {
val prefix = PtPrefix ( operator , assign . source . datatype , assign . source . array !! . position )
prefix . add ( assign . source . array )
prefix . parent = assign . target . origAstTarget ?: program
val prefixSrc = AsmAssignSource ( SourceStorageKind . EXPRESSION , program , asmgen , assign . source . datatype , expression = prefix )
return AsmAssignment ( prefixSrc , assign . target , assign . memsizer , assign . position )
}
2019-08-16 20:49:29 +00:00
}