cscg22-gearboy

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

msx.h (23168B)


      1/** @file msx/msx.h
      2    MSX specific functions.
      3*/
      4#ifndef _MSX_H
      5#define _MSX_H
      6
      7#include <types.h>
      8#include <stdint.h>
      9#include <gbdk/version.h>
     10#include <msx/hardware.h>
     11
     12#define MSX
     13#ifdef NINTENDO
     14#undef NINTENDO
     15#endif
     16#ifdef SEGA
     17#undef SEGA
     18#endif
     19#if defined(__TARGET_msxdos)
     20#define MSXDOS
     21#endif
     22
     23
     24#define VBK_REG VDP_ATTR_SHIFT
     25
     26/** Joypad bits.
     27    A logical OR of these is used in the wait_pad and joypad
     28    functions.  For example, to see if the B button is pressed
     29    try
     30
     31    uint8_t keys;
     32    keys = joypad();
     33    if (keys & J_B) {
     34    	...
     35    }
     36
     37    @see joypad
     38 */
     39#define	J_UP         0b00100000
     40#define	J_DOWN       0b01000000
     41#define	J_LEFT       0b00010000
     42#define	J_RIGHT      0b10000000
     43#define	J_A          0b00000001
     44#define	J_B          0b00000100
     45#define	J_SELECT     0b00001000
     46#define	J_START      0b00000010
     47
     48/** Screen modes.
     49    Normally used by internal functions only.
     50    @see mode()
     51 */
     52#define	M_TEXT_OUT   0x02U
     53#define	M_TEXT_INOUT 0x03U
     54/** Set this in addition to the others to disable scrolling
     55
     56    If scrolling is disabled, the cursor returns to (0,0)
     57    @see mode()
     58*/
     59#define M_NO_SCROLL  0x04U
     60/** Set this to disable interpretation
     61    @see mode()
     62*/
     63#define M_NO_INTERP  0x08U
     64
     65/** If set the background tile will be flipped horizontally.
     66 */
     67#define S_FLIPX      0x02U
     68/** If set the background tile will be flipped vertically.
     69 */
     70#define S_FLIPY      0x04U
     71/** If set the background tile palette.
     72 */
     73#define S_PALETTE    0x08U
     74/** If set the background tile priority.
     75 */
     76#define S_PRIORITY   0x10U
     77
     78// VDP helper macros
     79#define __WRITE_VDP_REG(REG, v) shadow_##REG=(v);__critical{VDP_CMD=(shadow_##REG),VDP_CMD=REG;}
     80#define __READ_VDP_REG(REG) shadow_##REG
     81
     82void WRITE_VDP_CMD(uint16_t cmd) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
     83void WRITE_VDP_DATA(uint16_t data) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
     84
     85/** Set the current screen mode - one of M_* modes
     86
     87    Normally used by internal functions only.
     88
     89    @see M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP
     90*/
     91void mode(uint8_t m) OLDCALL;
     92
     93/** Returns the current mode
     94
     95    @see M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP
     96*/
     97uint8_t get_mode() OLDCALL;
     98
     99/* Interrupt flags */
    100/** Disable calling of interrupt service routines
    101 */
    102#define EMPTY_IFLAG  0x00U
    103/** VBlank Interrupt occurs at the start of the vertical blank.
    104
    105    During this period the video ram may be freely accessed.
    106    @see set_interrupts(), @see add_VBL
    107 */
    108#define VBL_IFLAG    0x01U
    109/** LCD Interrupt when triggered by the STAT register.
    110    @see set_interrupts(), @see add_LCD
    111*/
    112#define LCD_IFLAG    0x02U
    113/** Does nothing on MSX
    114 */
    115#define TIM_IFLAG    0x04U
    116/** Does nothing on MSX
    117 */
    118#define SIO_IFLAG    0x08U
    119/** Does nothing on MSX
    120 */
    121#define JOY_IFLAG    0x10U
    122
    123void set_interrupts(uint8_t flags) Z88DK_FASTCALL;
    124
    125/* Limits */
    126/** Width of the visible screen in pixels.
    127 */
    128#define SCREENWIDTH  DEVICE_SCREEN_PX_WIDTH
    129/** Height of the visible screen in pixels.
    130 */
    131#define SCREENHEIGHT DEVICE_SCREEN_PX_HEIGHT
    132/** The Minimum X position of the Window Layer (Left edge of screen) @see move_win()
    133 */
    134#define MINWNDPOSX   0x00U
    135/** The Minimum Y position of the Window Layer (Top edge of screen) @see move_win()
    136 */
    137#define MINWNDPOSY   0x00U
    138/** The Maximum X position of the Window Layer (Right edge of screen) @see move_win()
    139 */
    140#define MAXWNDPOSX   0x00U
    141/** The Maximum Y position of the Window Layer (Bottom edge of screen) @see move_win()
    142 */
    143#define MAXWNDPOSY   0x00U
    144
    145
    146/** Interrupt handlers
    147 */
    148typedef void (*int_handler)(void) NONBANKED;
    149
    150/** Removes the VBL interrupt handler.
    151    @see add_VBL()
    152*/
    153void remove_VBL(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl);
    154
    155/** Removes the LCD interrupt handler.
    156    @see add_LCD(), remove_VBL()
    157*/
    158void remove_LCD(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(b, c, iyh, iyl);
    159
    160void remove_TIM(int_handler h) Z88DK_FASTCALL;
    161void remove_SIO(int_handler h) Z88DK_FASTCALL;
    162void remove_JOY(int_handler h) Z88DK_FASTCALL;
    163
    164/** Adds a V-blank interrupt handler.
    165*/
    166void add_VBL(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(d, e, iyh, iyl);
    167
    168/** Adds a LCD interrupt handler.
    169*/
    170void add_LCD(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(b, c, iyh, iyl);
    171
    172/** Does nothing on MSX
    173 */
    174void add_TIM(int_handler h) Z88DK_FASTCALL;
    175
    176/** Does nothing on MSX
    177 */
    178void add_SIO(int_handler h) Z88DK_FASTCALL;
    179
    180/** Does nothing on MSX
    181 */
    182void add_JOY(int_handler h) Z88DK_FASTCALL;
    183
    184/** Cancel pending interrupts
    185 */
    186inline uint8_t cancel_pending_interrupts() {
    187    return VDP_STATUS;
    188}
    189
    190inline void move_bkg(uint8_t x, uint8_t y) {
    191	__WRITE_VDP_REG(VDP_RSCX, -x);
    192	__WRITE_VDP_REG(VDP_RSCY, y);
    193}
    194
    195inline void scroll_bkg(int8_t x, int8_t y) {
    196	__WRITE_VDP_REG(VDP_RSCX, __READ_VDP_REG(VDP_RSCX) - x);
    197    int16_t tmp = __READ_VDP_REG(VDP_RSCY) + y;
    198	__WRITE_VDP_REG(VDP_RSCY, (tmp < 0) ? 224 + tmp : tmp % 224u);
    199}
    200
    201/** HALTs the CPU and waits for the vertical blank interrupt (VBL) to finish.
    202
    203    This is often used in main loops to idle the CPU at low power
    204    until it's time to start the next frame. It's also useful for
    205    syncing animation with the screen re-draw.
    206
    207    Warning: If the VBL interrupt is disabled, this function will
    208    never return. If the screen is off this function returns
    209    immediately.
    210*/
    211void wait_vbl_done() PRESERVES_REGS(b, c, d, e, h, l, iyh, iyl);
    212
    213/** Turns the display off.
    214
    215    @see DISPLAY_ON
    216*/
    217inline void display_off() {
    218	__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) &= (~R1_DISP_ON));
    219}
    220
    221/** Turns the display back on.
    222    @see display_off, DISPLAY_OFF
    223*/
    224#define DISPLAY_ON \
    225	__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) |= R1_DISP_ON)
    226
    227/** Turns the display off immediately.
    228    @see display_off, DISPLAY_ON
    229*/
    230#define DISPLAY_OFF \
    231	display_off();
    232
    233/** Copies data from shadow OAM to OAM
    234 */
    235void refresh_OAM();
    236
    237/** Blanks leftmost column, so it is not garbaged when you use horizontal scroll
    238    @see SHOW_LEFT_COLUMN
    239*/
    240#define HIDE_LEFT_COLUMN \
    241	__WRITE_VDP_REG(VDP_R0, __READ_VDP_REG(VDP_R0) |= R0_LCB)
    242
    243/** Shows leftmost column
    244    @see HIDE_LEFT_COLUMN
    245*/
    246#define SHOW_LEFT_COLUMN \
    247	__WRITE_VDP_REG(VDP_R0, __READ_VDP_REG(VDP_R0) &= (~R0_LCB))
    248
    249/** Turns on the background layer.
    250    Not yet implemented
    251*/
    252#define SHOW_BKG
    253
    254/** Turns off the background layer.
    255    Not yet implemented
    256*/
    257#define HIDE_BKG
    258
    259/** Turns on the window layer
    260    Not yet implemented
    261*/
    262#define SHOW_WIN
    263
    264/** Turns off the window layer.
    265    Not yet implemented
    266*/
    267#define HIDE_WIN
    268
    269/** Turns on the sprites layer.
    270    Not yet implemented
    271*/
    272#define SHOW_SPRITES
    273
    274/** Turns off the sprites layer.
    275    Not yet implemented
    276*/
    277#define HIDE_SPRITES
    278
    279/** Sets sprite size to 8x16 pixels, two tiles one above the other.
    280*/
    281#define SPRITES_16x16 \
    282	__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) |= R1_SPR_16X16)
    283
    284/** Sets sprite size to 8x8 pixels, one tile.
    285*/
    286#define SPRITES_8x8 \
    287	__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) &= (~R1_SPR_16X16))
    288
    289/** Macro returns TRUE if device supports color
    290 *  (it always does on MSX)
    291 */
    292#define DEVICE_SUPPORTS_COLOR (TRUE)
    293
    294/** Global Time Counter in VBL periods (60Hz)
    295
    296    Increments once per Frame
    297
    298    Will wrap around every ~18 minutes (unsigned 16 bits = 65535 / 60 / 60 = 18.2)
    299*/
    300extern volatile uint16_t sys_time;
    301
    302/** Tracks current active ROM bank in frame 1
    303*/
    304extern volatile uint8_t _current_bank;
    305#define CURRENT_BANK _current_bank
    306
    307/** Obtains the __bank number__ of VARNAME
    308
    309    @param VARNAME Name of the variable which has a __bank_VARNAME companion symbol which is adjusted by bankpack
    310
    311    Use this to obtain the bank number from a bank reference
    312    created with @ref BANKREF().
    313
    314    @see BANKREF_EXTERN(), BANKREF()
    315*/
    316#ifndef BANK
    317#define BANK(VARNAME) ( (uint8_t) & __bank_ ## VARNAME )
    318#endif
    319
    320/** Creates a reference for retrieving the bank number of a variable or function
    321
    322    @param VARNAME Variable name to use, which may be an existing identifier
    323
    324    @see BANK() for obtaining the bank number of the included data.
    325
    326    More than one `BANKREF()` may be created per file, but each call should
    327    always use a unique VARNAME.
    328
    329    Use @ref BANKREF_EXTERN() within another source file
    330    to make the variable and it's data accesible there.
    331*/
    332#define BANKREF(VARNAME) void __func_ ## VARNAME() __banked __naked { \
    333__asm \
    334    .local b___func_ ## VARNAME \
    335    ___bank_ ## VARNAME = b___func_ ## VARNAME \
    336    .globl ___bank_ ## VARNAME \
    337__endasm; \
    338}
    339
    340/** Creates extern references for accessing a BANKREF() generated variable.
    341
    342    @param VARNAME Name of the variable used with @ref BANKREF()
    343
    344    This makes a @ref BANKREF() reference in another source
    345    file accessible in the current file for use with @ref BANK().
    346
    347    @see BANKREF(), BANK()
    348*/
    349#define BANKREF_EXTERN(VARNAME) extern const void __bank_ ## VARNAME;
    350
    351
    352/** Makes switch the active ROM bank in frame 1
    353    @param b   ROM bank to switch to
    354*/
    355
    356void SWITCH_ROM(uint8_t bank) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
    357#define SWITCH_ROM1 SWITCH_ROM
    358
    359/** Makes switch the active ROM bank in frame 2
    360    @param b   ROM bank to switch to
    361*/
    362
    363#define SWITCH_ROM2(b) MAP_FRAME2=(b)
    364
    365/** Switches RAM bank
    366    @param b   SRAM bank to switch to
    367*/
    368
    369#define SWITCH_RAM(b) RAM_CONTROL=((b)&1)?RAM_CONTROL|RAMCTL_BANK:RAM_CONTROL&(~RAMCTL_BANK)
    370
    371/** Enables RAM
    372*/
    373
    374#define ENABLE_RAM RAM_CONTROL|=RAMCTL_RAM
    375
    376/** Disables RAM
    377*/
    378
    379#define DISABLE_RAM RAM_CONTROL&=(~RAMCTL_RAM)
    380
    381
    382/** Delays the given number of milliseconds.
    383    Uses no timers or interrupts, and can be called with
    384    interrupts disabled
    385 */
    386void delay(uint16_t d) Z88DK_FASTCALL;
    387
    388
    389/** Reads and returns the current state of the joypad.
    390*/
    391uint8_t joypad() OLDCALL PRESERVES_REGS(b, c, d, e, h, iyh, iyl);
    392
    393/** Waits until at least one of the buttons given in mask are pressed.
    394*/
    395uint8_t waitpad(uint8_t mask) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
    396
    397/** Waits for the directional pad and all buttons to be released.
    398
    399    Note: Checks in a loop that doesn't HALT at all, so the CPU
    400    will be maxed out until this call returns.
    401*/
    402void waitpadup() PRESERVES_REGS(b, c, d, e, iyh, iyl);
    403
    404/** Multiplayer joypad structure.
    405
    406    Must be initialized with @ref joypad_init() first then it
    407    may be used to poll all avaliable joypads with @ref joypad_ex()
    408*/
    409typedef struct {
    410    uint8_t npads;
    411    union {
    412        struct {
    413            uint8_t joy0, joy1, joy2, joy3;
    414        };
    415        uint8_t joypads[4];
    416    };
    417} joypads_t;
    418
    419/** Initializes joypads_t structure for polling multiple joypads
    420    @param npads	number of joypads requested (1, 2 or 4)
    421    @param joypads	pointer to joypads_t structure to be initialized
    422
    423    Only required for @ref joypad_ex, not required for calls to regular @ref joypad()
    424    @returns number of joypads avaliable
    425    @see joypad_ex(), joypads_t
    426*/
    427uint8_t joypad_init(uint8_t npads, joypads_t * joypads) Z88DK_CALLEE;
    428
    429/** Polls all avaliable joypads
    430    @param joypads	pointer to joypads_t structure to be filled with joypad statuses,
    431    	   must be previously initialized with joypad_init()
    432
    433    @see joypad_init(), joypads_t
    434*/
    435void joypad_ex(joypads_t * joypads) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl);
    436
    437
    438#if defined(__TARGET_msxdos)
    439
    440#define RGB(r,g,b)        ((r) | ((g) << 2) | ((b) << 4))
    441#define RGB8(r,g,b)       (((r) >> 6) | (((g) >> 6) << 2) | (((b) >> 6) << 4))
    442#define RGBHTML(RGB24bit) (((RGB24bit) >> 22) | ((((RGB24bit) & 0xFFFF) >> 14) << 2) | ((((RGB24bit) & 0xFF) >> 6) << 4))
    443
    444/** Common colors based on the EGA default palette.
    445 */
    446#define RGB_RED        RGB( 3,  0,  0)
    447#define RGB_DARKRED    RGB( 2,  0,  0)
    448#define RGB_GREEN      RGB( 0,  3,  0)
    449#define RGB_DARKGREEN  RGB( 0,  2,  0)
    450#define RGB_BLUE       RGB( 0,  0,  3)
    451#define RGB_DARKBLUE   RGB( 0,  0,  2)
    452#define RGB_YELLOW     RGB( 3,  3,  0)
    453#define RGB_DARKYELLOW RGB( 2,  2,  0)
    454#define RGB_CYAN       RGB( 0,  3,  3)
    455#define RGB_AQUA       RGB( 3,  1,  2)
    456#define RGB_PINK       RGB( 3,  0,  3)
    457#define RGB_PURPLE     RGB( 2,  0,  2)
    458#define RGB_BLACK      RGB( 0,  0,  0)
    459#define RGB_DARKGRAY   RGB( 1,  1,  1)
    460#define RGB_LIGHTGRAY  RGB( 2,  2,  2)
    461#define RGB_WHITE      RGB( 3,  3,  3)
    462
    463typedef uint8_t palette_color_t;
    464
    465#else
    466#error Unrecognized port
    467#endif
    468
    469void set_default_palette();
    470inline void cpu_fast() {}
    471
    472void set_palette_entry(uint8_t palette, uint8_t entry, uint16_t rgb_data) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    473#define set_bkg_palette_entry set_palette_entry
    474#define set_sprite_palette_entry(palette,entry,rgb_data) set_palette_entry(1,entry,rgb_data)
    475void set_palette(uint8_t first_palette, uint8_t nb_palettes, palette_color_t *rgb_data) Z88DK_CALLEE;
    476#define set_bkg_palette set_palette
    477#define set_sprite_palette(first_palette,nb_palettes,rgb_data) set_palette(1,1,rgb_data)
    478
    479void set_native_tile_data(uint16_t start, uint16_t ntiles, const void *src) Z88DK_CALLEE;
    480inline void set_bkg_4bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
    481    set_native_tile_data(start, ntiles, src);
    482}
    483void set_sprite_1bpp_data(uint16_t start, uint16_t ntiles, const void *src) Z88DK_CALLEE;
    484inline void set_native_sprite_data(uint16_t start, uint16_t ntiles, const void *src) {
    485    set_sprite_1bpp_data(start, ntiles, src);
    486}
    487
    488#define COMPAT_PALETTE(C0,C1,C2,C3) (((uint16_t)(C3) << 12) | ((uint16_t)(C2) << 8) | ((uint16_t)(C1) << 4) | (uint16_t)(C0))
    489extern uint16_t _current_2bpp_palette;
    490inline void set_2bpp_palette(uint16_t palette) {
    491    _current_2bpp_palette = palette;
    492}
    493//void set_tile_2bpp_data(uint16_t start, uint16_t ntiles, const void *src, uint16_t palette) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    494inline void set_bkg_data(uint16_t start, uint16_t ntiles, const void *src) {
    495    set_native_tile_data(start, ntiles, src);
    496}
    497inline void set_sprite_data(uint16_t start, uint16_t ntiles, const void *src) {
    498    set_sprite_1bpp_data(start, ntiles, src);
    499}
    500//inline void set_bkg_2bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
    501//    set_tile_2bpp_data(start, ntiles, src, _current_2bpp_palette);
    502//}
    503//inline void set_sprite_2bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
    504//    set_tile_2bpp_data((uint8_t)(start) + 0x100u, ntiles, src, _current_2bpp_palette);
    505//}
    506
    507extern uint16_t _current_1bpp_colors;
    508inline void set_1bpp_colors(uint8_t fgcolor, uint8_t bgcolor) {
    509    _current_1bpp_colors = ((uint16_t)bgcolor << 8) | fgcolor;
    510}
    511void set_tile_1bpp_data(uint16_t start, uint16_t ntiles, const void *src, uint16_t colors) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    512inline void set_bkg_1bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
    513    set_tile_1bpp_data(start, ntiles, src, _current_1bpp_colors);
    514}
    515
    516
    517/** Copies arbitrary data to an address in VRAM
    518
    519    @param dst       destination VRAM Address
    520    @param src       Pointer to source buffer
    521    @param size      Number of bytes to copy
    522
    523    Copies __size__ bytes from a buffer at _src__ to VRAM starting at __dst__.
    524*/
    525void set_data(uint16_t dst, const void *src, uint16_t size) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    526void vmemcpy(uint16_t dst, const void *src, uint16_t size) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    527
    528void set_tile_map(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    529#define set_bkg_tiles set_tile_map
    530#define set_win_tiles set_tile_map
    531
    532extern uint8_t _map_tile_offset;
    533inline void set_bkg_based_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles, uint8_t base_tile) {
    534    _map_tile_offset = base_tile;
    535    set_tile_map(x, y, w, h, tiles);
    536    _map_tile_offset = 0;
    537}
    538inline void set_win_based_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles, uint8_t base_tile) {
    539    _map_tile_offset = base_tile;
    540    set_tile_map(x, y, w, h, tiles);
    541    _map_tile_offset = 0;
    542}
    543
    544void set_tile_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t map_w, const uint8_t *map) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    545void set_tile_submap_compat(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t map_w, const uint8_t *map) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    546inline void set_bkg_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) {
    547    set_tile_submap_compat(x, y, w, h, map_w, map);
    548}
    549inline void set_win_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) {
    550    set_tile_submap_compat(x, y, w, h, map_w, map);
    551}
    552
    553extern uint8_t _submap_tile_offset;
    554inline void set_bkg_based_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w, uint8_t base_tile) {
    555    _submap_tile_offset = base_tile;
    556    set_tile_submap_compat(x, y, w, h, map_w, map);
    557    _submap_tile_offset = 0;
    558}
    559inline void set_win_based_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w, uint8_t base_tile) {
    560    _submap_tile_offset = base_tile;
    561    set_tile_submap_compat(x, y, w, h, map_w, map);
    562    _submap_tile_offset = 0;
    563}
    564
    565void fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t tile) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    566#define fill_bkg_rect fill_rect
    567#define fill_win_rect fill_rect
    568
    569/** Sprite Attributes structure
    570    @param x     X Coordinate of the sprite on screen
    571    @param y     Y Coordinate of the sprite on screen
    572    @param tile  Sprite tile number (see @ref set_sprite_tile)
    573    @param prop  OAM Property Flags (see @ref set_sprite_prop)
    574*/
    575typedef struct OAM_item_t {
    576    uint8_t y, x;  //< X, Y Coordinates of the sprite on screen
    577    uint8_t tile;  //< Sprite tile number
    578    uint8_t prop;  //< OAM Property Flags
    579} OAM_item_t;
    580
    581
    582/** Shadow OAM array in WRAM, that is DMA-transferred into the real OAM each VBlank
    583*/
    584extern volatile struct OAM_item_t shadow_OAM[];
    585
    586/** MSB of shadow_OAM address is used by OAM copying routine
    587*/
    588extern volatile uint8_t _shadow_OAM_base;
    589
    590/** Flag for disabling of OAM copying routine
    591
    592    Values:
    593    \li 1: OAM copy routine is disabled (non-isr VDP operation may be in progress)
    594    \li 0: OAM copy routine is enabled
    595
    596    This flag is modified by all MSX GBDK API calls that write to the VDP.
    597    It is set to DISABLED when they start and ENABLED when they complete.
    598
    599    @note It is recommended to avoid writing to the Video Display Processor
    600    (VDP) during an interrupt service routine (ISR) since it can corrupt
    601    the VDP pointer of an VDP operation already in progress.
    602
    603    If it is necessary, this flag can be used during an ISR to determine
    604    whether a VDP operation is already in progress. If the value is `1`
    605    then avoid writing to the VDP (tiles, map, scrolling, colors, etc).
    606
    607    \code{.c}
    608    // at the beginning of and ISR that would write to the VDP
    609    if (_shadow_OAM_OFF) return;
    610    \endcode
    611
    612    @see @ref docs_consoles_safe_display_controller_access
    613*/
    614extern volatile uint8_t _shadow_OAM_OFF;
    615
    616/** Disable shadow OAM to VRAM copy on each VBlank
    617*/
    618#define DISABLE_VBL_TRANSFER \
    619    _shadow_OAM_base = 0
    620
    621/** Enable shadow OAM to VRAM copy on each VBlank
    622*/
    623#define ENABLE_VBL_TRANSFER \
    624    _shadow_OAM_base = (uint8_t)((uint16_t)&shadow_OAM >> 8)
    625
    626/** Amount of hardware sprites in OAM
    627*/
    628#define MAX_HARDWARE_SPRITES 32
    629
    630/** Sets address of 256-byte aligned array of shadow OAM to be transferred on each VBlank
    631*/
    632inline void SET_SHADOW_OAM_ADDRESS(void * address) {
    633    _shadow_OAM_base = (uint8_t)((uint16_t)address >> 8);
    634}
    635
    636/** Sets sprite number __nb__in the OAM to display tile number __tile__.
    637
    638    @param nb    Sprite number, range 0 - 39
    639    @param tile  Selects a tile (0 - 255) from memory at 8000h - 8FFFh
    640                 \n In CGB Mode this could be either in VRAM Bank
    641                 \n 0 or 1, depending on Bit 3 of the OAM Attribute Flag
    642                 \n (see @ref set_sprite_prop)
    643
    644    In 8x16 mode:
    645    \li The sprite will also display the next tile (__tile__ + 1)
    646        directly below (y + 8) the first tile.
    647    \li The lower bit of the tile number is ignored:
    648        the upper 8x8 tile is (__tile__ & 0xFE), and
    649        the lower 8x8 tile is (__tile__ | 0x01).
    650    \li See: @ref SPRITES_8x16
    651*/
    652inline void set_sprite_tile(uint8_t nb, uint8_t tile) {
    653    shadow_OAM[nb].tile=tile;
    654}
    655
    656
    657/** Returns the tile number of sprite number __nb__ in the OAM.
    658
    659@param nb    Sprite number, range 0 - 39
    660
    661@see set_sprite_tile for more details
    662*/
    663inline uint8_t get_sprite_tile(uint8_t nb) {
    664    return shadow_OAM[nb].tile;
    665}
    666
    667inline void set_sprite_prop(uint8_t nb, uint8_t prop) {
    668    shadow_OAM[nb].prop = prop;
    669}
    670
    671inline uint8_t get_sprite_prop(uint8_t nb) {
    672    return shadow_OAM[nb].prop;
    673}
    674
    675/** Moves sprite number __nb__ to the __x__, __y__ position on the screen.
    676
    677    @param nb  Sprite number, range 0 - 39
    678    @param x   X Position. Specifies the sprites horizontal position on the screen (minus 8).
    679               \n An offscreen value (X=0 or X>=168) hides the sprite, but the sprite
    680               still affects the priority ordering - a better way to hide a sprite is to set
    681               its Y-coordinate offscreen.
    682    @param y   Y Position. Specifies the sprites vertical position on the screen (minus 16).
    683               \n An offscreen value (for example, Y=0 or Y>=160) hides the sprite.
    684
    685    Moving the sprite to 0,0 (or similar off-screen location) will hide it.
    686*/
    687inline void move_sprite(uint8_t nb, uint8_t x, uint8_t y) {
    688    OAM_item_t * itm = &shadow_OAM[nb];
    689    itm->y=y, itm->x=x;
    690}
    691
    692
    693/** Moves sprite number __nb__ relative to its current position.
    694
    695    @param nb  Sprite number, range 0 - 39
    696    @param x   Number of pixels to move the sprite on the __X axis__
    697               \n Range: -128 - 127
    698    @param y   Number of pixels to move the sprite on the __Y axis__
    699               \n Range: -128 - 127
    700
    701    @see move_sprite for more details about the X and Y position
    702 */
    703inline void scroll_sprite(uint8_t nb, int8_t x, int8_t y) {
    704    OAM_item_t * itm = &shadow_OAM[nb];
    705    itm->y+=y, itm->x+=x;
    706}
    707
    708
    709/** Hides sprite number __nb__ by moving it to zero position by Y.
    710
    711    @param nb  Sprite number, range 0 - 39
    712 */
    713inline void hide_sprite(uint8_t nb) {
    714    shadow_OAM[nb].y = 0xC0;
    715}
    716
    717/**
    718 * Set byte in vram at given memory location
    719 *
    720 * @param addr address to write to
    721 * @param v value
    722 */
    723void set_vram_byte(uint8_t * addr, uint8_t v) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    724
    725/**
    726 * Set single tile t with attributes on background layer at x,y
    727 * @param x X-coordinate
    728 * @param y Y-coordinate
    729 * @param t tile index
    730 * @return returns the address of tile, so you may use faster set_vram_byte() later
    731 */
    732uint8_t * set_attributed_tile_xy(uint8_t x, uint8_t y, uint16_t t) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    733
    734/**
    735 * Set single tile t on background layer at x,y
    736 * @param x X-coordinate
    737 * @param y Y-coordinate
    738 * @param t tile index
    739 * @return returns the address of tile, so you may use faster set_vram_byte() later
    740 */
    741uint8_t * set_tile_xy(uint8_t x, uint8_t y, uint8_t t) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    742#define set_bkg_tile_xy set_tile_xy
    743#define set_win_tile_xy set_tile_xy
    744
    745/**
    746 * Get address of X,Y tile of background map
    747 */
    748uint8_t * get_bkg_xy_addr(uint8_t x, uint8_t y) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
    749#define get_win_xy_addr get_bkg_xy_addr
    750
    751#endif /* _MSX_H */