From cb47e2c149a133dc3d0fd3cbcf177039f8da7384 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 3 Nov 2024 20:39:44 +0100 Subject: [PATCH] documented the romsub bank additions --- README.md | 1 + docs/source/index.rst | 1 + docs/source/programming.rst | 3 ++- docs/source/syntaxreference.rst | 15 ++++++++----- docs/source/technical.rst | 38 +++++++++++++++++++++++++++++++++ docs/source/todo.rst | 9 +++++--- examples/test.p8 | 24 ++++----------------- 7 files changed, 62 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 9777c9f3a..76820e4d7 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ What does Prog8 provide? - inline assembly allows you to have full control when every cycle or byte matters - supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets) - encode strings and characters into petscii or screencodes or even other encodings +- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks *Rapid edit-compile-run-debug cycle:* diff --git a/docs/source/index.rst b/docs/source/index.rst index 99ee9b8bb..5bccddfea 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -104,6 +104,7 @@ Features - Easy and highly efficient integration with external subroutines and ROM routines on the target systems. - Strings can contain escaped characters but also many symbols directly if they have a PETSCII equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \\, {, } and | are also accepted and converted to the closest PETSCII equivalents. - Encode strings and characters into petscii or screencodes or even other encodings, as desired (C64/Cx16) +- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks - Identifiers can contain Unicode Letters, so ``knäckebröd``, ``приблизительно``, ``見せしめ`` and ``π`` are all valid identifiers. - Advanced code optimizations to make the resulting program smaller and faster - Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations. diff --git a/docs/source/programming.rst b/docs/source/programming.rst index e2f80ef64..27c421058 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -805,7 +805,8 @@ Subroutines are parts of the code that can be repeatedly invoked using a subrout Their definition, using the ``sub`` statement, includes the specification of the required parameters and return value. Subroutines can be defined in a Block, but also nested inside another subroutine. Everything is scoped accordingly. With ``asmsub`` you can define a low-level subroutine that is implemented directly in assembly and takes parameters -directly in registers. +directly in registers. Finally with ``romsub`` you can define an external subroutine that's implemented outside +of the program (for instance, a ROM routine, or a routine in a library loaded elsewhere in RAM). Trivial ``asmsub`` routines can be tagged as ``inline`` to tell the compiler to copy their code in-place to the locations where the subroutine is called, rather than inserting an actual call and return to the diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 75a30e361..3bb232428 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -781,10 +781,10 @@ The parameters is a (possibly empty) comma separated list of " bool @Pc, ubyte @ A, ubyte @ X, ubyte @ Y @@ -793,9 +793,14 @@ This defines the ``LOAD`` subroutine at memory address $FFD5, taking arguments i and returning stuff in several registers as well. The ``clobbers`` clause is used to signify to the compiler what CPU registers are clobbered by the call instead of being unchanged or returning a meaningful result value. +**Banks:** it is possible to declare a non-standard ROM or RAM bank that the routine is living in, with ``@rombank`` or ``@rambank`` like this: +``romsub @rombank 10 $C09F = audio_init()`` to define a routine at $C09F in ROM bank 10. +See :ref:`banking` for more information. + .. note:: - Unlike what it's name may suggest, ``romsub`` can also define an external subroutine elsewhere in normal RAM. - It's just that you explicitly define the memory address where it is located and it doesn't matter if that is in ROM or in RAM. + ``romsub`` is most often used to define ROM subroutines. But contrary to what the name may suggest, + it can also define an external subroutine elsewhere in normal RAM. It simply states the address + and signature of the subroutine; it doesn't care if the routine is in ROM or RAM address space. User-written subroutines in the program source code itself, implemented purely in assembly and which have an assembly calling convention (i.e. the parameters are strictly passed via cpu registers), are defined with ``asmsub`` like this:: diff --git a/docs/source/technical.rst b/docs/source/technical.rst index de2210b29..41ff59049 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -25,6 +25,44 @@ It is possible to relocate the BSS section using a compiler option so that more system ram is available for the program code itself. +.. _banking: + +ROM/RAM bank selection +---------------------- + +On certain systems prog8 provides support for managing the ROM or RAM banks that are active. +For example, on the Commander X16, you can use ``cx16.getrombank()`` to get the active ROM bank, +and ``cx16.rombank(10)`` to make rom bank 10 active. Likewise, ``cx16.getrambank()`` to get the active RAM bank, +and ``cx16.rambank(10)`` to make ram bank 10 active. This is explicit manual banking control. + +However, Prog8 also provides something more sophisticated than this, when dealing with banked subroutines: + +External subroutines defined with ``romsub`` can have a non-standard ROM or RAM bank specified as well. +The compiler will then transparently change a call to this routine so that the correct bank is activated +automatically before the normal jump to the subroutine (and switched back on return). The programmer doesn't +have to bother anymore with setting/resetting the banks manually, or having the program crash because +the routine is called in the wrong bank! You define such a routine by adding ``@rombank `` or ``@rambank `` +to the romsub subroutine definition. This specifies the bank number where the subroutine is located in:: + + romsub @rombank 10 $C09F = audio_init() + +When you then call this routine in your program as usual, the compiler will no longer generate a simple JSR instruction to the +routine. Instead it will generate a piece of code that automatically switches the ROM or RAM bank to the +correct value, does the call, and switches the bank back. The exact code will be different for different +compilation targets, and not all targets even have banking or support this. As an example, +on the Commander X16, prog8 will use the JSRFAR kernal routine for this. On the Commodore 128, a similar call exists. +Other compilation targets don't have banking or prog8 doesn't yet support automatic bank selection on them. + +Notice that the symbol for this routine in the assembly source code will still be defined as usual. +The bank number is not translated into assembly (only as a comment):: + + p8s_audio_init = $c09f ; @rombank 10 + +.. caution:: + Calls with automatic bank switching like this are not safe to use from IRQ handlers. Don't use them there. + Instead change banks in a controlled manual way (or not at all). + + .. _symbol-prefixing: Symbol prefixing in generated Assembly code diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 666d48f2a..ca40c9629 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,14 +1,17 @@ TODO ==== -add docs for @rombank @rambank on romsubs. Add promo in docs that prog8 does automatic bank switching when calling such a romsub (on cx16 and c128) +consolidate @rombank and @rambank into just @bank -rename 'romsub' to 'extsub' ? +add example for cx16 that compiles and loads libraries in different ram banks and calls romsub from rom and ram banks automatically for releasenotes: gfx2.width and gfx2.height got renamed as gfx_lores.WIDTH/HEIGHT or gfx_hires4.WIDTH/HEIGTH constants. Screen mode routines also renamed. -regenerate symbol dump files +add support for banked romsubs on the C64 as well (banks basic/kernal rom in/out) +rename 'romsub' to 'extsub' ? keep romsub as alias? + +regenerate symbol dump files Improve register load order in subroutine call args assignments: in certain situations, the "wrong" order of evaluation of function call arguments is done which results diff --git a/examples/test.p8 b/examples/test.p8 index 739c51c2e..cc12099d3 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,27 +3,11 @@ %zeropage basicsafe main { + romsub @rombank 10 $C09F = audio_init() + romsub @rambank 22 $A000 = hiram_routine() sub start() { - block1.sub1() - block1.sub2() + audio_init() + hiram_routine() } } - -block1 { - %option merge - - sub sub1() { - txt.print("sub1") - } -} - - -block1 { - %option merge - - sub sub2() { - txt.print("sub2") - } -} -