cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

03_using_gbdk.md (9382B)


      1@page docs_using_gbdk Using GBDK
      2
      3
      4# Interrupts
      5Interrupts allow execution to jump to a different part of your code as soon as an external event occurs - for example the LCD entering the vertical blank period, serial data arriving or the timer reaching its end count. For an example see the irq.c sample project.
      6
      7Interrupts in GBDK are handled using the functions @ref disable_interrupts(), @ref enable_interrupts(), @ref set_interrupts(uint8_t ier) and the interrupt service routine (ISR) linkers @ref add_VBL(), @ref add_TIM, @ref add_LCD, @ref add_SIO and @ref add_JOY which add interrupt handlers for the vertical blank, timer, LCD, serial link and joypad interrupts respectively.
      8
      9Since an interrupt can occur at any time an Interrupt Service Request (ISR) cannot take any arguments or return anything. Its only way of communicating with the greater program is through the global variables. When interacting with those shared ISR global variables from main code outside the interrupt, it is a good idea to wrap them in a `critical {}` section in case the interrupt occurs and modifies the variable while it is being used.
     10
     11Interrupts should be disabled before adding ISRs. To use multiple interrupts, _logical OR_ the relevant IFLAGs together.
     12
     13ISRs should be kept as small and short as possible, do not write an ISR so long that the Game Boy hardware spends all of its time servicing interrupts and has no time spare for the main code.
     14
     15For more detail on the Game Boy interrupts consider reading about them in the @ref Pandocs.
     16
     17## Available Interrupts
     18The GameBoy hardware can generate 5 types of interrupts. Custom Interrupt Service Routines (ISRs) can be added in addition to the built-in ones available in GBDK.
     19
     20  - VBL : LCD Vertical Blanking period start
     21    - The default VBL ISR is installed automatically.
     22      - See @ref add_VBL() and @ref remove_VBL()
     23
     24  - LCD : LCDC status (such as the start of a horizontal line)
     25    - See @ref add_LCD() and @ref remove_LCD()
     26    - Example project: `lcd_isr_wobble`
     27
     28  - TIM : Timer overflow
     29    - See @ref add_TIM() and @ref remove_TIM()
     30    - Example project: `tim`
     31
     32  - SIO : Serial Link I/O transfer end
     33    - The default SIO ISR gets installed automatically if any of the standard SIO calls are used. These calls include add_SIO(), remove_SIO(), send_byte(), receive_byte().
     34    - The default SIO ISR cannot be removed once installed. Only secondary chained SIO ISRs (added with add_SIO() ) can be removed.
     35    - See @ref add_SIO() and @ref remove_SIO()
     36    - Example project: `comm`
     37
     38  - JOY : Transition from high to low of a joypad button
     39      - See @ref add_JOY() and @ref remove_JOY()
     40
     41## Adding your own interrupt handler
     42It is possible to install your own interrupt handlers (in C or in assembly) for any of these interrupts. Up to 4 chained handlers may be added, with the last added being called last. If the remove_VBL() function is to be called, only three may be added for VBL.
     43
     44Interrupt handlers are called in sequence. To install a new interrupt handler, do the following:
     45
     46  1. Write a function (say foo()) that takes no parameters, and that returns nothing. Remember that the code executed in an interrupt handler must be short.
     47  2. Inside a `__critical { ... }` section, install your interrupt handling routines using the add_XXX() function, where XXX is the interrupt that you want to handle.
     48  3. Enable interrupts for the IRQ you want to handle, using the set_interrupts() function. Note that the VBL interrupt is already enabled before the main() function is called. If you want to set the interrupts before main() is called, you must install an initialization routine.
     49
     50See the `irq` example project for additional details for a complete example.
     51
     52## Using your own Interrupt Dispatcher
     53If you want to use your own Interrupt Dispatcher instead of the GBDK chained dispatcher (for improved performance), then don't call the `add_...()` function for the respective interrupt and its dispatcher won't be installed.
     54  - Exception: the VBL dispatcher will always be linked in at compile time.
     55  - For the SIO interrupt, also do not make any standard SIO calls to avoid having its dispatcher installed.
     56
     57Then, @ref ISR_VECTOR() or @ref ISR_NESTED_VECTOR() can be used to install a custom ISR handler.
     58
     59## Returning from Interrupts and STAT mode
     60By default when an Interrupt handler completes and is ready to exit it will check STAT_REG and only return at the BEGINNING of either LCD Mode 0 or Mode 1. This helps prevent graphical glitches caused when an ISR interrupts a graphics operation in one mode but returns in a different mode for which that graphics operation is not allowed.
     61
     62You can change this behavior using nowait_int_handler() which does not check @ref STAT_REG before returning. Also see @ref wait_int_handler().
     63
     64
     65# What GBDK does automatically and behind the scenes
     66
     67## OAM (VRAM Sprite Attribute Table)
     68GBDK sets up a Shadow OAM which gets copied automatically to the hardware OAM by the default V-Blank ISR. The Shadow OAM allows updating sprites without worrying about whether it is safe to write to them or not based on the hardware LCD mode.
     69
     70## Font tiles when using stdio.h
     71Including @ref stdio.h and using functions such as @ref printf() will use a large number of the background tiles for font characters. If stdio.h is not included then that space will be available for use with other tiles instead.
     72
     73## Default Interrupt Service Handlers (ISRs)
     74  - V-Blank: A default V-Blank ISR is installed on startup which copies the Shadow OAM to the hardware OAM and increments the global @ref sys_time variable once per frame.
     75  - Serial Link I/O: If any of the GBDK serial link functions are used such as @ref send_byte() and @ref receive_byte(), the default SIO serial link handler will be installed automatically at compile-time.
     76
     77
     78# Copying Functions to RAM and HIRAM
     79See the `ram_function` example project included with GBDK which demonstrates copying functions to RAM and HIRAM.
     80
     81`Warning!` Copying of functions is generally not safe since they may contain jumps to absolute addresses that will not be converted to match the new location.
     82
     83It is possible to copy functions to RAM and HIRAM (using the memcpy() and hiramcpy() functions), and execute them from C. Ensure you have enough free space in RAM or HIRAM for copying a function.
     84
     85There are basically two ways for calling a function located in RAM, HIRAM, or ROM:
     86
     87  - Declare a pointer-to-function variable, and set it to the address of the function to call.
     88  - Declare the function as extern, and set its address at link time using the -Wl-gXXX=# flag (where XXX is the name of the function, and # is its address).
     89
     90The second approach is slightly more efficient. Both approaches are demonstrated in the `ram_function.c` example.
     91
     92
     93# Mixing C and Assembly
     94You can mix C and assembly (ASM) in two ways as described below. For additional detail see the @ref links_sdcc_docs.
     95
     96## Inline ASM within C source files
     97
     98Example:  
     99
    100       __asm__("nop");
    101
    102Another Example:  
    103
    104      void some_c_function() 
    105      {
    106        // Optionally do something
    107        __asm
    108            (ASM code goes here)
    109        __endasm;
    110      }
    111
    112
    113## In Separate ASM files
    114
    115@todo This is from GBDK 2.x docs, verify it with GBDK-2020 and modern SDCC
    116
    117It is possible to assemble and link files written in ASM alongside files written in C.
    118
    119  - A C identifier `i` will be called `_i` in assembly.
    120  - Results are always returned into the `DE` register.
    121  - Parameters are passed on the stack (starting at `SP+2` because the return address is also saved on the stack).
    122  - Assembly identifiers are exported using the `.globl` directive.
    123  - You can access GameBoy hardware registers using `_reg_0xXX` where `XX` is the register number (see `sound.c` for an example).
    124  - Registers must be preserved across function calls (you must store them at function begin, and restore them at the end), except `HL` (and `DE` when the function returns a result).
    125
    126Here is an example of how to mix assembly with C:
    127
    128`main.c`
    129
    130    main()
    131    {
    132      int16_t i;
    133      int16_t add(int16_t, int16_t);
    134
    135      i = add(1, 3);
    136    }
    137
    138`add.s`
    139
    140    .globl _add
    141    _add:         ; int16_t add(int16_t a, int16_t b)
    142                  ; There is no register to save:
    143                  ;  BC is not used
    144                  ;  DE is the return register
    145                  ;  HL needs never to be saved
    146    LDA  HL,2(SP)
    147    LD   E,(HL)   ; Get a in DE
    148    INC  HL
    149    LD   D,(HL)
    150    INC  HL
    151    LD   A,(HL)   ; Get b in HL
    152    INC  HL
    153    LD   H,(HL)
    154    LD   L,A
    155    ADD  HL,DE    ; Add DE to HL
    156    LD   D,H
    157    LD   E,L
    158                  ; There is no register to restore
    159    RET           ; Return result in DE
    160
    161
    162# Including binary files in C source with incbin
    163Data from binary files can be included in C source files as a const array using the @ref INCBIN() macro.
    164
    165See the `incbin` example project for a demo of how to use it.
    166
    167
    168# Known Issues and Limitations
    169
    170## SDCC
    171  - Const arrays declared with `somevar[n] = {x}` will __NOT__ get initialized with value `x`. This may change when the SDCC RLE initializer is fixed. Use memset for now if you need it.
    172
    173  - SDCC banked calls and @ref far_pointers in GBDK only save one byte for the ROM bank, so for example they are limtied to __bank 15__ max for MBC1 and __bank 255__ max for MBC5. See @ref banked_calls for more details.