mirror of
https://github.com/irmen/prog8.git
synced 2025-11-03 04:17:16 +00:00
work on longs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 -----
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 --
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user