Next: , Previous: Startup and Termination, Up: Top


8 Bank Switching

Because the 6809 has a native 16-bit address space, only 64KB of code and data can be addressed at a time. On most platforms, some of this space is reserved for I/O, limiting the amount that can be used by the compiler even further.

Many architectures allow for some form of bank switching, where a larger amount of memory exists, but only portions of it are accessible at a time. GCC6809 has some builtin support to make it easier to work with systems that support bank switching. However, currently it can only help with switching out code pages. Data accesses across different banks are not handled automatically, and require explicit instructions from the programmer.

8.1 Hardware Requirements

Bank switching can only work when the underlying hardware supports it. GCC does not care how the hardware works, aside from a few rules:

8.2 Declaring and Defining Banked Functions

When an ordinary jsr instruction will not suffice, GCC can emit what is called a far call. To determine when a far call is needed, GCC must know the bank number (if any) of the caller, and that of the callee.

The caller bank is identified from the -far-code-page command-line option. All functions in the same source file are assumed to be in the bank number identified by this option. If not stated, then all of the functions are assumed to be in a fixed section.

The callee bank is identified by using the far attribute on the declaration of that function. Remember that declarations occur in header files, not in source files. If you do not provide a prototype for a function, GCC assumes it is in a fixed section.

8.3 Making Far Function Calls

When GCC needs to emit a function call, the target function is in a banked section, and the caller is not in the same bank, then a special call sequence is emitted which looks like this:

     jsr __far_call_handler
     	.dw target_function
     	.db target_bank

Here, target_function is the function being called, and target_bank is the bank number where that function is located, according to the far attribute in its declaration.

The function __far_call_handler is system dependent. GCC6809 does not provide a default farcall handler; you must write it yourself. This function should:

It is practically impossible to write the function in C to meet all of these requirements; writing it in assembly language is much easier.

Here is the far call handler used on the FreeWPC platform:

     		.area direct
          	__far_call_address:
          		.blkb 2
     
          .area .text
          	.globl __far_call_handler
          	__far_call_handler:
          		pshs  b,u,x                 ; Save all registers used for parameters
          		ldu   5,s                   ; Get pointer to the parameters
          		ldx   ,u++                  ; Get the called function offset
          		ldb   ,u+                   ; Get the called function page
          		stu   5,s                   ; Update return address
          		stx   *__far_call_address   ; Move function offset to memory
          		lda   IO_BANK_REGISTER      ; Read current bank register value
          		stb   IO_BANK_REGISTER      ; Set new bank register value
          		puls  b,u,x                 ; Restore parameters
          		pshs  a                     ; Save bank switch value to be restored
          		jsr   [__far_call_address]  ; Call function
          		puls  a                     ; Restore A
          		sta   IO_BANK_REGISTER      ; Restore bank register
          		rts

GCC does not emit the far call sequence when the caller and callee are both in the same bank; in that case, the bank switch register is already correct.

GCC will raise a fatal error if one or more of a far call target's parameters needs to be pushed onto the stack. The thinking is that the farcall handler cannot save the previous value of the bank switch register without also pushing onto the stack, which causes confusion about where the arguments are actually located. If your farcall handler doesn't use the call stack (for example, it saves into a separately declared stack), then you can turn off this error by compiling with -mfar-stack-param.