diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 318f6dbd8..67faf36c1 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -823,6 +823,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } } "msb" -> prog.instr(Opcode.MSB) // note: LSB is not a function, it's just an alias for the cast "... as ubyte" + "mkword" -> prog.instr(Opcode.MKWORD) "lsl" -> { val arg = args.single() val dt = arg.resultingDatatype(namespace, heap) diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index 7f7201aa9..fd85b836e 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -133,6 +133,7 @@ enum class Opcode { // numeric type conversions MSB, // note: lsb is equivalent to CAST_UW_TO_UB or CAST_W_TO_UB + MKWORD, // create a word from lsb + msb CAST_UB_TO_B, CAST_UB_TO_UW, CAST_UB_TO_W, diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 77e5bf0ce..3bb78888c 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -783,6 +783,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.CAST_UB_TO_UW, Opcode.CAST_UB_TO_W -> " lda #0 | sta ${(ESTACK_HI+1).toHex()},x" // clear the msb Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1).toHex()},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x" + // TODO: Opcode.MKWORD -> " inx | lda ${ESTACK_LO.toHex()},x | sta ${(ESTACK_HI+1).toHex()},x " Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better? """ @@ -3011,6 +3012,66 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, adc ${(ESTACK_HI+1).toHex()},x sta ${(ESTACK_HI+1).toHex()},x """ + }, + + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment -> + """ + lda ${segment[0].callLabel} + sta ${ESTACK_LO.toHex()},x + lda ${segment[1].callLabel} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD)) { segment -> + """ + lda #${hexVal(segment[0])} + sta ${ESTACK_LO.toHex()},x + lda ${segment[1].callLabel} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.MKWORD)) { segment -> + """ + lda ${segment[0].callLabel} + sta ${ESTACK_LO.toHex()},x + lda #${hexVal(segment[1])} + sta ${ESTACK_HI.toHex()},x + dex + """ + }, + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD, Opcode.POP_VAR_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + sta ${segment[3].callLabel} + lda ${segment[1].callLabel} + sta ${segment[3].callLabel}+1 + """ + }, + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_BYTE, Opcode.MKWORD, Opcode.POP_VAR_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + sta ${segment[3].callLabel} + lda #${hexVal(segment[1])} + sta ${segment[3].callLabel}+1 + """ + }, + AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD, Opcode.POP_VAR_WORD)) { segment -> + """ + lda #${hexVal(segment[0])} + sta ${segment[3].callLabel} + lda ${segment[1].callLabel} + sta ${segment[3].callLabel}+1 + """ + }, + AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.PUSH_VAR_BYTE, Opcode.MKWORD, Opcode.CAST_UW_TO_W, Opcode.POP_VAR_WORD)) { segment -> + """ + lda ${segment[0].callLabel} + sta ${segment[4].callLabel} + lda ${segment[1].callLabel} + sta ${segment[4].callLabel}+1 + """ } ) diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index fc1d5e2b9..396a2cf16 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -56,6 +56,9 @@ val BuiltinFunctions = mapOf( "all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }}, "lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }}, "msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x ushr 8 and 255}}, + "mkword" to FunctionSignature(true, listOf( + BuiltinFunctionParam("lsb", setOf(DataType.UBYTE)), + BuiltinFunctionParam("msb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword), "rnd" to FunctionSignature(true, emptyList(), DataType.UBYTE), "rndw" to FunctionSignature(true, emptyList(), DataType.UWORD), "rndf" to FunctionSignature(true, emptyList(), DataType.FLOAT), @@ -302,6 +305,16 @@ private fun builtinLen(args: List, position: Position, namespace:IN } } + +private fun builtinMkword(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { + if (args.size != 2) + throw SyntaxError("mkword requires lsb and msb arguments", position) + val constLsb = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() + val constMsb = args[1].constValue(namespace, heap) ?: throw NotConstArgumentException() + val result = (constMsb.asIntegerValue!! shl 8) or constLsb.asIntegerValue!! + return LiteralValue(DataType.UWORD, wordvalue = result, position = position) +} + private fun builtinSin8(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { if (args.size != 1) throw SyntaxError("sin8 requires one argument", position) diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 25ca00b9e..fce5ef094 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1028,6 +1028,13 @@ class StackVm(private var traceOutputFile: String?) { checkDt(v, DataType.UWORD, DataType.WORD) evalstack.push(v.msb()) } + Opcode.MKWORD -> { + val msb = evalstack.pop() + val lsb = evalstack.pop() + checkDt(lsb, DataType.UBYTE) + checkDt(msb, DataType.UBYTE) + evalstack.push(Value(DataType.UWORD, (msb.integerValue() shl 8) or lsb.integerValue())) + } Opcode.AND_BYTE -> { val (top, second) = evalstack.pop2() checkDt(top, DataType.UBYTE) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 62787d81d..7ae33fd50 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -605,6 +605,9 @@ lsb(x) msb(x) Get the most significant byte of the word x. +mkword(lsb, msb) + Efficiently create a word value from two bytes (the lsb and the msb). Avoids multiplication and shifting. + any(x) 1 ('true') if any of the values in the array value x is 'true' (not zero), else 0 ('false') diff --git a/examples/test.p8 b/examples/test.p8 index 9bac7bbf2..f2a7378cd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,20 +1,46 @@ %import c64utils -%import c64flt ~ main { sub start() { -; @todo create word function ;c64.SPXY[i] = (rnd() as uword) * 256 + (50+25*i) ; @todo more efficient +1/-1 additions in expressions - float f1 = c64flt.TWOPI - c64flt.print_fln(3.1415) - c64flt.print_fln(f1) - f1 = 3.1415 - f1 = 3.1415 - f1 = 3.1415 - f1 = 3.1415 + ubyte lsbb = $aa + ubyte msbb = $44 + uword[4] uwarr + + uword uw = (msbb as uword)*256 + lsbb + + c64scr.print_uwhex(0, uw) + c64.CHROUT('\n') + uw = mkword(lsbb, msbb) + c64scr.print_uwhex(0, uw) + c64.CHROUT('\n') + uw = mkword($aa, $44) + c64scr.print_uwhex(0, uw) + c64.CHROUT('\n') + + uw = mkword(lsbb, $44) + c64scr.print_uwhex(0, uw) + c64.CHROUT('\n') + uw = mkword($aa, msbb) + c64scr.print_uwhex(0, uw) + c64.CHROUT('\n') + uwarr[2] = mkword(lsbb, msbb) + c64scr.print_uwhex(0, uwarr[2]) + c64.CHROUT('\n') + uwarr[2] = mkword(lsbb, $44) + c64scr.print_uwhex(0, uwarr[2]) + c64.CHROUT('\n') + uwarr[2] = mkword($aa, msbb) + c64scr.print_uwhex(0, uwarr[2]) + c64.CHROUT('\n') + + word w = mkword(lsbb,msbb) as word + c64scr.print_w(w) + c64.CHROUT('\n') + } }