implement mklong(a,b,c,d) and mklong2(w1,w2)

This commit is contained in:
Irmen de Jong
2025-09-20 03:27:01 +02:00
parent 3e07b6ca70
commit b058f1c7c2
10 changed files with 203 additions and 49 deletions
@@ -117,6 +117,8 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"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)),
"mklong" to FSignature(true, BaseDataType.LONG, FParam("msb", BaseDataType.UBYTE), FParam("b2", BaseDataType.UBYTE), FParam("b1", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
"mklong2" to FSignature(true, BaseDataType.LONG, FParam("msw", BaseDataType.UWORD), FParam("lsw", BaseDataType.UWORD)),
"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)),
@@ -32,6 +32,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"msb" -> funcMsb(fcall, resultRegister)
"lsb" -> funcLsb(fcall, resultRegister)
"mkword" -> funcMkword(fcall, resultRegister)
"mklong", "mklong2" -> funcMklong(fcall) // result is in R0:R1
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultRegister)
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultRegister)
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultRegister)
@@ -1115,6 +1116,40 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
}
private fun funcMklong(fcall: PtBuiltinFunctionCall) {
// result long in R0:R1 (r0=lsw, r1=msw)
fun isArgRegister(expression: PtExpression, reg: RegisterOrPair): Boolean {
if(expression !is PtIdentifier)
return false
return expression.name.startsWith("cx16.${reg.name.lowercase()}")
}
if(fcall.args.size==2) {
// mklong2(msw, lsw)
if(isArgRegister(fcall.args[0], RegisterOrPair.R0) || isArgRegister(fcall.args[0], RegisterOrPair.R1) ||
isArgRegister(fcall.args[1], RegisterOrPair.R0) || isArgRegister(fcall.args[1], RegisterOrPair.R1)) {
error("cannot use R0 and/or R1 as arguments for mklong2 because the result should go into R0:R1 ${fcall.position}")
} else {
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r1", DataType.UWORD)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r0", DataType.UWORD)
}
} else {
// mklong(msb, b2, b1, lsb)
if(isArgRegister(fcall.args[0], RegisterOrPair.R0) || isArgRegister(fcall.args[0], RegisterOrPair.R1) ||
isArgRegister(fcall.args[1], RegisterOrPair.R0) || isArgRegister(fcall.args[1], RegisterOrPair.R1) ||
isArgRegister(fcall.args[2], RegisterOrPair.R0) || isArgRegister(fcall.args[2], RegisterOrPair.R1) ||
isArgRegister(fcall.args[3], RegisterOrPair.R0) || isArgRegister(fcall.args[3], RegisterOrPair.R1)) {
error("cannot use R0 and/or R1 as arguments for mklong because the result should go into R0:R1 ${fcall.position}")
} else {
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r1H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r1L", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[2], "cx16.r0H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[3], "cx16.r0L", DataType.UBYTE)
}
}
}
private fun funcMkword(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
val reg = resultRegister ?: RegisterOrPair.AY
var needAsaveForArg0 = asmgen.needAsaveForExpr(fcall.args[0])
@@ -206,8 +206,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
is PtBuiltinFunctionCall -> {
if (arg.name in arrayOf("lsb", "msb", "lsw", "msw"))
return usesOtherRegistersWhileEvaluating(arg.args[0])
if (arg.name == "mkword")
if (arg.name == "mkword" || arg.name == "mklong2")
return usesOtherRegistersWhileEvaluating(arg.args[0]) || usesOtherRegistersWhileEvaluating(arg.args[1])
if (arg.name == "mklong")
return usesOtherRegistersWhileEvaluating(arg.args[0]) || usesOtherRegistersWhileEvaluating(arg.args[1]) ||
usesOtherRegistersWhileEvaluating(arg.args[2]) || usesOtherRegistersWhileEvaluating(arg.args[3])
return !arg.isSimple()
}
is PtAddressOf -> false
@@ -653,6 +653,10 @@ internal class AssignmentAsmGen(
else -> throw AssemblyError("str return value type mismatch with target")
}
}
returnDt== BaseDataType.LONG -> {
// longs are in R0:R1 (r0=lsw, r1=msw)
assignRegisterLong(target, RegisterOrPair.R0, RegisterOrPair.R1)
}
returnDt==BaseDataType.FLOAT -> {
// float result from function sits in FAC1
assignFAC1float(target)
@@ -3506,6 +3510,29 @@ $endLabel""")
}
}
internal fun assignRegisterLong(target: AsmAssignTarget, lsw: RegisterOrPair, msw: RegisterOrPair) {
when(target.kind) {
TargetStorageKind.VARIABLE -> {
asmgen.out("""
lda cx16.r0L
sta ${target.asmVarname}
lda cx16.r0H
sta ${target.asmVarname}+1
lda cx16.r1L
sta ${target.asmVarname}+2
lda cx16.r1H
sta ${target.asmVarname}+3""")
}
TargetStorageKind.ARRAY -> {
TODO("assign 32 bits int in R0:R1 into array ${target.position}")
}
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister, signed: Boolean, extendWord: Boolean) {
val assignAsWord = target.datatype.isWord
@@ -40,6 +40,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"pokef" -> funcPoke(call, IRDataType.FLOAT)
"pokemon" -> funcPokemon(call)
"mkword" -> funcMkword(call)
"mklong", "mklong2" -> funcMklong(call)
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(call)
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(call)
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(call)
@@ -283,6 +284,52 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1)
}
private fun funcMklong(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val resultReg = codeGen.registers.next(IRDataType.LONG)
if(call.args.size==2) {
// mklong2(word, word)
if((call.args[0] as? PtNumber)?.number == 0.0) {
// msw is 0, use EXT
val lswTr = exprGen.translateExpression(call.args[1])
addToResult(result, lswTr, lswTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.WORD, reg1=resultReg, reg2 = lswTr.resultReg), null)
} else {
val mswTr = exprGen.translateExpression(call.args[0])
addToResult(result, mswTr, mswTr.resultReg, -1)
val lswTr = exprGen.translateExpression(call.args[1])
addToResult(result, lswTr, lswTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.CONCAT, IRDataType.WORD, reg1=resultReg, reg2 = mswTr.resultReg, reg3 = lswTr.resultReg), null)
}
} else {
// mklong(msb, b3, b2, lsb)
if((call.args[0] as? PtNumber)?.number == 0.0 && (call.args[1] as? PtNumber)?.number == 0.0 && (call.args[2] as? PtNumber)?.number == 0.0) {
// use EXT.b + EXT.w
val lsbTr = exprGen.translateExpression(call.args[3])
addToResult(result, lsbTr, lsbTr.resultReg, -1)
val wordReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=wordReg, reg2 = lsbTr.resultReg), null)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.WORD, reg1=resultReg, reg2 = wordReg), null)
} else {
val msbTr = exprGen.translateExpression(call.args[0])
val b2Tr = exprGen.translateExpression(call.args[1])
val b1Tr = exprGen.translateExpression(call.args[2])
val lsbTr = exprGen.translateExpression(call.args[3])
addToResult(result, msbTr, msbTr.resultReg, -1)
addToResult(result, b2Tr, b2Tr.resultReg, -1)
addToResult(result, b1Tr, b1Tr.resultReg, -1)
addToResult(result, lsbTr, lsbTr.resultReg, -1)
val lswReg = codeGen.registers.next(IRDataType.WORD)
val mswReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=mswReg, reg2 = msbTr.resultReg, reg3 = b2Tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=lswReg, reg2 = b1Tr.resultReg, reg3 = lsbTr.resultReg), null)
addInstr(result, IRInstruction(Opcode.CONCAT, IRDataType.WORD, reg1=resultReg, reg2 = mswReg, reg3 = lswReg), null)
}
}
return ExpressionCodeResult(result, IRDataType.LONG, resultReg, -1)
}
private fun funcClamp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val type = irType(call.type)
@@ -26,6 +26,8 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 8 and 255).toDouble()} },
"msw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 16 and 65535).toDouble()} },
"mkword" to ::builtinMkword,
"mklong" to ::builtinMklong,
"mklong2" to ::builtinMklong,
"clamp__ubyte" to ::builtinClampUByte,
"clamp__byte" to ::builtinClampByte,
"clamp__uword" to ::builtinClampUWord,
@@ -203,6 +205,29 @@ private fun builtinMkword(args: List<Expression>, position: Position, program: P
return NumericLiteral(BaseDataType.UWORD, result.toDouble(), position)
}
private fun builtinMklong(args: List<Expression>, position: Position, program: Program): NumericLiteral {
when(args.size) {
2 -> {
val constMsw = args[0].constValue(program) ?: throw NotConstArgumentException()
val constLsw = args[1].constValue(program) ?: throw NotConstArgumentException()
val result = (constMsw.number.toInt() shl 16) or constLsw.number.toInt()
return NumericLiteral(BaseDataType.LONG, result.toDouble(), position)
}
4 -> {
val constMsb = args[0].constValue(program) ?: throw NotConstArgumentException()
val constB2 = args[1].constValue(program) ?: throw NotConstArgumentException()
val constB1 = args[2].constValue(program) ?: throw NotConstArgumentException()
val constLsb = args[3].constValue(program) ?: throw NotConstArgumentException()
val result = (constMsb.number.toInt() shl 24) or
(constB2.number.toInt() shl 16) or
(constB1.number.toInt() shl 8) or
constLsb.number.toInt()
return NumericLiteral(BaseDataType.LONG, result.toDouble(), position)
}
else -> throw SyntaxError("mkword requires msw and lsw, or msb,b2,b1,lsb arguments", position)
}
}
private fun builtinSgn(args: List<Expression>, position: Position, program: Program): NumericLiteral {
if (args.size != 1)
throw SyntaxError("sgn requires one argument", position)
@@ -172,7 +172,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
is PtAddressOf -> value.arrayIndexExpr == null || notComplex(value.arrayIndexExpr!!)
is PtBuiltinFunctionCall -> {
when (value.name) {
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> value.args.all { notComplex(it) }
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "mklong", "mklong2", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> value.args.all { notComplex(it) }
else -> false
}
}
@@ -1498,7 +1498,7 @@ class FunctionCallExpression(override var target: IdentifierReference,
override fun copy() = FunctionCallExpression(target.copy(), args.map { it.copy() }.toMutableList(), position)
override val isSimple = when (target.nameInSource.singleOrNull()) {
in arrayOf("msb", "lsb", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple }
in arrayOf("msb", "lsb", "mkword", "mklong", "mklong2", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple }
else -> false
}
override fun replaceChildNode(node: Node, replacement: Node) {
+60 -45
View File
@@ -14,53 +14,68 @@ main {
; }
sub start() {
long[] array = [-1999888777, -999, 42, 0, 77, 123456, 999999999]
long xx
for xx in array {
txt.print_uw(msw(xx))
txt.spc()
txt.print_uw(lsw(xx))
txt.nl()
}
txt.print_l(mklong2($a000,$bbbb))
txt.spc()
txt.print_l(mklong(9,8,7,6))
txt.nl()
cx16.r8 = $a000
cx16.r9 = $bbbb
cx16.r2L = 9
cx16.r3L = 8
cx16.r4L = 7
cx16.r5L = 6
txt.print_l(mklong2(cx16.r8, cx16.r9))
txt.spc()
txt.print_l(mklong(cx16.r2L,cx16.r3L,cx16.r4L,cx16.r5L))
txt.nl()
array[2] = 0
array[3] = 222222222
array[4] = bignum
array[5]++
array[6]--
txt.print_l(-1999888777)
txt.spc()
txt.print_l(-999)
txt.spc()
txt.print_l(-42)
txt.spc()
txt.print_l(0)
txt.spc()
txt.print_l(bignum)
txt.nl()
txt.print_l(bignum2)
txt.nl()
txt.print_l(-bignum2)
txt.nl()
bignum2 = -bignum2
bignum2++
bignum2++
txt.print_l(bignum2)
txt.nl()
bignum2--
bignum2--
txt.print_l(bignum2)
txt.spc()
txt.print_l(bignum)
txt.nl()
txt.nl()
bignum2 += bignum
txt.print_l(bignum2)
txt.nl()
bignum2 -= bignum
txt.print_l(bignum2)
txt.nl()
; long[] array = [-1999888777, -999, 42, 0, 77, 123456, 999999999]
; long xx
; for xx in array {
; txt.print_uw(msw(xx))
; txt.spc()
; txt.print_uw(lsw(xx))
; txt.nl()
; }
; txt.nl()
; array[2] = 0
; array[3] = 222222222
; array[4] = bignum
; array[5]++
; array[6]--
;
; txt.print_l(-1999888777)
; txt.spc()
; txt.print_l(-999)
; txt.spc()
; txt.print_l(-42)
; txt.spc()
; txt.print_l(0)
; txt.spc()
; txt.print_l(bignum)
; txt.nl()
; txt.print_l(bignum2)
; txt.nl()
; txt.print_l(-bignum2)
; txt.nl()
; bignum2 = -bignum2
; bignum2++
; bignum2++
; txt.print_l(bignum2)
; txt.nl()
; bignum2--
; bignum2--
; txt.print_l(bignum2)
; txt.spc()
; txt.print_l(bignum)
; txt.nl()
; txt.nl()
; bignum2 += bignum
; txt.print_l(bignum2)
; txt.nl()
; bignum2 -= bignum
; txt.print_l(bignum2)
; txt.nl()
; ^^Node test = []
;
@@ -124,7 +124,7 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
is PtBinaryExpression -> false
is PtBuiltinFunctionCall -> {
when (name) {
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple() }
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "mklong", "mklong2", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple() }
else -> false
}
}