mirror of
https://github.com/irmen/prog8.git
synced 2026-03-11 05:41:42 +00:00
changed the data type system to composite types
This commit is contained in:
@@ -208,25 +208,25 @@ class StStaticVariable(name: String,
|
||||
require(initializationArrayValue.isEmpty() ||initializationArrayValue.size==length)
|
||||
}
|
||||
if(initializationNumericValue!=null) {
|
||||
require(dt in NumericDatatypes || dt==DataType.BOOL)
|
||||
require(dt.isNumericOrBool)
|
||||
}
|
||||
if(initializationArrayValue!=null) {
|
||||
require(dt in ArrayDatatypes)
|
||||
require(length==initializationArrayValue.size)
|
||||
require(dt.isArray)
|
||||
require(length == initializationArrayValue.size)
|
||||
}
|
||||
if(initializationStringValue!=null) {
|
||||
require(dt == DataType.STR)
|
||||
require(length == initializationStringValue.first.length+1)
|
||||
require(dt.isString)
|
||||
require(length == initializationStringValue.first.length + 1)
|
||||
}
|
||||
if(align > 0) {
|
||||
require(dt == DataType.STR || dt in ArrayDatatypes)
|
||||
require(dt.isString || dt.isArray)
|
||||
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode) :
|
||||
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) :
|
||||
StNode(name, StNodeType.CONSTANT, astNode)
|
||||
|
||||
|
||||
@@ -238,8 +238,8 @@ class StMemVar(name: String,
|
||||
StNode(name, StNodeType.MEMVAR, astNode) {
|
||||
|
||||
init{
|
||||
require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
|
||||
if(dt in ArrayDatatypes || dt == DataType.STR)
|
||||
require(!dt.isBool && !dt.isBoolArray)
|
||||
if(dt.isStringly && !dt.isWord)
|
||||
requireNotNull(length)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
val st = SymbolTable(program)
|
||||
|
||||
BuiltinFunctions.forEach {
|
||||
st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, it.value.returnType ?: DataType.UNDEFINED, Position.DUMMY)))
|
||||
val dt = DataType.forDt(it.value.returnType ?: BaseDataType.UNDEFINED)
|
||||
st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, dt, Position.DUMMY)))
|
||||
}
|
||||
|
||||
val scopestack = ArrayDeque<StNode>()
|
||||
@@ -22,10 +23,10 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
|
||||
if(options.compTarget.name != VMTarget.NAME) {
|
||||
listOf(
|
||||
PtMemMapped("P8ZP_SCRATCH_B1", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||
).forEach {
|
||||
it.parent = program
|
||||
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
||||
@@ -46,7 +47,8 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
StNode(node.name, StNodeType.BLOCK, node)
|
||||
}
|
||||
is PtConstant -> {
|
||||
StConstant(node.name, node.type, node.value, node)
|
||||
require(node.type.isNumericOrBool)
|
||||
StConstant(node.name, node.type.base, node.value, node)
|
||||
}
|
||||
is PtLabel -> {
|
||||
StNode(node.name, StNodeType.LABEL, node)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.*
|
||||
import java.util.Objects
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.truncate
|
||||
|
||||
@@ -9,7 +9,7 @@ import kotlin.math.truncate
|
||||
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
||||
|
||||
init {
|
||||
if(type==DataType.UNDEFINED) {
|
||||
if(type.isUndefined) {
|
||||
@Suppress("LeakingThis")
|
||||
when(this) {
|
||||
is PtBuiltinFunctionCall -> { /* void function call */ }
|
||||
@@ -66,19 +66,17 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
||||
}
|
||||
}
|
||||
|
||||
infix fun isSameAs(target: PtAssignTarget): Boolean {
|
||||
return when {
|
||||
target.memory != null && this is PtMemoryByte-> {
|
||||
target.memory!!.address isSameAs this.address
|
||||
}
|
||||
target.identifier != null && this is PtIdentifier -> {
|
||||
this.name == target.identifier!!.name
|
||||
}
|
||||
target.array != null && this is PtArrayIndexer -> {
|
||||
this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords
|
||||
}
|
||||
else -> false
|
||||
infix fun isSameAs(target: PtAssignTarget): Boolean = when {
|
||||
target.memory != null && this is PtMemoryByte -> {
|
||||
target.memory!!.address isSameAs this.address
|
||||
}
|
||||
target.identifier != null && this is PtIdentifier -> {
|
||||
this.name == target.identifier!!.name
|
||||
}
|
||||
target.array != null && this is PtArrayIndexer -> {
|
||||
this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt()
|
||||
@@ -139,7 +137,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
||||
*/
|
||||
}
|
||||
|
||||
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
||||
class PtAddressOf(position: Position) : PtExpression(DataType.forDt(BaseDataType.UWORD), position) {
|
||||
val identifier: PtIdentifier
|
||||
get() = children[0] as PtIdentifier
|
||||
val arrayIndexExpr: PtExpression?
|
||||
@@ -156,10 +154,10 @@ class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(el
|
||||
val index: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
val splitWords: Boolean
|
||||
get() = variable.type in SplitWordArrayTypes
|
||||
get() = variable.type.isSplitWordArray
|
||||
|
||||
init {
|
||||
require(elementType in NumericDatatypesWithBoolean)
|
||||
require(elementType.isNumericOrBool)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +183,7 @@ class PtBuiltinFunctionCall(val name: String,
|
||||
position: Position) : PtExpression(type, position) {
|
||||
init {
|
||||
if(!void)
|
||||
require(type!=DataType.UNDEFINED)
|
||||
require(!type.isUndefined)
|
||||
}
|
||||
|
||||
val args: List<PtExpression>
|
||||
@@ -201,9 +199,9 @@ class PtBinaryExpression(val operator: String, type: DataType, position: Positio
|
||||
|
||||
init {
|
||||
if(operator in ComparisonOperators + LogicalOperators)
|
||||
require(type==DataType.BOOL)
|
||||
require(type.isBool)
|
||||
else
|
||||
require(type!=DataType.BOOL) { "no bool allowed for this operator $operator"}
|
||||
require(!type.isBool) { "no bool allowed for this operator $operator"}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +216,7 @@ class PtIfExpression(type: DataType, position: Position): PtExpression(type, pos
|
||||
}
|
||||
|
||||
|
||||
class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) {
|
||||
class PtContainmentCheck(position: Position): PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||
val needle: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val haystackHeapVar: PtIdentifier?
|
||||
@@ -241,7 +239,7 @@ class PtFunctionCall(val name: String,
|
||||
get() = children.map { it as PtExpression }
|
||||
|
||||
init {
|
||||
if(void) require(type==DataType.UNDEFINED) {
|
||||
if(void) require(type.isUndefined) {
|
||||
"void fcall should have undefined datatype"
|
||||
}
|
||||
// note: non-void calls can have UNDEFINED type: is if they return more than 1 value
|
||||
@@ -258,13 +256,13 @@ class PtIdentifier(val name: String, type: DataType, position: Position) : PtExp
|
||||
}
|
||||
|
||||
|
||||
class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) {
|
||||
class PtMemoryByte(position: Position) : PtExpression(DataType.forDt(BaseDataType.UBYTE), position) {
|
||||
val address: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
|
||||
class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOOL, position) {
|
||||
class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||
override fun hashCode(): Int = Objects.hash(type, value)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -279,28 +277,28 @@ class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOO
|
||||
}
|
||||
|
||||
|
||||
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
|
||||
class PtNumber(type: BaseDataType, val number: Double, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||
|
||||
companion object {
|
||||
fun fromBoolean(bool: Boolean, position: Position): PtNumber =
|
||||
PtNumber(DataType.UBYTE, if(bool) 1.0 else 0.0, position)
|
||||
PtNumber(BaseDataType.UBYTE, if(bool) 1.0 else 0.0, position)
|
||||
}
|
||||
|
||||
init {
|
||||
if(type==DataType.BOOL)
|
||||
if(type==BaseDataType.BOOL)
|
||||
throw IllegalArgumentException("use PtBool instead")
|
||||
if(type!=DataType.FLOAT) {
|
||||
if(type!=BaseDataType.FLOAT) {
|
||||
val trunc = truncate(number)
|
||||
if (trunc != number)
|
||||
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
|
||||
}
|
||||
when(type) {
|
||||
DataType.UBYTE -> require(number in 0.0..255.0)
|
||||
DataType.BYTE -> require(number in -128.0..127.0)
|
||||
DataType.UWORD -> require(number in 0.0..65535.0)
|
||||
DataType.WORD -> require(number in -32728.0..32767.0)
|
||||
DataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
else -> {}
|
||||
BaseDataType.UBYTE -> require(number in 0.0..255.0)
|
||||
BaseDataType.BYTE -> require(number in -128.0..127.0)
|
||||
BaseDataType.UWORD -> require(number in 0.0..65535.0)
|
||||
BaseDataType.WORD -> require(number in -32728.0..32767.0)
|
||||
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
else -> require(type.isNumeric) { "numeric literal type should be numeric: $type" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +307,7 @@ class PtNumber(type: DataType, val number: Double, position: Position) : PtExpre
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if(other==null || other !is PtNumber)
|
||||
false
|
||||
else if(type!=DataType.BOOL && other.type!=DataType.BOOL)
|
||||
else if(!type.isBool && !other.type.isBool)
|
||||
number==other.number
|
||||
else
|
||||
type==other.type && number==other.number
|
||||
@@ -368,7 +366,7 @@ class PtRange(type: DataType, position: Position) : PtExpression(type, position)
|
||||
}
|
||||
|
||||
|
||||
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.STR, position) {
|
||||
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.forDt(BaseDataType.STR), position) {
|
||||
override fun hashCode(): Int = Objects.hash(value, encoding)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if(other==null || other !is PtString)
|
||||
@@ -378,7 +376,7 @@ class PtString(val value: String, val encoding: Encoding, position: Position) :
|
||||
}
|
||||
|
||||
|
||||
class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
|
||||
class PtTypeCast(type: BaseDataType, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||
val value: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.escape
|
||||
import prog8.code.core.toHex
|
||||
|
||||
/**
|
||||
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
||||
* passing it as a String to the specified receiver function.
|
||||
*/
|
||||
fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
|
||||
fun type(dt: DataType) = "!${dt.name.lowercase()}!"
|
||||
fun type(dt: DataType) = "!${dt}!"
|
||||
fun txt(node: PtNode): String {
|
||||
return when(node) {
|
||||
is PtAlign -> "%align ${node.align}"
|
||||
@@ -48,14 +50,14 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
is PtIrRegister -> "IRREG#${node.register} ${type(node.type)}"
|
||||
is PtMemoryByte -> "@()"
|
||||
is PtNumber -> {
|
||||
val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex()
|
||||
val numstr = if(node.type.isFloat) node.number.toString() else node.number.toHex()
|
||||
"$numstr ${type(node.type)}"
|
||||
}
|
||||
is PtBool -> node.value.toString()
|
||||
is PtPrefix -> node.operator
|
||||
is PtRange -> "<range>"
|
||||
is PtString -> "\"${node.value.escape()}\""
|
||||
is PtTypeCast -> "as ${node.type.name.lowercase()}"
|
||||
is PtTypeCast -> "as ${node.type}"
|
||||
is PtForLoop -> "for"
|
||||
is PtIfElse -> "ifelse"
|
||||
is PtIncludeBinary -> "%incbin '${node.file}', ${node.offset}, ${node.length}"
|
||||
@@ -103,21 +105,20 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
"\nblock '${node.name}' $addr"
|
||||
}
|
||||
is PtConstant -> {
|
||||
val value = when(node.type) {
|
||||
DataType.BOOL -> if(node.value==0.0) "false" else "true"
|
||||
in IntegerDatatypes -> node.value.toInt().toString()
|
||||
val value = when {
|
||||
node.type.isBool -> if(node.value==0.0) "false" else "true"
|
||||
node.type.isInteger -> node.value.toInt().toString()
|
||||
else -> node.value.toString()
|
||||
}
|
||||
"const ${node.type.name.lowercase()} ${node.name} = $value"
|
||||
"const ${node.type} ${node.name} = $value"
|
||||
}
|
||||
is PtLabel -> "${node.name}:"
|
||||
is PtMemMapped -> {
|
||||
if(node.type in ArrayDatatypes) {
|
||||
if(node.type.isArray) {
|
||||
val arraysize = if(node.arraySize==null) "" else node.arraySize.toString()
|
||||
val eltType = ArrayToElementTypes.getValue(node.type)
|
||||
"&${eltType.name.lowercase()}[$arraysize] ${node.name} = ${node.address.toHex()}"
|
||||
"&${node.type.elementType()}[$arraysize] ${node.name} = ${node.address.toHex()}"
|
||||
} else {
|
||||
"&${node.type.name.lowercase()} ${node.name} = ${node.address.toHex()}"
|
||||
"&${node.type} ${node.name} = ${node.address.toHex()}"
|
||||
}
|
||||
}
|
||||
is PtSub -> {
|
||||
@@ -127,11 +128,11 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
}
|
||||
var str = "sub ${node.name}($params) "
|
||||
if(node.returntype!=null)
|
||||
str += "-> ${node.returntype.name.lowercase()}"
|
||||
str += "-> ${node.returntype}"
|
||||
str
|
||||
}
|
||||
is PtVariable -> {
|
||||
val split = if(node.type in SplitWordArrayTypes) "@split" else ""
|
||||
val split = if(node.type.isSplitWordArray) "@split" else ""
|
||||
val align = when(node.align) {
|
||||
0u -> ""
|
||||
2u -> "@alignword"
|
||||
@@ -140,15 +141,15 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
else -> throw IllegalArgumentException("invalid alignment size")
|
||||
}
|
||||
val str = if(node.arraySize!=null) {
|
||||
val eltType = ArrayToElementTypes.getValue(node.type)
|
||||
"${eltType.name.lowercase()}[${node.arraySize}] $split $align ${node.name}"
|
||||
val eltType = node.type.elementType()
|
||||
"${eltType}[${node.arraySize}] $split $align ${node.name}"
|
||||
}
|
||||
else if(node.type in ArrayDatatypes) {
|
||||
val eltType = ArrayToElementTypes.getValue(node.type)
|
||||
"${eltType.name.lowercase()}[] $split $align ${node.name}"
|
||||
else if(node.type.isArray) {
|
||||
val eltType = node.type.elementType()
|
||||
"${eltType}[] $split $align ${node.name}"
|
||||
}
|
||||
else
|
||||
"${node.type.name.lowercase()} ${node.name}"
|
||||
"${node.type} ${node.name}"
|
||||
if(node.value!=null)
|
||||
str + " = " + txt(node.value)
|
||||
else
|
||||
@@ -161,7 +162,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
is PtReturn -> "return"
|
||||
is PtSubroutineParameter -> {
|
||||
val reg = if(node.register!=null) "@${node.register}" else ""
|
||||
"${node.type.name.lowercase()} ${node.name} $reg"
|
||||
"${node.type} ${node.name} $reg"
|
||||
}
|
||||
is PtWhen -> "when"
|
||||
is PtWhenChoice -> {
|
||||
|
||||
@@ -30,9 +30,9 @@ class PtSub(
|
||||
) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer {
|
||||
init {
|
||||
// params and return value should not be str
|
||||
if(parameters.any{ it.type !in NumericDatatypes && it.type!=DataType.BOOL })
|
||||
if(parameters.any{ !it.type.isNumericOrBool })
|
||||
throw AssemblyError("non-numeric/non-bool parameter")
|
||||
if(returntype!=null && returntype !in NumericDatatypes && returntype!=DataType.BOOL)
|
||||
if(returntype!=null && !returntype.isNumericOrBool)
|
||||
throw AssemblyError("non-numeric/non-bool returntype $returntype")
|
||||
parameters.forEach { it.parent=this }
|
||||
}
|
||||
@@ -172,7 +172,7 @@ class PtConstant(name: String, override val type: DataType, val value: Double, p
|
||||
|
||||
class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
|
||||
init {
|
||||
require(type!=DataType.BOOL && type!=DataType.ARRAY_BOOL)
|
||||
require(!type.isBool && !type.isBoolArray)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package prog8.code.core
|
||||
|
||||
class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?)
|
||||
class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean)
|
||||
class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?)
|
||||
class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean)
|
||||
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
|
||||
override fun toString(): String {
|
||||
val paramConvs = params.mapIndexed { index, it ->
|
||||
@@ -21,26 +21,34 @@ class CallConvention(val params: List<ParamConvention>, val returns: ReturnConve
|
||||
}
|
||||
}
|
||||
|
||||
class FParam(val name: String, vararg val possibleDatatypes: DataType)
|
||||
class FParam(val name: String, vararg val possibleDatatypes: BaseDataType)
|
||||
|
||||
|
||||
private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
|
||||
private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
private val ByteDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
|
||||
private val ArrayDatatypes = arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
|
||||
|
||||
class FSignature(val pure: Boolean, // does it have side effects?
|
||||
val returnType: DataType?,
|
||||
val returnType: BaseDataType?,
|
||||
vararg val parameters: FParam) {
|
||||
|
||||
fun callConvention(actualParamTypes: List<DataType>): CallConvention {
|
||||
fun callConvention(actualParamTypes: List<BaseDataType>): CallConvention {
|
||||
val returns: ReturnConvention = when (returnType) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
|
||||
DataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
|
||||
BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
|
||||
in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
|
||||
null -> ReturnConvention(null, null)
|
||||
else -> {
|
||||
// return type depends on arg type
|
||||
when (val paramType = actualParamTypes.first()) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
DataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
|
||||
in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
else -> ReturnConvention(paramType, null)
|
||||
}
|
||||
}
|
||||
@@ -53,21 +61,21 @@ class FSignature(val pure: Boolean, // does it have side effects?
|
||||
// this avoids repeated code for every caller to store the value in the subroutine's argument variable.
|
||||
// (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
|
||||
val paramConv = when(val paramType = actualParamTypes[0]) {
|
||||
DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
|
||||
in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
|
||||
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
else -> ParamConvention(paramType, null, false)
|
||||
}
|
||||
CallConvention(listOf(paramConv), returns)
|
||||
}
|
||||
actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1] in WordDatatypes) -> {
|
||||
actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1].isWord) -> {
|
||||
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
actualParamTypes.size==2 && (actualParamTypes[0] in WordDatatypes && actualParamTypes[1] in ByteDatatypes) -> {
|
||||
actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> {
|
||||
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
actualParamTypes.size==3 && actualParamTypes.all { it in ByteDatatypes } -> {
|
||||
actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> {
|
||||
TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
else -> {
|
||||
@@ -80,65 +88,65 @@ class FSignature(val pure: Boolean, // does it have side effects?
|
||||
}
|
||||
|
||||
val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||
"setlsb" to FSignature(false, null, FParam("variable", DataType.WORD, DataType.UWORD), FParam("value", DataType.BYTE, DataType.UBYTE)),
|
||||
"setmsb" to FSignature(false, null, FParam("variable", DataType.WORD, DataType.UWORD), FParam("value", DataType.BYTE, DataType.UBYTE)),
|
||||
"rol" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)),
|
||||
"ror" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)),
|
||||
"rol2" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)),
|
||||
"ror2" to FSignature(false, null, FParam("item", DataType.UBYTE, DataType.UWORD)),
|
||||
"setlsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"setmsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"rol" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"ror" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"rol2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"ror2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns a status in the carry flag, but not a proper return value
|
||||
"prog8_lib_stringcompare" to FSignature(true, DataType.BYTE, FParam("str1", DataType.STR), FParam("str2", DataType.STR)),
|
||||
"prog8_lib_square_byte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.BYTE, DataType.UBYTE)),
|
||||
"prog8_lib_square_word" to FSignature(true, DataType.UWORD, FParam("value", DataType.WORD, DataType.UWORD)),
|
||||
"prog8_ifelse_bittest_set" to FSignature(true, DataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", DataType.UBYTE)),
|
||||
"prog8_ifelse_bittest_notset" to FSignature(true, DataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", DataType.UBYTE)),
|
||||
"prog8_lib_stringcompare" to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
|
||||
"prog8_lib_square_byte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"prog8_lib_square_word" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
|
||||
"prog8_ifelse_bittest_set" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||
"prog8_ifelse_bittest_notset" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||
"abs" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||
"abs__byte" to FSignature(true, DataType.BYTE, FParam("value", DataType.BYTE)),
|
||||
"abs__word" to FSignature(true, DataType.WORD, FParam("value", DataType.WORD)),
|
||||
"abs__float" to FSignature(true, DataType.FLOAT, FParam("value", DataType.FLOAT)),
|
||||
"len" to FSignature(true, DataType.UWORD, FParam("values", *IterableDatatypes)),
|
||||
"sizeof" to FSignature(true, DataType.UBYTE, FParam("object", *DataType.entries.toTypedArray())),
|
||||
"sgn" to FSignature(true, DataType.BYTE, FParam("value", *NumericDatatypes)),
|
||||
"abs__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE)),
|
||||
"abs__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD)),
|
||||
"abs__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||
"len" to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)),
|
||||
"sizeof" to FSignature(true, BaseDataType.UBYTE, FParam("object", *BaseDataType.entries.toTypedArray())),
|
||||
"sgn" to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)),
|
||||
"sqrt" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||
"sqrt__ubyte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UBYTE)),
|
||||
"sqrt__uword" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD)),
|
||||
"sqrt__float" to FSignature(true, DataType.FLOAT, FParam("value", DataType.FLOAT)),
|
||||
"divmod" to FSignature(false, null, FParam("dividend", DataType.UBYTE, DataType.UWORD), FParam("divisor", DataType.UBYTE, DataType.UWORD), FParam("quotient", DataType.UBYTE, DataType.UWORD), FParam("remainder", DataType.UBYTE, DataType.UWORD)),
|
||||
"divmod__ubyte" to FSignature(false, null, FParam("dividend", DataType.UBYTE), FParam("divisor", DataType.UBYTE), FParam("quotient", DataType.UBYTE), FParam("remainder", DataType.UBYTE)),
|
||||
"divmod__uword" to FSignature(false, null, FParam("dividend", DataType.UWORD), FParam("divisor", DataType.UWORD), FParam("quotient", DataType.UWORD), FParam("remainder", DataType.UWORD)),
|
||||
"lsb" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)),
|
||||
"lsw" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)),
|
||||
"msb" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)),
|
||||
"msw" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD, DataType.WORD, DataType.LONG)),
|
||||
"mkword" to FSignature(true, DataType.UWORD, FParam("msb", DataType.UBYTE), FParam("lsb", DataType.UBYTE)),
|
||||
"clamp" to FSignature(true, null, FParam("value", DataType.BYTE), FParam("minimum", DataType.BYTE), FParam("maximum", DataType.BYTE)),
|
||||
"clamp__byte" to FSignature(true, DataType.BYTE, FParam("value", DataType.BYTE), FParam("minimum", DataType.BYTE), FParam("maximum", DataType.BYTE)),
|
||||
"clamp__ubyte" to FSignature(true, DataType.UBYTE, FParam("value", DataType.UBYTE), FParam("minimum", DataType.UBYTE), FParam("maximum", DataType.UBYTE)),
|
||||
"clamp__word" to FSignature(true, DataType.WORD, FParam("value", DataType.WORD), FParam("minimum", DataType.WORD), FParam("maximum", DataType.WORD)),
|
||||
"clamp__uword" to FSignature(true, DataType.UWORD, FParam("value", DataType.UWORD), FParam("minimum", DataType.UWORD), FParam("maximum", DataType.UWORD)),
|
||||
"min" to FSignature(true, null, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)),
|
||||
"min__byte" to FSignature(true, DataType.BYTE, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)),
|
||||
"min__ubyte" to FSignature(true, DataType.UBYTE, FParam("val1", DataType.UBYTE), FParam("val2", DataType.UBYTE)),
|
||||
"min__word" to FSignature(true, DataType.WORD, FParam("val1", DataType.WORD), FParam("val2", DataType.WORD)),
|
||||
"min__uword" to FSignature(true, DataType.UWORD, FParam("val1", DataType.UWORD), FParam("val2", DataType.UWORD)),
|
||||
"max" to FSignature(true, null, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)),
|
||||
"max__byte" to FSignature(true, DataType.BYTE, FParam("val1", DataType.BYTE), FParam("val2", DataType.BYTE)),
|
||||
"max__ubyte" to FSignature(true, DataType.UBYTE, FParam("val1", DataType.UBYTE), FParam("val2", DataType.UBYTE)),
|
||||
"max__word" to FSignature(true, DataType.WORD, FParam("val1", DataType.WORD), FParam("val2", DataType.WORD)),
|
||||
"max__uword" to FSignature(true, DataType.UWORD, FParam("val1", DataType.UWORD), FParam("val2", DataType.UWORD)),
|
||||
"peek" to FSignature(true, DataType.UBYTE, FParam("address", DataType.UWORD)),
|
||||
"peekw" to FSignature(true, DataType.UWORD, FParam("address", DataType.UWORD)),
|
||||
"peekf" to FSignature(true, DataType.FLOAT, FParam("address", DataType.UWORD)),
|
||||
"poke" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.UBYTE)),
|
||||
"pokew" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.UWORD)),
|
||||
"pokef" to FSignature(false, null, FParam("address", DataType.UWORD), FParam("value", DataType.FLOAT)),
|
||||
"pokemon" to FSignature(false, DataType.UBYTE, FParam("address", DataType.UWORD), FParam("value", DataType.UBYTE)),
|
||||
"sqrt__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)),
|
||||
"sqrt__uword" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD)),
|
||||
"sqrt__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||
"divmod" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("quotient", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("remainder", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)),
|
||||
"divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)),
|
||||
"lsb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"msb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"msw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"mkword" to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
|
||||
"clamp" to FSignature(true, null, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||
"clamp__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||
"clamp__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)),
|
||||
"clamp__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)),
|
||||
"clamp__uword" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)),
|
||||
"min" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"min__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"min__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||
"min__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||
"min__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||
"max" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"max__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"max__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||
"max__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||
"max__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||
"peek" to FSignature(true, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD)),
|
||||
"peekw" to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||
"peekf" to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)),
|
||||
"poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||
"pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD)),
|
||||
"pokef" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)),
|
||||
"pokemon" to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||
"rsave" to FSignature(false, null),
|
||||
"rrestore" to FSignature(false, null),
|
||||
"memory" to FSignature(true, DataType.UWORD, FParam("name", DataType.STR), FParam("size", DataType.UWORD), FParam("alignment", DataType.UWORD)),
|
||||
"callfar" to FSignature(false, DataType.UWORD, FParam("bank", DataType.UBYTE), FParam("address", DataType.UWORD), FParam("arg", DataType.UWORD)),
|
||||
"callfar2" to FSignature(false, DataType.UWORD, FParam("bank", DataType.UBYTE), FParam("address", DataType.UWORD), FParam("argA", DataType.UBYTE), FParam("argX", DataType.UBYTE), FParam("argY", DataType.UBYTE), FParam("argC", DataType.BOOL)),
|
||||
"call" to FSignature(false, DataType.UWORD, FParam("address", DataType.UWORD)),
|
||||
"memory" to FSignature(true, BaseDataType.UWORD, FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)),
|
||||
"callfar" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("arg", BaseDataType.UWORD)),
|
||||
"callfar2" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)),
|
||||
"call" to FSignature(false, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||
)
|
||||
|
||||
val InplaceModifyingBuiltinFunctions = setOf(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package prog8.code.core
|
||||
|
||||
enum class DataType {
|
||||
import java.util.Objects
|
||||
|
||||
enum class BaseDataType {
|
||||
UBYTE, // pass by value 8 bits unsigned
|
||||
BYTE, // pass by value 8 bits signed
|
||||
UWORD, // pass by value 16 bits unsigned
|
||||
@@ -9,55 +11,246 @@ enum class DataType {
|
||||
FLOAT, // pass by value machine dependent
|
||||
BOOL, // pass by value bit 0 of an 8-bit byte
|
||||
STR, // pass by reference
|
||||
ARRAY_UB, // pass by reference
|
||||
ARRAY_B, // pass by reference
|
||||
ARRAY_UW, // pass by reference
|
||||
ARRAY_UW_SPLIT, // pass by reference, lo/hi byte split
|
||||
ARRAY_W, // pass by reference
|
||||
ARRAY_W_SPLIT, // pass by reference, lo/hi byte split
|
||||
ARRAY_F, // pass by reference
|
||||
ARRAY_BOOL, // pass by reference
|
||||
ARRAY, // pass by reference, subtype is the element type
|
||||
ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types)
|
||||
UNDEFINED;
|
||||
|
||||
/**
|
||||
* is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
|
||||
*/
|
||||
infix fun isAssignableTo(targetType: DataType) =
|
||||
when(this) {
|
||||
BOOL -> targetType == BOOL
|
||||
UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, LONG, FLOAT)
|
||||
BYTE -> targetType.oneOf(BYTE, WORD, LONG, FLOAT)
|
||||
UWORD -> targetType.oneOf(UWORD, LONG, FLOAT)
|
||||
WORD -> targetType.oneOf(WORD, LONG, FLOAT)
|
||||
LONG -> targetType.oneOf(LONG, FLOAT)
|
||||
FLOAT -> targetType.oneOf(FLOAT)
|
||||
STR -> targetType.oneOf(STR, UWORD)
|
||||
in ArrayDatatypes -> targetType == this
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun oneOf(vararg types: DataType) = this in types
|
||||
|
||||
infix fun largerThan(other: DataType) =
|
||||
fun largerSizeThan(other: BaseDataType) =
|
||||
when {
|
||||
this == other -> false
|
||||
this in ByteDatatypesWithBoolean -> false
|
||||
this in WordDatatypes -> other in ByteDatatypesWithBoolean
|
||||
this == LONG -> other in ByteDatatypesWithBoolean+WordDatatypes
|
||||
this.isByteOrBool -> false
|
||||
this.isWord -> other.isByteOrBool
|
||||
this == LONG -> other.isByteOrBool || other.isWord
|
||||
this == STR && other == UWORD || this == UWORD && other == STR -> false
|
||||
this.isArray -> other != FLOAT
|
||||
this == STR -> other != FLOAT
|
||||
else -> true
|
||||
}
|
||||
|
||||
infix fun equalsSize(other: DataType) =
|
||||
fun equalsSize(other: BaseDataType) =
|
||||
when {
|
||||
this == other -> true
|
||||
this in ByteDatatypesWithBoolean -> other in ByteDatatypesWithBoolean
|
||||
this in WordDatatypes -> other in WordDatatypes
|
||||
this== STR && other== UWORD || this== UWORD && other== STR -> true
|
||||
this.isByteOrBool -> other.isByteOrBool
|
||||
this.isWord -> other.isWord
|
||||
this == STR && other== UWORD || this== UWORD && other== STR -> true
|
||||
this == STR && other.isArray -> true
|
||||
this.isArray && other == STR -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
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.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.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)
|
||||
val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW
|
||||
val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW
|
||||
val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
val BaseDataType.isPassByRef get() = this.isIterable
|
||||
val BaseDataType.isPassByValue get() = !this.isIterable
|
||||
|
||||
|
||||
sealed class SubType(val dt: BaseDataType) {
|
||||
companion object {
|
||||
private val types by lazy {
|
||||
// lazy because of static initialization order
|
||||
mapOf(
|
||||
BaseDataType.UBYTE to SubUnsignedByte,
|
||||
BaseDataType.BYTE to SubSignedByte,
|
||||
BaseDataType.UWORD to SubUnsignedWord,
|
||||
BaseDataType.WORD to SubSignedWord,
|
||||
BaseDataType.FLOAT to SubFloat,
|
||||
BaseDataType.BOOL to SubBool
|
||||
)}
|
||||
|
||||
fun forDt(dt: BaseDataType) = types.getValue(dt)
|
||||
}
|
||||
}
|
||||
|
||||
private data object SubUnsignedByte: SubType(BaseDataType.UBYTE)
|
||||
private data object SubSignedByte: SubType(BaseDataType.BYTE)
|
||||
private data object SubUnsignedWord: SubType(BaseDataType.UWORD)
|
||||
private data object SubSignedWord: SubType(BaseDataType.WORD)
|
||||
private data object SubBool: SubType(BaseDataType.BOOL)
|
||||
private data object SubFloat: SubType(BaseDataType.FLOAT)
|
||||
|
||||
|
||||
class DataType private constructor(val base: BaseDataType, val sub: SubType?) {
|
||||
|
||||
init {
|
||||
if(base.isArray) {
|
||||
require(sub != null)
|
||||
if(base.isSplitWordArray)
|
||||
require(sub.dt == BaseDataType.UWORD || sub.dt == BaseDataType.WORD)
|
||||
}
|
||||
else if(base==BaseDataType.STR)
|
||||
require(sub?.dt==BaseDataType.UBYTE) { "STR subtype should be ubyte" }
|
||||
else
|
||||
require(sub == null)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is DataType) return false
|
||||
return base == other.base && sub == other.sub
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(base, sub)
|
||||
|
||||
companion object {
|
||||
private val simpletypes = mapOf(
|
||||
BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null),
|
||||
BaseDataType.BYTE to DataType(BaseDataType.BYTE, null),
|
||||
BaseDataType.UWORD to DataType(BaseDataType.UWORD, null),
|
||||
BaseDataType.WORD to DataType(BaseDataType.WORD, null),
|
||||
BaseDataType.LONG to DataType(BaseDataType.LONG, null),
|
||||
BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null),
|
||||
BaseDataType.BOOL to DataType(BaseDataType.BOOL, null),
|
||||
BaseDataType.STR to DataType(BaseDataType.STR, SubUnsignedByte),
|
||||
BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null)
|
||||
)
|
||||
|
||||
fun forDt(dt: BaseDataType) = simpletypes.getValue(dt)
|
||||
|
||||
fun arrayFor(elementDt: BaseDataType, split: Boolean=false): DataType {
|
||||
val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers
|
||||
if(split) return DataType(BaseDataType.ARRAY_SPLITW, SubType.forDt(actualElementDt))
|
||||
else return DataType(BaseDataType.ARRAY, SubType.forDt(actualElementDt))
|
||||
}
|
||||
}
|
||||
|
||||
fun elementToArray(split: Boolean = false): DataType {
|
||||
if(split) {
|
||||
return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, true)
|
||||
else throw IllegalArgumentException("invalid split array elt dt")
|
||||
}
|
||||
return arrayFor(base)
|
||||
}
|
||||
|
||||
fun elementType(): DataType =
|
||||
if(base.isArray || base==BaseDataType.STR)
|
||||
forDt(sub!!.dt)
|
||||
else
|
||||
throw IllegalArgumentException("not an array")
|
||||
|
||||
override fun toString(): String = when(base) {
|
||||
BaseDataType.ARRAY -> {
|
||||
when(sub) {
|
||||
SubBool -> "bool[]"
|
||||
SubFloat -> "float[]"
|
||||
SubSignedByte -> "byte[]"
|
||||
SubSignedWord -> "word[]"
|
||||
SubUnsignedByte -> "ubyte[]"
|
||||
SubUnsignedWord -> "uword[]"
|
||||
null -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.ARRAY_SPLITW -> {
|
||||
when(sub) {
|
||||
SubSignedWord -> "@split word[]"
|
||||
SubUnsignedWord -> "@split uword[]"
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else -> base.name.lowercase()
|
||||
}
|
||||
|
||||
fun sourceString(): String = when (base) {
|
||||
BaseDataType.BOOL -> "bool"
|
||||
BaseDataType.UBYTE -> "ubyte"
|
||||
BaseDataType.BYTE -> "byte"
|
||||
BaseDataType.UWORD -> "uword"
|
||||
BaseDataType.WORD -> "word"
|
||||
BaseDataType.LONG -> "long"
|
||||
BaseDataType.FLOAT -> "float"
|
||||
BaseDataType.STR -> "str"
|
||||
BaseDataType.ARRAY -> {
|
||||
when(sub) {
|
||||
SubUnsignedByte -> "ubyte["
|
||||
SubUnsignedWord -> "uword["
|
||||
SubBool -> "bool["
|
||||
SubSignedByte -> "byte["
|
||||
SubSignedWord -> "word["
|
||||
SubFloat -> "float["
|
||||
null -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.ARRAY_SPLITW -> {
|
||||
when(sub) {
|
||||
SubUnsignedWord -> "@split uword["
|
||||
SubSignedWord -> "@split word["
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt")
|
||||
}
|
||||
|
||||
// is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
|
||||
infix fun isAssignableTo(targetType: DataType) =
|
||||
when(base) {
|
||||
BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL
|
||||
BaseDataType.UBYTE -> targetType.base in arrayOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.BYTE -> targetType.base in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.UWORD -> targetType.base in arrayOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.WORD -> targetType.base in arrayOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.LONG -> targetType.base in arrayOf(BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT)
|
||||
BaseDataType.STR -> targetType.base in arrayOf(BaseDataType.STR, BaseDataType.UWORD)
|
||||
BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> targetType.base in arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub
|
||||
BaseDataType.UNDEFINED -> false
|
||||
}
|
||||
|
||||
fun largerSizeThan(other: DataType): Boolean {
|
||||
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||
return base.largerSizeThan(other.base)
|
||||
}
|
||||
fun equalsSize(other: DataType): Boolean {
|
||||
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||
return base.equalsSize(other.base)
|
||||
}
|
||||
|
||||
val isUndefined = base == BaseDataType.UNDEFINED
|
||||
val isByte = base.isByte
|
||||
val isUnsignedByte = base == BaseDataType.UBYTE
|
||||
val isSignedByte = base == BaseDataType.BYTE
|
||||
val isByteOrBool = base.isByteOrBool
|
||||
val isWord = base.isWord
|
||||
val isUnsignedWord = base == BaseDataType.UWORD
|
||||
val isSignedWord = base == BaseDataType.WORD
|
||||
val isInteger = base.isInteger
|
||||
val isIntegerOrBool = base.isIntegerOrBool
|
||||
val isNumeric = base.isNumeric
|
||||
val isNumericOrBool = base.isNumericOrBool
|
||||
val isSigned = base.isSigned
|
||||
val isUnsigned = !base.isSigned
|
||||
val isArray = base.isArray
|
||||
val isBoolArray = base.isArray && sub?.dt == BaseDataType.BOOL
|
||||
val isByteArray = base.isArray && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE)
|
||||
val isUnsignedByteArray = base.isArray && sub?.dt == BaseDataType.UBYTE
|
||||
val isSignedByteArray = base.isArray && sub?.dt == BaseDataType.BYTE
|
||||
val isWordArray = base.isArray && (sub?.dt == BaseDataType.UWORD || sub?.dt == BaseDataType.WORD)
|
||||
val isUnsignedWordArray = base.isArray && sub?.dt == BaseDataType.UWORD
|
||||
val isSignedWordArray = base.isArray && sub?.dt == BaseDataType.WORD
|
||||
val isFloatArray = base.isArray && sub?.dt == BaseDataType.FLOAT
|
||||
val isString = base == BaseDataType.STR
|
||||
val isBool = base == BaseDataType.BOOL
|
||||
val isFloat = base == BaseDataType.FLOAT
|
||||
val isLong = base == BaseDataType.LONG
|
||||
val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub?.dt == BaseDataType.UBYTE || sub?.dt == BaseDataType.BYTE))
|
||||
val isSplitWordArray = base.isSplitWordArray
|
||||
val isSplitUnsignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.UWORD
|
||||
val isSplitSignedWordArray = base.isSplitWordArray && sub?.dt == BaseDataType.WORD
|
||||
val isIterable = base.isIterable
|
||||
val isPassByRef = base.isPassByRef
|
||||
val isPassByValue = base.isPassByValue
|
||||
}
|
||||
|
||||
|
||||
enum class CpuRegister {
|
||||
A,
|
||||
X,
|
||||
@@ -97,11 +290,11 @@ enum class RegisterOrPair {
|
||||
|
||||
fun asScopedNameVirtualReg(type: DataType?): List<String> {
|
||||
require(this in Cx16VirtualRegisters)
|
||||
val suffix = when(type) {
|
||||
DataType.UBYTE, DataType.BOOL -> "L"
|
||||
DataType.BYTE -> "sL"
|
||||
DataType.WORD -> "s"
|
||||
DataType.UWORD, null -> ""
|
||||
val suffix = when(type?.base) {
|
||||
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
|
||||
BaseDataType.BYTE -> "sL"
|
||||
BaseDataType.WORD -> "s"
|
||||
BaseDataType.UWORD, null -> ""
|
||||
else -> throw kotlin.IllegalArgumentException("invalid register param type")
|
||||
}
|
||||
return listOf("cx16", name.lowercase()+suffix)
|
||||
@@ -134,48 +327,6 @@ enum class BranchCondition {
|
||||
VC
|
||||
}
|
||||
|
||||
|
||||
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE)
|
||||
val ByteDatatypesWithBoolean = ByteDatatypes + DataType.BOOL
|
||||
val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
|
||||
val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG)
|
||||
val IntegerDatatypesWithBoolean = IntegerDatatypes + DataType.BOOL
|
||||
val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT)
|
||||
val NumericDatatypesWithBoolean = NumericDatatypes + DataType.BOOL
|
||||
val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.LONG, DataType.FLOAT)
|
||||
val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL)
|
||||
val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD)
|
||||
val SplitWordArrayTypes = arrayOf(DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT)
|
||||
val IterableDatatypes = arrayOf(
|
||||
DataType.STR,
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B,
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W,
|
||||
DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT,
|
||||
DataType.ARRAY_F, DataType.ARRAY_BOOL
|
||||
)
|
||||
val PassByValueDatatypes = NumericDatatypesWithBoolean
|
||||
val PassByReferenceDatatypes = IterableDatatypes
|
||||
val ArrayToElementTypes = mapOf(
|
||||
DataType.STR to DataType.UBYTE,
|
||||
DataType.ARRAY_B to DataType.BYTE,
|
||||
DataType.ARRAY_UB to DataType.UBYTE,
|
||||
DataType.ARRAY_W to DataType.WORD,
|
||||
DataType.ARRAY_UW to DataType.UWORD,
|
||||
DataType.ARRAY_W_SPLIT to DataType.WORD,
|
||||
DataType.ARRAY_UW_SPLIT to DataType.UWORD,
|
||||
DataType.ARRAY_F to DataType.FLOAT,
|
||||
DataType.ARRAY_BOOL to DataType.BOOL
|
||||
)
|
||||
val ElementToArrayTypes = mapOf(
|
||||
DataType.BYTE to DataType.ARRAY_B,
|
||||
DataType.UBYTE to DataType.ARRAY_UB,
|
||||
DataType.WORD to DataType.ARRAY_W,
|
||||
DataType.UWORD to DataType.ARRAY_UW,
|
||||
DataType.FLOAT to DataType.ARRAY_F,
|
||||
DataType.BOOL to DataType.ARRAY_BOOL,
|
||||
DataType.STR to DataType.ARRAY_UW // array of str is just an array of pointers
|
||||
)
|
||||
|
||||
val Cx16VirtualRegisters = arrayOf(
|
||||
RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
|
||||
RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package prog8.code.core
|
||||
|
||||
interface IMemSizer {
|
||||
fun memorySize(dt: DataType): Int
|
||||
fun memorySize(arrayDt: DataType, numElements: Int): Int
|
||||
fun memorySize(dt: DataType, numElements: Int?): Int
|
||||
fun memorySize(dt: SubType): Int
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||
return Err(MemAllocationError("zero page usage has been disabled"))
|
||||
|
||||
val size: Int =
|
||||
when (datatype) {
|
||||
in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
|
||||
DataType.STR, in ArrayDatatypes -> {
|
||||
when {
|
||||
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||
datatype.isString || datatype.isArray -> {
|
||||
val memsize = options.compTarget.memorySize(datatype, numElements!!)
|
||||
if(position!=null)
|
||||
errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
|
||||
@@ -80,9 +80,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||
errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
|
||||
memsize
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
datatype.isFloat -> {
|
||||
if (options.floats) {
|
||||
val memsize = options.compTarget.memorySize(DataType.FLOAT)
|
||||
val memsize = options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||
if(position!=null)
|
||||
errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
|
||||
else
|
||||
@@ -118,10 +118,10 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||
require(size>=0)
|
||||
free.removeAll(address until address+size.toUInt())
|
||||
if(name.isNotEmpty()) {
|
||||
allocatedVariables[name] = when(datatype) {
|
||||
in NumericDatatypes, DataType.BOOL -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
||||
DataType.STR -> VarAllocation(address, datatype, size)
|
||||
in ArrayDatatypes -> VarAllocation(address, datatype, size)
|
||||
allocatedVariables[name] = when {
|
||||
datatype.isNumericOrBool -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
||||
datatype.isString -> VarAllocation(address, datatype, size)
|
||||
datatype.isArray -> VarAllocation(address, datatype, size)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
}
|
||||
@@ -150,14 +150,13 @@ class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAlloc
|
||||
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
|
||||
|
||||
val size: Int =
|
||||
when (datatype) {
|
||||
in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
|
||||
DataType.STR, in ArrayDatatypes -> {
|
||||
options.compTarget.memorySize(datatype, numElements!!)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
when {
|
||||
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||
datatype.isString -> numElements!!
|
||||
datatype.isArray -> options.compTarget.memorySize(datatype, numElements!!)
|
||||
datatype.isFloat -> {
|
||||
if (options.floats) {
|
||||
options.compTarget.memorySize(DataType.FLOAT)
|
||||
options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||
} else return Err(MemAllocationError("floating point option not enabled"))
|
||||
}
|
||||
else -> throw MemAllocationError("weird dt")
|
||||
|
||||
@@ -60,7 +60,7 @@ private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable, errors: I
|
||||
if(node.children.dropLast(1).all { (it as PtAssignTarget).void }) {
|
||||
// all targets are now void, the whole assignment can be discarded and replaced by just a (void) call to the subroutine
|
||||
val index = node.parent.children.indexOf(node)
|
||||
val voidCall = PtFunctionCall(functionName, true, DataType.UNDEFINED, value.position)
|
||||
val voidCall = PtFunctionCall(functionName, true, DataType.forDt(BaseDataType.UNDEFINED), value.position)
|
||||
value.children.forEach { voidCall.add(it) }
|
||||
node.parent.children[index] = voidCall
|
||||
voidCall.parent = node.parent
|
||||
@@ -81,12 +81,12 @@ private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): In
|
||||
fun makeBittestCall(condition: PtBinaryExpression, and: PtBinaryExpression, variable: PtIdentifier, bitmask: Int): PtBuiltinFunctionCall {
|
||||
require(bitmask==128 || bitmask==64)
|
||||
val setOrNot = if(condition.operator=="!=") "set" else "notset"
|
||||
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.BOOL, condition.position)
|
||||
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.forDt(BaseDataType.BOOL), condition.position)
|
||||
bittestCall.add(variable)
|
||||
if(bitmask==128)
|
||||
bittestCall.add(PtNumber(DataType.UBYTE, 7.0, and.right.position))
|
||||
bittestCall.add(PtNumber(BaseDataType.UBYTE, 7.0, and.right.position))
|
||||
else
|
||||
bittestCall.add(PtNumber(DataType.UBYTE, 6.0, and.right.position))
|
||||
bittestCall.add(PtNumber(BaseDataType.UBYTE, 6.0, and.right.position))
|
||||
return bittestCall
|
||||
}
|
||||
|
||||
@@ -94,17 +94,17 @@ private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): In
|
||||
if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) {
|
||||
if (condition.right.asConstInteger() == 0) {
|
||||
val and = condition.left as? PtBinaryExpression
|
||||
if (and != null && and.operator == "&" && and.type == DataType.UBYTE) {
|
||||
if (and != null && and.operator == "&" && and.type.isUnsignedByte) {
|
||||
val bitmask = and.right.asConstInteger()
|
||||
if(bitmask==128 || bitmask==64) {
|
||||
val variable = and.left as? PtIdentifier
|
||||
if (variable != null && variable.type in ByteDatatypes) {
|
||||
if (variable != null && variable.type.isByte) {
|
||||
return Triple(and, variable, bitmask)
|
||||
}
|
||||
val typecast = and.left as? PtTypeCast
|
||||
if (typecast != null && typecast.type == DataType.UBYTE) {
|
||||
if (typecast != null && typecast.type.isUnsignedByte) {
|
||||
val castedVariable = typecast.value as? PtIdentifier
|
||||
if(castedVariable!=null && castedVariable.type in ByteDatatypes)
|
||||
if(castedVariable!=null && castedVariable.type.isByte)
|
||||
return Triple(and, castedVariable, bitmask)
|
||||
}
|
||||
}
|
||||
@@ -165,12 +165,12 @@ internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister:
|
||||
cx16.r?sL BYTE
|
||||
cx16.r?sH BYTE
|
||||
*/
|
||||
if(identifier.type in ByteDatatypes && type in ByteDatatypes) {
|
||||
if(identifier.type.isByte && type.isByte) {
|
||||
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||
return identifierRegName.substring(2) in arrayOf("", "L", "sL") // note: not the -H (msb) variants!
|
||||
}
|
||||
}
|
||||
else if(identifier.type in WordDatatypes && type in WordDatatypes) {
|
||||
else if(identifier.type.isWord && type.isWord) {
|
||||
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||
return identifierRegName.substring(2) in arrayOf("", "s")
|
||||
}
|
||||
|
||||
@@ -13,19 +13,25 @@ class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
const val NAME = "atari"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType): Int {
|
||||
return when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
||||
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid datatype")
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
require(numElements!=null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
||||
if(arrayDt==DataType.UWORD)
|
||||
numElements // pointer to bytes.
|
||||
else
|
||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
||||
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,18 +13,25 @@ class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
const val NAME = "neo"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType): Int {
|
||||
return when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
||||
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid datatype")
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
require(numElements!=null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
||||
if(arrayDt== DataType.UWORD)
|
||||
numElements // pointer to bytes.
|
||||
else
|
||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,25 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
const val NAME = "virtual"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType): Int {
|
||||
return when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
||||
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid datatype")
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
require(numElements!=null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
||||
if(arrayDt==DataType.UWORD)
|
||||
numElements // pointer to bytes.
|
||||
else
|
||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,12 +85,12 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||
// The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02).
|
||||
for(reg in 0..15) {
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||
free.remove((4+reg*2).toUInt())
|
||||
free.remove((5+reg*2).toUInt())
|
||||
}
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
package prog8.code.target.cbm
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.SubType
|
||||
|
||||
|
||||
internal object CbmMemorySizer: IMemSizer {
|
||||
override fun memorySize(dt: DataType): Int {
|
||||
return when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> 2
|
||||
DataType.FLOAT -> Mflpt5.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid datatype")
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
require(numElements!=null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) =
|
||||
if(arrayDt==DataType.UWORD)
|
||||
numElements // pointer to bytes.
|
||||
else
|
||||
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
}
|
||||
@@ -57,12 +57,12 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||
for(reg in 0..15) {
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,12 +37,12 @@ class Neo6502Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||
for(reg in 0..15) {
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
var lookupName = node.name
|
||||
if(node.type in SplitWordArrayTypes && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) {
|
||||
if(node.type.isSplitWordArray && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) {
|
||||
lookupName = lookupName.dropLast(4)
|
||||
}
|
||||
val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node")
|
||||
@@ -413,17 +413,17 @@ class AsmGen6502Internal (
|
||||
|
||||
|
||||
internal val tempVarsCounters = mutableMapOf(
|
||||
DataType.BOOL to 0,
|
||||
DataType.BYTE to 0,
|
||||
DataType.UBYTE to 0,
|
||||
DataType.WORD to 0,
|
||||
DataType.UWORD to 0,
|
||||
DataType.FLOAT to 0
|
||||
BaseDataType.BOOL to 0,
|
||||
BaseDataType.BYTE to 0,
|
||||
BaseDataType.UBYTE to 0,
|
||||
BaseDataType.WORD to 0,
|
||||
BaseDataType.UWORD to 0,
|
||||
BaseDataType.FLOAT to 0
|
||||
)
|
||||
|
||||
internal fun buildTempVarName(dt: DataType, counter: Int): String = "prog8_tmpvar_${dt.toString().lowercase()}_$counter"
|
||||
internal fun buildTempVarName(dt: BaseDataType, counter: Int): String = "prog8_tmpvar_${dt.toString().lowercase()}_$counter"
|
||||
|
||||
internal fun getTempVarName(dt: DataType): String {
|
||||
internal fun getTempVarName(dt: BaseDataType): String {
|
||||
tempVarsCounters[dt] = tempVarsCounters.getValue(dt)+1
|
||||
return buildTempVarName(dt, tempVarsCounters.getValue(dt))
|
||||
}
|
||||
@@ -627,7 +627,7 @@ class AsmGen6502Internal (
|
||||
val indexValue = if(expr.splitWords)
|
||||
indexnum
|
||||
else
|
||||
indexnum * options.compTarget.memorySize(expr.type)
|
||||
indexnum * options.compTarget.memorySize(expr.type, null)
|
||||
out(" ld$reg #$indexValue")
|
||||
return
|
||||
}
|
||||
@@ -637,11 +637,11 @@ class AsmGen6502Internal (
|
||||
return
|
||||
}
|
||||
|
||||
when (expr.type) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
when {
|
||||
expr.type.isByteOrBool -> {
|
||||
assignExpressionToRegister(expr.index, RegisterOrPair.fromCpuRegister(register), false)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
expr.type.isWord -> {
|
||||
assignExpressionToRegister(expr.index, RegisterOrPair.A, false)
|
||||
out(" asl a")
|
||||
when (register) {
|
||||
@@ -650,8 +650,8 @@ class AsmGen6502Internal (
|
||||
CpuRegister.Y -> out(" tay")
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
require(options.compTarget.memorySize(DataType.FLOAT) == 5) {"invalid float size ${expr.position}"}
|
||||
expr.type.isFloat -> {
|
||||
require(options.compTarget.machine.FLOAT_MEM_SIZE == 5) {"invalid float size ${expr.position}"}
|
||||
assignExpressionToRegister(expr.index, RegisterOrPair.A, false)
|
||||
out("""
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@@ -670,7 +670,7 @@ class AsmGen6502Internal (
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? =
|
||||
internal fun translateBuiltinFunctionCallExpression(bfc: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): BaseDataType? =
|
||||
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultRegister)
|
||||
|
||||
internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) =
|
||||
@@ -692,7 +692,7 @@ class AsmGen6502Internal (
|
||||
when(reg) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
RegisterOrPair.Y -> assignmentAsmGen.assignRegisterByte(target, reg.asCpuRegister(), target.datatype in SignedDatatypes, true)
|
||||
RegisterOrPair.Y -> assignmentAsmGen.assignRegisterByte(target, reg.asCpuRegister(), target.datatype.isSigned, true)
|
||||
RegisterOrPair.AX,
|
||||
RegisterOrPair.AY,
|
||||
RegisterOrPair.XY,
|
||||
@@ -704,8 +704,8 @@ class AsmGen6502Internal (
|
||||
}
|
||||
|
||||
internal fun assignExpressionTo(value: PtExpression, target: AsmAssignTarget) {
|
||||
when (target.datatype) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
if (value.asConstInteger()==0) {
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
@@ -725,7 +725,7 @@ class AsmGen6502Internal (
|
||||
}
|
||||
}
|
||||
TargetStorageKind.REGISTER -> {
|
||||
val zero = PtNumber(DataType.UBYTE, 0.0, value.position)
|
||||
val zero = PtNumber(BaseDataType.UBYTE, 0.0, value.position)
|
||||
zero.parent = value
|
||||
assignExpressionToRegister(zero, target.register!!, false)
|
||||
return
|
||||
@@ -737,7 +737,7 @@ class AsmGen6502Internal (
|
||||
assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
assignRegister(RegisterOrPair.A, target)
|
||||
}
|
||||
in WordDatatypes, in PassByReferenceDatatypes -> {
|
||||
target.datatype.isWord || target.datatype.isPassByRef -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY)
|
||||
translateNormalAssignment(
|
||||
AsmAssignment(
|
||||
@@ -746,7 +746,7 @@ class AsmGen6502Internal (
|
||||
), value.definingISub()
|
||||
)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
target.datatype.isFloat -> {
|
||||
assignExpressionToRegister(value, RegisterOrPair.FAC1)
|
||||
assignRegister(RegisterOrPair.FAC1, target)
|
||||
}
|
||||
@@ -798,25 +798,25 @@ class AsmGen6502Internal (
|
||||
val symbol = symbolTable.lookup((stmt.count as PtIdentifier).name)
|
||||
val vardecl = symbol!!.astNode as IPtVariable
|
||||
val name = asmVariableName(stmt.count as PtIdentifier)
|
||||
when(vardecl.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
when {
|
||||
vardecl.type.isByte -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.Y, stmt.definingISub(), stmt.count.position)
|
||||
repeatCountInY(stmt, endLabel)
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
vardecl.type.isWord -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.AY, stmt.definingISub(), stmt.count.position)
|
||||
repeatWordCountInAY(endLabel, stmt)
|
||||
}
|
||||
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
||||
else -> throw AssemblyError("invalid loop variable datatype ${vardecl.type}")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
when (stmt.count.type) {
|
||||
in ByteDatatypes -> {
|
||||
when {
|
||||
stmt.count.type.isByte -> {
|
||||
assignExpressionToRegister(stmt.count, RegisterOrPair.Y)
|
||||
repeatCountInY(stmt, endLabel)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
stmt.count.type.isWord -> {
|
||||
assignExpressionToRegister(stmt.count, RegisterOrPair.AY)
|
||||
repeatWordCountInAY(endLabel, stmt)
|
||||
}
|
||||
@@ -831,7 +831,7 @@ class AsmGen6502Internal (
|
||||
private fun repeatWordCount(iterations: Int, stmt: PtRepeatLoop) {
|
||||
require(iterations in 257..65536) { "invalid repeat count ${stmt.position}" }
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val counterVar = createRepeatCounterVar(DataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UWORD, isTargetCpu(CpuType.CPU65c02), stmt)
|
||||
val loopcount = if(iterations==65536) 0 else if(iterations and 0x00ff == 0) iterations else iterations + 0x0100 // so that the loop can simply use a double-dec
|
||||
out("""
|
||||
ldy #>$loopcount
|
||||
@@ -851,7 +851,7 @@ $repeatLabel""")
|
||||
// note: A/Y must have been loaded with the number of iterations!
|
||||
// the iny + double dec is microoptimization of the 16 bit loop
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UWORD, false, stmt)
|
||||
out("""
|
||||
cmp #0
|
||||
beq +
|
||||
@@ -874,13 +874,13 @@ $repeatLabel""")
|
||||
require(count in 2..256) { "invalid repeat count ${stmt.position}" }
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
if(isTargetCpu(CpuType.CPU65c02)) {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, true, stmt)
|
||||
out(" lda #${count and 255} | sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.statements)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
} else {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, false, stmt)
|
||||
out(" lda #${count and 255} | sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.statements)
|
||||
@@ -892,13 +892,13 @@ $repeatLabel""")
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
out(" cpy #0")
|
||||
if(isTargetCpu(CpuType.CPU65c02)) {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, true, stmt)
|
||||
out(" beq $endLabel | sty $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.statements)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
} else {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt)
|
||||
val counterVar = createRepeatCounterVar(BaseDataType.UBYTE, false, stmt)
|
||||
out(" beq $endLabel | sty $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.statements)
|
||||
@@ -907,7 +907,7 @@ $repeatLabel""")
|
||||
out(endLabel)
|
||||
}
|
||||
|
||||
private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String {
|
||||
private fun createRepeatCounterVar(dt: BaseDataType, preferZeropage: Boolean, stmt: PtRepeatLoop): String {
|
||||
val scope = stmt.definingISub()!!
|
||||
val asmInfo = subroutineExtra(scope)
|
||||
var parent = stmt.parent
|
||||
@@ -929,8 +929,8 @@ $repeatLabel""")
|
||||
|
||||
val counterVar = makeLabel("counter")
|
||||
when(dt) {
|
||||
DataType.UBYTE, DataType.UWORD -> {
|
||||
val result = zeropage.allocate(counterVar, dt, null, stmt.position, errors)
|
||||
BaseDataType.UBYTE, BaseDataType.UWORD -> {
|
||||
val result = zeropage.allocate(counterVar, DataType.forDt(dt), null, stmt.position, errors)
|
||||
result.fold(
|
||||
success = { (address, _, _) -> asmInfo.extraVars.add(Triple(dt, counterVar, address)) },
|
||||
failure = { asmInfo.extraVars.add(Triple(dt, counterVar, null)) } // allocate normally
|
||||
@@ -945,7 +945,7 @@ $repeatLabel""")
|
||||
val endLabel = makeLabel("choice_end")
|
||||
val choiceBlocks = mutableListOf<Pair<String, PtNodeGroup>>()
|
||||
val conditionDt = stmt.value.type
|
||||
if(conditionDt in ByteDatatypes)
|
||||
if(conditionDt.isByte)
|
||||
assignExpressionToRegister(stmt.value, RegisterOrPair.A)
|
||||
else
|
||||
assignExpressionToRegister(stmt.value, RegisterOrPair.AY)
|
||||
@@ -959,7 +959,7 @@ $repeatLabel""")
|
||||
choiceBlocks.add(choiceLabel to choice.statements)
|
||||
for (cv in choice.values.children) {
|
||||
val value = (cv as PtNumber).number.toInt()
|
||||
if(conditionDt in ByteDatatypes) {
|
||||
if(conditionDt.isByte) {
|
||||
out(" cmp #${value.toHex()} | beq $choiceLabel")
|
||||
} else {
|
||||
out("""
|
||||
@@ -1051,17 +1051,15 @@ $repeatLabel""")
|
||||
ret.value?.let { returnvalue ->
|
||||
val sub = ret.definingSub()!!
|
||||
val returnReg = sub.returnRegister()!!
|
||||
when (sub.returntype) {
|
||||
in NumericDatatypes, DataType.BOOL -> {
|
||||
assignExpressionToRegister(returnvalue, returnReg.registerOrPair!!)
|
||||
}
|
||||
else -> {
|
||||
// all else take its address and assign that also to AY register pair
|
||||
val addrofValue = PtAddressOf(returnvalue.position)
|
||||
addrofValue.add(returnvalue as PtIdentifier)
|
||||
addrofValue.parent = ret.parent
|
||||
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false)
|
||||
}
|
||||
if (sub.returntype?.isNumericOrBool==true) {
|
||||
assignExpressionToRegister(returnvalue, returnReg.registerOrPair!!)
|
||||
}
|
||||
else {
|
||||
// all else take its address and assign that also to AY register pair
|
||||
val addrofValue = PtAddressOf(returnvalue.position)
|
||||
addrofValue.add(returnvalue as PtIdentifier)
|
||||
addrofValue.parent = ret.parent
|
||||
assignmentAsmGen.assignExpressionToRegister(addrofValue, returnReg.registerOrPair!!, false)
|
||||
}
|
||||
}
|
||||
out(" rts")
|
||||
@@ -1098,11 +1096,11 @@ $repeatLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun signExtendAYlsb(valueDt: DataType) {
|
||||
internal fun signExtendAYlsb(valueDt: BaseDataType) {
|
||||
// sign extend signed byte in A to full word in AY
|
||||
when(valueDt) {
|
||||
DataType.UBYTE -> out(" ldy #0")
|
||||
DataType.BYTE -> out("""
|
||||
BaseDataType.UBYTE -> out(" ldy #0")
|
||||
BaseDataType.BYTE -> out("""
|
||||
ldy #0
|
||||
cmp #$80
|
||||
bcc +
|
||||
@@ -1113,16 +1111,16 @@ $repeatLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun signExtendVariableLsb(asmvar: String, valueDt: DataType) {
|
||||
internal fun signExtendVariableLsb(asmvar: String, valueDt: BaseDataType) {
|
||||
// sign extend signed byte in a var to a full word in that variable
|
||||
when(valueDt) {
|
||||
DataType.UBYTE -> {
|
||||
BaseDataType.UBYTE -> {
|
||||
if(isTargetCpu(CpuType.CPU65c02))
|
||||
out(" stz $asmvar+1")
|
||||
else
|
||||
out(" lda #0 | sta $asmvar+1")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
BaseDataType.BYTE -> {
|
||||
out("""
|
||||
lda $asmvar
|
||||
ora #$7f
|
||||
@@ -1155,24 +1153,24 @@ $repeatLabel""")
|
||||
if (operator != "+") return null
|
||||
val leftDt = left.type
|
||||
val rightDt = right.type
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UBYTE)
|
||||
if(leftDt.isUnsignedWord && rightDt.isUnsignedByte)
|
||||
return Pair(left, right)
|
||||
if(leftDt == DataType.UBYTE && rightDt == DataType.UWORD)
|
||||
if(leftDt.isUnsignedByte && rightDt.isUnsignedWord)
|
||||
return Pair(right, left)
|
||||
if(leftDt == DataType.UWORD && rightDt == DataType.UWORD) {
|
||||
if(leftDt.isUnsignedWord && rightDt.isUnsignedWord) {
|
||||
// could be that the index was a constant numeric byte but converted to word, check that
|
||||
val constIdx = right as? PtNumber
|
||||
if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) {
|
||||
val num = PtNumber(DataType.UBYTE, constIdx.number, constIdx.position)
|
||||
val num = PtNumber(BaseDataType.UBYTE, constIdx.number, constIdx.position)
|
||||
num.parent = right.parent
|
||||
return Pair(left, num)
|
||||
}
|
||||
// could be that the index was typecasted into uword, check that
|
||||
val rightTc = right as? PtTypeCast
|
||||
if(rightTc!=null && rightTc.value.type == DataType.UBYTE)
|
||||
if(rightTc!=null && rightTc.value.type.isUnsignedByte)
|
||||
return Pair(left, rightTc.value)
|
||||
val leftTc = left as? PtTypeCast
|
||||
if(leftTc!=null && leftTc.value.type == DataType.UBYTE)
|
||||
if(leftTc!=null && leftTc.value.type.isUnsignedByte)
|
||||
return Pair(right, leftTc.value)
|
||||
}
|
||||
return null
|
||||
@@ -1182,8 +1180,7 @@ $repeatLabel""")
|
||||
// optimize pointer,indexregister if possible
|
||||
|
||||
fun evalBytevalueWillClobberA(expr: PtExpression): Boolean {
|
||||
val dt = expr.type
|
||||
if(dt != DataType.UBYTE && dt != DataType.BYTE)
|
||||
if(!expr.type.isByte)
|
||||
return true
|
||||
return when(expr) {
|
||||
is PtIdentifier -> false
|
||||
@@ -1222,14 +1219,14 @@ $repeatLabel""")
|
||||
if(saveA)
|
||||
out(" pha")
|
||||
if(ptrAndIndex.second.isSimple()) {
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
|
||||
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
|
||||
if(saveA)
|
||||
out(" pla")
|
||||
out(" sta (P8ZP_SCRATCH_W2),y")
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
|
||||
restoreRegisterStack(CpuRegister.Y, true)
|
||||
if(saveA)
|
||||
out(" pla")
|
||||
@@ -1243,12 +1240,12 @@ $repeatLabel""")
|
||||
} else {
|
||||
// copy the pointer var to zp first
|
||||
if(ptrAndIndex.second.isSimple()) {
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
|
||||
assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y)
|
||||
out(" lda (P8ZP_SCRATCH_W2),y")
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
pushCpuStack(BaseDataType.UBYTE, ptrAndIndex.second)
|
||||
assignExpressionToVariable(ptrAndIndex.first, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
out(" lda (P8ZP_SCRATCH_W2),y")
|
||||
}
|
||||
@@ -1273,22 +1270,22 @@ $repeatLabel""")
|
||||
|
||||
internal fun assignByteOperandsToAAndVar(left: PtExpression, right: PtExpression, rightVarName: String) {
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, rightVarName, DataType.UBYTE)
|
||||
assignExpressionToVariable(right, rightVarName, DataType.forDt(BaseDataType.UBYTE))
|
||||
assignExpressionToRegister(left, RegisterOrPair.A)
|
||||
} else {
|
||||
pushCpuStack(DataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, rightVarName, DataType.UBYTE)
|
||||
pushCpuStack(BaseDataType.UBYTE, left)
|
||||
assignExpressionToVariable(right, rightVarName, DataType.forDt(BaseDataType.UBYTE))
|
||||
out(" pla")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun assignWordOperandsToAYAndVar(left: PtExpression, right: PtExpression, rightVarname: String) {
|
||||
if(left.isSimple()) {
|
||||
assignExpressionToVariable(right, rightVarname, DataType.UWORD)
|
||||
assignExpressionToVariable(right, rightVarname, DataType.forDt(BaseDataType.UWORD))
|
||||
assignExpressionToRegister(left, RegisterOrPair.AY)
|
||||
} else {
|
||||
pushCpuStack(DataType.UWORD, left)
|
||||
assignExpressionToVariable(right, rightVarname, DataType.UWORD)
|
||||
pushCpuStack(BaseDataType.UWORD, left)
|
||||
assignExpressionToVariable(right, rightVarname, DataType.forDt(BaseDataType.UWORD))
|
||||
restoreRegisterStack(CpuRegister.Y, false)
|
||||
restoreRegisterStack(CpuRegister.A, false)
|
||||
}
|
||||
@@ -1297,7 +1294,7 @@ $repeatLabel""")
|
||||
internal fun translateDirectMemReadExpressionToRegA(expr: PtMemoryByte) {
|
||||
|
||||
fun assignViaExprEval() {
|
||||
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.UWORD)
|
||||
assignExpressionToVariable(expr.address, "P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD))
|
||||
if (isTargetCpu(CpuType.CPU65c02)) {
|
||||
out(" lda (P8ZP_SCRATCH_W2)")
|
||||
} else {
|
||||
@@ -1324,12 +1321,12 @@ $repeatLabel""")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun pushCpuStack(dt: DataType, value: PtExpression) {
|
||||
val signed = value.type.oneOf(DataType.BYTE, DataType.WORD)
|
||||
if(dt in ByteDatatypesWithBoolean) {
|
||||
internal fun pushCpuStack(dt: BaseDataType, value: PtExpression) {
|
||||
val signed = value.type.isSigned
|
||||
if(dt.isByteOrBool) {
|
||||
assignExpressionToRegister(value, RegisterOrPair.A, signed)
|
||||
out(" pha")
|
||||
} else if(dt in WordDatatypes) {
|
||||
} else if(dt.isWord) {
|
||||
assignExpressionToRegister(value, RegisterOrPair.AY, signed)
|
||||
if (isTargetCpu(CpuType.CPU65c02))
|
||||
out(" pha | phy")
|
||||
@@ -1400,5 +1397,5 @@ internal class SubroutineExtraAsmInfo {
|
||||
var usedFloatEvalResultVar1 = false
|
||||
var usedFloatEvalResultVar2 = false
|
||||
|
||||
val extraVars = mutableListOf<Triple<DataType, String, UInt?>>()
|
||||
val extraVars = mutableListOf<Triple<BaseDataType, String, UInt?>>()
|
||||
}
|
||||
@@ -9,7 +9,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
private val asmgen: AsmGen6502Internal,
|
||||
private val assignAsmGen: AssignmentAsmGen) {
|
||||
|
||||
internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): DataType? {
|
||||
internal fun translateFunctioncallExpression(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?): BaseDataType? {
|
||||
return translateFunctioncall(fcall, discardResult = false, resultRegister = resultRegister)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
translateFunctioncall(fcall, discardResult = true, resultRegister = null)
|
||||
}
|
||||
|
||||
private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): DataType? {
|
||||
private fun translateFunctioncall(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultRegister: RegisterOrPair?): BaseDataType? {
|
||||
if (discardResult && fcall.hasNoSideEffects)
|
||||
return null // can just ignore the whole function call altogether
|
||||
|
||||
@@ -55,7 +55,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
memread.parent = fcall
|
||||
asmgen.assignExpressionToRegister(memread, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
val memtarget = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.position, memory=memread)
|
||||
val memtarget = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.position, memory=memread)
|
||||
asmgen.assignExpressionTo(fcall.args[1], memtarget)
|
||||
asmgen.out(" pla")
|
||||
}
|
||||
@@ -69,25 +69,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
"prog8_ifelse_bittest_set" -> throw AssemblyError("prog8_ifelse_bittest_set() should have been translated as part of an ifElse statement")
|
||||
"prog8_ifelse_bittest_notset" -> throw AssemblyError("prog8_ifelse_bittest_notset() should have been translated as part of an ifElse statement")
|
||||
"prog8_lib_stringcompare" -> funcStringCompare(fcall, resultRegister)
|
||||
"prog8_lib_square_byte" -> funcSquare(fcall, DataType.UBYTE, resultRegister)
|
||||
"prog8_lib_square_word" -> funcSquare(fcall, DataType.UWORD, resultRegister)
|
||||
"prog8_lib_square_byte" -> funcSquare(fcall, BaseDataType.UBYTE, resultRegister)
|
||||
"prog8_lib_square_word" -> funcSquare(fcall, BaseDataType.UWORD, resultRegister)
|
||||
else -> throw AssemblyError("missing asmgen for builtin func ${fcall.name}")
|
||||
}
|
||||
|
||||
return BuiltinFunctions.getValue(fcall.name).returnType
|
||||
}
|
||||
|
||||
private fun funcSquare(fcall: PtBuiltinFunctionCall, resultType: DataType, resultRegister: RegisterOrPair?) {
|
||||
private fun funcSquare(fcall: PtBuiltinFunctionCall, resultType: BaseDataType, resultRegister: RegisterOrPair?) {
|
||||
// square of word value is faster with dedicated routine, square of byte just use the regular multiplication routine.
|
||||
when (resultType) {
|
||||
DataType.UBYTE -> {
|
||||
BaseDataType.UBYTE -> {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A)
|
||||
asmgen.out(" tay | jsr prog8_math.multiply_bytes")
|
||||
if(resultRegister!=null) {
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister, false, fcall.position, null, asmgen), CpuRegister.A, false, false)
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out(" jsr prog8_math.square")
|
||||
if(resultRegister!=null) {
|
||||
@@ -109,8 +109,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" jsr prog8_math.divmod_ub_asm")
|
||||
val var2name = asmgen.asmVariableName(fcall.args[2] as PtIdentifier)
|
||||
val var3name = asmgen.asmVariableName(fcall.args[3] as PtIdentifier)
|
||||
val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[2].position, var2name)
|
||||
val remainderTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[3].position, var3name)
|
||||
val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[2].position, var2name)
|
||||
val remainderTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[3].position, var3name)
|
||||
assignAsmGen.assignRegisterByte(remainderTarget, CpuRegister.A, false, false)
|
||||
assignAsmGen.assignRegisterByte(divisionTarget, CpuRegister.Y, false, false)
|
||||
}
|
||||
@@ -122,7 +122,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
// output: P8ZP_SCRATCH_W2 in ZP: 16-bit remainder, A/Y: 16 bit division result
|
||||
asmgen.out(" jsr prog8_math.divmod_uw_asm")
|
||||
val var2name = asmgen.asmVariableName(fcall.args[2] as PtIdentifier)
|
||||
val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingISub(), fcall.args[2].position, var2name)
|
||||
val divisionTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingISub(), fcall.args[2].position, var2name)
|
||||
val remainderVar = asmgen.asmVariableName(fcall.args[3] as PtIdentifier)
|
||||
assignAsmGen.assignRegisterpairWord(divisionTarget, RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
@@ -198,7 +198,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
return
|
||||
}
|
||||
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD) // jump address
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.forDt(BaseDataType.UWORD)) // jump address
|
||||
asmgen.out("""
|
||||
; push a return address so the jmp becomes indirect jsr
|
||||
lda #>((+)-1)
|
||||
@@ -305,8 +305,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
private fun funcCmp(fcall: PtBuiltinFunctionCall) {
|
||||
val arg1 = fcall.args[0]
|
||||
val arg2 = fcall.args[1]
|
||||
if(arg1.type in ByteDatatypes) {
|
||||
if(arg2.type in ByteDatatypes) {
|
||||
if(arg1.type.isByte) {
|
||||
if(arg2.type.isByte) {
|
||||
when (arg2) {
|
||||
is PtIdentifier -> {
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
@@ -338,7 +338,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
throw AssemblyError("args for cmp() should have same dt")
|
||||
} else {
|
||||
// arg1 is a word
|
||||
if(arg2.type in WordDatatypes) {
|
||||
if(arg2.type.isWord) {
|
||||
when (arg2) {
|
||||
is PtIdentifier -> {
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
|
||||
@@ -376,11 +376,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||
val name = (fcall.args[0] as PtString).value
|
||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"}
|
||||
val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.UWORD, fcall.position)
|
||||
val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.forDt(BaseDataType.UWORD), fcall.position)
|
||||
val addressOf = PtAddressOf(fcall.position)
|
||||
addressOf.add(slabname)
|
||||
addressOf.parent = fcall
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = addressOf)
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.forDt(BaseDataType.UWORD), expression = addressOf)
|
||||
val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
||||
val assign = AsmAssignment(src, target, program.memsizer, fcall.position)
|
||||
asmgen.translateNormalAssignment(assign, fcall.definingISub())
|
||||
@@ -388,16 +388,16 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcSqrt(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
translateArguments(fcall, scope)
|
||||
when(fcall.args[0].type) {
|
||||
DataType.UBYTE -> {
|
||||
when(fcall.args[0].type.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
asmgen.out(" ldy #0 | jsr prog8_lib.func_sqrt16_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sqrt16_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
asmgen.out(" jsr floats.func_sqrt_into_FAC1")
|
||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
||||
}
|
||||
@@ -407,8 +407,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcRor2(fcall: PtBuiltinFunctionCall) {
|
||||
val what = fcall.args.single()
|
||||
when (what.type) {
|
||||
DataType.UBYTE -> {
|
||||
when (what.type.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
|
||||
@@ -431,7 +431,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
|
||||
@@ -454,8 +454,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcRor(fcall: PtBuiltinFunctionCall) {
|
||||
val what = fcall.args.single()
|
||||
when (what.type) {
|
||||
DataType.UBYTE -> {
|
||||
when (what.type.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
|
||||
@@ -498,7 +498,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
|
||||
@@ -523,8 +523,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcRol2(fcall: PtBuiltinFunctionCall) {
|
||||
val what = fcall.args.single()
|
||||
when (what.type) {
|
||||
DataType.UBYTE -> {
|
||||
when (what.type.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
|
||||
@@ -547,7 +547,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(what, CpuRegister.X)
|
||||
@@ -570,8 +570,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcRol(fcall: PtBuiltinFunctionCall) {
|
||||
val what = fcall.args.single()
|
||||
when (what.type) {
|
||||
DataType.UBYTE -> {
|
||||
when (what.type.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
|
||||
@@ -614,7 +614,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
when (what) {
|
||||
is PtArrayIndexer -> {
|
||||
if(!what.index.isSimple()) asmgen.out(" php") // save Carry
|
||||
@@ -642,27 +642,27 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
when(fcall.args[0]) {
|
||||
is PtIdentifier -> {
|
||||
val varname = asmgen.asmVariableName(fcall.args[0] as PtIdentifier) + if(msb) "+1" else ""
|
||||
target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, variableAsmName = varname)
|
||||
target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, variableAsmName = varname)
|
||||
}
|
||||
is PtNumber -> {
|
||||
val num = (fcall.args[0] as PtNumber).number + if(msb) 1 else 0
|
||||
val mem = PtMemoryByte(fcall.position)
|
||||
mem.add(PtNumber(DataType.UBYTE, num, fcall.position))
|
||||
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, memory = mem)
|
||||
mem.add(PtNumber(BaseDataType.UBYTE, num, fcall.position))
|
||||
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem)
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
val mem = PtMemoryByte(fcall.position)
|
||||
if((fcall.args[0] as PtAddressOf).isFromArrayElement)
|
||||
TODO("address-of arrayelement")
|
||||
if(msb) {
|
||||
val address = PtBinaryExpression("+", DataType.UWORD, fcall.args[0].position)
|
||||
val address = PtBinaryExpression("+", DataType.forDt(BaseDataType.UWORD), fcall.args[0].position)
|
||||
address.add(fcall.args[0])
|
||||
address.add(PtNumber(address.type, 1.0, fcall.args[0].position))
|
||||
address.add(PtNumber(address.type.base, 1.0, fcall.args[0].position))
|
||||
mem.add(address)
|
||||
} else {
|
||||
mem.add(fcall.args[0])
|
||||
}
|
||||
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, memory = mem)
|
||||
target = AsmAssignTarget(TargetStorageKind.MEMORY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, memory = mem)
|
||||
}
|
||||
is PtArrayIndexer -> {
|
||||
val indexer = fcall.args[0] as PtArrayIndexer
|
||||
@@ -670,7 +670,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val msbAdd: Int
|
||||
if(indexer.splitWords) {
|
||||
val arrayVariable = indexer.variable
|
||||
indexer.children[0] = PtIdentifier(arrayVariable.name + if(msb) "_msb" else "_lsb", DataType.ARRAY_UB, arrayVariable.position)
|
||||
indexer.children[0] = PtIdentifier(arrayVariable.name + if(msb) "_msb" else "_lsb", DataType.arrayFor(BaseDataType.UBYTE), arrayVariable.position)
|
||||
indexer.children[0].parent = indexer
|
||||
elementSize = 1
|
||||
msbAdd = 0
|
||||
@@ -682,7 +682,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
// double the index because of word array (if not split), add one if msb (if not split)
|
||||
val constIndexNum = (indexer.index as? PtNumber)?.number
|
||||
if(constIndexNum!=null) {
|
||||
indexer.children[1] = PtNumber(indexer.index.type, constIndexNum*elementSize + msbAdd, indexer.position)
|
||||
indexer.children[1] = PtNumber(indexer.index.type.base, constIndexNum*elementSize + msbAdd, indexer.position)
|
||||
indexer.children[1].parent = indexer
|
||||
} else {
|
||||
val multipliedIndex: PtExpression
|
||||
@@ -691,12 +691,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
} else {
|
||||
multipliedIndex = PtBinaryExpression("<<", indexer.index.type, indexer.position)
|
||||
multipliedIndex.add(indexer.index)
|
||||
multipliedIndex.add(PtNumber(DataType.UBYTE, 1.0, indexer.position))
|
||||
multipliedIndex.add(PtNumber(BaseDataType.UBYTE, 1.0, indexer.position))
|
||||
}
|
||||
if(msbAdd>0) {
|
||||
val msbIndex = PtBinaryExpression("+", indexer.index.type, indexer.position)
|
||||
msbIndex.add(multipliedIndex)
|
||||
msbIndex.add(PtNumber(DataType.UBYTE, msbAdd.toDouble(), indexer.position))
|
||||
msbIndex.add(PtNumber(BaseDataType.UBYTE, msbAdd.toDouble(), indexer.position))
|
||||
indexer.children[1] = msbIndex
|
||||
msbIndex.parent = indexer
|
||||
} else {
|
||||
@@ -704,7 +704,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
multipliedIndex.parent=indexer
|
||||
}
|
||||
}
|
||||
target = AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, DataType.UBYTE, fcall.definingSub(), fcall.position, array = indexer)
|
||||
target = AsmAssignTarget(TargetStorageKind.ARRAY, asmgen, DataType.forDt(BaseDataType.UBYTE), fcall.definingSub(), fcall.position, array = indexer)
|
||||
}
|
||||
else -> throw AssemblyError("setlsb/setmsb on weird target ${fcall.args[0]}")
|
||||
}
|
||||
@@ -719,12 +719,12 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
translateArguments(fcall, scope)
|
||||
when (val dt = fcall.args.single().type) {
|
||||
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
|
||||
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
|
||||
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
|
||||
DataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
|
||||
DataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
|
||||
when (val dt = fcall.args.single().type.base) {
|
||||
BaseDataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
|
||||
BaseDataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
|
||||
BaseDataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
|
||||
BaseDataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
|
||||
BaseDataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, true, true)
|
||||
@@ -732,24 +732,24 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcAbs(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
translateArguments(fcall, scope)
|
||||
val dt = fcall.args.single().type
|
||||
val dt = fcall.args.single().type.base
|
||||
when (dt) {
|
||||
DataType.BYTE -> {
|
||||
BaseDataType.BYTE -> {
|
||||
asmgen.out(" jsr prog8_lib.abs_b_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A,false, true)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
BaseDataType.WORD -> {
|
||||
asmgen.out(" jsr prog8_lib.abs_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
|
||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
BaseDataType.UBYTE -> {
|
||||
asmgen.assignRegister(RegisterOrPair.A, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.A, false, fcall.position, scope, asmgen))
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
asmgen.assignRegister(RegisterOrPair.AY, AsmAssignTarget.fromRegisters(resultRegister?:RegisterOrPair.AY, false, fcall.position, scope, asmgen))
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
@@ -775,8 +775,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.assignConstFloatToPointerAY(number)
|
||||
}
|
||||
else -> {
|
||||
val tempvar = asmgen.getTempVarName(DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(fcall.args[1], tempvar, DataType.FLOAT)
|
||||
val tempvar = asmgen.getTempVarName(BaseDataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(fcall.args[1], tempvar, DataType.forDt(BaseDataType.FLOAT))
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
pha
|
||||
@@ -851,7 +851,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" jsr floats.MOVFM")
|
||||
if(resultRegister!=null) {
|
||||
assignAsmGen.assignFAC1float(
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, fcall.definingISub(), fcall.position, null, null, null, resultRegister, null))
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.FLOAT), fcall.definingISub(), fcall.position, null, null, null, resultRegister, null))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,9 +919,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun funcClamp(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
val signed = fcall.type in SignedDatatypes
|
||||
when(fcall.type) {
|
||||
in ByteDatatypes -> {
|
||||
val signed = fcall.type.isSigned
|
||||
when {
|
||||
fcall.type.isByte -> {
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value
|
||||
@@ -929,7 +929,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||
assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed, true)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
fcall.type.isWord -> {
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value
|
||||
@@ -942,9 +942,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun funcMin(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
val signed = fcall.type in SignedDatatypes
|
||||
when (fcall.type) {
|
||||
in ByteDatatypes -> {
|
||||
val signed = fcall.type.isSigned
|
||||
when {
|
||||
fcall.type.isByte -> {
|
||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_B1", fcall.type) // right
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A) // left
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
@@ -955,7 +955,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
fcall.type.isWord -> {
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
||||
if(signed) {
|
||||
@@ -1000,8 +1000,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun funcMax(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
val signed = fcall.type in SignedDatatypes
|
||||
if(fcall.type in ByteDatatypes) {
|
||||
val signed = fcall.type.isSigned
|
||||
if(fcall.type.isByte) {
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_B1", fcall.type) // left
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // right
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
@@ -1011,7 +1011,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
+""")
|
||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||
asmgen.assignRegister(RegisterOrPair.A, targetReg)
|
||||
} else if(fcall.type in WordDatatypes) {
|
||||
} else if(fcall.type.isWord) {
|
||||
asmgen.assignExpressionToVariable(fcall.args[0], "P8ZP_SCRATCH_W1", fcall.type) // left
|
||||
asmgen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W2", fcall.type) // right
|
||||
if(signed) {
|
||||
@@ -1102,7 +1102,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
val arg = fcall.args.single()
|
||||
if (arg.type !in WordDatatypes)
|
||||
if (!arg.type.isWord)
|
||||
throw AssemblyError("msb required word argument")
|
||||
if (arg is PtNumber)
|
||||
throw AssemblyError("msb(const) should have been const-folded away")
|
||||
@@ -1201,7 +1201,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
|
||||
val arg = fcall.args.single()
|
||||
if (arg.type !in WordDatatypes)
|
||||
if (!arg.type.isWord)
|
||||
throw AssemblyError("lsb required word argument")
|
||||
if (arg is PtNumber)
|
||||
throw AssemblyError("lsb(const) should have been const-folded away")
|
||||
@@ -1284,7 +1284,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun translateArguments(call: PtBuiltinFunctionCall, scope: IPtSubroutine?) {
|
||||
val signature = BuiltinFunctions.getValue(call.name)
|
||||
val callConv = signature.callConvention(call.args.map { it.type})
|
||||
val callConv = signature.callConvention(call.args.map {
|
||||
require(it.type.isNumericOrBool)
|
||||
it.type.base
|
||||
})
|
||||
|
||||
fun getSourceForFloat(value: PtExpression): AsmAssignSource {
|
||||
return when (value) {
|
||||
@@ -1302,11 +1305,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
throw AssemblyError("cannot use float arguments outside of a subroutine scope")
|
||||
|
||||
asmgen.subroutineExtra(scope).usedFloatEvalResultVar2 = true
|
||||
val variable = PtIdentifier(subroutineFloatEvalResultVar2, DataType.FLOAT, value.position)
|
||||
val variable = PtIdentifier(subroutineFloatEvalResultVar2, DataType.forDt(BaseDataType.FLOAT), value.position)
|
||||
val addr = PtAddressOf(value.position)
|
||||
addr.add(variable)
|
||||
addr.parent = call
|
||||
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(value, asmgen.asmVariableName(variable), DataType.forDt(BaseDataType.FLOAT))
|
||||
AsmAssignSource.fromAstSource(addr, program, asmgen)
|
||||
}
|
||||
}
|
||||
@@ -1319,9 +1322,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
when {
|
||||
conv.variable -> {
|
||||
val varname = "prog8_lib.func_${call.name}._arg_${paramName}"
|
||||
val src = when (conv.dt) {
|
||||
DataType.FLOAT -> getSourceForFloat(value)
|
||||
in PassByReferenceDatatypes -> {
|
||||
val src = when {
|
||||
conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value)
|
||||
conv.dt.isPassByRef -> {
|
||||
// put the address of the argument in AY
|
||||
val addr = PtAddressOf(value.position)
|
||||
addr.add(value)
|
||||
@@ -1332,14 +1335,14 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
AsmAssignSource.fromAstSource(value, program, asmgen)
|
||||
}
|
||||
}
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, conv.dt, null, value.position, variableAsmName = varname)
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(conv.dt), null, value.position, variableAsmName = varname)
|
||||
val assign = AsmAssignment(src, tgt, program.memsizer, value.position)
|
||||
asmgen.translateNormalAssignment(assign, scope)
|
||||
}
|
||||
conv.reg != null -> {
|
||||
val src = when (conv.dt) {
|
||||
DataType.FLOAT -> getSourceForFloat(value)
|
||||
in PassByReferenceDatatypes -> {
|
||||
val src = when {
|
||||
conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value)
|
||||
conv.dt.isPassByRef -> {
|
||||
// put the address of the argument in AY
|
||||
val addr = PtAddressOf(value.position)
|
||||
addr.add(value)
|
||||
|
||||
@@ -3,7 +3,9 @@ package prog8.codegen.cpu6502
|
||||
import prog8.code.ast.IPtSubroutine
|
||||
import prog8.code.ast.PtAsmSub
|
||||
import prog8.code.ast.PtSub
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.RegisterOrPair
|
||||
import prog8.code.core.RegisterOrStatusflag
|
||||
|
||||
|
||||
internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, DataType>> {
|
||||
@@ -16,10 +18,10 @@ internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, D
|
||||
return if(returntype==null)
|
||||
emptyList()
|
||||
else {
|
||||
val register = when (returntype!!) {
|
||||
in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
|
||||
in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
|
||||
val register = when {
|
||||
returntype!!.isByteOrBool -> RegisterOrStatusflag(RegisterOrPair.A, null)
|
||||
returntype!!.isWord -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
returntype!!.isFloat -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
|
||||
else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
}
|
||||
listOf(Pair(register, returntype!!))
|
||||
@@ -30,11 +32,11 @@ internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, D
|
||||
|
||||
|
||||
internal fun PtSub.returnRegister(): RegisterOrStatusflag? {
|
||||
return when(returntype) {
|
||||
in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
|
||||
in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
|
||||
null -> null
|
||||
return when {
|
||||
returntype?.isByteOrBool==true -> RegisterOrStatusflag(RegisterOrPair.A, null)
|
||||
returntype?.isWord==true -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
returntype?.isFloat==true -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
|
||||
returntype==null -> null
|
||||
else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ internal class ForLoopsAsmGen(
|
||||
throw AssemblyError("for unsigned loop variable it's not possible to count down with step != -1 from a non-const value to exactly zero due to value wrapping")
|
||||
}
|
||||
|
||||
when(iterableDt) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||
when {
|
||||
iterableDt.isByteArray -> {
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.assignExpressionToVariable(range.from, varname, iterableDt.elementType())
|
||||
if (stepsize==-1 && range.to.asConstInteger()==0) {
|
||||
// simple loop downto 0 step -1
|
||||
asmgen.out(loopLabel)
|
||||
@@ -75,7 +75,7 @@ internal class ForLoopsAsmGen(
|
||||
// loop over byte range via loopvar
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_B) {
|
||||
if(iterableDt.isSignedByteArray) {
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
if(stepsize<0) {
|
||||
asmgen.out("""
|
||||
@@ -121,7 +121,7 @@ $modifiedLabel cmp #0 ; modified
|
||||
// loop over byte range via loopvar
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_B) {
|
||||
if(iterableDt.isSignedByteArray) {
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
@@ -171,7 +171,7 @@ $modifiedLabel cmp #0 ; modified
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
iterableDt.isWordArray && !iterableDt.isSplitWordArray -> {
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
assignLoopvarWord(stmt, range)
|
||||
if(stepsize==-1 && range.to.asConstInteger()==0) {
|
||||
@@ -249,7 +249,7 @@ $modifiedLabel2 cmp #0 ; modified
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.statements)
|
||||
|
||||
if (iterableDt == DataType.ARRAY_UW) {
|
||||
if (iterableDt.isUnsignedWordArray) {
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
clc
|
||||
@@ -324,7 +324,7 @@ $endLabel""")
|
||||
private fun precheckFromToWord(iterableDt: DataType, stepsize: Int, fromVar: String, endLabel: String) {
|
||||
// pre-check for end already reached.
|
||||
// 'to' is in AY, do NOT clobber this!
|
||||
if(iterableDt==DataType.ARRAY_W) {
|
||||
if(iterableDt.isSignedWordArray) {
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_W2 ; to
|
||||
@@ -381,8 +381,8 @@ $endLabel""")
|
||||
is StMemVar -> symbol.length!!
|
||||
else -> 0
|
||||
}
|
||||
when(iterableDt) {
|
||||
DataType.STR -> {
|
||||
when {
|
||||
iterableDt.isString -> {
|
||||
asmgen.out("""
|
||||
lda #<$iterableName
|
||||
ldy #>$iterableName
|
||||
@@ -399,7 +399,7 @@ $loopLabel lda ${65535.toHex()} ; modified
|
||||
bne $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
|
||||
iterableDt.isByteArray || iterableDt.isBoolArray -> {
|
||||
val indexVar = asmgen.makeLabel("for_index")
|
||||
asmgen.out("""
|
||||
ldy #0
|
||||
@@ -424,7 +424,7 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
if(numElements>=16) {
|
||||
// allocate index var on ZP if possible
|
||||
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
|
||||
val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors)
|
||||
result.fold(
|
||||
success = { (address, _, _)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
@@ -434,7 +434,45 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
iterableDt.isSplitWordArray -> {
|
||||
val indexVar = asmgen.makeLabel("for_index")
|
||||
val loopvarName = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.out("""
|
||||
ldy #0
|
||||
$loopLabel sty $indexVar
|
||||
lda ${iterableName}_lsb,y
|
||||
sta $loopvarName
|
||||
lda ${iterableName}_msb,y
|
||||
sta $loopvarName+1""")
|
||||
asmgen.translate(stmt.statements)
|
||||
if(numElements<=255) {
|
||||
asmgen.out("""
|
||||
ldy $indexVar
|
||||
iny
|
||||
cpy #$numElements
|
||||
beq $endLabel
|
||||
bne $loopLabel""")
|
||||
} else {
|
||||
// length is 256
|
||||
asmgen.out("""
|
||||
ldy $indexVar
|
||||
iny
|
||||
bne $loopLabel
|
||||
beq $endLabel""")
|
||||
}
|
||||
if(numElements>=16) {
|
||||
// allocate index var on ZP if possible
|
||||
val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors)
|
||||
result.fold(
|
||||
success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
)
|
||||
} else {
|
||||
asmgen.out("$indexVar .byte 0")
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
iterableDt.isWordArray -> {
|
||||
val length = numElements * 2
|
||||
val indexVar = asmgen.makeLabel("for_index")
|
||||
val loopvarName = asmgen.asmVariableName(stmt.variable)
|
||||
@@ -465,7 +503,7 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
if(length>=16) {
|
||||
// allocate index var on ZP if possible
|
||||
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
|
||||
val result = zeropage.allocate(indexVar, DataType.forDt(BaseDataType.UBYTE), null, stmt.position, asmgen.errors)
|
||||
result.fold(
|
||||
success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
@@ -475,45 +513,7 @@ $loopLabel sty $indexVar
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> {
|
||||
val indexVar = asmgen.makeLabel("for_index")
|
||||
val loopvarName = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.out("""
|
||||
ldy #0
|
||||
$loopLabel sty $indexVar
|
||||
lda ${iterableName}_lsb,y
|
||||
sta $loopvarName
|
||||
lda ${iterableName}_msb,y
|
||||
sta $loopvarName+1""")
|
||||
asmgen.translate(stmt.statements)
|
||||
if(numElements<=255) {
|
||||
asmgen.out("""
|
||||
ldy $indexVar
|
||||
iny
|
||||
cpy #$numElements
|
||||
beq $endLabel
|
||||
bne $loopLabel""")
|
||||
} else {
|
||||
// length is 256
|
||||
asmgen.out("""
|
||||
ldy $indexVar
|
||||
iny
|
||||
bne $loopLabel
|
||||
beq $endLabel""")
|
||||
}
|
||||
if(numElements>=16) {
|
||||
// allocate index var on ZP if possible
|
||||
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
|
||||
result.fold(
|
||||
success = { (address,_,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
|
||||
failure = { asmgen.out("$indexVar .byte 0") }
|
||||
)
|
||||
} else {
|
||||
asmgen.out("$indexVar .byte 0")
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
iterableDt.isFloatArray -> {
|
||||
throw AssemblyError("for loop with floating point variables is not supported")
|
||||
}
|
||||
else -> throw AssemblyError("can't iterate over $iterableDt")
|
||||
@@ -524,12 +524,12 @@ $loopLabel sty $indexVar
|
||||
private fun translateForOverConstRange(stmt: PtForLoop, iterableDt: DataType, range: IntProgression) {
|
||||
if (range.isEmpty() || range.step==0)
|
||||
throw AssemblyError("empty range or step 0")
|
||||
if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
|
||||
if(iterableDt.isByteArray) {
|
||||
if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range)
|
||||
if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
|
||||
if(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range, iterableDt==DataType.ARRAY_UB)
|
||||
if(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range, iterableDt.isUnsignedByteArray)
|
||||
}
|
||||
else if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
|
||||
else if(iterableDt.isWordArray) {
|
||||
if(range.last==range.first) return translateForSimpleWordRangeAsc(stmt, range)
|
||||
if(range.step==1 && range.last>range.first) return translateForSimpleWordRangeAsc(stmt, range)
|
||||
if(range.step==-1 && range.last<range.first) return translateForSimpleWordRangeDesc(stmt, range)
|
||||
@@ -539,8 +539,8 @@ $loopLabel sty $indexVar
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
asmgen.loopEndLabels.add(endLabel)
|
||||
when(iterableDt) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||
when {
|
||||
iterableDt.isByteArray -> {
|
||||
// loop over byte range via loopvar, step >= 2 or <= -2
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.out("""
|
||||
@@ -605,7 +605,7 @@ $loopLabel""")
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
iterableDt.isWordArray && !iterableDt.isSplitWordArray -> {
|
||||
// loop over word range via loopvar, step >= 2 or <= -2
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
when (range.step) {
|
||||
|
||||
@@ -17,8 +17,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
|
||||
internal fun optimizeIntArgsViaCpuRegisters(params: List<PtSubroutineParameter>) =
|
||||
when(params.size) {
|
||||
1 -> params[0].type in IntegerDatatypesWithBoolean
|
||||
2 -> params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean
|
||||
1 -> params[0].type.isIntegerOrBool
|
||||
2 -> params[0].type.isByteOrBool && params[1].type.isByteOrBool
|
||||
else -> false
|
||||
}
|
||||
|
||||
@@ -153,11 +153,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
val params = sub.parameters
|
||||
when(params.size) {
|
||||
1 -> {
|
||||
val register = if (params[0].type in ByteDatatypesWithBoolean) RegisterOrPair.A else RegisterOrPair.AY
|
||||
val register = if (params[0].type.isByteOrBool) RegisterOrPair.A else RegisterOrPair.AY
|
||||
argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], register)
|
||||
}
|
||||
2 -> {
|
||||
if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) {
|
||||
if(params[0].type.isByteOrBool && params[1].type.isByteOrBool) {
|
||||
// 2 byte params, second in Y, first in A
|
||||
argumentViaRegister(sub, IndexedValue(0, params[0]), args[0], RegisterOrPair.A)
|
||||
if(asmgen.needAsaveForExpr(args[1]))
|
||||
@@ -259,7 +259,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
val register = paramRegister.registerOrPair
|
||||
val requiredDt = parameter.value.type
|
||||
if(requiredDt!=value.type) {
|
||||
if(value.type largerThan requiredDt)
|
||||
if(value.type.largerSizeThan(requiredDt))
|
||||
throw AssemblyError("can only convert byte values to word param types")
|
||||
}
|
||||
if (statusflag!=null) {
|
||||
@@ -298,21 +298,20 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
else {
|
||||
// via register or register pair
|
||||
register!!
|
||||
if(requiredDt largerThan value.type) {
|
||||
if(requiredDt.largerSizeThan(value.type)) {
|
||||
// we need to sign extend the source, do this via temporary word variable
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE)
|
||||
asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type.base)
|
||||
asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, null, Position.DUMMY)
|
||||
} else {
|
||||
val scope = value.definingISub()
|
||||
val target: AsmAssignTarget =
|
||||
if(parameter.value.type in ByteDatatypes && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters))
|
||||
if(parameter.value.type.isByte && (register==RegisterOrPair.AX || register == RegisterOrPair.AY || register==RegisterOrPair.XY || register in Cx16VirtualRegisters))
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, parameter.value.type, scope, value.position, register = register)
|
||||
else {
|
||||
val signed = parameter.value.type == DataType.BYTE || parameter.value.type == DataType.WORD
|
||||
AsmAssignTarget.fromRegisters(register, signed, value.position, scope, asmgen)
|
||||
AsmAssignTarget.fromRegisters(register, parameter.value.type.isSigned, value.position, scope, asmgen)
|
||||
}
|
||||
val src = if(value.type in PassByReferenceDatatypes) {
|
||||
val src = if(value.type.isPassByRef) {
|
||||
if(value is PtIdentifier) {
|
||||
val addr = PtAddressOf(Position.DUMMY)
|
||||
addr.add(value)
|
||||
@@ -333,18 +332,18 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
private fun isArgumentTypeCompatible(argType: DataType, paramType: DataType): Boolean {
|
||||
if(argType isAssignableTo paramType)
|
||||
return true
|
||||
if(argType==DataType.BOOL && paramType==DataType.BOOL)
|
||||
if(argType.isBool && paramType.isBool)
|
||||
return true
|
||||
if(argType in ByteDatatypes && paramType in ByteDatatypes)
|
||||
if(argType.isByte && paramType.isByte)
|
||||
return true
|
||||
if(argType in WordDatatypes && paramType in WordDatatypes)
|
||||
if(argType.isWord && paramType.isWord)
|
||||
return true
|
||||
|
||||
// we have a special rule for some types.
|
||||
// strings are assignable to UWORD, for example, and vice versa
|
||||
if(argType==DataType.STR && paramType==DataType.UWORD)
|
||||
if(argType.isString && paramType.isUnsignedWord)
|
||||
return true
|
||||
if(argType==DataType.UWORD && paramType == DataType.STR)
|
||||
if(argType.isUnsignedWord && paramType.isString)
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
@@ -16,7 +16,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
private val errors: IErrorReporter) {
|
||||
|
||||
fun translate(stmt: PtIfElse) {
|
||||
require(stmt.condition.type== DataType.BOOL)
|
||||
require(stmt.condition.type.isBool)
|
||||
checkNotExtsubReturnsStatusReg(stmt.condition)
|
||||
|
||||
val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump
|
||||
@@ -33,10 +33,11 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
|
||||
val compareCond = stmt.condition as? PtBinaryExpression
|
||||
if(compareCond!=null) {
|
||||
return when(compareCond.right.type) {
|
||||
in ByteDatatypesWithBoolean -> translateIfByte(stmt, jumpAfterIf)
|
||||
in WordDatatypes -> translateIfWord(stmt, compareCond, jumpAfterIf)
|
||||
DataType.FLOAT -> translateIfFloat(stmt, compareCond, jumpAfterIf)
|
||||
val rightDt = compareCond.right.type
|
||||
return when {
|
||||
rightDt.isByteOrBool -> translateIfByte(stmt, jumpAfterIf)
|
||||
rightDt.isWord -> translateIfWord(stmt, compareCond, jumpAfterIf)
|
||||
rightDt.isFloat -> translateIfFloat(stmt, compareCond, jumpAfterIf)
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
@@ -64,8 +65,8 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
val falseLabel = asmgen.makeLabel("ifexpr_false")
|
||||
val endLabel = asmgen.makeLabel("ifexpr_end")
|
||||
evalIfExpressionConditonAndBranchWhenFalse(expr.condition, falseLabel)
|
||||
when(expr.type) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
when {
|
||||
expr.type.isByteOrBool -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
@@ -73,7 +74,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
expr.type.isWord -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
@@ -81,7 +82,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
asmgen.out(endLabel)
|
||||
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
expr.type.isFloat -> {
|
||||
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
|
||||
asmgen.jmp(endLabel)
|
||||
asmgen.out(falseLabel)
|
||||
@@ -95,10 +96,11 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun evalIfExpressionConditonAndBranchWhenFalse(condition: PtExpression, falseLabel: String) {
|
||||
if (condition is PtBinaryExpression) {
|
||||
return when(condition.right.type) {
|
||||
in ByteDatatypesWithBoolean -> translateIfExpressionByteConditionBranch(condition, falseLabel)
|
||||
in WordDatatypes -> translateIfExpressionWordConditionBranch(condition, falseLabel)
|
||||
DataType.FLOAT -> translateIfExpressionFloatConditionBranch(condition, falseLabel)
|
||||
val rightDt = condition.right.type
|
||||
return when {
|
||||
rightDt.isByteOrBool -> translateIfExpressionByteConditionBranch(condition, falseLabel)
|
||||
rightDt.isWord -> translateIfExpressionWordConditionBranch(condition, falseLabel)
|
||||
rightDt.isFloat -> translateIfExpressionFloatConditionBranch(condition, falseLabel)
|
||||
else -> throw AssemblyError("weird dt")
|
||||
}
|
||||
}
|
||||
@@ -138,7 +140,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun checkNotExtsubReturnsStatusReg(condition: PtExpression) {
|
||||
val fcall = condition as? PtFunctionCall
|
||||
if(fcall!=null && fcall.type==DataType.BOOL) {
|
||||
if(fcall!=null && fcall.type.isBool) {
|
||||
val extsub = st.lookup(fcall.name) as? StExtSub
|
||||
if(extsub!=null && extsub.returns.any { it.register.statusflag!=null }) {
|
||||
throw AssemblyError("if extsub() returning a status register boolean should have been changed into a Conditional branch such as if_cc")
|
||||
@@ -158,7 +160,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
is PtIfExpression,
|
||||
is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ }
|
||||
is PtTypeCast -> {
|
||||
if(condition.value.type !in ByteDatatypes && condition.value.type !in WordDatatypes)
|
||||
if(!condition.value.type.isByte && !condition.value.type.isWord)
|
||||
asmgen.out(" cmp #0")
|
||||
}
|
||||
else -> asmgen.out(" cmp #0")
|
||||
@@ -281,7 +283,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun translateIfByte(stmt: PtIfElse, jumpAfterIf: PtJump?) {
|
||||
val condition = stmt.condition as PtBinaryExpression
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
return translateIfCompareWithZeroByte(stmt, signed, jumpAfterIf)
|
||||
@@ -340,7 +342,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
in LogicalOperators -> {
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.BOOL, stmt.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), stmt.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) {
|
||||
if (jumpAfterIf != null)
|
||||
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
|
||||
@@ -360,7 +362,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun translateIfExpressionByteConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
return translateIfCompareWithZeroByteBranch(condition, signed, falseLabel)
|
||||
@@ -380,7 +382,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" beq $falseLabel")
|
||||
}
|
||||
in LogicalOperators -> {
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.BOOL, condition.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
val regAtarget = AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.BOOL), condition.definingISub(), condition.position, register=RegisterOrPair.A)
|
||||
if (assignmentAsmGen.optimizedLogicalExpr(condition, regAtarget)) {
|
||||
asmgen.out(" beq $falseLabel")
|
||||
} else {
|
||||
@@ -734,7 +736,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
is PtArrayIndexer -> {
|
||||
val constIndex = value.index.asConstInteger()
|
||||
if(constIndex!=null) {
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
if(offset<256) {
|
||||
return asmgen.out(" ldy #$offset | $compare ${asmgen.asmVariableName(value.variable)},y")
|
||||
}
|
||||
@@ -828,7 +830,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun translateIfWord(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) {
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
val constValue = condition.right.asConstInteger()
|
||||
if(constValue==0) {
|
||||
// optimized comparisons with zero
|
||||
@@ -1221,7 +1223,7 @@ _jump jmp ($asmLabel)
|
||||
if(value.splitWords) {
|
||||
return compareLsbMsb("${varname}_lsb+$constIndex", "${varname}_msb+$constIndex")
|
||||
} else {
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
return compareLsbMsb("$varname+$offset", "$varname+$offset+1")
|
||||
}
|
||||
} else {
|
||||
@@ -1358,7 +1360,7 @@ _jump jmp ($asmLabel)
|
||||
if(value.splitWords) {
|
||||
return compareLsbMsb("${varname}_lsb+$constIndex", "${varname}_msb+$constIndex")
|
||||
} else {
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
return compareLsbMsb("$varname+$offset", "$varname+$offset+1")
|
||||
}
|
||||
} else {
|
||||
@@ -1465,7 +1467,7 @@ _jump jmp ($asmLabel)
|
||||
if(value.splitWords) {
|
||||
return translateLoadFromVarSplitw(varName, constIndex, "bne", "beq")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
if (offset < 256) {
|
||||
return translateLoadFromVar("$varName+$offset", "bne", "beq")
|
||||
}
|
||||
@@ -1486,7 +1488,7 @@ _jump jmp ($asmLabel)
|
||||
if(value.splitWords) {
|
||||
return translateLoadFromVarSplitw(varName, constIndex, "beq", "bne")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(value.type)
|
||||
val offset = program.memsizer.memorySize(value.type, constIndex)
|
||||
if (offset < 256) {
|
||||
return translateLoadFromVar("$varName+$offset", "beq", "bne")
|
||||
}
|
||||
@@ -1841,7 +1843,7 @@ _jump jmp ($asmLabel)
|
||||
else
|
||||
translateAYEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
|
||||
}
|
||||
val offset = constIndex * program.memsizer.memorySize(left.type)
|
||||
val offset = program.memsizer.memorySize(left.type, constIndex)
|
||||
if(offset<256) {
|
||||
return if(notEquals)
|
||||
translateAYNotEquals("$varName+$offset", "$varName+$offset+1")
|
||||
@@ -2116,7 +2118,7 @@ _jump jmp ($asmLabel)
|
||||
is PtIdentifier -> equalf(asmgen.asmVariableName(left), asmgen.asmVariableName(right))
|
||||
is PtNumber -> equalf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
@@ -2126,7 +2128,7 @@ _jump jmp ($asmLabel)
|
||||
is PtIdentifier -> equalf(left, asmgen.asmVariableName(right))
|
||||
is PtNumber -> equalf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
equalf(left, subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
@@ -2161,7 +2163,7 @@ _jump jmp ($asmLabel)
|
||||
is PtIdentifier -> lessf(asmgen.asmVariableName(left), asmgen.asmVariableName(right))
|
||||
is PtNumber -> lessf(asmgen.asmVariableName(left), allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(asmgen.asmVariableName(left), subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
@@ -2171,7 +2173,7 @@ _jump jmp ($asmLabel)
|
||||
is PtIdentifier -> lessf(left, asmgen.asmVariableName(right))
|
||||
is PtNumber -> lessf(left, allocator.getFloatAsmConst(right.number))
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.forDt(BaseDataType.FLOAT))
|
||||
lessf(left, subroutineFloatEvalResultVar1)
|
||||
asmgen.subroutineExtra(left.definingISub()!!).usedFloatEvalResultVar1 = true
|
||||
}
|
||||
|
||||
@@ -198,12 +198,12 @@ internal class ProgramAndVarsGen(
|
||||
for(num in 1..count) {
|
||||
val name = asmgen.buildTempVarName(dt, num)
|
||||
when (dt) {
|
||||
DataType.BOOL -> asmgen.out("$name .byte ?")
|
||||
DataType.BYTE -> asmgen.out("$name .char ?")
|
||||
DataType.UBYTE -> asmgen.out("$name .byte ?")
|
||||
DataType.WORD -> asmgen.out("$name .sint ?")
|
||||
DataType.UWORD -> asmgen.out("$name .word ?")
|
||||
DataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
BaseDataType.BOOL -> asmgen.out("$name .byte ?")
|
||||
BaseDataType.BYTE -> asmgen.out("$name .char ?")
|
||||
BaseDataType.UBYTE -> asmgen.out("$name .byte ?")
|
||||
BaseDataType.WORD -> asmgen.out("$name .sint ?")
|
||||
BaseDataType.UWORD -> asmgen.out("$name .word ?")
|
||||
BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
else -> throw AssemblyError("weird dt for extravar $dt")
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ internal class ProgramAndVarsGen(
|
||||
1 -> {
|
||||
val dt = params[0].type
|
||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, dt, sub, params[0].position, variableAsmName = varname(params[0]))
|
||||
if(dt in ByteDatatypesWithBoolean)
|
||||
if(dt.isByteOrBool)
|
||||
asmgen.assignRegister(RegisterOrPair.A, target) // single byte in A
|
||||
else
|
||||
asmgen.assignRegister(RegisterOrPair.AY, target) // word in AY
|
||||
@@ -443,7 +443,7 @@ internal class ProgramAndVarsGen(
|
||||
2 -> {
|
||||
val target1 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[0].type, sub, params[0].position, variableAsmName = varname(params[0]))
|
||||
val target2 = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, params[1].type, sub, params[1].position, variableAsmName = varname(params[1]))
|
||||
if(params[0].type in ByteDatatypesWithBoolean && params[1].type in ByteDatatypesWithBoolean) {
|
||||
if(params[0].type.isByteOrBool && params[1].type.isByteOrBool) {
|
||||
// 2 byte args, first in A, second in Y
|
||||
asmgen.assignRegister(RegisterOrPair.A, target1)
|
||||
asmgen.assignRegister(RegisterOrPair.Y, target2)
|
||||
@@ -463,9 +463,9 @@ internal class ProgramAndVarsGen(
|
||||
if(addr!=null)
|
||||
asmgen.out("$name = $addr")
|
||||
else when(dt) {
|
||||
DataType.UBYTE -> asmgen.out("$name .byte ?")
|
||||
DataType.UWORD -> asmgen.out("$name .word ?")
|
||||
DataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
BaseDataType.UBYTE -> asmgen.out("$name .byte ?")
|
||||
BaseDataType.UWORD -> asmgen.out("$name .word ?")
|
||||
BaseDataType.FLOAT -> asmgen.out("$name .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
else -> throw AssemblyError("weird dt for extravar $dt")
|
||||
}
|
||||
}
|
||||
@@ -557,7 +557,7 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun getZpStringVarsWithInitvalue(): Collection<ZpStringWithInitial> {
|
||||
val result = mutableListOf<ZpStringWithInitial>()
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt.isString }
|
||||
for (variable in vars) {
|
||||
val scopedName = variable.key
|
||||
val svar = symboltable.lookup(scopedName) as? StStaticVariable
|
||||
@@ -569,7 +569,7 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun getZpArrayVarsWithInitvalue(): Collection<ZpArrayWithInitial> {
|
||||
val result = mutableListOf<ZpArrayWithInitial>()
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt.isArray }
|
||||
for (variable in vars) {
|
||||
val scopedName = variable.key
|
||||
val svar = symboltable.lookup(scopedName) as? StStaticVariable
|
||||
@@ -585,7 +585,7 @@ internal class ProgramAndVarsGen(
|
||||
if (scopedName.startsWith("cx16.r"))
|
||||
continue // The 16 virtual registers of the cx16 are not actual variables in zp, they're memory mapped
|
||||
val variable = symboltable.flat.getValue(scopedName) as StStaticVariable
|
||||
if(variable.dt in SplitWordArrayTypes) {
|
||||
if(variable.dt.isSplitWordArray) {
|
||||
val lsbAddr = zpvar.address
|
||||
val msbAddr = zpvar.address + (zpvar.size/2).toUInt()
|
||||
asmgen.out("${scopedName.substringAfterLast('.')}_lsb \t= $lsbAddr \t; zp ${zpvar.dt} (lsbs)")
|
||||
@@ -603,10 +603,10 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out("; non-zeropage variables")
|
||||
asmgen.out(" .section BSS")
|
||||
val (notAligned, aligned) = varsNoInit.partition { it.align==0 }
|
||||
notAligned.sortedWith(compareBy<StStaticVariable> { it.name }.thenBy { it.dt }).forEach {
|
||||
notAligned.sortedWith(compareBy<StStaticVariable> { it.name }.thenBy { it.dt.base }).forEach {
|
||||
uninitializedVariable2asm(it)
|
||||
}
|
||||
aligned.sortedWith(compareBy<StStaticVariable> { it.align }.thenBy { it.name }.thenBy { it.dt }).forEach {
|
||||
aligned.sortedWith(compareBy<StStaticVariable> { it.align }.thenBy { it.name }.thenBy { it.dt.base }).forEach {
|
||||
uninitializedVariable2asm(it)
|
||||
}
|
||||
asmgen.out(" .send BSS")
|
||||
@@ -614,7 +614,7 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
if(varsWithInit.isNotEmpty()) {
|
||||
asmgen.out("; non-zeropage variables with init value")
|
||||
val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt == DataType.STR }
|
||||
val (stringvars, othervars) = varsWithInit.sortedBy { it.name }.partition { it.dt.isString }
|
||||
val (notAlignedStrings, alignedStrings) = stringvars.partition { it.align==0 }
|
||||
val (notAlignedOther, alignedOther) = othervars.partition { it.align==0 }
|
||||
notAlignedStrings.forEach {
|
||||
@@ -644,19 +644,20 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
|
||||
private fun uninitializedVariable2asm(variable: StStaticVariable) {
|
||||
when (variable.dt) {
|
||||
DataType.BOOL, DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ?")
|
||||
DataType.BYTE -> asmgen.out("${variable.name}\t.char ?")
|
||||
DataType.UWORD -> asmgen.out("${variable.name}\t.word ?")
|
||||
DataType.WORD -> asmgen.out("${variable.name}\t.sint ?")
|
||||
DataType.FLOAT -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
in SplitWordArrayTypes -> {
|
||||
val dt = variable.dt
|
||||
when {
|
||||
dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ?")
|
||||
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.isFloat -> asmgen.out("${variable.name}\t.fill ${compTarget.machine.FLOAT_MEM_SIZE}")
|
||||
dt.isSplitWordArray -> {
|
||||
alignVar(variable.align)
|
||||
val numbytesPerHalf = compTarget.memorySize(variable.dt, variable.length!!) / 2
|
||||
asmgen.out("${variable.name}_lsb\t.fill $numbytesPerHalf")
|
||||
asmgen.out("${variable.name}_msb\t.fill $numbytesPerHalf")
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
dt.isArray -> {
|
||||
alignVar(variable.align)
|
||||
val numbytes = compTarget.memorySize(variable.dt, variable.length!!)
|
||||
asmgen.out("${variable.name}\t.fill $numbytes")
|
||||
@@ -675,18 +676,19 @@ internal class ProgramAndVarsGen(
|
||||
private fun staticVariable2asm(variable: StStaticVariable) {
|
||||
val initialValue: Number =
|
||||
if(variable.initializationNumericValue!=null) {
|
||||
if(variable.dt== DataType.FLOAT)
|
||||
if(variable.dt.isFloat)
|
||||
variable.initializationNumericValue!!
|
||||
else
|
||||
variable.initializationNumericValue!!.toInt()
|
||||
} else 0
|
||||
|
||||
when (variable.dt) {
|
||||
DataType.BOOL, DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}")
|
||||
DataType.BYTE -> asmgen.out("${variable.name}\t.char $initialValue")
|
||||
DataType.UWORD -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}")
|
||||
DataType.WORD -> asmgen.out("${variable.name}\t.sint $initialValue")
|
||||
DataType.FLOAT -> {
|
||||
val dt=variable.dt
|
||||
when {
|
||||
dt.isBool || dt.isUnsignedByte -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}")
|
||||
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.isFloat -> {
|
||||
if(initialValue==0) {
|
||||
asmgen.out("${variable.name}\t.byte 0,0,0,0,0 ; float")
|
||||
} else {
|
||||
@@ -694,10 +696,10 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out("${variable.name}\t.byte $floatFill ; float $initialValue")
|
||||
}
|
||||
}
|
||||
DataType.STR -> {
|
||||
dt.isString -> {
|
||||
throw AssemblyError("all string vars should have been interned into prog")
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
dt.isArray -> {
|
||||
arrayVariable2asm(variable.name, variable.dt, variable.align, variable.initializationArrayValue, variable.length)
|
||||
}
|
||||
else -> {
|
||||
@@ -708,8 +710,8 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun arrayVariable2asm(varname: String, dt: DataType, align: Int, value: StArray?, orNumberOfZeros: Int?) {
|
||||
alignVar(align)
|
||||
when(dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_BOOL -> {
|
||||
when {
|
||||
dt.isUnsignedByteArray || dt.isBoolArray -> {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
if (data.size <= 16)
|
||||
asmgen.out("$varname\t.byte ${data.joinToString()}")
|
||||
@@ -719,7 +721,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" .byte " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
dt.isSignedByteArray -> {
|
||||
val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros)
|
||||
if (data.size <= 16)
|
||||
asmgen.out("$varname\t.char ${data.joinToString()}")
|
||||
@@ -729,7 +731,20 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" .char " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
dt.isSplitWordArray -> {
|
||||
if(dt.elementType().isUnsignedWord) {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
asmgen.out("_array_$varname := ${data.joinToString()}")
|
||||
asmgen.out("${varname}_lsb\t.byte <_array_$varname")
|
||||
asmgen.out("${varname}_msb\t.byte >_array_$varname")
|
||||
} else {
|
||||
val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros)
|
||||
asmgen.out("_array_$varname := ${data.joinToString()}")
|
||||
asmgen.out("${varname}_lsb\t.byte <_array_$varname")
|
||||
asmgen.out("${varname}_msb\t.byte >_array_$varname")
|
||||
}
|
||||
}
|
||||
dt.isUnsignedWordArray -> {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
if (data.size <= 16)
|
||||
asmgen.out("$varname\t.word ${data.joinToString()}")
|
||||
@@ -739,7 +754,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" .word " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
dt.isSignedWordArray -> {
|
||||
val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros)
|
||||
if (data.size <= 16)
|
||||
asmgen.out("$varname\t.sint ${data.joinToString()}")
|
||||
@@ -749,19 +764,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" .sint " + chunk.joinToString())
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UW_SPLIT -> {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
asmgen.out("_array_$varname := ${data.joinToString()}")
|
||||
asmgen.out("${varname}_lsb\t.byte <_array_$varname")
|
||||
asmgen.out("${varname}_msb\t.byte >_array_$varname")
|
||||
}
|
||||
DataType.ARRAY_W_SPLIT -> {
|
||||
val data = makeArrayFillDataSigned(dt, value, orNumberOfZeros)
|
||||
asmgen.out("_array_$varname := ${data.joinToString()}")
|
||||
asmgen.out("${varname}_lsb\t.byte <_array_$varname")
|
||||
asmgen.out("${varname}_msb\t.byte >_array_$varname")
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
dt.isFloatArray -> {
|
||||
val array = value ?: zeroFilledArray(orNumberOfZeros!!)
|
||||
val floatFills = array.map {
|
||||
compTarget.machine.getFloatAsmBytes(it.number!!)
|
||||
@@ -787,7 +790,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out(" ${it.name} = ${it.address.toHex()}")
|
||||
}
|
||||
consts.sortedBy { it.name }.forEach {
|
||||
if(it.dt==DataType.FLOAT)
|
||||
if(it.dt==BaseDataType.FLOAT)
|
||||
asmgen.out(" ${it.name} = ${it.value}")
|
||||
else
|
||||
asmgen.out(" ${it.name} = ${it.value.toHex()}")
|
||||
@@ -818,8 +821,8 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun makeArrayFillDataUnsigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value ?: zeroFilledArray(orNumberOfZeros!!)
|
||||
return when (dt) {
|
||||
DataType.ARRAY_BOOL ->
|
||||
return when {
|
||||
dt.isBoolArray ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
if(it.boolean!=null)
|
||||
@@ -829,13 +832,13 @@ internal class ProgramAndVarsGen(
|
||||
if(number==0.0) "0" else "1"
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_UB ->
|
||||
dt.isUnsignedByteArray ->
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
array.map {
|
||||
val number = it.number!!.toInt()
|
||||
"$"+number.toString(16).padStart(2, '0')
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map {
|
||||
dt.isArray && dt.elementType().isUnsignedWord -> array.map {
|
||||
if(it.number!=null) {
|
||||
"$" + it.number!!.toInt().toString(16).padStart(4, '0')
|
||||
}
|
||||
@@ -851,14 +854,14 @@ internal class ProgramAndVarsGen(
|
||||
|
||||
private fun makeArrayFillDataSigned(dt: DataType, value: StArray?, orNumberOfZeros: Int?): List<String> {
|
||||
val array = value ?: zeroFilledArray(orNumberOfZeros!!)
|
||||
return when (dt) {
|
||||
return when {
|
||||
// byte array can never contain pointer-to types, so treat values as all integers
|
||||
DataType.ARRAY_UB ->
|
||||
dt.isUnsignedByteArray ->
|
||||
array.map {
|
||||
val number = it.number!!.toInt()
|
||||
"$"+number.toString(16).padStart(2, '0')
|
||||
}
|
||||
DataType.ARRAY_B ->
|
||||
dt.isSignedByteArray ->
|
||||
array.map {
|
||||
val number = it.number!!.toInt()
|
||||
val hexnum = number.absoluteValue.toString(16).padStart(2, '0')
|
||||
@@ -867,11 +870,11 @@ internal class ProgramAndVarsGen(
|
||||
else
|
||||
"-$$hexnum"
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT -> array.map {
|
||||
dt.isArray && dt.elementType().isUnsignedWord -> array.map {
|
||||
val number = it.number!!.toInt()
|
||||
"$" + number.toString(16).padStart(4, '0')
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_W_SPLIT -> array.map {
|
||||
dt.isArray && dt.elementType().isSignedWord -> array.map {
|
||||
val number = it.number!!.toInt()
|
||||
val hexnum = number.absoluteValue.toString(16).padStart(4, '0')
|
||||
if(number>=0)
|
||||
|
||||
@@ -91,7 +91,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
if(errors.noErrors()) {
|
||||
val sortedList = varsDontCareWithoutAlignment.sortedByDescending { it.scopedName }
|
||||
for (variable in sortedList) {
|
||||
if(variable.dt in IntegerDatatypesWithBoolean) {
|
||||
if(variable.dt.isIntegerOrBool) {
|
||||
if(zeropage.free.isEmpty()) {
|
||||
break
|
||||
} else {
|
||||
@@ -124,6 +124,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
}
|
||||
}
|
||||
collect(st)
|
||||
return vars.sortedBy { it.dt }
|
||||
return vars.sortedBy { it.dt.base }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,28 +17,28 @@ internal class AnyExprAsmGen(
|
||||
private val asmgen: AsmGen6502Internal
|
||||
) {
|
||||
fun assignAnyExpressionUsingStack(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||
when(expr.type) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
if(expr.left.type in ByteDatatypesWithBoolean && expr.right.type in ByteDatatypesWithBoolean)
|
||||
when {
|
||||
expr.type.isByteOrBool -> {
|
||||
if(expr.left.type.isByteOrBool && expr.right.type.isByteOrBool)
|
||||
return assignByteBinExpr(expr, assign)
|
||||
if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) {
|
||||
if (expr.left.type.isWord && expr.right.type.isWord) {
|
||||
require(expr.operator in ComparisonOperators)
|
||||
throw AssemblyError("words operands comparison -> byte, should have been handled elsewhere")
|
||||
}
|
||||
if (expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) {
|
||||
if (expr.left.type.isFloat && expr.right.type.isFloat) {
|
||||
require(expr.operator in ComparisonOperators)
|
||||
return assignFloatBinExpr(expr, assign)
|
||||
}
|
||||
throw AssemblyError("weird expr operand types: ${expr.left.type} and ${expr.right.type}")
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) {
|
||||
expr.type.isWord -> {
|
||||
require(expr.left.type.isWord && expr.right.type.isWord) {
|
||||
"both operands must be words"
|
||||
}
|
||||
throw AssemblyError("expression should have been handled otherwise: word ${expr.operator} at ${expr.position}")
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
require(expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) {
|
||||
expr.type.isFloat -> {
|
||||
require(expr.left.type.isFloat && expr.right.type.isFloat) {
|
||||
"both operands must be floats"
|
||||
}
|
||||
return assignFloatBinExpr(expr, assign)
|
||||
@@ -52,7 +52,7 @@ internal class AnyExprAsmGen(
|
||||
"+" -> {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.out(" pla | clc | adc P8ZP_SCRATCH_B1")
|
||||
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||
return true
|
||||
@@ -60,7 +60,7 @@ internal class AnyExprAsmGen(
|
||||
"-" -> {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.out(" pla | sec | sbc P8ZP_SCRATCH_B1")
|
||||
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||
return true
|
||||
@@ -75,7 +75,7 @@ internal class AnyExprAsmGen(
|
||||
"&" -> {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.out(" pla | and P8ZP_SCRATCH_B1")
|
||||
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||
return true
|
||||
@@ -83,7 +83,7 @@ internal class AnyExprAsmGen(
|
||||
"|" -> {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.out(" pla | ora P8ZP_SCRATCH_B1")
|
||||
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||
return true
|
||||
@@ -91,7 +91,7 @@ internal class AnyExprAsmGen(
|
||||
"^", "xor" -> {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
|
||||
asmgen.out(" pha")
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
asmgen.out(" pla | eor P8ZP_SCRATCH_B1")
|
||||
asmgen.assignRegister(RegisterOrPair.A, assign.target)
|
||||
return true
|
||||
@@ -197,7 +197,7 @@ internal class AnyExprAsmGen(
|
||||
private fun setupFloatComparisonFAC1vsVarAY(expr: PtBinaryExpression) {
|
||||
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.FAC1, true)
|
||||
if(!expr.right.isSimple()) asmgen.pushFAC1()
|
||||
asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.FLOAT)
|
||||
asmgen.assignExpressionToVariable(expr.right, "floats.floats_temp_var", DataType.forDt(BaseDataType.FLOAT))
|
||||
if(!expr.right.isSimple()) asmgen.popFAC1()
|
||||
asmgen.out(" lda #<floats.floats_temp_var | ldy #>floats.floats_temp_var")
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
}
|
||||
|
||||
init {
|
||||
if(register!=null && datatype !in NumericDatatypesWithBoolean)
|
||||
if(register!=null && !datatype.isNumericOrBool)
|
||||
throw AssemblyError("must be numeric type")
|
||||
}
|
||||
|
||||
@@ -77,12 +77,20 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
when(registers) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.BYTE else DataType.UBYTE, scope, pos, register = registers)
|
||||
RegisterOrPair.Y -> {
|
||||
val dt = DataType.forDt(if(signed) BaseDataType.BYTE else BaseDataType.UBYTE)
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
|
||||
}
|
||||
RegisterOrPair.AX,
|
||||
RegisterOrPair.AY,
|
||||
RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
|
||||
RegisterOrPair.XY -> {
|
||||
val dt = DataType.forDt(if(signed) BaseDataType.WORD else BaseDataType.UWORD)
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
|
||||
}
|
||||
RegisterOrPair.FAC1,
|
||||
RegisterOrPair.FAC2 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, pos, register = registers)
|
||||
RegisterOrPair.FAC2 -> {
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.FLOAT), scope, pos, register = registers)
|
||||
}
|
||||
RegisterOrPair.R0,
|
||||
RegisterOrPair.R1,
|
||||
RegisterOrPair.R2,
|
||||
@@ -98,7 +106,10 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
RegisterOrPair.R12,
|
||||
RegisterOrPair.R13,
|
||||
RegisterOrPair.R14,
|
||||
RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
|
||||
RegisterOrPair.R15 -> {
|
||||
val dt = DataType.forDt(if(signed) BaseDataType.WORD else BaseDataType.UWORD)
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +162,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv)
|
||||
val bv = value as? PtBool
|
||||
if(bv!=null)
|
||||
return AsmAssignSource(SourceStorageKind.LITERALBOOLEAN, program, asmgen, DataType.BOOL, boolean = bv)
|
||||
return AsmAssignSource(SourceStorageKind.LITERALBOOLEAN, program, asmgen, DataType.forDt(BaseDataType.BOOL), boolean = bv)
|
||||
|
||||
return when(value) {
|
||||
// checked above: is PtNumber -> throw AssemblyError("should have been constant value")
|
||||
@@ -163,7 +174,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}")
|
||||
val varName=asmgen.asmVariableName(value)
|
||||
// special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system
|
||||
if(value.type == DataType.UWORD && varName.lowercase().startsWith("cx16.r")) {
|
||||
if(value.type.isUnsignedWord && varName.lowercase().startsWith("cx16.r")) {
|
||||
val regStr = varName.lowercase().substring(5)
|
||||
val reg = RegisterOrPair.valueOf(regStr.uppercase())
|
||||
AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, value.type, register = reg)
|
||||
@@ -172,7 +183,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
}
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value)
|
||||
AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.forDt(BaseDataType.UBYTE), memory = value)
|
||||
}
|
||||
is PtArrayIndexer -> {
|
||||
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, value.type, array = value)
|
||||
@@ -202,9 +213,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
AsmAssignSource(kind, program, asmgen, newType, variableAsmName, array, memory, register, number, boolean, expression)
|
||||
|
||||
if(target.datatype!=datatype) {
|
||||
if(target.datatype in ByteDatatypes && datatype in ByteDatatypes) {
|
||||
if(target.datatype.isByte && datatype.isByte) {
|
||||
return withAdjustedDt(target.datatype)
|
||||
} else if(target.datatype in WordDatatypes && datatype in WordDatatypes) {
|
||||
} else if(target.datatype.isWord && datatype.isWord) {
|
||||
return withAdjustedDt(target.datatype)
|
||||
}
|
||||
}
|
||||
@@ -220,8 +231,9 @@ internal sealed class AsmAssignmentBase(val source: AsmAssignSource,
|
||||
val position: Position) {
|
||||
init {
|
||||
if(target.register !in arrayOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
|
||||
require(source.datatype != DataType.UNDEFINED) { "must not be placeholder/undefined datatype at $position" }
|
||||
require(memsizer.memorySize(source.datatype) <= memsizer.memorySize(target.datatype)) {
|
||||
require(!source.datatype.isUndefined) { "must not be placeholder/undefined datatype at $position" }
|
||||
if(!source.datatype.isArray && !target.datatype.isArray)
|
||||
require(memsizer.memorySize(source.datatype, null) <= memsizer.memorySize(target.datatype, null)) {
|
||||
"source dt size must be less or equal to target dt size at $position srcdt=${source.datatype} targetdt=${target.datatype}"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -58,20 +58,20 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
// the asm-gen code can deal with situations where you want to assign a byte into a word.
|
||||
// it will create the most optimized code to do this (so it type-extends for us).
|
||||
// But we can't deal with writing a word into a byte - explicit typeconversion should be done
|
||||
if(program.memsizer.memorySize(value.datatype) > program.memsizer.memorySize(target.datatype))
|
||||
if(program.memsizer.memorySize(value.datatype, null) > program.memsizer.memorySize(target.datatype, null))
|
||||
throw AssemblyError("missing type cast: value type > target type ${target.position}")
|
||||
|
||||
fun regName(v: AsmAssignSource) = "cx16.${v.register!!.name.lowercase()}"
|
||||
|
||||
when (target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
when (target.datatype) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(target.asmVarname, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype, operator, regName(value))
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(target.asmVarname, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(target.asmVarname, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
@@ -84,7 +84,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
target.datatype.isWord -> {
|
||||
val block = target.origAstTarget?.definingBlock()
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationWordWithLiteralval(target.asmVarname, target.datatype, operator, value.boolean!!.asInt(), block)
|
||||
@@ -104,7 +104,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
target.datatype.isFloat -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.boolean!!.asInt().toDouble())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.number!!.number)
|
||||
@@ -131,18 +131,18 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
is PtNumber -> {
|
||||
val addr = (memory.address as PtNumber).number.toInt()
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.UBYTE, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.UBYTE, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(addr.toHex(), DataType.UBYTE, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(addr.toHex(), DataType.UBYTE, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.array!!)
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(addr.toHex(), false, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
if(value.expression is PtTypeCast) {
|
||||
if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.expression)
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
} else {
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.UBYTE, operator, value.expression!!)
|
||||
inplacemodificationByteVariableWithValue(addr.toHex(), DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,21 +192,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
SourceStorageKind.MEMORY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.memory!!)
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.memory!!)
|
||||
asmgen.out(" ldx P8ZP_SCRATCH_B1")
|
||||
}
|
||||
SourceStorageKind.ARRAY -> {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_B1")
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.UBYTE, operator, value.array!!)
|
||||
inplacemodificationByteVariableWithValue("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), operator, value.array!!)
|
||||
asmgen.out(" ldx P8ZP_SCRATCH_B1")
|
||||
}
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
val tempVar = asmgen.getTempVarName(DataType.UBYTE)
|
||||
val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE)
|
||||
asmgen.out(" sta $tempVar")
|
||||
if(value.expression is PtTypeCast)
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.UBYTE, operator, value.expression)
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression)
|
||||
else
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.UBYTE, operator, value.expression!!)
|
||||
inplacemodificationByteVariableWithValue(tempVar, DataType.forDt(BaseDataType.UBYTE), operator, value.expression!!)
|
||||
asmgen.out(" ldx $tempVar")
|
||||
}
|
||||
}
|
||||
@@ -235,14 +235,14 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
return
|
||||
}
|
||||
// normal array
|
||||
val targetVarName = "${target.asmVarname} + ${index*program.memsizer.memorySize(target.datatype)}"
|
||||
when (target.datatype) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
val targetVarName = "${target.asmVarname} + ${index*program.memsizer.memorySize(target.datatype, null)}"
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationByteVariableWithLiteralval(targetVarName, target.datatype, operator, value.number!!.number.toInt())
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype, operator, regName(value))
|
||||
SourceStorageKind.VARIABLE -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, value.asmVarname)
|
||||
SourceStorageKind.REGISTER -> inplacemodificationByteVariableWithVariable(targetVarName, target.datatype.isSigned, operator, regName(value))
|
||||
SourceStorageKind.MEMORY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.memory!!)
|
||||
SourceStorageKind.ARRAY -> inplacemodificationByteVariableWithValue(targetVarName, target.datatype, operator, value.array!!)
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
@@ -256,7 +256,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
in WordDatatypes -> {
|
||||
target.datatype.isWord -> {
|
||||
val block = target.origAstTarget?.definingBlock()
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationWordWithLiteralval(targetVarName, target.datatype, operator, value.boolean!!.asInt(), block)
|
||||
@@ -276,7 +276,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
DataType.FLOAT -> {
|
||||
target.datatype.isFloat -> {
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.boolean!!.asInt().toDouble())
|
||||
SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.number!!.number)
|
||||
@@ -305,8 +305,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
&& tryIndexedIncDec(target.array, operator))
|
||||
return
|
||||
|
||||
when (target.datatype) {
|
||||
in ByteDatatypesWithBoolean -> {
|
||||
when {
|
||||
target.datatype.isByteOrBool -> {
|
||||
if(value.kind==SourceStorageKind.EXPRESSION
|
||||
&& value.expression is PtTypeCast
|
||||
&& tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
|
||||
@@ -316,21 +316,21 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" lda ${target.array.variable.name},y")
|
||||
when(value.kind) {
|
||||
SourceStorageKind.LITERALBOOLEAN -> {
|
||||
inplacemodificationRegisterAwithVariable(operator, "#${value.boolean!!.asInt()}", target.datatype in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariable(operator, "#${value.boolean!!.asInt()}", target.datatype.isSigned)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, true)
|
||||
}
|
||||
SourceStorageKind.LITERALNUMBER -> {
|
||||
inplacemodificationRegisterAwithVariable(operator, "#${value.number!!.number.toInt()}", target.datatype in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariable(operator, "#${value.number!!.number.toInt()}", target.datatype.isSigned)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, true)
|
||||
}
|
||||
|
||||
SourceStorageKind.VARIABLE -> {
|
||||
inplacemodificationRegisterAwithVariable(operator, value.asmVarname, target.datatype in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariable(operator, value.asmVarname, target.datatype.isSigned)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, true)
|
||||
}
|
||||
|
||||
SourceStorageKind.REGISTER -> {
|
||||
inplacemodificationRegisterAwithVariable(operator, regName(value), target.datatype in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariable(operator, regName(value), target.datatype.isSigned)
|
||||
asmgen.restoreRegisterStack(CpuRegister.Y, true)
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
val tempVar = asmgen.getTempVarName(DataType.UBYTE)
|
||||
val tempVar = asmgen.getTempVarName(BaseDataType.UBYTE)
|
||||
asmgen.out(" sta $tempVar")
|
||||
if(value.expression is PtTypeCast)
|
||||
inplacemodificationByteVariableWithValue(tempVar, target.datatype, operator, value.expression)
|
||||
@@ -362,7 +362,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta ${target.array.variable.name},y")
|
||||
}
|
||||
|
||||
in WordDatatypes -> {
|
||||
target.datatype.isWord -> {
|
||||
if(value.kind==SourceStorageKind.EXPRESSION
|
||||
&& value.expression is PtTypeCast
|
||||
&& tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator))
|
||||
@@ -399,7 +399,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
if(!inplacemodificationRegisterAXwithVariable(
|
||||
operator,
|
||||
value.asmVarname,
|
||||
value.datatype
|
||||
value.datatype.base
|
||||
)) {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
|
||||
inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, value.asmVarname, value.datatype, block)
|
||||
@@ -411,7 +411,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
if(!inplacemodificationRegisterAXwithVariable(
|
||||
operator,
|
||||
regName(value),
|
||||
value.datatype
|
||||
value.datatype.base
|
||||
)) {
|
||||
asmgen.out(" sta P8ZP_SCRATCH_W1 | stx P8ZP_SCRATCH_W1+1")
|
||||
inplacemodificationWordWithVariable("P8ZP_SCRATCH_W1", target.datatype, operator, regName(value), value.datatype, block)
|
||||
@@ -432,7 +432,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
SourceStorageKind.EXPRESSION -> {
|
||||
val tempVar = asmgen.getTempVarName(DataType.UWORD)
|
||||
val tempVar = asmgen.getTempVarName(BaseDataType.UWORD)
|
||||
asmgen.out(" sta $tempVar | stx $tempVar+1")
|
||||
if(value.expression is PtTypeCast)
|
||||
inplacemodificationWordWithValue(tempVar, target.datatype, operator, value.expression, block)
|
||||
@@ -448,9 +448,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" sta ${target.array.variable.name},y | txa | sta ${target.array.variable.name}+1,y")
|
||||
}
|
||||
|
||||
DataType.FLOAT -> {
|
||||
target.datatype.isFloat -> {
|
||||
// copy array value into tempvar
|
||||
val tempvar = asmgen.getTempVarName(DataType.FLOAT)
|
||||
val tempvar = asmgen.getTempVarName(BaseDataType.FLOAT)
|
||||
asmgen.loadScaledArrayIndexIntoRegister(target.array, CpuRegister.A)
|
||||
asmgen.out("""
|
||||
ldy #>${target.asmVarname}
|
||||
@@ -508,8 +508,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun tryIndexedIncDec(array: PtArrayIndexer, operator: String): Boolean {
|
||||
val arrayvar = asmgen.asmVariableName(array.variable)
|
||||
when (array.type) {
|
||||
in ByteDatatypes -> {
|
||||
when {
|
||||
array.type.isByte -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.X)
|
||||
if (operator == "+")
|
||||
asmgen.out(" inc $arrayvar,x")
|
||||
@@ -517,7 +517,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
asmgen.out(" dec $arrayvar,x")
|
||||
return true
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
array.type.isWord -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.X)
|
||||
if(array.splitWords) {
|
||||
if(operator=="+") {
|
||||
@@ -551,7 +551,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
return true
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
array.type.isFloat -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(array, CpuRegister.A)
|
||||
asmgen.out("""
|
||||
ldy #>$arrayvar
|
||||
@@ -568,7 +568,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun tryOptimizedMemoryInplace(address: PtBinaryExpression, operator: String, value: AsmAssignSource): Boolean {
|
||||
if(value.datatype !in ByteDatatypes || operator !in "|&^+-")
|
||||
if(!value.datatype.isByte || operator !in "|&^+-")
|
||||
return false
|
||||
|
||||
fun addrIntoZpPointer(): String {
|
||||
@@ -583,7 +583,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
|
||||
fun assignValueToA() {
|
||||
val assignValue = AsmAssignment(value,
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UBYTE,
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.forDt(BaseDataType.UBYTE),
|
||||
address.definingISub(), Position.DUMMY, register = RegisterOrPair.A),
|
||||
program.memsizer, Position.DUMMY)
|
||||
assignmentAsmGen.translateNormalAssignment(assignValue, address.definingISub()) // calculate value into A
|
||||
@@ -591,7 +591,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
|
||||
val rightTc = address.right as? PtTypeCast
|
||||
val constOffset = (address.right as? PtNumber)?.number?.toInt()
|
||||
if(address.operator=="+" && (address.right.type in ByteDatatypes || (rightTc!=null && rightTc.value.type in ByteDatatypes) || (constOffset!=null && constOffset<256)) ) {
|
||||
if(address.operator=="+" && (address.right.type.isByte || (rightTc!=null && rightTc.value.type.isByte) || (constOffset!=null && constOffset<256)) ) {
|
||||
if(constOffset!=null) {
|
||||
val zpPointerVarName = addrIntoZpPointer()
|
||||
if(value.number==null) assignValueToA()
|
||||
@@ -677,10 +677,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
inplacemodificationSomeWordWithLiteralval("${arrayVar}_lsb+$index", "${arrayVar}_msb+$index", dt, operator, value, null)
|
||||
}
|
||||
|
||||
private fun inplacemodificationRegisterAXwithVariable(operator: String, variable: String, varDt: DataType): Boolean {
|
||||
private fun inplacemodificationRegisterAXwithVariable(operator: String, variable: String, varDt: BaseDataType): Boolean {
|
||||
when(operator) {
|
||||
"+" -> {
|
||||
return if(varDt in WordDatatypes) {
|
||||
return if(varDt.isWord) {
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc $variable
|
||||
@@ -704,7 +704,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
"-" -> {
|
||||
return if(varDt in WordDatatypes) {
|
||||
return if(varDt.isWord) {
|
||||
asmgen.out("""
|
||||
sec
|
||||
sbc $variable
|
||||
@@ -882,7 +882,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
private fun tryInplaceModifyWithRemovedRedundantCast(value: PtTypeCast, target: AsmAssignTarget, operator: String): Boolean {
|
||||
if (target.datatype == value.type) {
|
||||
val childDt = value.value.type
|
||||
if (value.type!=DataType.FLOAT && (value.type.equalsSize(childDt) || value.type.largerThan(childDt))) {
|
||||
if (!value.type.isFloat && (value.type.equalsSize(childDt) || value.type.largerSizeThan(childDt))) {
|
||||
// this typecast is redundant here; the rest of the code knows how to deal with the uncasted value.
|
||||
// (works for integer types, not for float.)
|
||||
val src = AsmAssignSource.fromAstSource(value.value, program, asmgen)
|
||||
@@ -894,7 +894,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun inplacemodificationBytePointerWithValue(pointervar: PtIdentifier, operator: String, value: PtExpression) {
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.UBYTE)
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE))
|
||||
inplacemodificationBytePointerWithVariable(pointervar, operator, "P8ZP_SCRATCH_B1")
|
||||
}
|
||||
|
||||
@@ -1058,6 +1058,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
}
|
||||
|
||||
private fun inplacemodificationByteVariableWithValue(name: String, dt: DataType, operator: String, value: PtExpression) {
|
||||
require(dt.isByteOrBool)
|
||||
if(!value.isSimple()) {
|
||||
// attempt short-circuit (McCarthy) evaluation
|
||||
when (operator) {
|
||||
@@ -1065,7 +1066,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
|
||||
// short-circuit LEFT and RIGHT --> if LEFT then RIGHT else LEFT (== if !LEFT then LEFT else RIGHT)
|
||||
val shortcutLabel = asmgen.makeLabel("shortcut")
|
||||
asmgen.out(" lda $name | beq $shortcutLabel")
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes)
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned)
|
||||
asmgen.out("""
|
||||
and $name
|
||||
sta $name
|
||||
@@ -1076,7 +1077,7 @@ $shortcutLabel:""")
|
||||
// short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT
|
||||
val shortcutLabel = asmgen.makeLabel("shortcut")
|
||||
asmgen.out(" lda $name | bne $shortcutLabel")
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes)
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned)
|
||||
asmgen.out("""
|
||||
ora $name
|
||||
sta $name
|
||||
@@ -1089,25 +1090,25 @@ $shortcutLabel:""")
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
||||
if(operator=="&" && value is PtPrefix && value.operator=="~") {
|
||||
// M &= ~A --> use TRB 65c02 instruction for that
|
||||
asmgen.assignExpressionToRegister(value.value, RegisterOrPair.A, dt in SignedDatatypes)
|
||||
asmgen.assignExpressionToRegister(value.value, RegisterOrPair.A, dt.isSigned)
|
||||
asmgen.out(" trb $name")
|
||||
return
|
||||
}
|
||||
else if(operator=="|") {
|
||||
// M |= A --> use TSB 65c02 instruction for that
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes)
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned)
|
||||
asmgen.out(" tsb $name")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// normal evaluation
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt in SignedDatatypes)
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt.isSigned)
|
||||
inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt.isSigned)
|
||||
asmgen.out(" sta $name")
|
||||
}
|
||||
|
||||
private fun inplacemodificationByteVariableWithVariable(name: String, dt: DataType, operator: String, otherName: String) {
|
||||
private fun inplacemodificationByteVariableWithVariable(name: String, signed: Boolean, operator: String, otherName: String) {
|
||||
// note: no logical and/or shortcut here, not worth it due to simple right operand
|
||||
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
||||
@@ -1119,7 +1120,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
asmgen.out(" lda $name")
|
||||
inplacemodificationRegisterAwithVariable(operator, otherName, dt in SignedDatatypes)
|
||||
inplacemodificationRegisterAwithVariable(operator, otherName, signed)
|
||||
asmgen.out(" sta $name")
|
||||
}
|
||||
|
||||
@@ -1467,6 +1468,7 @@ $shortcutLabel:""")
|
||||
private fun inplacemodificationByteVariableWithLiteralval(name: String, dt: DataType, operator: String, value: Int) {
|
||||
// note: this contains special optimized cases because we know the exact value. Don't replace this with another routine.
|
||||
// note: no logical and/or shortcut here, not worth it due to simple right operand
|
||||
require(dt.isByteOrBool)
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
if(value==1) asmgen.out(" inc $name")
|
||||
@@ -1484,13 +1486,13 @@ $shortcutLabel:""")
|
||||
}
|
||||
"/" -> {
|
||||
// replacing division by shifting is done in an optimizer step.
|
||||
if (dt == DataType.UBYTE)
|
||||
if (dt.isUnsignedByte)
|
||||
asmgen.out(" lda $name | ldy #$value | jsr prog8_math.divmod_ub_asm | sty $name")
|
||||
else
|
||||
asmgen.out(" lda $name | ldy #$value | jsr prog8_math.divmod_b_asm | sty $name")
|
||||
}
|
||||
"%" -> {
|
||||
if(dt==DataType.BYTE)
|
||||
if(dt.isSignedByte)
|
||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
@@ -1509,7 +1511,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">>" -> {
|
||||
if(value>0) {
|
||||
if (dt == DataType.UBYTE) {
|
||||
if (dt.isUnsignedByte) {
|
||||
if(value>=8) {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz $name")
|
||||
@@ -1560,7 +1562,7 @@ $shortcutLabel:""")
|
||||
+ sta $name""")
|
||||
}
|
||||
"<" -> {
|
||||
if(dt==DataType.UBYTE) {
|
||||
if(dt.isUnsignedByte) {
|
||||
asmgen.out("""
|
||||
lda #0
|
||||
ldy $name
|
||||
@@ -1585,7 +1587,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
"<=" -> {
|
||||
if(dt==DataType.UBYTE) {
|
||||
if(dt.isUnsignedByte) {
|
||||
asmgen.out("""
|
||||
lda #0
|
||||
ldy #$value
|
||||
@@ -1608,7 +1610,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
">" -> {
|
||||
if(dt==DataType.UBYTE) {
|
||||
if(dt.isUnsignedByte) {
|
||||
asmgen.out("""
|
||||
lda #0
|
||||
ldy $name
|
||||
@@ -1632,7 +1634,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
">=" -> {
|
||||
if(dt==DataType.UBYTE) {
|
||||
if(dt.isUnsignedByte) {
|
||||
asmgen.out("""
|
||||
lda #0
|
||||
ldy $name
|
||||
@@ -1675,6 +1677,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
private fun inplacemodificationWordWithMemread(name: String, dt: DataType, operator: String, memread: PtMemoryByte) {
|
||||
require(dt.isInteger)
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||
@@ -1707,7 +1710,7 @@ $shortcutLabel:""")
|
||||
"&" -> {
|
||||
asmgen.translateDirectMemReadExpressionToRegA(memread)
|
||||
asmgen.out(" and $name | sta $name")
|
||||
if(dt in WordDatatypes) {
|
||||
if(dt.isWord) {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz $name+1")
|
||||
else
|
||||
@@ -1732,6 +1735,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
private fun inplacemodificationSomeWordWithLiteralval(lsb: String, msb: String, dt: DataType, operator: String, value: Int, block: PtBlock?) {
|
||||
require(dt.isWord)
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
when {
|
||||
@@ -1836,7 +1840,7 @@ $shortcutLabel:""")
|
||||
if(value==0) {
|
||||
throw AssemblyError("division by zero")
|
||||
} else {
|
||||
if(dt==DataType.WORD) {
|
||||
if(dt.isSignedWord) {
|
||||
asmgen.out("""
|
||||
lda $lsb
|
||||
ldy $msb
|
||||
@@ -1867,7 +1871,7 @@ $shortcutLabel:""")
|
||||
"%" -> {
|
||||
if(value==0)
|
||||
throw AssemblyError("division by zero")
|
||||
if(dt==DataType.WORD)
|
||||
if(dt.isSignedWord)
|
||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||
asmgen.out("""
|
||||
lda $lsb
|
||||
@@ -1910,7 +1914,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">>" -> {
|
||||
if (value > 0) {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
when {
|
||||
value>=16 -> {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
@@ -2050,7 +2054,7 @@ $shortcutLabel:""")
|
||||
sta $msb""")
|
||||
}
|
||||
"<" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda $msb
|
||||
cmp #>$value
|
||||
@@ -2091,7 +2095,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
"<=" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda $msb
|
||||
cmp #>$value
|
||||
@@ -2134,7 +2138,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">" -> {
|
||||
// word > value --> value < word
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda #>$value
|
||||
cmp $msb
|
||||
@@ -2176,7 +2180,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">=" -> {
|
||||
// word >= value --> value <= word
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda #>$value
|
||||
cmp $msb
|
||||
@@ -2222,12 +2226,14 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
private fun inplacemodificationWordWithVariable(name: String, dt: DataType, operator: String, otherName: String, valueDt: DataType, block: PtBlock?) {
|
||||
when (valueDt) {
|
||||
in ByteDatatypes -> {
|
||||
require(dt.isWord)
|
||||
require(valueDt.isInteger)
|
||||
when {
|
||||
valueDt.isByte -> {
|
||||
// the other variable is a BYTE type so optimize for that
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
if(valueDt==DataType.UBYTE)
|
||||
if(valueDt.isUnsignedByte)
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
clc
|
||||
@@ -2250,7 +2256,7 @@ $shortcutLabel:""")
|
||||
sta $name+1""")
|
||||
}
|
||||
"-" -> {
|
||||
if(valueDt==DataType.UBYTE)
|
||||
if(valueDt.isUnsignedByte)
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sec
|
||||
@@ -2276,7 +2282,7 @@ $shortcutLabel:""")
|
||||
"*" -> {
|
||||
if(block?.options?.veraFxMuls==true) {
|
||||
// cx16 verafx hardware muls
|
||||
if(valueDt==DataType.UBYTE) {
|
||||
if(valueDt.isUnsignedByte) {
|
||||
asmgen.out(" lda $otherName | sta cx16.r1")
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz cx16.r1+1")
|
||||
@@ -2284,7 +2290,7 @@ $shortcutLabel:""")
|
||||
asmgen.out(" lda #0 | sta cx16.r1+1")
|
||||
} else {
|
||||
asmgen.out(" lda $otherName")
|
||||
asmgen.signExtendAYlsb(valueDt)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
asmgen.out(" sta cx16.r1 | sty cx16.r1+1")
|
||||
}
|
||||
asmgen.out("""
|
||||
@@ -2296,7 +2302,7 @@ $shortcutLabel:""")
|
||||
sta $name
|
||||
sty $name+1""")
|
||||
} else {
|
||||
if(valueDt==DataType.UBYTE) {
|
||||
if(valueDt.isUnsignedByte) {
|
||||
asmgen.out(" lda $otherName | sta prog8_math.multiply_words.multiplier")
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz prog8_math.multiply_words.multiplier+1")
|
||||
@@ -2304,7 +2310,7 @@ $shortcutLabel:""")
|
||||
asmgen.out(" lda #0 | sta prog8_math.multiply_words.multiplier+1")
|
||||
} else {
|
||||
asmgen.out(" lda $otherName")
|
||||
asmgen.signExtendAYlsb(valueDt)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
asmgen.out(" sta prog8_math.multiply_words.multiplier | sty prog8_math.multiply_words.multiplier+1")
|
||||
}
|
||||
asmgen.out("""
|
||||
@@ -2316,7 +2322,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
"/" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
ldy $name+1
|
||||
@@ -2343,7 +2349,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
"%" -> {
|
||||
if(valueDt!=DataType.UBYTE || dt!=DataType.UWORD)
|
||||
if(!valueDt.isUnsignedByte || !dt.isUnsignedWord)
|
||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
@@ -2370,7 +2376,7 @@ $shortcutLabel:""")
|
||||
+""")
|
||||
}
|
||||
">>" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
ldy $otherName
|
||||
beq +
|
||||
@@ -2394,7 +2400,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
"&" -> {
|
||||
asmgen.out(" lda $otherName | and $name | sta $name")
|
||||
if(dt in WordDatatypes) {
|
||||
if(dt.isWord) {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz $name+1")
|
||||
else
|
||||
@@ -2436,7 +2442,7 @@ $shortcutLabel:""")
|
||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||
}
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
valueDt.isWord -> {
|
||||
// the value is a proper 16-bit word, so use both bytes of it.
|
||||
when (operator) {
|
||||
"+" -> asmgen.out(" lda $name | clc | adc $otherName | sta $name | lda $name+1 | adc $otherName+1 | sta $name+1")
|
||||
@@ -2469,7 +2475,7 @@ $shortcutLabel:""")
|
||||
sty $name+1""")
|
||||
}
|
||||
"/" -> {
|
||||
if(dt==DataType.WORD) {
|
||||
if(dt.isSignedWord) {
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
ldy $name+1
|
||||
@@ -2495,7 +2501,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
}
|
||||
"%" -> {
|
||||
if(dt==DataType.WORD)
|
||||
if(dt.isSignedWord)
|
||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
@@ -2548,7 +2554,7 @@ $shortcutLabel:""")
|
||||
sta $name+1""")
|
||||
}
|
||||
"<" -> {
|
||||
val compareRoutine = if(dt==DataType.UWORD) "reg_less_uw" else "reg_less_w"
|
||||
val compareRoutine = if(dt.isUnsignedWord) "reg_less_uw" else "reg_less_w"
|
||||
asmgen.out("""
|
||||
lda $otherName
|
||||
ldy $otherName+1
|
||||
@@ -2563,7 +2569,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">" -> {
|
||||
// a > b --> b < a
|
||||
val compareRoutine = if(dt==DataType.UWORD) "reg_less_uw" else "reg_less_w"
|
||||
val compareRoutine = if(dt.isUnsignedWord) "reg_less_uw" else "reg_less_w"
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
ldy $name+1
|
||||
@@ -2577,7 +2583,7 @@ $shortcutLabel:""")
|
||||
sta $name+1""")
|
||||
}
|
||||
"<=" -> {
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda $otherName
|
||||
ldy $otherName+1
|
||||
@@ -2606,7 +2612,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">=" -> {
|
||||
// a>=b --> b<=a
|
||||
if(dt==DataType.UWORD) {
|
||||
if(dt.isUnsignedWord) {
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
ldy $name+1
|
||||
@@ -2645,6 +2651,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
private fun inplacemodificationWordWithValue(name: String, dt: DataType, operator: String, value: PtExpression, block: PtBlock?) {
|
||||
require(dt.isWord)
|
||||
fun multiplyVarByWordInAY() {
|
||||
if(block?.options?.veraFxMuls==true)
|
||||
// cx16 verafx hardware muls
|
||||
@@ -2679,7 +2686,7 @@ $shortcutLabel:""")
|
||||
lda $name+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
txa""")
|
||||
if (dt == DataType.WORD)
|
||||
if (dt.isSignedWord)
|
||||
asmgen.out(" jsr prog8_math.divmod_w_asm")
|
||||
else
|
||||
asmgen.out(" jsr prog8_math.divmod_uw_asm")
|
||||
@@ -2687,7 +2694,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
|
||||
fun remainderVarByWordInAY() {
|
||||
if(dt==DataType.WORD)
|
||||
if(dt.isSignedWord)
|
||||
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||
asmgen.out("""
|
||||
tax
|
||||
@@ -2703,14 +2710,14 @@ $shortcutLabel:""")
|
||||
sty $name+1
|
||||
""")
|
||||
}
|
||||
|
||||
when (val valueDt = value.type) {
|
||||
in ByteDatatypes -> {
|
||||
val valueDt = value.type
|
||||
when {
|
||||
valueDt.isByte -> {
|
||||
// the other variable is a BYTE type so optimize for that
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
// name += byteexpression
|
||||
if(valueDt==DataType.UBYTE) {
|
||||
if(valueDt.isUnsignedByte) {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, false)
|
||||
asmgen.out("""
|
||||
clc
|
||||
@@ -2737,7 +2744,7 @@ $shortcutLabel:""")
|
||||
"-" -> {
|
||||
// name -= byteexpression
|
||||
asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_B1", valueDt)
|
||||
if(valueDt==DataType.UBYTE)
|
||||
if(valueDt.isUnsignedByte)
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sec
|
||||
@@ -2764,21 +2771,21 @@ $shortcutLabel:""")
|
||||
// value is (u) byte value, sign extend that and proceed with regular 16 bit operation
|
||||
// TODO use an optimized word * byte multiplication routine?
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
asmgen.signExtendAYlsb(valueDt)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
multiplyVarByWordInAY()
|
||||
}
|
||||
"/" -> {
|
||||
// value is (u) byte value, sign extend that and proceed with regular 16 bit operation
|
||||
// TODO use an optimized word / byte divmod routine?
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
asmgen.signExtendAYlsb(valueDt)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
divideVarByWordInAY()
|
||||
}
|
||||
"%" -> {
|
||||
// value is (u) byte value, sign extend that and proceed with regular 16 bit operation
|
||||
// TODO use an optimized word / byte divmod routine?
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
asmgen.signExtendAYlsb(valueDt)
|
||||
asmgen.signExtendAYlsb(valueDt.base)
|
||||
remainderVarByWordInAY()
|
||||
}
|
||||
"<<" -> {
|
||||
@@ -2793,7 +2800,7 @@ $shortcutLabel:""")
|
||||
}
|
||||
">>" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.Y)
|
||||
if(dt==DataType.UWORD)
|
||||
if(dt.isUnsignedWord)
|
||||
asmgen.out("""
|
||||
beq +
|
||||
- lsr $name+1
|
||||
@@ -2815,7 +2822,7 @@ $shortcutLabel:""")
|
||||
"&" -> {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.A)
|
||||
asmgen.out(" and $name | sta $name")
|
||||
if(dt in WordDatatypes) {
|
||||
if(dt.isWord) {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
asmgen.out(" stz $name+1")
|
||||
else
|
||||
@@ -2863,7 +2870,7 @@ $shortcutLabel:""")
|
||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||
}
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
valueDt.isWord -> {
|
||||
// the value is a proper 16-bit word, so use both bytes of it.
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
@@ -2889,9 +2896,9 @@ $shortcutLabel:""")
|
||||
}
|
||||
"<<", ">>" -> {
|
||||
if(value is PtNumber && value.number<=255) {
|
||||
when (dt) {
|
||||
in WordDatatypes -> TODO("shift a word var by ${value.number}")
|
||||
in ByteDatatypes -> TODO("shift a byte var by ${value.number}")
|
||||
when {
|
||||
dt.isWord -> TODO("shift a word var by ${value.number}")
|
||||
dt.isByte -> TODO("shift a byte var by ${value.number}")
|
||||
else -> throw AssemblyError("weird dt for shift")
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,16 +4,25 @@ import prog8.code.core.*
|
||||
|
||||
|
||||
internal object DummyMemsizer : IMemSizer {
|
||||
override fun memorySize(dt: DataType) = when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
DataType.FLOAT -> 5
|
||||
else -> 2
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
require(numElements != null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements*2
|
||||
BaseDataType.FLOAT -> numElements*5
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> 5 * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) = when(arrayDt) {
|
||||
DataType.ARRAY_UW -> numElements*2
|
||||
DataType.ARRAY_W -> numElements*2
|
||||
DataType.ARRAY_F -> numElements*5
|
||||
else -> numElements
|
||||
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,16 +50,16 @@ class TestCodegen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"pi",
|
||||
DataType.UBYTE,
|
||||
DataType.forDt(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
PtNumber(DataType.UBYTE, 0.0, Position.DUMMY),
|
||||
PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleX",
|
||||
DataType.ARRAY_UB,
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -68,7 +68,7 @@ class TestCodegen: FunSpec({
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleDX",
|
||||
DataType.ARRAY_UB,
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -77,51 +77,51 @@ class TestCodegen: FunSpec({
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"xx",
|
||||
DataType.WORD,
|
||||
DataType.forDt(BaseDataType.WORD),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
PtNumber(DataType.WORD, 1.0, Position.DUMMY),
|
||||
PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
|
||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
||||
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
||||
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||
val targetIdx = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY).also { idx ->
|
||||
idx.add(PtIdentifier("main.start.particleX", DataType.arrayFor(BaseDataType.UBYTE), Position.DUMMY))
|
||||
idx.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
|
||||
}
|
||||
it.add(targetIdx)
|
||||
}
|
||||
val value = PtArrayIndexer(DataType.UBYTE, Position.DUMMY)
|
||||
value.add(PtIdentifier("main.start.particleDX", DataType.ARRAY_UB, Position.DUMMY))
|
||||
value.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||
val value = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)
|
||||
value.add(PtIdentifier("main.start.particleDX", DataType.arrayFor(BaseDataType.UBYTE), Position.DUMMY))
|
||||
value.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
|
||||
assign.add(target)
|
||||
assign.add(value)
|
||||
sub.add(assign)
|
||||
|
||||
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
||||
val prefixTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
prefixAssign.add(prefixTarget)
|
||||
prefixAssign.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
prefixAssign.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
sub.add(prefixAssign)
|
||||
|
||||
val numberAssign = PtAugmentedAssign("-=", Position.DUMMY)
|
||||
val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
numberAssign.add(numberAssignTarget)
|
||||
numberAssign.add(PtNumber(DataType.WORD, 42.0, Position.DUMMY))
|
||||
numberAssign.add(PtNumber(BaseDataType.WORD, 42.0, Position.DUMMY))
|
||||
sub.add(numberAssign)
|
||||
|
||||
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
cxregAssign.add(cxregAssignTarget)
|
||||
cxregAssign.add(PtIdentifier("cx16.r0", DataType.UWORD, Position.DUMMY))
|
||||
cxregAssign.add(PtIdentifier("cx16.r0", DataType.forDt(BaseDataType.UWORD), Position.DUMMY))
|
||||
sub.add(cxregAssign)
|
||||
|
||||
block.add(sub)
|
||||
@@ -129,7 +129,7 @@ class TestCodegen: FunSpec({
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
cx16block.add(PtMemMapped("r0", DataType.forDt(BaseDataType.UWORD), 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
val options = getTestOptions()
|
||||
|
||||
@@ -83,7 +83,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val symbol = target.identifier?.name
|
||||
val array = target.array
|
||||
val value = augAssign.value
|
||||
val signed = target.type in SignedDatatypes
|
||||
val signed = target.type.isSigned
|
||||
|
||||
val chunks = when (augAssign.operator) {
|
||||
"+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
||||
@@ -182,7 +182,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
|
||||
private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val vmDt = irType(array.type)
|
||||
val constIndex = array.index.asConstInteger()
|
||||
@@ -336,7 +336,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
addToResult(result, tr, valueRegister, -1)
|
||||
if(extendByteToWord) {
|
||||
valueRegister = codeGen.registers.nextFree()
|
||||
val opcode = if(assignment.value.type in SignedDatatypes) Opcode.EXTS else Opcode.EXT
|
||||
val opcode = if(assignment.value.type.isSigned) Opcode.EXTS else Opcode.EXT
|
||||
addInstr(result, IRInstruction(opcode, IRDataType.BYTE, reg1=valueRegister, reg2=tr.resultReg), null)
|
||||
}
|
||||
}
|
||||
@@ -357,7 +357,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
else if(targetArray!=null) {
|
||||
val variable = targetArray.variable.name
|
||||
val itemsize = codeGen.program.memsizer.memorySize(targetArray.type)
|
||||
val itemsize = codeGen.program.memsizer.memorySize(targetArray.type, null)
|
||||
|
||||
val fixedIndex = targetArray.index.asConstInteger()
|
||||
val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name)
|
||||
@@ -465,10 +465,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
|
||||
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
|
||||
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
|
||||
&& (ptrWithOffset.right.type.isByte || offsetTypecast?.value?.type?.isByte==true)) {
|
||||
// STOREIX only works with byte index.
|
||||
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
|
||||
expressionEval.translateExpression(offsetTypecast!!.value)
|
||||
val tr = if(offsetTypecast?.value?.type?.isByte==true)
|
||||
expressionEval.translateExpression(offsetTypecast.value)
|
||||
else
|
||||
expressionEval.translateExpression(ptrWithOffset.right)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
@@ -498,9 +498,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return Pair(result, tr.resultReg)
|
||||
}
|
||||
val mult: PtExpression = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
val mult: PtExpression = PtBinaryExpression("*", DataType.forDt(BaseDataType.UBYTE), array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
mult.children += PtNumber(BaseDataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
val tr = expressionEval.translateExpression(mult)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return Pair(result, tr.resultReg)
|
||||
@@ -511,7 +511,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
if(constIndex!=null && constValue!=null) {
|
||||
if(array.splitWords) {
|
||||
val valueRegLsb = codeGen.registers.nextFree()
|
||||
@@ -551,7 +551,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
if(constIndex!=null && constValue!=null) {
|
||||
if(array.splitWords) {
|
||||
val valueRegLsb = codeGen.registers.nextFree()
|
||||
@@ -611,7 +611,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
if(constIndex!=null && constValue!=null) {
|
||||
if(array.splitWords) {
|
||||
val valueRegLsb = codeGen.registers.nextFree()
|
||||
@@ -651,7 +651,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
if(constIndex!=null && constValue!=null) {
|
||||
if(array.splitWords) {
|
||||
val valueRegLsb = codeGen.registers.nextFree()
|
||||
@@ -716,7 +716,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val factor = constFactorRight.number
|
||||
result += codeGen.divideByConstFloatInplace(constAddress, symbol, factor)
|
||||
} else {
|
||||
@@ -737,7 +737,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
addInstr(result, ins, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.divideByConstInplace(vmDt, constAddress, symbol, factor, signed)
|
||||
} else {
|
||||
@@ -763,7 +763,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
|
||||
private fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
||||
if(array!=null) {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(array.splitWords)
|
||||
return operatorMultiplyInplaceSplitArray(array, operand)
|
||||
@@ -801,7 +801,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
, null)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
result += codeGen.multiplyByConstInplace(vmDt, constAddress, symbol, factor)
|
||||
} else {
|
||||
@@ -819,7 +819,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
|
||||
private fun operatorMinusInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
|
||||
if(array!=null) {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(array.splitWords)
|
||||
return operatorMinusInplaceSplitArray(array, operand)
|
||||
@@ -915,7 +915,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(array.splitWords)
|
||||
return operatorPlusInplaceSplitArray(array, operand)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
val elementDt = irType(array.type)
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
@@ -1055,7 +1055,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constIndex = array.index.asConstInteger()
|
||||
val constValue = operand.asConstInteger()
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
if(constIndex!=null && constValue!=null) {
|
||||
if(array.splitWords) {
|
||||
val valueRegLsb = codeGen.registers.nextFree()
|
||||
@@ -1369,10 +1369,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
|
||||
private fun createInplaceArrayComparison(array: PtArrayIndexer, value: PtExpression, comparisonOperator: String): IRCodeChunks? {
|
||||
if(array.type==DataType.FLOAT)
|
||||
if(array.type.isFloat)
|
||||
return null // TODO("optimized in-place compare on float arrays"))
|
||||
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(array.type, null)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(array.splitWords)
|
||||
TODO("inplace compare for split word array")
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.intermediate.*
|
||||
|
||||
|
||||
@@ -169,13 +170,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val sourceDt = call.args.single().type
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(sourceDt==DataType.UWORD)
|
||||
if(sourceDt.isUnsignedWord)
|
||||
return ExpressionCodeResult.EMPTY
|
||||
|
||||
val tr = exprGen.translateExpression(call.args[0])
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
when (sourceDt) {
|
||||
DataType.BYTE -> {
|
||||
when (sourceDt.base) {
|
||||
BaseDataType.BYTE -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
@@ -186,7 +187,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
result += IRCodeChunk(notNegativeLabel, null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, tr.resultReg, -1)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
BaseDataType.WORD -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
@@ -197,7 +198,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
result += IRCodeChunk(notNegativeLabel, null)
|
||||
return ExpressionCodeResult(result, IRDataType.WORD, tr.resultReg, -1)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
val resultFpReg = codeGen.registers.nextFreeFloat()
|
||||
addInstr(result, IRInstruction(Opcode.FABS, IRDataType.FLOAT, fpReg1 = resultFpReg, fpReg2 = tr.resultFpReg), null)
|
||||
return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultFpReg)
|
||||
@@ -229,8 +230,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = exprGen.translateExpression(call.args.single())
|
||||
val dt = call.args[0].type
|
||||
when(dt) {
|
||||
DataType.UBYTE -> {
|
||||
when(dt.base) {
|
||||
BaseDataType.UBYTE -> {
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
@@ -238,7 +239,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
@@ -246,7 +247,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
val resultFpReg = codeGen.registers.nextFreeFloat()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
@@ -296,11 +297,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
)
|
||||
return ExpressionCodeResult(result, type, -1, valueTr.resultFpReg)
|
||||
} else {
|
||||
val syscall = when(call.type) {
|
||||
DataType.UBYTE -> IMSyscall.CLAMP_UBYTE
|
||||
DataType.BYTE -> IMSyscall.CLAMP_BYTE
|
||||
DataType.UWORD -> IMSyscall.CLAMP_UWORD
|
||||
DataType.WORD -> IMSyscall.CLAMP_WORD
|
||||
val syscall = when(call.type.base) {
|
||||
BaseDataType.UBYTE -> IMSyscall.CLAMP_UBYTE
|
||||
BaseDataType.BYTE -> IMSyscall.CLAMP_BYTE
|
||||
BaseDataType.UWORD -> IMSyscall.CLAMP_UWORD
|
||||
BaseDataType.WORD -> IMSyscall.CLAMP_WORD
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
result += codeGen.makeSyscall(syscall, listOf(
|
||||
@@ -320,7 +321,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = exprGen.translateExpression(call.args[1])
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val comparisonOpcode = if(call.type in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR
|
||||
val comparisonOpcode = if(call.type.isSigned) Opcode.BGTSR else Opcode.BGTR
|
||||
val after = codeGen.createLabelName()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(comparisonOpcode, type, reg1 = rightTr.resultReg, reg2 = leftTr.resultReg, labelSymbol = after)
|
||||
@@ -339,7 +340,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val rightTr = exprGen.translateExpression(call.args[1])
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
val comparisonOpcode = if(call.type in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR
|
||||
val comparisonOpcode = if(call.type.isSigned) Opcode.BGTSR else Opcode.BGTR
|
||||
val after = codeGen.createLabelName()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(comparisonOpcode, type, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg, labelSymbol = after)
|
||||
@@ -546,8 +547,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
if(arr!=null && index!=null) {
|
||||
if(arr.splitWords) TODO("IR rol/ror on split words array")
|
||||
val variable = arr.variable.name
|
||||
val itemsize = codeGen.program.memsizer.memorySize(arr.type)
|
||||
addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = index*itemsize), null)
|
||||
val offset = codeGen.program.memsizer.memorySize(arr.type, index)
|
||||
addInstr(result, IRInstruction(opcodeMemAndReg.first, vmDt, labelSymbol = variable, symbolOffset = offset), null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, -1)
|
||||
}
|
||||
|
||||
@@ -632,7 +633,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
}
|
||||
else {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(target.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(target.type, null)
|
||||
val constIndex = target.index.asConstInteger()
|
||||
if(isConstZeroValue) {
|
||||
if(constIndex!=null) {
|
||||
|
||||
@@ -53,7 +53,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val code = IRCodeChunk(null, null)
|
||||
if (expr.type in PassByValueDatatypes) {
|
||||
if (expr.type.isPassByValue) {
|
||||
val vmDt = irType(expr.type)
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
val resultFpRegister = codeGen.registers.nextFreeFloat()
|
||||
@@ -67,7 +67,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
} else {
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
val vmDt = if(expr.type==DataType.UNDEFINED) IRDataType.WORD else irType(expr.type)
|
||||
val vmDt = if(expr.type.isUndefined) IRDataType.WORD else irType(expr.type)
|
||||
val resultRegister = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = expr.name)
|
||||
ExpressionCodeResult(code, vmDt, resultRegister, -1)
|
||||
@@ -131,13 +131,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val resultRegister = codeGen.registers.nextFree()
|
||||
if(expr.isFromArrayElement) {
|
||||
require(expr.identifier.type !in SplitWordArrayTypes)
|
||||
require(!expr.identifier.type.isSplitWordArray)
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol), null)
|
||||
val indexTr2 = translateExpression(expr.arrayIndexExpr!!)
|
||||
addToResult(result, indexTr2, indexTr2.resultReg, -1)
|
||||
val indexWordReg = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexWordReg, reg2=indexTr2.resultReg), null)
|
||||
if(expr.identifier.type == DataType.UWORD) {
|
||||
if(expr.identifier.type.isUnsignedWord) {
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=resultRegister, reg2=indexWordReg)
|
||||
@@ -184,10 +184,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
|
||||
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
|
||||
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
|
||||
&& (ptrWithOffset.right.type.isByte || offsetTypecast?.value?.type?.isByte==true)) {
|
||||
// LOADIX only works with byte index.
|
||||
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
|
||||
translateExpression(offsetTypecast!!.value)
|
||||
val tr = if(offsetTypecast?.value?.type?.isByte==true)
|
||||
translateExpression(offsetTypecast.value)
|
||||
else
|
||||
translateExpression(ptrWithOffset.right)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
@@ -211,10 +211,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
if(it is PtBool) it.asInt()
|
||||
else (it as PtNumber).number.toInt()
|
||||
}
|
||||
when(elementDt) {
|
||||
in IntegerDatatypesWithBoolean -> {
|
||||
if (elementDt in ByteDatatypesWithBoolean) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_BYTE)
|
||||
if (elementDt in WordDatatypes) require(haystack.size in 0..PtContainmentCheck.MAX_SIZE_FOR_INLINE_CHECKS_WORD)
|
||||
when {
|
||||
elementDt.isIntegerOrBool -> {
|
||||
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()
|
||||
val endLabel = codeGen.createLabelName()
|
||||
val elementTr = translateExpression(check.needle)
|
||||
@@ -231,14 +231,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
result += IRCodeChunk(endLabel, null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.FLOAT -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine")
|
||||
elementDt.isFloat -> throw AssemblyError("containmentchecks for floats should always be done on an array variable with subroutine")
|
||||
else -> throw AssemblyError("weird dt $elementDt")
|
||||
}
|
||||
}
|
||||
|
||||
val haystackVar = check.haystackHeapVar!!
|
||||
when(haystackVar.type) {
|
||||
DataType.STR -> {
|
||||
when {
|
||||
haystackVar.type.isString -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 2), null)
|
||||
val elementTr = translateExpression(check.needle)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
@@ -248,7 +248,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
haystackVar.type.isByteArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val elementTr = translateExpression(check.needle)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
@@ -261,7 +261,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
haystackVar.type.isWordArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val elementTr = translateExpression(check.needle)
|
||||
addToResult(result, elementTr, elementTr.resultReg, -1)
|
||||
@@ -274,7 +274,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=elementTr.resultReg, immediate = 0), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, elementTr.resultReg, -1)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
haystackVar.type.isFloatArray -> {
|
||||
addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = 3), null)
|
||||
val elementTr = translateExpression(check.needle)
|
||||
addToResult(result, elementTr, -1, elementTr.resultFpReg)
|
||||
@@ -293,7 +293,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
|
||||
private fun translate(arrayIx: PtArrayIndexer): ExpressionCodeResult {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
|
||||
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type, null)
|
||||
val vmDt = irType(arrayIx.type)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val arrayVarSymbol = arrayIx.variable.name
|
||||
@@ -384,18 +384,19 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addToResult(result, tr, tr.resultReg, tr.resultFpReg)
|
||||
var actualResultReg2 = -1
|
||||
var actualResultFpReg2 = -1
|
||||
when(cast.type) {
|
||||
DataType.BOOL -> {
|
||||
when (cast.value.type) {
|
||||
in ByteDatatypes -> {
|
||||
val valueDt = cast.value.type
|
||||
when(cast.type.base) {
|
||||
BaseDataType.BOOL -> {
|
||||
when {
|
||||
valueDt.isByte -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.BYTE, reg1=actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
valueDt.isWord -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.WORD, reg1=actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
valueDt.isFloat -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.SGN, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg)
|
||||
@@ -405,87 +406,87 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BOOL, DataType.BYTE, DataType.UWORD, DataType.WORD -> {
|
||||
BaseDataType.UBYTE -> {
|
||||
when(valueDt.base) {
|
||||
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD -> {
|
||||
actualResultReg2 = tr.resultReg // just keep the LSB as it is
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BOOL, DataType.UBYTE, DataType.UWORD, DataType.WORD -> {
|
||||
BaseDataType.BYTE -> {
|
||||
when(valueDt.base) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.WORD -> {
|
||||
actualResultReg2 = tr.resultReg // just keep the LSB as it is
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
BaseDataType.UWORD -> {
|
||||
when(valueDt.base) {
|
||||
BaseDataType.BYTE -> {
|
||||
// byte -> uword: sign extend
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2 = tr.resultReg), null)
|
||||
}
|
||||
DataType.BOOL, DataType.UBYTE -> {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE -> {
|
||||
// ubyte -> uword: sign extend
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2 = tr.resultReg), null)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
BaseDataType.WORD -> {
|
||||
actualResultReg2 = tr.resultReg
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
BaseDataType.WORD -> {
|
||||
when(valueDt.base) {
|
||||
BaseDataType.BYTE -> {
|
||||
// byte -> word: sign extend
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
DataType.BOOL, DataType.UBYTE -> {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE -> {
|
||||
// byte -> word: sign extend
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
actualResultReg2 = tr.resultReg
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
BaseDataType.FLOAT -> {
|
||||
actualResultFpReg2 = codeGen.registers.nextFreeFloat()
|
||||
when(cast.value.type) {
|
||||
DataType.BOOL, DataType.UBYTE -> {
|
||||
when(valueDt.base) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE -> {
|
||||
addInstr(result, IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
BaseDataType.BYTE -> {
|
||||
addInstr(result, IRInstruction(Opcode.FFROMSB, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
BaseDataType.UWORD -> {
|
||||
addInstr(result, IRInstruction(Opcode.FFROMUW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
BaseDataType.WORD -> {
|
||||
addInstr(result, IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=tr.resultReg, fpReg1 = actualResultFpReg2), null)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
@@ -499,7 +500,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
|
||||
val vmDt = irType(binExpr.left.type)
|
||||
val signed = binExpr.left.type in SignedDatatypes
|
||||
val signed = binExpr.left.type.isSigned
|
||||
return when(binExpr.operator) {
|
||||
"+" -> operatorPlus(binExpr, vmDt)
|
||||
"-" -> operatorMinus(binExpr, vmDt)
|
||||
@@ -592,7 +593,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
fcallArgs = FunctionCallArgs(argRegisters, if(returnRegSpec==null) emptyList() else listOf(returnRegSpec))), null)
|
||||
return if(fcall.void)
|
||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
else if(fcall.type==DataType.FLOAT)
|
||||
else if(fcall.type.isFloat)
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, -1, returnRegSpec.registerNum)
|
||||
else
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, returnRegSpec.registerNum, -1)
|
||||
@@ -705,7 +706,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
return if(fcall.void)
|
||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
else if(fcall.type==DataType.FLOAT)
|
||||
else if(fcall.type.isFloat)
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, -1, finalReturnRegister)
|
||||
else
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, finalReturnRegister, -1)
|
||||
@@ -768,7 +769,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
): ExpressionCodeResult {
|
||||
// return multiple values
|
||||
val returnRegisters = callTarget.returns.map {
|
||||
val regnum = if(it.type==DataType.FLOAT) codeGen.registers.nextFreeFloat() else codeGen.registers.nextFree()
|
||||
val regnum = if(it.type.isFloat) codeGen.registers.nextFreeFloat() else codeGen.registers.nextFree()
|
||||
FunctionCallArgs.RegSpec(irType(it.type), regnum, it.register)
|
||||
}
|
||||
// create the call
|
||||
@@ -817,7 +818,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultReg, reg2 = resultRegister, reg3 = zeroRegister), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultReg, -1)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||
if(binExpr.left.type.isString || binExpr.right.type.isString) {
|
||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||
} else {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
@@ -860,7 +861,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1=cmpResultRegister, reg2 = resultRegister, reg3 = zeroRegister), null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, cmpResultRegister, -1)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||
if(binExpr.left.type.isString || binExpr.right.type.isString) {
|
||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||
} else {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
@@ -901,7 +902,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
result += IRCodeChunk(label, null)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||
if(binExpr.left.type.isString || binExpr.right.type.isString) {
|
||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||
} else {
|
||||
return if(binExpr.right.asConstValue()==0.0) {
|
||||
@@ -1073,7 +1074,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val tr = translateExpression(binExpr.left)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
val factor = constFactorRight.number
|
||||
@@ -1092,7 +1093,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return ExpressionCodeResult(result, vmDt, -1, leftTr.resultFpReg)
|
||||
}
|
||||
} else {
|
||||
return if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
return if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val tr = translateExpression(binExpr.left)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val factor = constFactorRight.number.toInt()
|
||||
@@ -1150,13 +1151,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
ExpressionCodeResult(result, vmDt, -1, leftTr.resultFpReg)
|
||||
}
|
||||
} else {
|
||||
return if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
|
||||
return if(constFactorLeft!=null && !constFactorLeft.type.isFloat) {
|
||||
val tr = translateExpression(binExpr.right)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val factor = constFactorLeft.number.toInt()
|
||||
result += codeGen.multiplyByConst(vmDt, tr.resultReg, factor)
|
||||
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
|
||||
} else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
} else if(constFactorRight!=null && !constFactorRight.type.isFloat) {
|
||||
val tr = translateExpression(binExpr.left)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val factor = constFactorRight.number.toInt()
|
||||
|
||||
@@ -432,8 +432,8 @@ class IRCodeGen(
|
||||
val tmpReg = registers.nextFree()
|
||||
val loopLabel = createLabelName()
|
||||
val endLabel = createLabelName()
|
||||
when (iterable.type) {
|
||||
DataType.STR -> {
|
||||
when {
|
||||
iterable.type.isString -> {
|
||||
// iterate over a zero-terminated string
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
@@ -448,10 +448,10 @@ class IRCodeGen(
|
||||
result += jumpChunk
|
||||
result += IRCodeChunk(endLabel, null)
|
||||
}
|
||||
in SplitWordArrayTypes -> {
|
||||
iterable.type.isSplitWordArray -> {
|
||||
// iterate over lsb/msb split word array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
if(elementDt !in WordDatatypes)
|
||||
val elementDt = iterable.type.elementType()
|
||||
if(!elementDt.isWord)
|
||||
throw AssemblyError("weird dt")
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
@@ -475,13 +475,14 @@ class IRCodeGen(
|
||||
}
|
||||
else -> {
|
||||
// iterate over regular array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val element = iterable.type.sub!!
|
||||
val elementDt = element.dt
|
||||
val elementSize = program.memsizer.memorySize(element)
|
||||
val lengthBytes = iterableLength!! * elementSize
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
|
||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
it += IRInstruction(Opcode.LOADX, irType(DataType.forDt(elementDt)), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
|
||||
it += IRInstruction(Opcode.STOREM, irType(DataType.forDt(elementDt)), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
|
||||
@@ -548,7 +549,7 @@ class IRCodeGen(
|
||||
addToResult(result, fromTr, fromTr.resultReg, -1)
|
||||
|
||||
val labelAfterFor = createLabelName()
|
||||
val precheckInstruction = if(loopvarDt in SignedDatatypes) {
|
||||
val precheckInstruction = if(loopvarDt.isSigned) {
|
||||
if(step>0)
|
||||
IRInstruction(Opcode.BGTSR, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor)
|
||||
else
|
||||
@@ -616,7 +617,7 @@ class IRCodeGen(
|
||||
val chunk2 = addConstMem(loopvarDtIr, null, loopvarSymbol, iterable.step)
|
||||
if(loopvarDtIr==IRDataType.BYTE && iterable.step==-1 && iterable.last==0) {
|
||||
// downto 0 optimization (byte)
|
||||
if(loopvarDt==DataType.BYTE || iterable.first<=127) {
|
||||
if(loopvarDt.isSignedByte || iterable.first<=127) {
|
||||
chunk2 += IRInstruction(Opcode.BSTPOS, labelSymbol = loopLabel)
|
||||
} else {
|
||||
chunk2 += IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||
@@ -977,7 +978,7 @@ class IRCodeGen(
|
||||
|
||||
private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump): MutableList<IRCodeChunkBase> {
|
||||
val condition = ifElse.condition as? PtBinaryExpression
|
||||
if(condition==null || condition.left.type!=DataType.FLOAT) {
|
||||
if(condition==null || !condition.left.type.isFloat) {
|
||||
return if(isIndirectJump(goto))
|
||||
ifWithOnlyIndirectJump_IntegerCond(ifElse, goto)
|
||||
else
|
||||
@@ -1082,7 +1083,7 @@ class IRCodeGen(
|
||||
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
val irDt = leftTr.dt
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||
if(number!=null) {
|
||||
@@ -1170,7 +1171,7 @@ class IRCodeGen(
|
||||
|
||||
when(val cond = ifElse.condition) {
|
||||
is PtTypeCast -> {
|
||||
require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes)
|
||||
require(cond.type.isBool && cond.value.type.isNumeric)
|
||||
val tr = expressionEval.translateExpression(cond)
|
||||
result += tr.chunks
|
||||
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel), null)
|
||||
@@ -1212,7 +1213,7 @@ class IRCodeGen(
|
||||
|
||||
val leftTr = expressionEval.translateExpression(condition.left)
|
||||
val irDt = leftTr.dt
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||
if(number!=null) {
|
||||
@@ -1301,7 +1302,7 @@ class IRCodeGen(
|
||||
|
||||
when(val cond = ifElse.condition) {
|
||||
is PtTypeCast -> {
|
||||
require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes)
|
||||
require(cond.type.isBool && cond.value.type.isNumeric)
|
||||
val tr = expressionEval.translateExpression(cond)
|
||||
result += tr.chunks
|
||||
addInstr(result, branchInstr(goto, Opcode.BSTNE), null)
|
||||
@@ -1328,7 +1329,7 @@ class IRCodeGen(
|
||||
throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks")
|
||||
|
||||
val condition = ifElse.condition as? PtBinaryExpression
|
||||
if(condition==null || condition.left.type != DataType.FLOAT) {
|
||||
if(condition==null || !condition.left.type.isFloat) {
|
||||
return ifWithElse_IntegerCond(ifElse)
|
||||
}
|
||||
|
||||
@@ -1421,7 +1422,7 @@ class IRCodeGen(
|
||||
if(condition.operator in LogicalOperators)
|
||||
return translateSimple(condition, Opcode.BSTEQ, false)
|
||||
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val signed = condition.left.type.isSigned
|
||||
val elseBranchFirstReg: Int
|
||||
val elseBranchSecondReg: Int
|
||||
val number = (condition.right as? PtNumber)?.number?.toInt()
|
||||
@@ -1562,7 +1563,7 @@ class IRCodeGen(
|
||||
translateSimple(cond, Opcode.BSTEQ, false)
|
||||
}
|
||||
is PtTypeCast -> {
|
||||
require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes)
|
||||
require(cond.type.isBool && cond.value.type.isNumeric)
|
||||
translateSimple(cond, Opcode.BSTEQ, false)
|
||||
}
|
||||
is PtIdentifier, is PtArrayIndexer, is PtContainmentCheck -> {
|
||||
@@ -1589,7 +1590,7 @@ class IRCodeGen(
|
||||
1 -> return translateGroup(repeat.children)
|
||||
256 -> {
|
||||
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
|
||||
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
|
||||
repeat.children[0] = PtNumber(BaseDataType.UBYTE, 0.0, repeat.count.position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1662,7 +1663,7 @@ class IRCodeGen(
|
||||
if(value==null) {
|
||||
addInstr(result, IRInstruction(Opcode.RETURN), null)
|
||||
} else {
|
||||
if(value.type==DataType.FLOAT) {
|
||||
if(value.type.isFloat) {
|
||||
if(value is PtNumber) {
|
||||
addInstr(result, IRInstruction(Opcode.RETURNI, IRDataType.FLOAT, immediateFp = value.number), null)
|
||||
} else {
|
||||
|
||||
@@ -2,16 +2,25 @@ import prog8.code.core.*
|
||||
|
||||
|
||||
internal object DummyMemsizer : IMemSizer {
|
||||
override fun memorySize(dt: DataType) = when(dt) {
|
||||
in ByteDatatypesWithBoolean -> 1
|
||||
DataType.FLOAT -> 5
|
||||
else -> 2
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray || dt.isSplitWordArray) {
|
||||
require(numElements!=null)
|
||||
return when(dt.sub?.dt) {
|
||||
BaseDataType.BOOL, BaseDataType.BYTE, BaseDataType.UBYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> numElements*2
|
||||
BaseDataType.FLOAT -> numElements*5
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> 5 * (numElements ?: 1)
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
override fun memorySize(arrayDt: DataType, numElements: Int) = when(arrayDt) {
|
||||
DataType.ARRAY_UW -> numElements*2
|
||||
DataType.ARRAY_W -> numElements*2
|
||||
DataType.ARRAY_F -> numElements*5
|
||||
else -> numElements
|
||||
|
||||
override fun memorySize(dt: SubType): Int {
|
||||
return memorySize(DataType.forDt(dt.dt), null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,16 +47,16 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"pi",
|
||||
DataType.UBYTE,
|
||||
DataType.forDt(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
PtNumber(DataType.UBYTE, 0.0, Position.DUMMY),
|
||||
PtNumber(BaseDataType.UBYTE, 0.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleX",
|
||||
DataType.ARRAY_UB,
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -65,7 +65,7 @@ class TestVmCodeGen: FunSpec({
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"particleDX",
|
||||
DataType.ARRAY_UB,
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -74,51 +74,55 @@ class TestVmCodeGen: FunSpec({
|
||||
))
|
||||
sub.add(PtVariable(
|
||||
"xx",
|
||||
DataType.WORD,
|
||||
DataType.forDt(BaseDataType.WORD),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
PtNumber(DataType.WORD, 1.0, Position.DUMMY),
|
||||
PtNumber(BaseDataType.WORD, 1.0, Position.DUMMY),
|
||||
null,
|
||||
Position.DUMMY
|
||||
))
|
||||
|
||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
||||
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
||||
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||
val targetIdx = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY).also { idx ->
|
||||
idx.add(PtIdentifier("main.start.particleX",
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
Position.DUMMY))
|
||||
idx.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
|
||||
}
|
||||
it.add(targetIdx)
|
||||
}
|
||||
val value = PtArrayIndexer(DataType.UBYTE, Position.DUMMY)
|
||||
value.add(PtIdentifier("main.start.particleDX", DataType.ARRAY_UB, Position.DUMMY))
|
||||
value.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||
val value = PtArrayIndexer(DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)
|
||||
value.add(PtIdentifier("main.start.particleDX",
|
||||
DataType.arrayFor(BaseDataType.UBYTE),
|
||||
Position.DUMMY))
|
||||
value.add(PtNumber(BaseDataType.UBYTE, 2.0, Position.DUMMY))
|
||||
assign.add(target)
|
||||
assign.add(value)
|
||||
sub.add(assign)
|
||||
|
||||
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
||||
val prefixTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
prefixAssign.add(prefixTarget)
|
||||
prefixAssign.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
prefixAssign.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
sub.add(prefixAssign)
|
||||
|
||||
val numberAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
numberAssign.add(numberAssignTarget)
|
||||
numberAssign.add(PtNumber(DataType.WORD, 42.0, Position.DUMMY))
|
||||
numberAssign.add(PtNumber(BaseDataType.WORD, 42.0, Position.DUMMY))
|
||||
sub.add(numberAssign)
|
||||
|
||||
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||
val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||
it.add(PtIdentifier("main.start.xx", DataType.forDt(BaseDataType.WORD), Position.DUMMY))
|
||||
}
|
||||
cxregAssign.add(cxregAssignTarget)
|
||||
cxregAssign.add(PtIdentifier("cx16.r0", DataType.UWORD, Position.DUMMY))
|
||||
cxregAssign.add(PtIdentifier("cx16.r0", DataType.forDt(BaseDataType.UWORD), Position.DUMMY))
|
||||
sub.add(cxregAssign)
|
||||
|
||||
block.add(sub)
|
||||
@@ -126,7 +130,7 @@ class TestVmCodeGen: FunSpec({
|
||||
|
||||
// define the "cx16.r0" virtual register
|
||||
val cx16block = PtBlock("cx16", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
|
||||
cx16block.add(PtMemMapped("r0", DataType.UWORD, 100u, null, Position.DUMMY))
|
||||
cx16block.add(PtMemMapped("r0", DataType.forDt(BaseDataType.UWORD), 100u, null, Position.DUMMY))
|
||||
program.add(cx16block)
|
||||
|
||||
val options = getTestOptions()
|
||||
@@ -158,7 +162,7 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
DataType.forDt(BaseDataType.FLOAT),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -166,33 +170,33 @@ class TestVmCodeGen: FunSpec({
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp1.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||
val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp1.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
|
||||
if1.add(cmp1)
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if1)
|
||||
val if2 = PtIfElse(Position.DUMMY)
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp2.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp2.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
|
||||
if2.add(cmp2)
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if2)
|
||||
val if3 = PtIfElse(Position.DUMMY)
|
||||
val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp3.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||
val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp3.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
|
||||
if3.add(cmp3)
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if3)
|
||||
val if4 = PtIfElse(Position.DUMMY)
|
||||
val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp4.add(PtNumber(DataType.FLOAT, 0.0, Position.DUMMY))
|
||||
val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp4.add(PtNumber(BaseDataType.FLOAT, 0.0, Position.DUMMY))
|
||||
if4.add(cmp4)
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
@@ -229,7 +233,7 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
DataType.forDt(BaseDataType.FLOAT),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -237,33 +241,33 @@ class TestVmCodeGen: FunSpec({
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if1.add(cmp1)
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if1)
|
||||
val if2 = PtIfElse(Position.DUMMY)
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if2.add(cmp2)
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if2)
|
||||
val if3 = PtIfElse(Position.DUMMY)
|
||||
val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp3.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp3.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if3.add(cmp3)
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if3)
|
||||
val if4 = PtIfElse(Position.DUMMY)
|
||||
val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp4.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp4.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if4.add(cmp4)
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
@@ -296,7 +300,7 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"f1",
|
||||
DataType.FLOAT,
|
||||
DataType.forDt(BaseDataType.FLOAT),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -304,17 +308,17 @@ class TestVmCodeGen: FunSpec({
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp1.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if1.add(cmp1)
|
||||
if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup())
|
||||
sub.add(if1)
|
||||
val if2 = PtIfElse(Position.DUMMY)
|
||||
val cmp2 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.FLOAT, Position.DUMMY))
|
||||
cmp2.add(PtNumber(DataType.FLOAT, 42.0, Position.DUMMY))
|
||||
val cmp2 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY))
|
||||
cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY))
|
||||
if2.add(cmp2)
|
||||
if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup())
|
||||
@@ -351,7 +355,7 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"sb1",
|
||||
DataType.BYTE,
|
||||
DataType.forDt(BaseDataType.BYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -359,33 +363,33 @@ class TestVmCodeGen: FunSpec({
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
cmp1.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||
val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
|
||||
cmp1.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
|
||||
if1.add(cmp1)
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if1)
|
||||
val if2 = PtIfElse(Position.DUMMY)
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
cmp2.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
|
||||
cmp2.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
|
||||
if2.add(cmp2)
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if2)
|
||||
val if3 = PtIfElse(Position.DUMMY)
|
||||
val cmp3 = PtBinaryExpression("<", DataType.BOOL, Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
cmp3.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||
val cmp3 = PtBinaryExpression("<", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp3.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
|
||||
cmp3.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
|
||||
if3.add(cmp3)
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if3.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if3)
|
||||
val if4 = PtIfElse(Position.DUMMY)
|
||||
val cmp4 = PtBinaryExpression(">", DataType.BOOL, Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
cmp4.add(PtNumber(DataType.BYTE, 0.0, Position.DUMMY))
|
||||
val cmp4 = PtBinaryExpression(">", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp4.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
|
||||
cmp4.add(PtNumber(BaseDataType.BYTE, 0.0, Position.DUMMY))
|
||||
if4.add(cmp4)
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if4.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
@@ -422,7 +426,7 @@ class TestVmCodeGen: FunSpec({
|
||||
val sub = PtSub("start", emptyList(), null, Position.DUMMY)
|
||||
sub.add(PtVariable(
|
||||
"sb1",
|
||||
DataType.BYTE,
|
||||
DataType.forDt(BaseDataType.BYTE),
|
||||
ZeropageWish.DONTCARE,
|
||||
0u,
|
||||
null,
|
||||
@@ -430,33 +434,33 @@ class TestVmCodeGen: FunSpec({
|
||||
Position.DUMMY
|
||||
))
|
||||
val if1 = PtIfElse(Position.DUMMY)
|
||||
val cmp1 = PtBinaryExpression("==", DataType.BOOL, Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.BYTE, Position.DUMMY))
|
||||
cmp1.add(PtNumber(DataType.BYTE, 42.0, Position.DUMMY))
|
||||
val cmp1 = PtBinaryExpression("==", DataType.forDt(BaseDataType.BOOL), Position.DUMMY)
|
||||
cmp1.add(PtIdentifier("main.start.sb1", DataType.forDt(BaseDataType.BYTE), Position.DUMMY))
|
||||
cmp1.add(PtNumber(BaseDataType.BYTE, 42.0, Position.DUMMY))
|
||||
if1.add(cmp1)
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtNop(Position.DUMMY)) })
|
||||
sub.add(if1)
|
||||
val if2 = PtIfElse(Position.DUMMY)
|
||||
val cmp2 = PtBinaryExpression("!=", DataType.BOOL, Position.DUMMY)
|
||||
cmp2.add(PtIdentifier("main.start.sb1", DataType.BYTE | ||||