mirror of
https://github.com/gbdk-2020/gbdk-2020.git
synced 2026-03-12 02:09:50 +01:00
841 lines
25 KiB
C++
841 lines
25 KiB
C++
/** @file msx/msx.h
|
|
MSX specific functions.
|
|
*/
|
|
#ifndef _MSX_H
|
|
#define _MSX_H
|
|
|
|
#include <types.h>
|
|
#include <stdint.h>
|
|
#include <gbdk/version.h>
|
|
#include <msx/hardware.h>
|
|
|
|
#define MSX
|
|
|
|
// Here NINTENDO means Game Boy & related clones
|
|
#ifdef NINTENDO
|
|
#undef NINTENDO
|
|
#endif
|
|
|
|
#ifdef NINTENDO_NES
|
|
#undef NINTENDO_NES
|
|
#endif
|
|
|
|
#ifdef SEGA
|
|
#undef SEGA
|
|
#endif
|
|
|
|
#if defined(__TARGET_msxdos)
|
|
#define MSXDOS
|
|
#endif
|
|
|
|
extern const uint8_t _SYSTEM;
|
|
|
|
#define SYSTEM_60HZ 0x00
|
|
#define SYSTEM_50HZ 0x01
|
|
|
|
#define VBK_REG VDP_ATTR_SHIFT
|
|
|
|
/** Joypad bits.
|
|
A logical OR of these is used in the wait_pad and joypad
|
|
functions. For example, to see if the B button is pressed
|
|
try
|
|
|
|
uint8_t keys;
|
|
keys = joypad();
|
|
if (keys & J_B) {
|
|
...
|
|
}
|
|
|
|
@see joypad
|
|
*/
|
|
#define J_UP 0b00100000
|
|
#define J_DOWN 0b01000000
|
|
#define J_LEFT 0b00010000
|
|
#define J_RIGHT 0b10000000
|
|
#define J_A 0b00000001
|
|
#define J_B 0b00000100
|
|
#define J_SELECT 0b00001000
|
|
#define J_START 0b00000010
|
|
|
|
/** Screen modes.
|
|
Normally used by internal functions only.
|
|
@see mode()
|
|
*/
|
|
#define M_TEXT_OUT 0x02U
|
|
#define M_TEXT_INOUT 0x03U
|
|
/** Set this in addition to the others to disable scrolling
|
|
|
|
If scrolling is disabled, the cursor returns to (0,0)
|
|
@see mode()
|
|
*/
|
|
#define M_NO_SCROLL 0x04U
|
|
/** Set this to disable interpretation
|
|
@see mode()
|
|
*/
|
|
#define M_NO_INTERP 0x08U
|
|
|
|
/** The nineth bit of the tile id
|
|
*/
|
|
#define S_BANK 0x01U
|
|
/** If set the background tile will be flipped horizontally.
|
|
*/
|
|
#define S_FLIPX 0x02U
|
|
/** If set the background tile will be flipped vertically.
|
|
*/
|
|
#define S_FLIPY 0x04U
|
|
/** If set the background tile palette.
|
|
*/
|
|
#define S_PALETTE 0x08U
|
|
/** If set the background tile priority.
|
|
*/
|
|
#define S_PRIORITY 0x10U
|
|
/** Defines how palette number is encoded in OAM.
|
|
Required for the png2asset tool's metasprite output.
|
|
*/
|
|
#define S_PAL(n) (((n) & 0x01U) << 3)
|
|
|
|
// VDP helper macros
|
|
#define __WRITE_VDP_REG_UNSAFE(REG, v) shadow_##REG=(v),VDP_CMD=(shadow_##REG),VDP_CMD=REG
|
|
#define __WRITE_VDP_REG(REG, v) shadow_##REG=(v);__asm__("di");VDP_CMD=(shadow_##REG);VDP_CMD=REG;__asm__("ei")
|
|
#define __READ_VDP_REG(REG) shadow_##REG
|
|
|
|
void WRITE_VDP_CMD(uint16_t cmd) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
|
|
void WRITE_VDP_DATA(uint16_t data) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
|
|
|
|
/** Set the current screen mode - one of M_* modes
|
|
|
|
Normally used by internal functions only.
|
|
|
|
@see M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP
|
|
*/
|
|
void mode(uint8_t m) OLDCALL;
|
|
|
|
/** Returns the current mode
|
|
|
|
@see M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP
|
|
*/
|
|
uint8_t get_mode(void) OLDCALL;
|
|
|
|
/** Returns the system gbdk is running on.
|
|
|
|
*/
|
|
inline uint8_t get_system(void) {
|
|
return _SYSTEM;
|
|
}
|
|
|
|
/* Interrupt flags */
|
|
/** Disable calling of interrupt service routines
|
|
*/
|
|
#define EMPTY_IFLAG 0x00U
|
|
/** VBlank Interrupt occurs at the start of the vertical blank.
|
|
|
|
During this period the video ram may be freely accessed.
|
|
@see set_interrupts(), @see add_VBL
|
|
*/
|
|
#define VBL_IFLAG 0x01U
|
|
/** LCD Interrupt when triggered by the STAT register.
|
|
@see set_interrupts(), @see add_LCD
|
|
*/
|
|
#define LCD_IFLAG 0x02U
|
|
/** Does nothing on MSX
|
|
*/
|
|
#define TIM_IFLAG 0x04U
|
|
/** Does nothing on MSX
|
|
*/
|
|
#define SIO_IFLAG 0x08U
|
|
/** Does nothing on MSX
|
|
*/
|
|
#define JOY_IFLAG 0x10U
|
|
|
|
void set_interrupts(uint8_t flags) Z88DK_FASTCALL;
|
|
|
|
/* Limits */
|
|
/** Width of the visible screen in pixels.
|
|
*/
|
|
#define SCREENWIDTH DEVICE_SCREEN_PX_WIDTH
|
|
/** Height of the visible screen in pixels.
|
|
*/
|
|
#define SCREENHEIGHT DEVICE_SCREEN_PX_HEIGHT
|
|
/** The Minimum X position of the Window Layer (Left edge of screen) @see move_win()
|
|
*/
|
|
#define MINWNDPOSX 0x00U
|
|
/** The Minimum Y position of the Window Layer (Top edge of screen) @see move_win()
|
|
*/
|
|
#define MINWNDPOSY 0x00U
|
|
/** The Maximum X position of the Window Layer (Right edge of screen) @see move_win()
|
|
*/
|
|
#define MAXWNDPOSX 0x00U
|
|
/** The Maximum Y position of the Window Layer (Bottom edge of screen) @see move_win()
|
|
*/
|
|
#define MAXWNDPOSY 0x00U
|
|
|
|
|
|
/** Interrupt handlers
|
|
*/
|
|
typedef void (*int_handler)(void) NONBANKED;
|
|
|
|
/** Removes the VBL interrupt handler.
|
|
@see add_VBL()
|
|
*/
|
|
void remove_VBL(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl);
|
|
|
|
/** Removes the LCD interrupt handler.
|
|
@see add_LCD(), remove_VBL()
|
|
*/
|
|
void remove_LCD(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(b, c, iyh, iyl);
|
|
|
|
void remove_TIM(int_handler h) Z88DK_FASTCALL;
|
|
void remove_SIO(int_handler h) Z88DK_FASTCALL;
|
|
void remove_JOY(int_handler h) Z88DK_FASTCALL;
|
|
|
|
/** Adds a V-blank interrupt handler.
|
|
*/
|
|
void add_VBL(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(d, e, iyh, iyl);
|
|
|
|
/** Adds a LCD interrupt handler.
|
|
*/
|
|
void add_LCD(int_handler h) Z88DK_FASTCALL PRESERVES_REGS(b, c, iyh, iyl);
|
|
|
|
/** Does nothing on MSX
|
|
*/
|
|
void add_TIM(int_handler h) Z88DK_FASTCALL;
|
|
|
|
/** Does nothing on MSX
|
|
*/
|
|
void add_SIO(int_handler h) Z88DK_FASTCALL;
|
|
|
|
/** Does nothing on MSX
|
|
*/
|
|
void add_JOY(int_handler h) Z88DK_FASTCALL;
|
|
|
|
/** Cancel pending interrupts
|
|
*/
|
|
inline uint8_t cancel_pending_interrupts(void) {
|
|
return VDP_STATUS;
|
|
}
|
|
|
|
inline void move_bkg(uint8_t x, uint8_t y) {
|
|
__WRITE_VDP_REG(VDP_RSCX, -x);
|
|
__WRITE_VDP_REG(VDP_RSCY, y);
|
|
}
|
|
|
|
inline void scroll_bkg(int8_t x, int8_t y) {
|
|
__WRITE_VDP_REG(VDP_RSCX, __READ_VDP_REG(VDP_RSCX) - x);
|
|
int16_t tmp = __READ_VDP_REG(VDP_RSCY) + y;
|
|
__WRITE_VDP_REG(VDP_RSCY, (tmp < 0) ? 224 + tmp : tmp % 224u);
|
|
}
|
|
|
|
/** HALTs the CPU and waits for the vertical blank interrupt.
|
|
|
|
This is often used in main loops to idle the CPU at low power
|
|
until it's time to start the next frame. It's also useful for
|
|
syncing animation with the screen re-draw.
|
|
|
|
Warning: If the VBL interrupt is disabled, this function will
|
|
never return. If the screen is off this function returns
|
|
immediately.
|
|
*/
|
|
void vsync(void) PRESERVES_REGS(b, c, d, e, h, l, iyh, iyl);
|
|
|
|
/** Obsolete. This function has been replaced by vsync(), which has identical behavior.
|
|
*/
|
|
void wait_vbl_done(void) PRESERVES_REGS(b, c, d, e, h, l, iyh, iyl);
|
|
|
|
/** Turns the display off.
|
|
|
|
@see DISPLAY_ON
|
|
*/
|
|
inline void display_off(void) {
|
|
__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) &= (~R1_DISP_ON));
|
|
}
|
|
|
|
/** Turns the display back on.
|
|
@see display_off, DISPLAY_OFF
|
|
*/
|
|
#define DISPLAY_ON \
|
|
__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) |= R1_DISP_ON)
|
|
|
|
/** Turns the display off immediately.
|
|
@see display_off, DISPLAY_ON
|
|
*/
|
|
#define DISPLAY_OFF \
|
|
display_off();
|
|
|
|
/** Copies data from shadow OAM to OAM
|
|
*/
|
|
void refresh_OAM(void);
|
|
|
|
/** Blanks leftmost column, so it is not garbaged when you use horizontal scroll
|
|
@see SHOW_LEFT_COLUMN
|
|
*/
|
|
#define HIDE_LEFT_COLUMN \
|
|
__WRITE_VDP_REG(VDP_R0, __READ_VDP_REG(VDP_R0) |= R0_LCB)
|
|
|
|
/** Shows leftmost column
|
|
@see HIDE_LEFT_COLUMN
|
|
*/
|
|
#define SHOW_LEFT_COLUMN \
|
|
__WRITE_VDP_REG(VDP_R0, __READ_VDP_REG(VDP_R0) &= (~R0_LCB))
|
|
|
|
/** Sets border color
|
|
*/
|
|
#define SET_BORDER_COLOR(C) __WRITE_VDP_REG(VDP_R7, ((C) | 0xf0u))
|
|
|
|
/** Turns on the background layer.
|
|
Not yet implemented
|
|
*/
|
|
#define SHOW_BKG
|
|
|
|
/** Turns off the background layer.
|
|
Not yet implemented
|
|
*/
|
|
#define HIDE_BKG
|
|
|
|
/** Turns on the window layer
|
|
Not yet implemented
|
|
*/
|
|
#define SHOW_WIN
|
|
|
|
/** Turns off the window layer.
|
|
Not yet implemented
|
|
*/
|
|
#define HIDE_WIN
|
|
|
|
/** Turns on the sprites layer.
|
|
Not yet implemented
|
|
*/
|
|
#define SHOW_SPRITES
|
|
|
|
/** Turns off the sprites layer.
|
|
Not yet implemented
|
|
*/
|
|
#define HIDE_SPRITES
|
|
|
|
/** Sets sprite size to 8x16 pixels, two tiles one above the other.
|
|
*/
|
|
#define SPRITES_16x16 \
|
|
__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) |= R1_SPR_16X16)
|
|
|
|
/** Sets sprite size to 8x8 pixels, one tile.
|
|
*/
|
|
#define SPRITES_8x8 \
|
|
__WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) &= (~R1_SPR_16X16))
|
|
|
|
/** Macro returns TRUE if device supports color
|
|
* (it always does on MSX)
|
|
*/
|
|
#define DEVICE_SUPPORTS_COLOR (TRUE)
|
|
|
|
/** Global Time Counter in VBL periods (60Hz)
|
|
|
|
Increments once per Frame
|
|
|
|
Will wrap around every ~18 minutes (unsigned 16 bits = 65535 / 60 / 60 = 18.2)
|
|
*/
|
|
extern volatile uint16_t sys_time;
|
|
|
|
/** Flag indicating the VBlank ISR has run
|
|
|
|
Flag gets cleared at the start of @ref vsync() / @ref wait_vbl_done()
|
|
and set in the default VBlank ISR handler.
|
|
*/
|
|
extern volatile uint8_t _vbl_done;
|
|
#define VBL_DONE _vbl_done
|
|
|
|
/** Return R register for the DIV_REG emulation
|
|
|
|
Increments once per CPU instruction (fetches the Z80 CPU R register)
|
|
|
|
*/
|
|
uint8_t get_r_reg(void) PRESERVES_REGS(b, c, d, e, h, l, iyh, iyl);
|
|
|
|
#define DIV_REG get_r_reg()
|
|
|
|
/** Tracks current active ROM bank in frame 1
|
|
*/
|
|
extern volatile uint8_t _current_bank;
|
|
#define CURRENT_BANK _current_bank
|
|
|
|
/** Obtains the __bank number__ of VARNAME
|
|
|
|
@param VARNAME Name of the variable which has a __bank_VARNAME companion symbol which is adjusted by bankpack
|
|
|
|
Use this to obtain the bank number from a bank reference
|
|
created with @ref BANKREF().
|
|
|
|
@see BANKREF_EXTERN(), BANKREF()
|
|
*/
|
|
#ifndef BANK
|
|
#define BANK(VARNAME) ( (uint8_t) & __bank_ ## VARNAME )
|
|
#endif
|
|
|
|
/** Creates a reference for retrieving the bank number of a variable or function
|
|
|
|
@param VARNAME Variable name to use, which may be an existing identifier
|
|
|
|
@see BANK() for obtaining the bank number of the included data.
|
|
|
|
More than one `BANKREF()` may be created per file, but each call should
|
|
always use a unique VARNAME.
|
|
|
|
Use @ref BANKREF_EXTERN() within another source file
|
|
to make the variable and it's data accesible there.
|
|
*/
|
|
#define BANKREF(VARNAME) void __func_ ## VARNAME(void) __banked __naked { \
|
|
__asm \
|
|
.local b___func_ ## VARNAME \
|
|
___bank_ ## VARNAME = b___func_ ## VARNAME \
|
|
.globl ___bank_ ## VARNAME \
|
|
__endasm; \
|
|
}
|
|
|
|
/** Creates extern references for accessing a BANKREF() generated variable.
|
|
|
|
@param VARNAME Name of the variable used with @ref BANKREF()
|
|
|
|
This makes a @ref BANKREF() reference in another source
|
|
file accessible in the current file for use with @ref BANK().
|
|
|
|
@see BANKREF(), BANK()
|
|
*/
|
|
#define BANKREF_EXTERN(VARNAME) extern const void __bank_ ## VARNAME;
|
|
|
|
|
|
/** Makes switch the active ROM bank in frame 1
|
|
@param bank ROM bank to switch to
|
|
*/
|
|
|
|
void SWITCH_ROM(uint8_t bank) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
|
|
#define SWITCH_ROM1 SWITCH_ROM
|
|
|
|
/** Makes switch the active ROM bank in frame 2
|
|
@param b ROM bank to switch to
|
|
*/
|
|
|
|
#define SWITCH_ROM2(b) MAP_FRAME2=(b)
|
|
|
|
/** Switches RAM bank
|
|
@param b SRAM bank to switch to
|
|
*/
|
|
|
|
#define SWITCH_RAM(b) RAM_CONTROL=((b)&1)?RAM_CONTROL|RAMCTL_BANK:RAM_CONTROL&(~RAMCTL_BANK)
|
|
|
|
/** Enables RAM
|
|
*/
|
|
|
|
#define ENABLE_RAM RAM_CONTROL|=RAMCTL_RAM
|
|
|
|
/** Disables RAM
|
|
*/
|
|
|
|
#define DISABLE_RAM RAM_CONTROL&=(~RAMCTL_RAM)
|
|
|
|
|
|
/** Delays the given number of milliseconds.
|
|
Uses no timers or interrupts, and can be called with
|
|
interrupts disabled
|
|
*/
|
|
void delay(uint16_t d) Z88DK_FASTCALL;
|
|
|
|
|
|
/** Reads and returns the current state of the joypad.
|
|
*/
|
|
uint8_t joypad(void) OLDCALL PRESERVES_REGS(b, c, d, e, h, iyh, iyl);
|
|
|
|
/** Waits until at least one of the buttons given in mask are pressed.
|
|
*/
|
|
uint8_t waitpad(uint8_t mask) Z88DK_FASTCALL PRESERVES_REGS(b, c, d, e, iyh, iyl);
|
|
|
|
/** Waits for the directional pad and all buttons to be released.
|
|
|
|
Note: Checks in a loop that doesn't HALT at all, so the CPU
|
|
will be maxed out until this call returns.
|
|
*/
|
|
void waitpadup(void) PRESERVES_REGS(b, c, d, e, iyh, iyl);
|
|
|
|
/** Multiplayer joypad structure.
|
|
|
|
Must be initialized with @ref joypad_init() first then it
|
|
may be used to poll all avaliable joypads with @ref joypad_ex()
|
|
*/
|
|
typedef struct {
|
|
uint8_t npads;
|
|
union {
|
|
struct {
|
|
uint8_t joy0, joy1, joy2, joy3;
|
|
};
|
|
uint8_t joypads[4];
|
|
};
|
|
} joypads_t;
|
|
|
|
/** Initializes joypads_t structure for polling multiple joypads
|
|
@param npads number of joypads requested (1, 2 or 4)
|
|
@param joypads pointer to joypads_t structure to be initialized
|
|
|
|
Only required for @ref joypad_ex, not required for calls to regular @ref joypad()
|
|
@returns number of joypads avaliable
|
|
@see joypad_ex(), joypads_t
|
|
*/
|
|
uint8_t joypad_init(uint8_t npads, joypads_t * joypads) Z88DK_CALLEE;
|
|
|
|
/** Polls all avaliable joypads
|
|
@param joypads pointer to joypads_t structure to be filled with joypad statuses,
|
|
must be previously initialized with joypad_init()
|
|
|
|
@see joypad_init(), joypads_t
|
|
*/
|
|
void joypad_ex(joypads_t * joypads) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl);
|
|
|
|
|
|
/** Enables unmasked interrupts
|
|
|
|
@note Use @ref CRITICAL {...} instead for creating a block of
|
|
of code which should execute with interrupts temporarily
|
|
turned off.
|
|
|
|
@see disable_interrupts, set_interrupts, CRITICAL
|
|
*/
|
|
inline void enable_interrupts(void) PRESERVES_REGS(a, b, c, d, e, h, l, iyh, iyl) {
|
|
__asm__("ei");
|
|
}
|
|
|
|
/** Disables interrupts
|
|
|
|
@note Use @ref CRITICAL {...} instead for creating a block of
|
|
of code which should execute with interrupts temporarily
|
|
turned off.
|
|
|
|
This function may be called as many times as you like;
|
|
however the first call to @ref enable_interrupts will re-enable
|
|
them.
|
|
|
|
@see enable_interrupts, set_interrupts, CRITICAL
|
|
*/
|
|
inline void disable_interrupts(void) PRESERVES_REGS(a, b, c, d, e, h, l, iyh, iyl) {
|
|
__asm__("di");
|
|
}
|
|
|
|
|
|
#if defined(__TARGET_msxdos)
|
|
|
|
#define RGB(r,g,b) ((r) | ((g) << 2) | ((b) << 4))
|
|
#define RGB8(r,g,b) (((r) >> 6) | (((g) >> 6) << 2) | (((b) >> 6) << 4))
|
|
#define RGBHTML(RGB24bit) (((RGB24bit) >> 22) | ((((RGB24bit) & 0xFFFF) >> 14) << 2) | ((((RGB24bit) & 0xFF) >> 6) << 4))
|
|
|
|
/** Common colors based on the EGA default palette.
|
|
*/
|
|
#define RGB_RED RGB( 3, 0, 0)
|
|
#define RGB_DARKRED RGB( 2, 0, 0)
|
|
#define RGB_GREEN RGB( 0, 3, 0)
|
|
#define RGB_DARKGREEN RGB( 0, 2, 0)
|
|
#define RGB_BLUE RGB( 0, 0, 3)
|
|
#define RGB_DARKBLUE RGB( 0, 0, 2)
|
|
#define RGB_YELLOW RGB( 3, 3, 0)
|
|
#define RGB_DARKYELLOW RGB( 2, 2, 0)
|
|
#define RGB_CYAN RGB( 0, 3, 3)
|
|
#define RGB_AQUA RGB( 3, 1, 2)
|
|
#define RGB_PINK RGB( 3, 0, 3)
|
|
#define RGB_PURPLE RGB( 2, 0, 2)
|
|
#define RGB_BLACK RGB( 0, 0, 0)
|
|
#define RGB_DARKGRAY RGB( 1, 1, 1)
|
|
#define RGB_LIGHTGRAY RGB( 2, 2, 2)
|
|
#define RGB_WHITE RGB( 3, 3, 3)
|
|
|
|
typedef uint8_t palette_color_t;
|
|
|
|
#else
|
|
#error Unrecognized port
|
|
#endif
|
|
|
|
void set_default_palette(void);
|
|
inline void cpu_fast(void) {}
|
|
|
|
void set_palette_entry(uint8_t palette, uint8_t entry, uint16_t rgb_data) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
#define set_bkg_palette_entry set_palette_entry
|
|
#define set_sprite_palette_entry(palette,entry,rgb_data) set_palette_entry(1,entry,rgb_data)
|
|
void set_palette(uint8_t first_palette, uint8_t nb_palettes, const palette_color_t *rgb_data) Z88DK_CALLEE;
|
|
#define set_bkg_palette set_palette
|
|
#define set_sprite_palette(first_palette,nb_palettes,rgb_data) set_palette(1,1,rgb_data)
|
|
|
|
void set_native_tile_data(uint16_t start, uint16_t ntiles, const void *src) Z88DK_CALLEE;
|
|
inline void set_bkg_4bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
set_native_tile_data(start, ntiles, src);
|
|
}
|
|
void set_sprite_1bpp_data(uint16_t start, uint16_t ntiles, const void *src) Z88DK_CALLEE;
|
|
inline void set_native_sprite_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
set_sprite_1bpp_data(start, ntiles, src);
|
|
}
|
|
|
|
#define COMPAT_PALETTE(C0,C1,C2,C3) (((uint16_t)(C3) << 12) | ((uint16_t)(C2) << 8) | ((uint16_t)(C1) << 4) | (uint16_t)(C0))
|
|
extern uint16_t _current_2bpp_palette;
|
|
inline void set_2bpp_palette(uint16_t palette) {
|
|
_current_2bpp_palette = palette;
|
|
}
|
|
//void set_tile_2bpp_data(uint16_t start, uint16_t ntiles, const void *src, uint16_t palette) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
inline void set_bkg_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
set_native_tile_data(start, ntiles, src);
|
|
}
|
|
inline void set_sprite_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
set_sprite_1bpp_data(start, ntiles, src);
|
|
}
|
|
//inline void set_bkg_2bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
// set_tile_2bpp_data(start, ntiles, src, _current_2bpp_palette);
|
|
//}
|
|
//inline void set_sprite_2bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
// set_tile_2bpp_data((uint8_t)(start) + 0x100u, ntiles, src, _current_2bpp_palette);
|
|
//}
|
|
|
|
extern uint16_t _current_1bpp_colors;
|
|
inline void set_1bpp_colors(uint8_t fgcolor, uint8_t bgcolor) {
|
|
_current_1bpp_colors = ((uint16_t)bgcolor << 8) | fgcolor;
|
|
}
|
|
void set_tile_1bpp_data(uint16_t start, uint16_t ntiles, const void *src, uint16_t colors) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
inline void set_bkg_1bpp_data(uint16_t start, uint16_t ntiles, const void *src) {
|
|
set_tile_1bpp_data(start, ntiles, src, _current_1bpp_colors);
|
|
}
|
|
|
|
|
|
/** Copies arbitrary data to an address in VRAM
|
|
|
|
@param dst destination VRAM Address
|
|
@param src Pointer to source buffer
|
|
@param size Number of bytes to copy
|
|
|
|
Copies __size__ bytes from a buffer at _src__ to VRAM starting at __dst__.
|
|
*/
|
|
void set_data(uint16_t dst, const void *src, uint16_t size) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
void vmemcpy(uint16_t dst, const void *src, uint16_t size) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
|
|
void 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);
|
|
#define set_bkg_tiles set_tile_map
|
|
#define set_win_tiles set_tile_map
|
|
|
|
extern uint8_t _map_tile_offset;
|
|
inline 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) {
|
|
_map_tile_offset = base_tile;
|
|
set_tile_map(x, y, w, h, tiles);
|
|
_map_tile_offset = 0;
|
|
}
|
|
inline 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) {
|
|
_map_tile_offset = base_tile;
|
|
set_tile_map(x, y, w, h, tiles);
|
|
_map_tile_offset = 0;
|
|
}
|
|
|
|
void 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);
|
|
void 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);
|
|
inline void set_bkg_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) {
|
|
set_tile_submap_compat(x, y, w, h, map_w, map);
|
|
}
|
|
inline void set_win_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) {
|
|
set_tile_submap_compat(x, y, w, h, map_w, map);
|
|
}
|
|
|
|
extern uint8_t _submap_tile_offset;
|
|
inline 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) {
|
|
_submap_tile_offset = base_tile;
|
|
set_tile_submap_compat(x, y, w, h, map_w, map);
|
|
_submap_tile_offset = 0;
|
|
}
|
|
inline 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) {
|
|
_submap_tile_offset = base_tile;
|
|
set_tile_submap_compat(x, y, w, h, map_w, map);
|
|
_submap_tile_offset = 0;
|
|
}
|
|
|
|
void fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t tile) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
#define fill_bkg_rect fill_rect
|
|
#define fill_win_rect fill_rect
|
|
|
|
/** Sprite Attributes structure
|
|
@param x X Coordinate of the sprite on screen
|
|
@param y Y Coordinate of the sprite on screen
|
|
@param tile Sprite tile number (see @ref set_sprite_tile)
|
|
@param prop OAM Property Flags (see @ref set_sprite_prop)
|
|
*/
|
|
typedef struct OAM_item_t {
|
|
uint8_t y, x; //< X, Y Coordinates of the sprite on screen
|
|
uint8_t tile; //< Sprite tile number
|
|
uint8_t prop; //< OAM Property Flags
|
|
} OAM_item_t;
|
|
|
|
|
|
/** Shadow OAM array in WRAM, that is DMA-transferred into the real OAM each VBlank
|
|
*/
|
|
extern volatile struct OAM_item_t shadow_OAM[];
|
|
|
|
/** MSB of shadow_OAM address is used by OAM copying routine
|
|
*/
|
|
extern volatile uint8_t _shadow_OAM_base;
|
|
|
|
/** Flag for disabling of OAM copying routine
|
|
|
|
Values:
|
|
\li 1: OAM copy routine is disabled (non-isr VDP operation may be in progress)
|
|
\li 0: OAM copy routine is enabled
|
|
|
|
This flag is modified by all MSX GBDK API calls that write to the VDP.
|
|
It is set to DISABLED when they start and ENABLED when they complete.
|
|
|
|
@note It is recommended to avoid writing to the Video Display Processor
|
|
(VDP) during an interrupt service routine (ISR) since it can corrupt
|
|
the VDP pointer of an VDP operation already in progress.
|
|
|
|
If it is necessary, this flag can be used during an ISR to determine
|
|
whether a VDP operation is already in progress. If the value is `1`
|
|
then avoid writing to the VDP (tiles, map, scrolling, colors, etc).
|
|
|
|
\code{.c}
|
|
// at the beginning of and ISR that would write to the VDP
|
|
if (_shadow_OAM_OFF) return;
|
|
\endcode
|
|
|
|
@see @ref docs_consoles_safe_display_controller_access
|
|
*/
|
|
extern volatile uint8_t _shadow_OAM_OFF;
|
|
|
|
/** Disable shadow OAM to VRAM copy on each VBlank
|
|
*/
|
|
#define DISABLE_VBL_TRANSFER \
|
|
_shadow_OAM_base = 0
|
|
|
|
/** Enable shadow OAM to VRAM copy on each VBlank
|
|
*/
|
|
#define ENABLE_VBL_TRANSFER \
|
|
_shadow_OAM_base = (uint8_t)((uint16_t)&shadow_OAM >> 8)
|
|
|
|
/** Amount of hardware sprites in OAM
|
|
*/
|
|
#define MAX_HARDWARE_SPRITES 32
|
|
|
|
/** True if sprite hardware can flip sprites by X (horizontally)
|
|
*/
|
|
#define HARDWARE_SPRITE_CAN_FLIP_X 0
|
|
|
|
/** True if sprite hardware can flip sprites by Y (vertically)
|
|
*/
|
|
#define HARDWARE_SPRITE_CAN_FLIP_Y 0
|
|
|
|
/** Sets address of 256-byte aligned array of shadow OAM to be transferred on each VBlank
|
|
*/
|
|
inline void SET_SHADOW_OAM_ADDRESS(void * address) {
|
|
_shadow_OAM_base = (uint8_t)((uint16_t)address >> 8);
|
|
}
|
|
|
|
/** Sets sprite number __nb__in the OAM to display tile number __tile__.
|
|
|
|
@param nb Sprite number, range 0 - 39
|
|
@param tile Selects a tile (0 - 255) from memory at 8000h - 8FFFh
|
|
\n In CGB Mode this could be either in VRAM Bank
|
|
\n 0 or 1, depending on Bit 3 of the OAM Attribute Flag
|
|
\n (see @ref set_sprite_prop)
|
|
|
|
In 8x16 mode:
|
|
\li The sprite will also display the next tile (__tile__ + 1)
|
|
directly below (y + 8) the first tile.
|
|
\li The lower bit of the tile number is ignored:
|
|
the upper 8x8 tile is (__tile__ & 0xFE), and
|
|
the lower 8x8 tile is (__tile__ | 0x01).
|
|
\li See: @ref SPRITES_8x16
|
|
*/
|
|
inline void set_sprite_tile(uint8_t nb, uint8_t tile) {
|
|
shadow_OAM[nb].tile=tile;
|
|
}
|
|
|
|
|
|
/** Returns the tile number of sprite number __nb__ in the OAM.
|
|
|
|
@param nb Sprite number, range 0 - 39
|
|
|
|
@see set_sprite_tile for more details
|
|
*/
|
|
inline uint8_t get_sprite_tile(uint8_t nb) {
|
|
return shadow_OAM[nb].tile;
|
|
}
|
|
|
|
inline void set_sprite_prop(uint8_t nb, uint8_t prop) {
|
|
shadow_OAM[nb].prop = prop;
|
|
}
|
|
|
|
inline uint8_t get_sprite_prop(uint8_t nb) {
|
|
return shadow_OAM[nb].prop;
|
|
}
|
|
|
|
/** Moves sprite number __nb__ to the __x__, __y__ position on the screen.
|
|
|
|
@param nb Sprite number, range 0 - 39
|
|
@param x X Position. Specifies the sprites horizontal position on the screen (minus 8).
|
|
\n An offscreen value (X=0 or X>=168) hides the sprite, but the sprite
|
|
still affects the priority ordering - a better way to hide a sprite is to set
|
|
its Y-coordinate offscreen.
|
|
@param y Y Position. Specifies the sprites vertical position on the screen (minus 16).
|
|
\n An offscreen value (for example, Y=0 or Y>=160) hides the sprite.
|
|
|
|
Moving the sprite to 0,0 (or similar off-screen location) will hide it.
|
|
*/
|
|
inline void move_sprite(uint8_t nb, uint8_t x, uint8_t y) {
|
|
OAM_item_t * itm = &shadow_OAM[nb];
|
|
itm->y=y, itm->x=x;
|
|
}
|
|
|
|
|
|
/** Moves sprite number __nb__ relative to its current position.
|
|
|
|
@param nb Sprite number, range 0 - 39
|
|
@param x Number of pixels to move the sprite on the __X axis__
|
|
\n Range: -128 - 127
|
|
@param y Number of pixels to move the sprite on the __Y axis__
|
|
\n Range: -128 - 127
|
|
|
|
@see move_sprite for more details about the X and Y position
|
|
*/
|
|
inline void scroll_sprite(uint8_t nb, int8_t x, int8_t y) {
|
|
OAM_item_t * itm = &shadow_OAM[nb];
|
|
itm->y+=y, itm->x+=x;
|
|
}
|
|
|
|
|
|
/** Hides sprite number __nb__ by moving it to zero position by Y.
|
|
|
|
@param nb Sprite number, range 0 - 39
|
|
*/
|
|
inline void hide_sprite(uint8_t nb) {
|
|
shadow_OAM[nb].y = 0xC0;
|
|
}
|
|
|
|
/**
|
|
* Set byte in vram at given memory location
|
|
*
|
|
* @param addr address to write to
|
|
* @param v value
|
|
*/
|
|
void set_vram_byte(uint8_t * addr, uint8_t v) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
|
|
/**
|
|
* Set single tile t with attributes on background layer at x,y
|
|
* @param x X-coordinate
|
|
* @param y Y-coordinate
|
|
* @param t tile index
|
|
* @return returns the address of tile, so you may use faster set_vram_byte() later
|
|
*/
|
|
uint8_t * set_attributed_tile_xy(uint8_t x, uint8_t y, uint16_t t) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
|
|
/**
|
|
* Set single tile t on background layer at x,y
|
|
* @param x X-coordinate
|
|
* @param y Y-coordinate
|
|
* @param t tile index
|
|
* @return returns the address of tile, so you may use faster set_vram_byte() later
|
|
*/
|
|
uint8_t * set_tile_xy(uint8_t x, uint8_t y, uint8_t t) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
#define set_bkg_tile_xy set_tile_xy
|
|
#define set_win_tile_xy set_tile_xy
|
|
|
|
/**
|
|
* Get address of X,Y tile of background map
|
|
*/
|
|
uint8_t * get_bkg_xy_addr(uint8_t x, uint8_t y) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl);
|
|
#define get_win_xy_addr get_bkg_xy_addr
|
|
|
|
#endif /* _MSX_H */
|