From 58f696d00a7d3797981182455cd8e75a17f4dbc1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 30 Nov 2024 20:46:31 +0100 Subject: [PATCH] document the @R0 - @R15 register support for normal subroutine parameters --- docs/source/programming.rst | 21 +++++++++++++++++++++ docs/source/technical.rst | 5 ++++- docs/source/todo.rst | 2 -- examples/test.p8 | 23 +++++++++++++++-------- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index ed4b4c141..7cf9bb5d7 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -987,6 +987,27 @@ Subroutines can be defined in a Block, but also nested inside another subroutine There are three different types of subroutines: regular subroutines (the one above), assembly-only, and external subroutines. These last two are described in detail below. +Reusing *virtual registers* R0-R15 for parameters +************************************************* +.. sidebar:: + 🦶🔫 Footgun warning + + when using this the program can clobber the contents of R0-R15 when doing other operations that also + use these registers, or when calling other routines because Prog8 doesn't have a callstack. + Be very aware of what you are doing, the compiler can't guarantee correct values by itself anymore. + +Normally, every subroutine parameter will get its own local variable in the subroutine where the argument value +will be stored when the subroutine is called. In certain situations, this may lead to many variables being allocated. +You *can* instruct the compiler to not allocate a new variable, but instead to reuse one of the *virtual registers* R0-R15 +(accessible in the code as ``cx16.r0`` - ``cx16.r15``) for the parameter. This is done by adding a ``@Rx`` tag +to the parameter. This can only be done for byte and word types. +Note: the R0-R15 *virtual registers* are described in more detail below for the Assembly subroutines. +Here's an example that reuses the R0 and the R1L (lower byte of R1) virtual registers for the paremeters:: + + sub get_indexed_byte(uword pointer @R0, ubyte index @R1) -> ubyte { + return @(cx16.r0 + cx16.r1L) + } + Assembly-Subroutines ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/technical.rst b/docs/source/technical.rst index 271155b99..e946ea9c1 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -157,7 +157,10 @@ some builtin functions are special and won't exactly follow these rules. **Some arguments will be passed in registers:** For single byte and word arguments, the values are simply loaded in cpu registers by the caller before calling the subroutine. *The subroutine itself will take care of putting the values into the parameter variables.* This saves on code size because -otherwise all callers would have to store the values in those variables themselves. The rules for this are as follows: +otherwise all callers would have to store the values in those variables themselves. +Note that his convention is also still used for subroutines that specify parameters to be put into +one of the *virtual registers* R0-R15, as those are in the end just variables too. +The rules are as follows: Single byte parameter: ``sub foo(ubyte bar) { ... }`` gets bar in the accumulator A, *subroutine* stores it into parameter variable diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5ef9f3521..6d73effb9 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,6 @@ TODO ==== -document the @R0 - @R15 register support for normal subroutine parameters (🦶🔫 Footgun warning!) - make a compiler switch to disable footgun warnings what to do with bankof(): keep it? add another syntax like \`value or ^value to get the bank byte? diff --git a/examples/test.p8 b/examples/test.p8 index ddf0d8fc1..028b77e77 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,12 +1,19 @@ +%import textio +%option no_sysinit +%zeropage basicsafe + main { sub start() { - } -} - -xyz { - uword buffer_ptr = memory("buffers_stack", 8192, 0) - - sub pop() -> ubyte { - return buffer_ptr[2] + @($2005) = 0 + txt.print_ub(get_indexed_byte($2000, 5)) + txt.nl() + @($2005) = 123 + txt.print_ub(get_indexed_byte($2000, 5)) + txt.nl() + + } + + sub get_indexed_byte(uword pointer @R0, ubyte index @R1) -> ubyte { + return @(cx16.r0 + cx16.r1L) } }