diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 8a5cf2be7..bba5cebc6 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -518,12 +518,8 @@ internal class AstChecker(private val program: Program, override fun visit(addressOf: AddressOf) { val variable=addressOf.identifier.targetVarDecl(program) - if(variable!=null - && variable.datatype !in ArrayDatatypes - && variable.type!=VarDeclType.MEMORY - && variable.struct == null - && variable.datatype != DataType.STR && variable.datatype!=DataType.STRUCT) - errors.err("invalid pointer-of operand type", addressOf.position) + if(variable!=null && variable.type==VarDeclType.CONST) + errors.err("invalid pointer-of operand type", addressOf.position) super.visit(addressOf) } diff --git a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt index 9c32fa9f0..d61a9a06f 100644 --- a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt @@ -144,6 +144,7 @@ private val functionSignatures: List = listOf( FSignature("rndf" , false, emptyList(), DataType.FLOAT), FSignature("memory" , true, listOf(FParam("name", setOf(DataType.STR)), FParam("size", setOf(DataType.UWORD))), DataType.UWORD), FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null), + FSignature("callfar" , false, listOf(FParam("bank", setOf(DataType.UBYTE)), FParam("address", setOf(DataType.UWORD)), FParam("arg", setOf(DataType.UWORD))), null), ) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index 6324c785e..0ce08cfc4 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -13,6 +13,7 @@ import prog8.ast.toHex import prog8.compiler.AssemblyError import prog8.compiler.functions.FSignature import prog8.compiler.target.CpuType +import prog8.compiler.target.Cx16Target import prog8.compiler.target.cpu6502.codegen.assignment.* import prog8.compiler.target.subroutineFloatEvalResultVar2 @@ -65,10 +66,56 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val "pokew" -> funcPokeW(fcall) "poke" -> throw AssemblyError("poke() should have been replaced by @()") "cmp" -> funcCmp(fcall) + "callfar" -> funcCallFar(fcall) else -> throw AssemblyError("missing asmgen for builtin func ${func.name}") } } + private fun funcCallFar(fcall: IFunctionCall) { + if(asmgen.options.compTarget !is Cx16Target) + throw AssemblyError("callfar only works on cx16 target at this time") + + val bank = fcall.args[0].constValue(program)?.number?.toInt() + val address = fcall.args[1].constValue(program)?.number?.toInt() + if(bank==null || address==null) + throw AssemblyError("callfar (jsrfar) requires constant arguments") + + if(address !in 0xa000..0xbfff) + throw AssemblyError("callfar done on address outside of cx16 banked ram") + if(bank==0) + throw AssemblyError("callfar done on bank 0 which is reserved for the kernal") + + val argAddrArg = fcall.args[2] + if(argAddrArg.constValue(program)?.number == 0) { + asmgen.out(""" + jsr cx16.jsrfar + .word ${address.toHex()} + .byte ${bank.toHex()}""") + } else { + when(argAddrArg) { + is AddressOf -> { + if(argAddrArg.identifier.targetVarDecl(program)?.datatype != DataType.UBYTE) + throw AssemblyError("callfar done with 'arg' pointer to variable that's not UBYTE") + asmgen.out(""" + lda ${asmgen.asmVariableName(argAddrArg.identifier)} + jsr cx16.jsrfar + .word ${address.toHex()} + .byte ${bank.toHex()} + sta ${asmgen.asmVariableName(argAddrArg.identifier)}""") + } + is NumericLiteralValue -> { + asmgen.out(""" + lda ${argAddrArg.number.toHex()} + jsr cx16.jsrfar + .word ${address.toHex()} + .byte ${bank.toHex()} + sta ${argAddrArg.number.toHex()}""") + } + else -> throw AssemblyError("callfar only accepts pointer-of a (ubyte) variable or constant memory address for the 'arg' parameter") + } + } + } + private fun funcCmp(fcall: IFunctionCall) { val arg1 = fcall.args[0] val arg2 = fcall.args[1] diff --git a/docs/source/programming.rst b/docs/source/programming.rst index dae71a46f..8e4d3cc44 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -897,6 +897,15 @@ memory(name, size) The return value is just a simple uword address so it cannot be used as an array in your program. You can only treat it as a pointer or use it in inline assembly. +callfar(bank, address, argumentaddress) ; NOTE: specific to cx16 compiler target for now + Calls an assembly routine in another ram-bank on the CommanderX16 (using the ``jsrfar`` routine) + The banked RAM is located in the address range $A000-$BFFF (8 kilobyte). + Notice that bank $00 is used by the Kernal and should not be used by user code. + The third argument can be used to designate the memory address + of an argument for the routine; it will be loaded into the A register and will + receive the result value returned by the routine in the A register. If you leave this at zero, + no argument passing will be done. + Library routines ---------------- diff --git a/examples/test.p8 b/examples/test.p8 index e51822822..76a117383 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,23 +1,30 @@ %import textio -%import string -%zeropage dontuse -%import test_stack +%zeropage basicsafe main { sub start() { - uword zz = $4000 + ubyte uu + cx16.rambank(1) + sys.memcopy(&banked.double, $a000, 100) + cx16.rambank(0) + txt.nl() - txt.print("hello") - - txt.print_uwhex(peekw(zz+2), true) - - @(zz+2) = lsb($ea31) - @(zz+3) = msb($ea31) - pokew(zz+2, $ea32) ; TODO fix crash - zz = peekw(zz+2) ; TODO fix crash with asm - txt.print_uwhex(zz, true) + uword ww + uu = 99 + txt.print_ub(uu) + txt.nl() + callfar($01, $a000, &uu) + txt.print_ub(uu) } - } + +banked { + asmsub double(ubyte number @A) -> ubyte @A { + %asm {{ + asl a + rts + }} + } +} diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index 7bdf45ca9..c16e8a749 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -14,7 +14,7 @@ - + diff --git a/syntax-files/Vim/prog8_builtins.vim b/syntax-files/Vim/prog8_builtins.vim index 613c7411b..298e1073c 100644 --- a/syntax-files/Vim/prog8_builtins.vim +++ b/syntax-files/Vim/prog8_builtins.vim @@ -17,7 +17,7 @@ syn keyword prog8BuiltInFunc any all len max min reverse sum sort " Miscellaneous functions syn keyword prog8BuiltInFunc cmp lsb msb mkword peek peekw poke pokew rnd rndw syn keyword prog8BuiltInFunc rndf fastrnd8 rol rol2 ror ror2 sizeof offsetof -syn keyword prog8BuiltInFunc swap memory +syn keyword prog8BuiltInFunc swap memory callfar " c64/floats.p8