work on longs

This commit is contained in:
Irmen de Jong
2025-09-19 06:41:16 +02:00
parent a2b9d78cf3
commit d66dc664de
17 changed files with 483 additions and 64 deletions

View File

@@ -50,8 +50,10 @@ enum class BaseDataType {
val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)
val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD)
val BaseDataType.isLong get() = this == BaseDataType.LONG
val BaseDataType.isInteger get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
val BaseDataType.isIntegerOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL)
val BaseDataType.isWordOrByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.BOOL)
val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger
val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric
val BaseDataType.isSigned get() = this in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
@@ -344,6 +346,7 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType
val isUnsignedWord = base == BaseDataType.UWORD
val isSignedWord = base == BaseDataType.WORD
val isInteger = base.isInteger
val isWordOrByteOrBool = base.isWordOrByteOrBool
val isIntegerOrBool = base.isIntegerOrBool
val isNumeric = base.isNumeric
val isNumericOrBool = base.isNumericOrBool

View File

@@ -14,6 +14,7 @@ internal class NormalMemSizer(val floatsize: Int): IMemSizer {
return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
BaseDataType.LONG -> numElements * 4
BaseDataType.FLOAT-> numElements * floatsize
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
else -> throw IllegalArgumentException("invalid sub type")

View File

@@ -21,7 +21,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
// we consider them NOT to be optimized into (possibly different) CPU registers.
// Just load them in whatever the register spec says.
return when (params.size) {
1 -> params[0].register == null && (params[0].type.isIntegerOrBool || params[0].type.isPointer)
1 -> params[0].register == null && (params[0].type.isWordOrByteOrBool || params[0].type.isPointer)
2 -> params[0].type.isByteOrBool && params[1].type.isByteOrBool && params[0].register == null && params[1].register == null
else -> false
}

View File

@@ -46,6 +46,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
return when {
rightDt.isByteOrBool -> translateIfByte(stmt, jumpAfterIf)
rightDt.isWord || rightDt.isPointer -> translateIfWord(stmt, compareCond, jumpAfterIf)
rightDt.isLong -> translateIfLong(stmt, compareCond, jumpAfterIf)
rightDt.isFloat -> translateIfFloat(stmt, compareCond, jumpAfterIf)
else -> throw AssemblyError("weird dt")
}
@@ -575,6 +576,32 @@ internal class IfElseAsmGen(private val program: PtProgram,
}
}
private fun translateIfLong(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) {
val constValue = condition.right.asConstInteger()
if(constValue==0) {
// optimized comparisons with zero
return when (condition.operator) {
"==" -> longEqualsZero(condition.left, false, jumpAfterIf, stmt)
"!=" -> longEqualsZero(condition.left, true, jumpAfterIf, stmt)
"<" -> longLessZero(condition.left, false, jumpAfterIf, stmt)
"<=" -> longLessZero(condition.left, true, jumpAfterIf, stmt)
">" -> longGreaterZero(condition.left, false, jumpAfterIf, stmt)
">=" -> longGreaterZero(condition.left, true, jumpAfterIf, stmt)
else -> throw AssemblyError("expected comparison operator")
}
}
return when (condition.operator) {
"==" -> longEqualsValue(condition.left, condition.right, false, jumpAfterIf, stmt)
"!=" -> longEqualsValue(condition.left, condition.right, true, jumpAfterIf, stmt)
"<" -> TODO("long < 0")
"<=" -> TODO("long <= 0")
">" -> TODO("long > 0")
">=" -> TODO("long >= 0")
else -> throw AssemblyError("expected comparison operator")
}
}
private fun translateIfWord(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) {
val signed = condition.left.type.isSigned
val constValue = condition.right.asConstInteger()
@@ -606,7 +633,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
private fun wordGreaterEqualsZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
// special case for word>=0
if(signed) {
loadAndCmp0MSB(value)
loadAndCmp0MSB(value, false)
if (jump != null)
translateJumpElseBodies("bpl", "bmi", jump, stmt.elseScope)
else
@@ -619,7 +646,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
private fun wordLessZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
// special case for word<0
if(signed) {
loadAndCmp0MSB(value)
loadAndCmp0MSB(value, false)
if (jump != null)
translateJumpElseBodies("bmi", "bpl", jump, stmt.elseScope)
else
@@ -894,23 +921,31 @@ _jump jmp (${target.asmLabel})
}
private fun loadAndCmp0MSB(value: PtExpression) {
private fun loadAndCmp0MSB(value: PtExpression, long: Boolean) {
when(value) {
is PtArrayIndexer -> {
if(value.variable==null)
TODO("support for ptr indexing ${value.position}")
val varname = asmgen.asmVariableName(value.variable!!)
asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.Y)
if(value.splitWords)
if(value.splitWords) {
require(!long)
asmgen.out(" lda ${varname}_msb,y")
}
else if(long)
asmgen.out(" lda $varname+3,y")
else
asmgen.out(" lda $varname+1,y")
}
is PtIdentifier -> {
val varname = asmgen.asmVariableName(value)
asmgen.out(" lda $varname+1")
if(long)
asmgen.out(" lda $varname+3")
else
asmgen.out(" lda $varname+1")
}
is PtAddressOf -> {
require(!long)
if(value.isFromArrayElement) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" cpy #0")
@@ -923,6 +958,7 @@ _jump jmp (${target.asmLabel})
}
}
else -> {
require(!long)
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" cpy #0")
}
@@ -1226,6 +1262,34 @@ _jump jmp (${target.asmLabel})
}
}
private fun longEqualsZero(value: PtExpression, notEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
TODO("long == 0")
}
private fun longLessZero(value: PtExpression, lessEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(lessEquals) {
TODO("long <= 0")
} else {
loadAndCmp0MSB(value, true)
if (jump != null)
translateJumpElseBodies("bmi", "bpl", jump, stmt.elseScope)
else
translateIfElseBodies("bpl", stmt)
}
}
private fun longGreaterZero(value: PtExpression, lessEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(lessEquals) {
TODO("long >= 0")
} else {
loadAndCmp0MSB(value, true)
if (jump != null)
translateJumpElseBodies("bpl", "bmi", jump, stmt.elseScope)
else
translateIfElseBodies("bmi", stmt)
}
}
private fun wordEqualsZero(value: PtExpression, notEquals: Boolean, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
// special case for (u)word == 0
@@ -1303,6 +1367,16 @@ _jump jmp (${target.asmLabel})
}
}
private fun longEqualsValue(
left: PtExpression,
right: PtExpression,
notEquals: Boolean,
jump: PtJump?,
stmt: PtIfElse
) {
TODO("long == value")
}
private fun wordEqualsValue(
left: PtExpression,
right: PtExpression,

View File

@@ -377,6 +377,7 @@ internal class ProgramAndVarsGen(
dt.isSignedByte -> ".char"
dt.isUnsignedWord || dt.isPointer -> ".word"
dt.isSignedWord -> ".sint"
dt.isLong -> ".dint"
dt.isFloat -> ".byte"
else -> {
throw AssemblyError("weird dt")
@@ -418,14 +419,7 @@ internal class ProgramAndVarsGen(
structtype.fields.withIndex().forEach { (index, field) ->
val dt = field.first
val varname = "f${index}"
val type = when {
dt.isBool || dt.isUnsignedByte -> ".byte"
dt.isSignedByte -> ".char"
dt.isUnsignedWord || dt.isPointer -> ".word"
dt.isSignedWord -> ".sint"
dt.isFloat -> ".byte" // TODO check that float bytes are passed as an array parameter
else -> throw AssemblyError("weird dt")
}
val type = asmTypeString(dt)
asmgen.out("p8v_${field.second} $type \\$varname") // note: struct field symbol prefixing done here because that is a lot simpler than fixing up all expressions in the AST
}
asmgen.out(" .endstruct\n")
@@ -781,6 +775,7 @@ internal class ProgramAndVarsGen(
dt.isSignedByte -> asmgen.out("${variable.name}\t.char ?")
dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ?")
dt.isSignedWord -> asmgen.out("${variable.name}\t.sint ?")
dt.isLong -> asmgen.out("${variable.name}\t.dint ?")
dt.isFloat -> asmgen.out("${variable.name}\t.fill ${compTarget.FLOAT_MEM_SIZE}")
dt.isSplitWordArray -> {
alignVar(variable.align)
@@ -829,6 +824,7 @@ internal class ProgramAndVarsGen(
// dt.isSignedByte -> asmgen.out("${variable.name}\t.char $initialValue")
// dt.isUnsignedWord -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}")
// dt.isSignedWord -> asmgen.out("${variable.name}\t.sint $initialValue")
// dt.isLong -> asmgen.out("${variable.name}\t.dint $initialValue")
// dt.isFloat -> {
// if(initialValue==0) {
// asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float")

View File

@@ -222,6 +222,7 @@ internal class AssignmentAsmGen(
BaseDataType.BOOL -> assignConstantByte(assign.target, if(num==0.0) 0 else 1)
BaseDataType.UBYTE, BaseDataType.BYTE -> assignConstantByte(assign.target, num.toInt())
BaseDataType.UWORD, BaseDataType.WORD -> assignConstantWord(assign.target, num.toInt())
BaseDataType.LONG -> assignConstantLong(assign.target, num.toInt())
BaseDataType.FLOAT -> assignConstantFloat(assign.target, num)
BaseDataType.POINTER -> assignConstantWord(assign.target, num.toInt())
else -> throw AssemblyError("weird numval type")
@@ -244,6 +245,7 @@ internal class AssignmentAsmGen(
else
assignVariableWord(assign.target, variable, assign.source.datatype)
}
targetDt.isLong -> assignVariableLong(assign.target, variable, assign.source.datatype)
targetDt.isFloat -> assignVariableFloat(assign.target, variable)
targetDt.isString -> assignVariableString(assign.target, variable)
targetDt.isPointer -> assignVariableWord(assign.target, variable, assign.source.datatype)
@@ -536,7 +538,7 @@ internal class AssignmentAsmGen(
private fun assignPrefixExpr(assign: AsmAssignment, value: PtPrefix, scope: IPtSubroutine?) {
if(assign.target.array==null) {
if(assign.source.datatype isAssignableTo assign.target.datatype || (assign.source.datatype.isBool && assign.target.datatype.isByte)) {
if(assign.source.datatype.isIntegerOrBool) {
if(assign.source.datatype.isWordOrByteOrBool) {
val signed = assign.source.datatype.isSigned
if(assign.source.datatype.isByteOrBool) {
assignExpressionToRegister(value.value, RegisterOrPair.A, signed)
@@ -2417,8 +2419,8 @@ $endLabel""")
}
}
if(targetDt.isInteger && valueDt.isIntegerOrBool && valueDt.isAssignableTo(targetDt)) {
require(targetDt.isWord && valueDt.isByteOrBool) {
if(targetDt.isInteger && valueDt.isByteOrBool && valueDt.isAssignableTo(targetDt)) {
require(targetDt.isWord) {
"should be byte to word assignment ${origTypeCastExpression.position}"
}
when(target.kind) {
@@ -3003,6 +3005,28 @@ $endLabel""")
}
}
private fun assignVariableLong(target: AsmAssignTarget, varName: String, sourceDt: DataType) {
require(sourceDt.isLong)
when(target.kind) {
TargetStorageKind.VARIABLE -> {
asmgen.out("""
lda $varName
sta ${target.asmVarname}
lda $varName+1
sta ${target.asmVarname}+1
lda $varName+2
sta ${target.asmVarname}+2
lda $varName+3
sta ${target.asmVarname}+3""")
}
TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
private fun assignVariableWord(target: AsmAssignTarget, varName: String, sourceDt: DataType) {
if(sourceDt.isSignedByte) {
// need to sign extend
@@ -3929,6 +3953,49 @@ $endLabel""")
}
}
private fun assignConstantLong(target: AsmAssignTarget, long: Int) {
if(long==0 && asmgen.isTargetCpu(CpuType.CPU65C02)) {
// optimize setting zero value for this processor
when(target.kind) {
TargetStorageKind.VARIABLE -> {
asmgen.out("""
stz ${target.asmVarname}
stz ${target.asmVarname}+1
stz ${target.asmVarname}+2
stz ${target.asmVarname}+3""")
}
TargetStorageKind.ARRAY -> TODO("assign long zero to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
return
}
when(target.kind) {
TargetStorageKind.VARIABLE -> {
fun store(hexbyte: String, offset: Int) {
if(asmgen.isTargetCpu(CpuType.CPU65C02) && hexbyte=="00") {
asmgen.out(" stz ${target.asmVarname}+$offset")
} else {
asmgen.out(" lda #$$hexbyte | sta ${target.asmVarname}+$offset")
}
}
val hex = long.toUInt().toString(16).padStart(8, '0')
store(hex.substring(6,8), 0)
store(hex.substring(4,6), 1)
store(hex.substring(2,4), 2)
store(hex.substring(0,2), 3)
}
TargetStorageKind.ARRAY -> TODO("assign long $long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
private fun assignConstantWord(target: AsmAssignTarget, word: Int) {
if(word==0 && asmgen.isTargetCpu(CpuType.CPU65C02)) {
// optimize setting zero value for this processor
@@ -4627,6 +4694,31 @@ $endLabel""")
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
datatype.isLong -> {
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
lda #0
sbc ${target.asmVarname}+2
sta ${target.asmVarname}+2
lda #0
sbc ${target.asmVarname}+3
sta ${target.asmVarname}+3""")
}
TargetStorageKind.ARRAY -> TODO(" - long array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
datatype.isFloat -> {
when (target.kind) {
TargetStorageKind.REGISTER -> {

View File

@@ -106,6 +106,17 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
}
}
}
target.datatype.isLong -> {
when(value.kind) {
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationLongWithLiteralval(target.asmVarname, operator, value.boolean!!.asInt())
SourceStorageKind.LITERALNUMBER -> inplacemodificationLongWithLiteralval(target.asmVarname, operator, value.number!!.number.toInt())
SourceStorageKind.VARIABLE -> inplacemodificationLongWithVariable(target.asmVarname, operator, value.asmVarname)
SourceStorageKind.EXPRESSION -> TODO("inplace modify long with expression ${target.position}")
SourceStorageKind.REGISTER -> TODO("32 bits register inplace modification? ${target.position}")
SourceStorageKind.ARRAY -> TODO("inplace modify long with array ${target.position}")
SourceStorageKind.MEMORY -> TODO("memread into long ${target.position}")
}
}
target.datatype.isFloat -> {
when(value.kind) {
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.boolean!!.asInt().toDouble())
@@ -523,6 +534,132 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
}
}
private fun inplacemodificationLongWithVariable(targetVar: String, operator: String, sourceVar: String) {
when(operator) {
"+" -> {
asmgen.out("""
clc
lda $targetVar
adc $sourceVar
sta $targetVar
lda $targetVar+1
adc $sourceVar+1
sta $targetVar+1
lda $targetVar+2
adc $sourceVar+2
sta $targetVar+2
lda $targetVar+3
adc $sourceVar+3
sta $targetVar+3""")
}
"-" -> {
asmgen.out("""
sec
lda $targetVar
sbc $sourceVar
sta $targetVar
lda $targetVar+1
sbc $sourceVar+1
sta $targetVar+1
lda $targetVar+2
sbc $sourceVar+2
sta $targetVar+2
lda $targetVar+3
sbc $sourceVar+3
sta $targetVar+3""")
}
else -> {
TODO("Not yet implemented")
}
}
}
private fun inplacemodificationLongWithLiteralval(variable: String, operator: String, value: Int) {
when(operator) {
"+" -> {
when(value) {
0 -> {}
1 -> {
asmgen.out("""
inc $variable
bne +
inc $variable+1
bne +
inc $variable+2
bne +
inc $variable+3
+""")
}
else -> {
if(value in 1..255) {
TODO("optimized inplace long += $value")
} else if(value in 1..65535) {
TODO("optimized inplace long += $value")
} else {
val hex = value.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
clc
lda $variable
adc #$${hex.substring(6,8)}
sta $variable
lda $variable+1
adc #$${hex.substring(4, 6)}
sta $variable+1
lda $variable+2
adc #$${hex.substring(2, 4)}
sta $variable+2
lda $variable+3
adc #$${hex.take(2)}
sta $variable+3""")
}
}
}
}
"-" -> {
when(value) {
0 -> {}
1 -> {
asmgen.out("""
lda $variable
bne +
dec $variable+1
bne +
dec $variable+2
bne +
dec $variable+3
+ dec $variable""")
}
else -> {
if(value in 1..255) {
TODO("optimized inplace long += $value")
} else if(value in 1..65535) {
TODO("optimized inplace long += $value")
} else {
val hex = value.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
sec
lda $variable
sbc #$${hex.substring(6,8)}
sta $variable
lda $variable+1
sbc #$${hex.substring(4, 6)}
sta $variable+1
lda $variable+2
sbc #$${hex.substring(2, 4)}
sta $variable+2
lda $variable+3
sbc #$${hex.take(2)}
sta $variable+3""")
}
}
}
}
else -> {
TODO("inplace long $operator $value")
}
}
}
private fun tryIndexedIncDec(array: PtArrayIndexer, operator: String): Boolean {
val arrayVar = array.variable
if(arrayVar==null) {

View File

@@ -12,12 +12,14 @@ internal object DummyMemsizer : IMemSizer {
return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD -> numElements*2
BaseDataType.LONG -> numElements*4
BaseDataType.FLOAT -> numElements*5
else -> throw IllegalArgumentException("invalid sub type")
}
}
return when {
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isLong -> 4 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}

View File

@@ -446,7 +446,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
else (it as PtNumber).number.toInt()
}
when {
elementDt.isIntegerOrBool -> {
elementDt.isWordOrByteOrBool -> {
if (elementDt.isByteOrBool) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE)
if (elementDt.isWord) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD)
val gottemLabel = codeGen.createLabelName()

View File

@@ -10,12 +10,14 @@ internal object DummyMemsizer : IMemSizer {
return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD -> numElements*2
BaseDataType.LONG -> numElements*4
BaseDataType.FLOAT -> numElements*5
else -> throw IllegalArgumentException("invalid sub type")
}
}
return when {
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isLong -> 4 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}

View File

@@ -228,22 +228,85 @@ asmsub str_w (word value @ AY) clobbers(X) -> str @AY {
}}
}
asmsub str_l (uword msw @ R0, uword lsw @ R1) clobbers(X) -> str @AY {
; ---- convert the long in R0:R1 into decimal string form, without left padding 0s
%asm {{
lda #'?'
sta string_out
lda #'?'
sta string_out+1
lda #0
sta string_out+2
; TODO implement this!
sta string_out
lda #<string_out
ldy #>string_out
rts
}}
}
sub str_l (long value) -> str {
; ---- convert the long value into decimal string form, without left padding 0s
; source: https://codebase64.net/doku.php?id=base:32_bit_hexadecimal_to_decimal_conversion
bool negative
if value<0 {
negative = true
value = -value
}
%asm {{
jsr hex2dec
ldx #0
- lda result,x
bne +
inx ; skip leading zeros
cpx #9
bne -
; convert to petscii numbers and return ptr to first nonzero
+ stx P8ZP_SCRATCH_B1
inc P8ZP_SCRATCH_B1
- lda result,x
ora #$30
sta result,x
inx
cpx #10
bne -
lda #0
sta result,x
; sign needed?
lda negative
beq +
dec P8ZP_SCRATCH_B1
ldx P8ZP_SCRATCH_B1
lda #'-'
sta result_sign,x
+ lda #<result_sign
ldy #>result_sign
clc
adc P8ZP_SCRATCH_B1
bcc +
iny
+ rts
; converts 10 digits (32 bit values have max. 10 decimal digits)
hex2dec
ldx #9
l3 jsr div10
sta result,x
dex
bpl l3
rts
; divides a 32 bit value by 10
; remainder is returned in akku
div10
ldy #32 ; 32 bits
lda #0
clc
l4 rol
cmp #10
bcc skip
sbc #10
skip rol value
rol value+1
rol value+2
rol value+3
dey
bpl l4
rts
.section BSS
result_sign .byte ? ; room for the '-' sign
result .fill 10
.byte ? ; string 0 terminator
.send
}}
}
; ---- string conversion to numbers -----

View File

@@ -165,9 +165,9 @@ _allzero lda #'0'
}}
}
sub print_l (long value) {
; ---- print the (signed) long in decimal form, without left padding 0's
print(conv.str_l(msw(value), lsw(value)))
sub print_l(long value) {
; prints a 32 bit value to the screen
print(conv.str_l(value))
}
asmsub input_chars (^^ubyte buffer @ AY) clobbers(A) -> ubyte @ Y {

View File

@@ -269,7 +269,7 @@ class AstPreprocessor(val program: Program,
.filter { it.name !in namesInSub && it.name !in existingAliases }
.forEach {
if (it.registerOrPair in Cx16VirtualRegisters) {
if(it.type.isIntegerOrBool) {
if(it.type.isWordOrByteOrBool) {
val mappedParamVar = VarDecl.fromParameter(it)
mods += IAstModification.InsertFirst(mappedParamVar, subroutine)
} else {

View File

@@ -28,12 +28,14 @@ internal object DummyMemsizer : IMemSizer {
return when(dt.sub) {
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements
BaseDataType.UWORD, BaseDataType.WORD -> numElements*2
BaseDataType.LONG -> numElements*4
BaseDataType.FLOAT -> numElements*5
else -> throw IllegalArgumentException("invalid sub type")
}
}
return when {
dt.isByteOrBool -> 1 * (numElements ?: 1)
dt.isLong -> 4 * (numElements ?: 1)
dt.isFloat -> 5 * (numElements ?: 1)
else -> 2 * (numElements ?: 1)
}

View File

@@ -1,39 +1,76 @@
%import textio
%zeropage basicsafe
main {
long bignum = 12345678
long bignum2 = -999999
struct Node {
ubyte id
str name
long array
bool flag
long counter
}
; struct Node {
; ubyte id
; str name
; long array
; bool flag
; long counter
; }
sub start() {
^^Node test = []
bignum++
bignum2--
txt.print_l(bignum)
txt.print_l(-1999888777)
txt.spc()
txt.print_l(-999)
txt.spc()
txt.print_l(-42)
txt.spc()
txt.print_l(0)
txt.spc()
txt.print_l(bignum)
txt.nl()
txt.print_l(bignum2)
txt.nl()
txt.print_l(-bignum2)
txt.nl()
bignum2 = -bignum2
bignum2++
bignum2++
txt.print_l(bignum2)
txt.nl()
bignum2--
bignum2--
txt.print_l(bignum2)
txt.spc()
txt.print_l(bignum)
txt.nl()
txt.nl()
bignum2 += bignum
txt.print_l(bignum2)
txt.nl()
bignum2 -= bignum
txt.print_l(bignum2)
txt.nl()
str output = "...................."
txt.print(conv.str_l(bignum))
txt.nl()
; ^^Node test = []
;
; bignum++
; bignum2--
bignum = 999999
bignum-- ; TODO this works in the current VM...
bignum = -888888
test.counter = 0
test.counter ++ ; TODO ... why doesn't this? (requires plusMinusMultAnyLong routine)
test.counter = bignum2
test.counter --
; txt.print_l(bignum)
; txt.spc()
; txt.print_l(bignum2)
; txt.nl()
;
; str output = "...................."
; txt.print_l(bignum)
; txt.spc()
; txt.print(conv.str_l(bignum))
; txt.nl()
;
; bignum = 999999
; bignum-- ; TODO this works in the current VM...
; bignum = -888888
;
; test.counter = 0
; test.counter ++ ; TODO ... why doesn't this? (requires plusMinusMultAnyLong routine)
; test.counter = bignum2
; test.counter --
}
}

View File

@@ -41,7 +41,7 @@ sealed interface IPtSubroutine {
val others = returns.drop(1).map { type ->
when {
type.isFloat -> RegisterOrStatusflag(availableFloatRegisters.removeLastOrNull()!!, null) to type
type.isIntegerOrBool -> RegisterOrStatusflag(availableIntegerRegisters.removeLastOrNull()!!, null) to type
type.isWordOrByteOrBool -> RegisterOrStatusflag(availableIntegerRegisters.removeLastOrNull()!!, null) to type
else -> throw AssemblyError("unsupported return type $type")
}
}

View File

@@ -2942,7 +2942,17 @@ class VirtualMachine(irProgram: IRProgram) {
}
private fun plusMinusMultAnyLongInplace(operator: String, reg1: Int, address: Int) {
TODO("Not yet implemented")
val memvalue = memory.getSL(address)
val operand = registers.getSL(reg1)
val result: Int
when(operator) {
"+" -> result = memvalue + operand
"-" -> result = memvalue - operand
"*" -> result = memvalue * operand
else -> throw IllegalArgumentException("operator word $operator")
}
memory.setSL(address, result)
}
private fun plusMinusMultAnyLongSigned(operator: String, reg1: Int, reg2: Int) {