From 85c7f8314b4bc751210f0d2dfc54f7dafea255c0 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 13 Mar 2020 02:05:15 +0100 Subject: [PATCH] added exit(rc) builtin function to immediately exit the program with a return code in A register --- compiler/res/prog8lib/prog8lib.asm | 12 ++ .../VarInitValueAndAddressOfCreator.kt | 4 +- .../compiler/target/c64/codegen/AsmGen.kt | 9 +- .../c64/codegen/BuiltinFunctionsAsmGen.kt | 10 +- .../src/prog8/functions/BuiltinFunctions.kt | 141 +++++++++--------- docs/source/programming.rst | 4 + docs/source/todo.rst | 3 +- examples/test.p8 | 44 ++++-- 8 files changed, 135 insertions(+), 92 deletions(-) diff --git a/compiler/res/prog8lib/prog8lib.asm b/compiler/res/prog8lib/prog8lib.asm index cf0f3b2a2..bbe67c02b 100644 --- a/compiler/res/prog8lib/prog8lib.asm +++ b/compiler/res/prog8lib/prog8lib.asm @@ -651,6 +651,18 @@ greatereq_w .proc bmi equal_b._equal_b_false .pend + +orig_stackpointer .byte 0 ; stores the Stack pointer register at program start + +func_exit .proc + ; -- immediately exit the program with a return code in the A register + lda c64.ESTACK_LO+1,x + ldx orig_stackpointer + txs + rts ; return to original caller + .pend + + func_read_flags .proc ; -- put the processor status register on the stack php diff --git a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt index 8e121d135..def02a8b7 100644 --- a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt +++ b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt @@ -9,7 +9,7 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.CompilerException import prog8.functions.BuiltinFunctions -import prog8.functions.FunctionSignature +import prog8.functions.FSignature internal class VarInitValueAndAddressOfCreator(private val program: Program): IAstModifyingVisitor { @@ -129,7 +129,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA } } - private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FunctionSignature, args: MutableList, parent: Statement) { + private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FSignature, args: MutableList, parent: Statement) { // val paramTypesForAddressOf = PassByReferenceDatatypes + DataType.UWORD for(arg in args.withIndex().zip(signature.parameters)) { val argvalue = arg.first.value diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 5c9ba0e26..2dab330f2 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -16,7 +16,7 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.Petscii import prog8.compiler.target.generatedLabelPrefix import prog8.functions.BuiltinFunctions -import prog8.functions.FunctionSignature +import prog8.functions.FSignature import java.math.RoundingMode import java.nio.file.Path import java.time.LocalDate @@ -97,11 +97,15 @@ internal class AsmGen(private val program: Program, out(" .null $9e, format(' %d ', _prog8_entrypoint), $3a, $8f, ' prog8 by idj'") out("+\t.word 0") out("_prog8_entrypoint\t; assembly code starts here\n") + out(" tsx") + out(" stx prog8_lib.orig_stackpointer") out(" jsr prog8_lib.init_system") } options.output == OutputType.PRG -> { out("; ---- program without basic sys call ----") out("* = ${program.actualLoadAddress.toHex()}\n") + out(" tsx") + out(" stx prog8_lib.orig_stackpointer") out(" jsr prog8_lib.init_system") } options.output == OutputType.RAW -> { @@ -138,7 +142,6 @@ internal class AsmGen(private val program: Program, out(" jmp (c64.RESET_VEC)\t; cold reset") } } - out("") } private fun footer() { @@ -840,7 +843,7 @@ internal class AsmGen(private val program: Program, internal fun translateExpression(expression: Expression) = expressionsAsmGen.translateExpression(expression) - internal fun translateFunctioncallExpression(functionCall: FunctionCall, signature: FunctionSignature) = + internal fun translateFunctioncallExpression(functionCall: FunctionCall, signature: FSignature) = builtinFunctionsAsmGen.translateFunctioncallExpression(functionCall, signature) internal fun translateFunctionCall(functionCall: FunctionCall) = diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index c648de2c6..d55a26abb 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -16,19 +16,19 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.toHex import prog8.compiler.AssemblyError -import prog8.functions.FunctionSignature +import prog8.functions.FSignature internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen) { - internal fun translateFunctioncallExpression(fcall: FunctionCall, func: FunctionSignature) { + internal fun translateFunctioncallExpression(fcall: FunctionCall, func: FSignature) { translateFunctioncall(fcall, func, false) } - internal fun translateFunctioncallStatement(fcall: FunctionCallStatement, func: FunctionSignature) { + internal fun translateFunctioncallStatement(fcall: FunctionCallStatement, func: FSignature) { translateFunctioncall(fcall, func, true) } - private fun translateFunctioncall(fcall: IFunctionCall, func: FunctionSignature, discardResult: Boolean) { + private fun translateFunctioncall(fcall: IFunctionCall, func: FSignature, discardResult: Boolean) { val functionName = fcall.target.nameInSource.last() if (discardResult) { if (func.pure) @@ -603,7 +603,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val """) } - private fun translateFunctionArguments(args: MutableList, signature: FunctionSignature) { + private fun translateFunctionArguments(args: MutableList, signature: FSignature) { args.forEach { asmgen.translateExpression(it) } diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 128f81661..44514b804 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -7,88 +7,87 @@ import prog8.compiler.CompilerException import kotlin.math.* -class BuiltinFunctionParam(val name: String, val possibleDatatypes: Set) +class FParam(val name: String, val possibleDatatypes: Set) typealias ConstExpressionCaller = (args: List, position: Position, program: Program) -> NumericLiteralValue -class FunctionSignature(val pure: Boolean, // does it have side effects? - val parameters: List, - val returntype: DataType?, - val constExpressionFunc: ConstExpressionCaller? = null) +class FSignature(val pure: Boolean, // does it have side effects? + val parameters: List, + val returntype: DataType?, + val constExpressionFunc: ConstExpressionCaller? = null) val BuiltinFunctions = mapOf( // this set of function have no return value and operate in-place: - "rol" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "ror" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "rol2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "ror2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), - "lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), - "sort" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null), - "reverse" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null), + "rol" to FSignature(false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + "ror" to FSignature(false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + "rol2" to FSignature(false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + "ror2" to FSignature(false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + "lsl" to FSignature(false, listOf(FParam("item", IntegerDatatypes)), null), + "lsr" to FSignature(false, listOf(FParam("item", IntegerDatatypes)), null), + "sort" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null), + "reverse" to FSignature(false, listOf(FParam("array", ArrayDatatypes)), null), // these few have a return value depending on the argument(s): - "max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args - "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args - "sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args - "abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument - "len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length + "max" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args + "min" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args + "sum" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args + "abs" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument + "len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length // normal functions follow: - "sgn" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ), - "sin" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) }, - "sin8" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ), - "sin8u" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ), - "sin16" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ), - "sin16u" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ), - "cos" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) }, - "cos8" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ), - "cos8u" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ), - "cos16" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ), - "cos16u" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ), - "tan" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) }, - "atan" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) }, - "ln" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) }, - "log2" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) }, - "sqrt16" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()).toInt() } }, - "sqrt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) }, - "rad" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) }, - "deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) }, - "round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::round) }, - "floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) }, - "ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) }, - "any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) }, - "all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) }, - "lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 }}, - "msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { 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), - "rsave" to FunctionSignature(false, emptyList(), null), - "rrestore" to FunctionSignature(false, emptyList(), null), - "set_carry" to FunctionSignature(false, emptyList(), null), - "clear_carry" to FunctionSignature(false, emptyList(), null), - "set_irqd" to FunctionSignature(false, emptyList(), null), - "clear_irqd" to FunctionSignature(false, emptyList(), null), - "read_flags" to FunctionSignature(false, emptyList(), DataType.UBYTE), - "swap" to FunctionSignature(false, listOf(BuiltinFunctionParam("first", NumericDatatypes), BuiltinFunctionParam("second", NumericDatatypes)), null), - "memcopy" to FunctionSignature(false, listOf( - BuiltinFunctionParam("from", IterableDatatypes + DataType.UWORD), - BuiltinFunctionParam("to", IterableDatatypes + DataType.UWORD), - BuiltinFunctionParam("numbytes", setOf(DataType.UBYTE))), null), - "memset" to FunctionSignature(false, listOf( - BuiltinFunctionParam("address", IterableDatatypes + DataType.UWORD), - BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)), - BuiltinFunctionParam("bytevalue", ByteDatatypes)), null), - "memsetw" to FunctionSignature(false, listOf( - BuiltinFunctionParam("address", IterableDatatypes + DataType.UWORD), - BuiltinFunctionParam("numwords", setOf(DataType.UWORD)), - BuiltinFunctionParam("wordvalue", setOf(DataType.UWORD, DataType.WORD))), null), - "strlen" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", setOf(DataType.STR))), DataType.UBYTE, ::builtinStrlen) + "sgn" to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ), + "sin" to FSignature(true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) }, + "sin8" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ), + "sin8u" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ), + "sin16" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ), + "sin16u" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ), + "cos" to FSignature(true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) }, + "cos8" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ), + "cos8u" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ), + "cos16" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ), + "cos16u" to FSignature(true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ), + "tan" to FSignature(true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) }, + "atan" to FSignature(true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) }, + "ln" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) }, + "log2" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) }, + "sqrt16" to FSignature(true, listOf(FParam("value", setOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()).toInt() } }, + "sqrt" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) }, + "rad" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) }, + "deg" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) }, + "round" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::round) }, + "floor" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) }, + "ceil" to FSignature(true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) }, + "any" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) }, + "all" to FSignature(true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) }, + "lsb" to FSignature(true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 }}, + "msb" to FSignature(true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> x ushr 8 and 255}}, + "mkword" to FSignature(true, listOf(FParam("lsb", setOf(DataType.UBYTE)), FParam("msb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword), + "rnd" to FSignature(true, emptyList(), DataType.UBYTE), + "rndw" to FSignature(true, emptyList(), DataType.UWORD), + "rndf" to FSignature(true, emptyList(), DataType.FLOAT), + "exit" to FSignature(false, listOf(FParam("returnvalue", setOf(DataType.UBYTE))), null), + "rsave" to FSignature(false, emptyList(), null), + "rrestore" to FSignature(false, emptyList(), null), + "set_carry" to FSignature(false, emptyList(), null), + "clear_carry" to FSignature(false, emptyList(), null), + "set_irqd" to FSignature(false, emptyList(), null), + "clear_irqd" to FSignature(false, emptyList(), null), + "read_flags" to FSignature(false, emptyList(), DataType.UBYTE), + "swap" to FSignature(false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null), + "memcopy" to FSignature(false, listOf( + FParam("from", IterableDatatypes + DataType.UWORD), + FParam("to", IterableDatatypes + DataType.UWORD), + FParam("numbytes", setOf(DataType.UBYTE))), null), + "memset" to FSignature(false, listOf( + FParam("address", IterableDatatypes + DataType.UWORD), + FParam("numbytes", setOf(DataType.UWORD)), + FParam("bytevalue", ByteDatatypes)), null), + "memsetw" to FSignature(false, listOf( + FParam("address", IterableDatatypes + DataType.UWORD), + FParam("numwords", setOf(DataType.UWORD)), + FParam("wordvalue", setOf(DataType.UWORD, DataType.WORD))), null), + "strlen" to FSignature(true, listOf(FParam("string", setOf(DataType.STR))), DataType.UBYTE, ::builtinStrlen) ) fun builtinMax(array: List): Number = array.maxBy { it.toDouble() }!! diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 17209b72a..031a24258 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -836,6 +836,10 @@ rrestore() read_flags() Returns the current value of the CPU status register. +exit(returncode) + Immediately stops the program and exits it, with the returncode in the A register. + Note: custom interrupt handlers remain active unless manually cleared first! + Library routines diff --git a/docs/source/todo.rst b/docs/source/todo.rst index dcb9c98f0..e776b423a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,8 @@ TODO ==== - option to load library files from a directory instead of the embedded ones -- exit('message', returncode) function to immediately exit the program with this message (restores stack) +- compiler warning 'unreachable code' for statement following an exit() function call +- code optimizer: remove all statements following an exit() function call - vector inc/dec/add/sub/mul/div...? arrayvar++ / arrayvar-- / arrayvar += 2 / arrayvar -= 2 / arrayvar *= 3 / arrayvar /= 3 diff --git a/examples/test.p8 b/examples/test.p8 index c681fe433..c6d64e8d1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,14 +4,38 @@ main { sub start() { - - lsr(@(9999+A)) - ror(@(9999+A)) - rol(@(9999+A)) - ror2(@(9999+A)) - rol2(@(9999+A)) - - c64scr.print_ub(X) - + c64scr.print("spstart:") + print_stackpointer() + sub1() + c64scr.print("spend:") + print_stackpointer() } -} + + sub sub1() { + c64scr.print("sp1:") + print_stackpointer() + sub2() + } + + sub sub2() { + c64scr.print("sp2:") + print_stackpointer() + exit(65) + sub3() ; TODO unreachable code compiler warning + remove the code in optimizer + sub3() ; TODO unreachable code compiler warning + remove the code in optimizer + sub3() ; TODO unreachable code compiler warning + remove the code in optimizer + } + + sub sub3() { + c64scr.print("sp3:") + print_stackpointer() + } + + sub print_stackpointer() { + %asm {{ + tsx + }} + c64scr.print_ub(X) ; prints stack pointer + c64.CHROUT('\n') + } + }