diff --git a/.gitignore b/.gitignore index 0a25f36..90de6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/target -/out +target/ +out/ diff --git a/Cargo.lock b/Cargo.lock index c5585eb..297691d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,21 +60,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "buddy_system_allocator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7913f22349ffcfc6ca0ca9a656ec26cfbba538ed49c31a273dff2c5d1ea83d9" -dependencies = [ - "spin", -] - [[package]] name = "cc" version = "1.1.18" @@ -140,6 +125,10 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "filltest" +version = "0.1.0" + [[package]] name = "heck" version = "0.5.0" @@ -158,16 +147,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "memchr" version = "2.7.4" @@ -183,6 +162,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "project-root" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bccbff07d5ed689c4087d20d7307a52ab6141edeedf487c3876a55b86cf63df" + [[package]] name = "quote" version = "1.0.37" @@ -192,6 +177,10 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand-text" +version = "0.1.0" + [[package]] name = "regex" version = "1.10.6" @@ -224,15 +213,6 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rust-gb" version = "0.1.0" -dependencies = [ - "buddy_system_allocator", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "shlex" @@ -240,15 +220,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "strsim" version = "0.11.1" @@ -452,6 +423,7 @@ dependencies = [ "cc", "clap", "colored", + "project-root", "tree-sitter", "tree-sitter-c", ] diff --git a/Cargo.toml b/Cargo.toml index 0934e20..4ff6ed2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,8 @@ resolver = "2" members = [ "source", "xtask/*", + "examples/*", ] exclude = [ - "ext/rust-deps" + "ext/rust-deps", ] diff --git a/examples/filltest/Cargo.toml b/examples/filltest/Cargo.toml new file mode 100644 index 0000000..327b0fe --- /dev/null +++ b/examples/filltest/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "filltest" +version = "0.1.0" +edition = "2021" + + diff --git a/examples/filltest/gbdk.rs b/examples/filltest/src/gbdk.rs similarity index 100% rename from examples/filltest/gbdk.rs rename to examples/filltest/src/gbdk.rs diff --git a/examples/filltest/main.rs b/examples/filltest/src/main.rs similarity index 100% rename from examples/filltest/main.rs rename to examples/filltest/src/main.rs diff --git a/examples/rand-text/.cargo/config.toml b/examples/rand-text/.cargo/config.toml new file mode 100644 index 0000000..3c495f3 --- /dev/null +++ b/examples/rand-text/.cargo/config.toml @@ -0,0 +1,14 @@ +[build] +target = "avr-unknown-gnu-atmega328" +rustflags = ["--emit=llvm-ir"] + +# [target.avr-unknown-gnu-atmega328] + +[unstable] +build-std = ["core", "alloc"] + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/examples/rand-text/Cargo.toml b/examples/rand-text/Cargo.toml new file mode 100644 index 0000000..a0d3682 --- /dev/null +++ b/examples/rand-text/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rand-text" +version = "0.1.0" +edition = "2021" + + diff --git a/examples/rand-text/src/gbdk/gb.rs b/examples/rand-text/src/gbdk/gb.rs new file mode 100644 index 0000000..f720171 --- /dev/null +++ b/examples/rand-text/src/gbdk/gb.rs @@ -0,0 +1,63 @@ +pub mod gb { + extern "C" { + #[link_name="delay"] + pub fn delay(delay: u16); + #[link_name="waitpad __preserves_regs(b, c, h, l)"] + pub fn waitpad(mask: u8) -> u8; + #[link_name="waitpadup __preserves_regs(a, b, c, d, e, h, l)"] + pub fn waitpadup(); + } +} + +pub mod drawing { + use core::ffi::c_char; + + pub const GRAPHICS_WIDTH: u8 = 160; + pub const GRAPHICS_HEIGHT: u8 = 144; + + pub const SOLID: u8 = 0x00; + pub const OR: u8 = 0x01; + pub const XOR: u8 = 0x02; + pub const AND: u8 = 0x03; + + pub const WHITE: u8 = 0; + pub const LTGREY: u8 = 1; + pub const DKGREY: u8 = 2; + pub const BLACK: u8 = 3; + + pub const M_NOFILL: u8 = 0; + pub const M_FILL: u8 = 1; + + pub const SIGNED: u8 = 1; + pub const UNSIGNED: u8 = 0; + + extern "C" { + #[link_name="gprint __nonbanked"] + pub fn gprint(str: *const c_char); + //gprintln + //gprintn + //gprintf + #[link_name="plot __sdcccall(0)"] + pub fn plot(x: u8, y: u8, colour: u8, mode: u8); + #[link_name="plot_point __sdcccall(0)"] + pub fn plot_point(x: u8, y:u8); + #[link_name="switch_data __sdcccall(0)"] + pub fn switch_data(x: u8, y: u8, src: *const u8, dst: *const u8); + #[link_name="draw_image"] + pub fn draw_image(data: *const u8); + #[link_name="line __sdcccall(0)"] + pub fn line(x1: u8, y1: u8, x2: u8, y2: u8); + #[link_name="box __sdcccall(0)"] + pub fn r#box(x1: u8, y1: u8, x2: u8, y2: u8, style: u8); + #[link_name="circle __sdcccall(0)"] + pub fn circle(x: u8, y: u8, radius: u8, style: u8); + #[link_name="getpix __sdcccall(0)"] + pub fn getpix(x: u8, y: u8) -> u8; + #[link_name="wrtchr __sdcccall(0)"] + pub fn wrtchr(chr: i8); + #[link_name="gotogxy __sdcccall(0)"] + pub fn gotogxy(x: u8, y: u8); + #[link_name="color __sdcccall(0)"] + pub fn color(forecolor: u8, backcolor: u8, mode: u8); + } +} diff --git a/examples/rand-text/src/gbdk/mod.rs b/examples/rand-text/src/gbdk/mod.rs new file mode 100644 index 0000000..a7e0d96 --- /dev/null +++ b/examples/rand-text/src/gbdk/mod.rs @@ -0,0 +1,2 @@ +pub mod gb; +pub mod rand; diff --git a/examples/rand-text/src/gbdk/rand.rs b/examples/rand-text/src/gbdk/rand.rs new file mode 100644 index 0000000..6c8a1c8 --- /dev/null +++ b/examples/rand-text/src/gbdk/rand.rs @@ -0,0 +1,8 @@ +extern "C" { + #[link_name="rand __sdcccall(0)"] + pub fn rand() -> u8; + #[link_name="arand __sdcccall(0)"] + pub fn arand() -> u8; + #[link_name="initarand __sdcccall(0)"] + pub fn initarand(seed: u16); +} diff --git a/examples/rand-text/src/main.rs b/examples/rand-text/src/main.rs new file mode 100644 index 0000000..5e73d72 --- /dev/null +++ b/examples/rand-text/src/main.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] +#![allow(dead_code)] +#![feature(asm_experimental_arch)] + +mod gbdk; + +use core::ffi::c_char; + +use gbdk::{gb::{drawing::{gotogxy, gprint, plot, plot_point, LTGREY, SOLID}, gb::{delay, waitpad, waitpadup}}, rand::{initarand, rand}}; + +#[no_mangle] +pub extern fn main() { + unsafe { + gprint("Getting seed\0".as_ptr() as *const c_char); + gotogxy(0, 1); + gprint("Push any key (1)\0".as_ptr() as *const c_char); + let a: u8 = waitpad(0xFF); + waitpadup(); + let mut seed = a as u16; + gotogxy(0, 2); + gprint("Push any key (2)\0".as_ptr() as *const c_char); + let b: u8 = waitpad(0xFF); + waitpadup(); + seed |= (b as u16) << 8; + + initarand(seed); + + loop { + let r = rand(); + gprint([r, 0].as_ptr() as *const c_char); + } + } +} + +#[allow(unconditional_recursion)] +#[cfg(not(test))] +#[panic_handler] +fn panic_handler_phony(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/ext/include/asm/mos6502/provides.h b/ext/include/asm/mos6502/provides.h new file mode 100644 index 0000000..8e29739 --- /dev/null +++ b/ext/include/asm/mos6502/provides.h @@ -0,0 +1,4 @@ +#define USE_C_MEMCPY 0 +#define USE_C_STRCPY 0 +#define USE_C_STRCMP 0 + diff --git a/ext/include/asm/mos6502/stdarg.h b/ext/include/asm/mos6502/stdarg.h new file mode 100644 index 0000000..3b99338 --- /dev/null +++ b/ext/include/asm/mos6502/stdarg.h @@ -0,0 +1,18 @@ +#ifndef ASM_MOS6502_STDARG_INCLUDE +#define ASM_MOS6502_STDARG_INCLUDE + +/* sdcc pushes right to left with the real sizes, not cast up + to an int. + so printf(int, char, long) + results in push long, push char, push int + On the 6502 the stack grows down, so the things seem to be in + the correct order. + */ + +typedef unsigned char * va_list; +#define va_start(list, last) list = (unsigned char *)&last + sizeof(last) +#define va_arg(list, type) *((type *)((list += sizeof(type)) - sizeof(type))) + +#define va_end(list) + +#endif diff --git a/ext/include/asm/mos6502/string.h b/ext/include/asm/mos6502/string.h new file mode 100644 index 0000000..1f54844 --- /dev/null +++ b/ext/include/asm/mos6502/string.h @@ -0,0 +1,145 @@ +/** @file string.h + Generic string functions. + */ +#ifndef STRING_INCLUDE +#define STRING_INCLUDE + +#include + +/** Copies the string pointed to by __src__ (including the terminating + `\0' character) to the array pointed to by __dest__. + + The strings may not overlap, and the destination string dest must + be large enough to receive the copy. + + @param dest Array to copy into + @param src Array to copy from + + @return A pointer to dest +*/ +char *strcpy(char *dest, const char *src) OLDCALL; + +/** Compares strings + + @param s1 First string to compare + @param s2 Second string to compare + + Returns: + \li > 0 if __s1__ > __s2__ + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ +*/ +int strcmp(const char *s1, const char *s2); + +/** Copies n bytes from memory area src to memory area dest. + + The memory areas may not overlap. + + @param dest Buffer to copy into + @param src Buffer to copy from + @param len Number of Bytes to copy +*/ +void *__memcpy(void *dest, const void *src, size_t len); +#define memcpy(dst, src, n) __memcpy(dst, src, n) + +/** Copies n bytes from memory area src to memory area dest, areas may overlap + */ +void *memmove (void *dest, const void *src, size_t n) OLDCALL; + +/** Fills the memory region __s__ with __n__ bytes using value __c__ + + @param s Buffer to fill + @param c char value to fill with (truncated from int) + @param n Number of bytes to fill +*/ +void *memset (void *s, int c, size_t n); + +/** Reverses the characters in a string + + @param s Pointer to string to reverse. + + For example 'abcdefg' will become 'gfedcba'. + + Banked as the string must be modifiable. + + Returns: Pointer to __s__ +*/ +char *reverse(char *s) NONBANKED; + +/** Concatenate Strings. Appends string __s2__ to the end of string __s1__ + + @param s1 String to append onto + @param s2 String to copy from + + For example 'abc' and 'def' will become 'abcdef'. + + String __s1__ must be large enough to store both __s1__ and __s2__. + + Returns: Pointer to __s1__ +*/ +char *strcat(char *s1, const char *s2) NONBANKED; + +/** Calculates the length of a string + + @param s String to calculate length of + + Returns: Length of string not including the terminating `\0' character. +*/ +int strlen(const char *s) OLDCALL; + +/**Concatenate at most __n__ characters from string __s2__ onto the end of __s1__. + + @param s1 String to append onto + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + String __s1__ must be large enough to store both __s1__ and __n__ characters of __s2__ + + Returns: Pointer to __s1__ +*/ +char *strncat(char *s1, const char *s2, int n) NONBANKED; + +/** Compare strings (at most n characters): + + @param s1 First string to compare + @param s2 Second string to compare + @param n Max number of characters to compare + + Returns: + \li > 0 if __s1__ > __s2__ + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ +*/ +int strncmp(const char *s1, const char *s2, int n) NONBANKED; + +/** Copy __n__ characters from string __s2__ to __s1__ + + + @param s1 String to copy into + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + If __s2__ is shorter than __n__, the remaining + bytes in __s1__ are filled with \0. + + Warning: If there is no \0 in the first __n__ bytes of __s2__ then __s1__ + will not be null terminated. + + Returns: Pointer to __s1__ +*/ +char *strncpy(char *s1, const char *s2, int n) NONBANKED; + +/** Compares buffers + + @param buf1 First buffer to compare + @param buf2 Second buffer to compare + @param count Buffer length + + Returns: + \li > 0 if __buf1__ > __buf2__ + \li 0 if __buf1__ == __buf2__ + \li < 0 if __buf1__ < __buf2__ +*/ +int memcmp(const void *buf1, const void *buf2, size_t count); + +#endif diff --git a/ext/include/asm/mos6502/types.h b/ext/include/asm/mos6502/types.h new file mode 100644 index 0000000..84c3545 --- /dev/null +++ b/ext/include/asm/mos6502/types.h @@ -0,0 +1,74 @@ +/** @file asm/mos6502/types.h + @anchor file_asm_mos6502_types_h + Types definitions for the gb. +*/ +#ifndef ASM_MOS6502_TYPES_INCLUDE +#define ASM_MOS6502_TYPES_INCLUDE + +#ifndef __PORT_mos6502 + #error mos6502 only. +#endif + +#ifdef __SDCC + +#define NONBANKED __nonbanked +#define BANKED __banked +#define REENTRANT __reentrant /**< Needed for mos6502 target when functions take too many parameters. */ +#define NO_OVERLAY_LOCALS __no_overlay_locals /**< Optimization for mos6502 target, indicating locals won't conflict with compiler's overlay segment */ + +/** Use to create a block of code which should execute with interrupts temporarily turned off. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. + + @see enable_interrupts, disable_interrupts +*/ +#define CRITICAL __critical + +/** Indicate to the compiler the function will be used as an interrupt handler. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. + + @see ISR_VECTOR(), ISR_NESTED_VECTOR() +*/ +#define INTERRUPT __interrupt + +#endif + +/** Signed eight bit. + */ +typedef signed char INT8; +/** Unsigned eight bit. + */ +typedef unsigned char UINT8; +/** Signed sixteen bit. + */ +typedef signed int INT16; +/** Unsigned sixteen bit. + */ +typedef unsigned int UINT16; +/** Signed 32 bit. + */ +typedef signed long INT32; +/** Unsigned 32 bit. + */ +typedef unsigned long UINT32; + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +typedef unsigned int size_t; +#endif + +/** Returned from clock + @see clock +*/ +typedef unsigned int clock_t; + +#endif diff --git a/ext/include/asm/sm83/provides.h b/ext/include/asm/sm83/provides.h new file mode 100644 index 0000000..8e29739 --- /dev/null +++ b/ext/include/asm/sm83/provides.h @@ -0,0 +1,4 @@ +#define USE_C_MEMCPY 0 +#define USE_C_STRCPY 0 +#define USE_C_STRCMP 0 + diff --git a/ext/include/asm/sm83/stdarg.h b/ext/include/asm/sm83/stdarg.h new file mode 100644 index 0000000..0c6e384 --- /dev/null +++ b/ext/include/asm/sm83/stdarg.h @@ -0,0 +1,18 @@ +#ifndef ASM_SM83_STDARG_INCLUDE +#define ASM_SM83_STDARG_INCLUDE + +/* sdcc pushes right to left with the real sizes, not cast up + to an int. + so printf(int, char, long) + results in push long, push char, push int + On the z80 the stack grows down, so the things seem to be in + the correct order. + */ + +typedef unsigned char * va_list; +#define va_start(list, last) list = (unsigned char *)&last + sizeof(last) +#define va_arg(list, type) *((type *)((list += sizeof(type)) - sizeof(type))) + +#define va_end(list) + +#endif diff --git a/ext/include/asm/sm83/string.h b/ext/include/asm/sm83/string.h new file mode 100644 index 0000000..ceb9298 --- /dev/null +++ b/ext/include/asm/sm83/string.h @@ -0,0 +1,150 @@ +/** @file string.h + Generic string functions. + */ +#ifndef STRING_INCLUDE +#define STRING_INCLUDE + +#include + +/** Copies the string pointed to by __src__ (including the terminating + `\0' character) to the array pointed to by __dest__. + + The strings may not overlap, and the destination string dest must + be large enough to receive the copy. + + @param dest Array to copy into + @param src Array to copy from + + @return A pointer to dest +*/ +char *strcpy(char *dest, const char *src) OLDCALL PRESERVES_REGS(b, c); + +/** Compares strings + + @param s1 First string to compare + @param s2 Second string to compare + + Returns: + \li > 0 if __s1__ > __s2__ + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ +*/ +int strcmp(const char *s1, const char *s2) OLDCALL PRESERVES_REGS(b, c); + +/** Copies n bytes from memory area src to memory area dest. + + The memory areas may not overlap. + + @param dest Buffer to copy into + @param src Buffer to copy from + @param len Number of Bytes to copy +*/ +void *memcpy(void *dest, const void *src, size_t len); + +/** Copies n bytes from memory area src to memory area dest, areas may overlap + */ +void *memmove (void *dest, const void *src, size_t n); + +/** Fills the memory region __s__ with __n__ bytes using value __c__ + + @param s Buffer to fill + @param c char value to fill with (truncated from int) + @param n Number of bytes to fill +*/ +void *memset (void *s, int c, size_t n) OLDCALL PRESERVES_REGS(b, c); + +/** Reverses the characters in a string + + @param s Pointer to string to reverse. + + For example 'abcdefg' will become 'gfedcba'. + + Banked as the string must be modifiable. + + Returns: Pointer to __s__ +*/ +char *reverse(char *s) OLDCALL PRESERVES_REGS(b, c); + +/** Concatenate Strings. Appends string __s2__ to the end of string __s1__ + + @param s1 String to append onto + @param s2 String to copy from + + For example 'abc' and 'def' will become 'abcdef'. + + String __s1__ must be large enough to store both __s1__ and __s2__. + + Returns: Pointer to __s1__ +*/ +char *strcat(char *s1, const char *s2); + +/** Calculates the length of a string + + @param s String to calculate length of + + Returns: Length of string not including the terminating `\0' character. +*/ +int strlen(const char *s) OLDCALL PRESERVES_REGS(b, c); + +/**Concatenate at most __n__ characters from string __s2__ onto the end of __s1__. + + @param s1 String to append onto + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + String __s1__ must be large enough to store both __s1__ and __n__ characters of __s2__ + + Returns: Pointer to __s1__ +*/ +char *strncat(char *s1, const char *s2, int n); + +/** Compare strings (at most __n__ characters): + + @param s1 First string to compare + @param s2 Second string to compare + @param n Max number of characters to compare + + Returns zero if the strings are identical, or non-zero + if they are not (see below). + + Returns: + \li > 0 if __s1__ > __s2__ (at first non-matching byte) + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ (at first non-matching byte) +*/ +int strncmp(const char *s1, const char *s2, int n); + +/** Copy __n__ characters from string __s2__ to __s1__ + + + @param s1 String to copy into + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + If __s2__ is shorter than __n__, the remaining + bytes in __s1__ are filled with \0. + + Warning: If there is no \0 in the first __n__ bytes of __s2__ then __s1__ + will not be null terminated. + + Returns: Pointer to __s1__ +*/ +char *strncpy(char *s1, const char *s2, int n); + +/** Compare up to __count__ bytes in buffers __buf1__ and __buf2__ + + @param buf1 Pointer to First buffer to compare + @param buf2 Pointer to Second buffer to compare + @param count Max number of bytes to compare + + Returns zero if the buffers are identical, or non-zero + if they are not (see below). + + Returns: + \li > 0 if __buf1__ > __buf2__ (at first non-matching byte) + \li 0 if __buf1__ == __buf2__ + \li < 0 if __buf1__ < __buf2__ (at first non-matching byte) +*/ +int memcmp(const void *buf1, const void *buf2, size_t count) OLDCALL; + +#endif diff --git a/ext/include/asm/sm83/types.h b/ext/include/asm/sm83/types.h new file mode 100644 index 0000000..59d3520 --- /dev/null +++ b/ext/include/asm/sm83/types.h @@ -0,0 +1,74 @@ +/** @file asm/sm83/types.h + @anchor file_asm_sm83_types_h + Types definitions for the gb. +*/ +#ifndef ASM_SM83_TYPES_INCLUDE +#define ASM_SM83_TYPES_INCLUDE + +#ifndef __PORT_sm83 + #error sm83 only. +#endif + +#ifdef __SDCC + +#define NONBANKED __nonbanked /**< Placed in the non-banked lower 16K region (bank 0), regardless of the bank selected by it's source file. */ +#define BANKED __banked /**< The function will use banked sdcc calls, and is placed in the bank selected by it's source file (or compiler switches). */ +#define REENTRANT /**< Needed for mos6502 target when functions take too many parameters. */ +#define NO_OVERLAY_LOCALS /**< Optimization for mos6502 target, indicating locals won't conflict with compiler's overlay segment */ + +/** Use to create a block of code which should execute with interrupts temporarily turned off. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. + + @see enable_interrupts, disable_interrupts +*/ +#define CRITICAL __critical + +/** Indicate to the compiler the function will be used as an interrupt handler. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. + + @see ISR_VECTOR(), ISR_NESTED_VECTOR() +*/ +#define INTERRUPT __interrupt + +#endif + +/** Signed eight bit. + */ +typedef signed char INT8; +/** Unsigned eight bit. + */ +typedef unsigned char UINT8; +/** Signed sixteen bit. + */ +typedef signed int INT16; +/** Unsigned sixteen bit. + */ +typedef unsigned int UINT16; +/** Signed 32 bit. + */ +typedef signed long INT32; +/** Unsigned 32 bit. + */ +typedef unsigned long UINT32; + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +typedef unsigned int size_t; +#endif + +/** Returned from clock + @see clock +*/ +typedef unsigned int clock_t; + +#endif diff --git a/ext/include/asm/types.h b/ext/include/asm/types.h new file mode 100644 index 0000000..6eaee0d --- /dev/null +++ b/ext/include/asm/types.h @@ -0,0 +1,94 @@ +/** @file asm/types.h + Shared types definitions. +*/ +#ifndef ASM_TYPES_INCLUDE +#define ASM_TYPES_INCLUDE + +#if defined(__PORT_sm83) +#include +#elif defined(__PORT_z80) +#include +#elif defined(__PORT_mos6502) +#include +#else +#error Unrecognised port +#endif + +#ifndef OLDCALL +#if __SDCC_REVISION >= 12608 +#define OLDCALL __sdcccall(0) +#else +#define OLDCALL +#endif +#endif + +#ifdef __SDCC +#define PRESERVES_REGS(...) __preserves_regs(__VA_ARGS__) +#define NAKED __naked +#define SFR __sfr +#define AT(A) __at(A) +#define NORETURN _Noreturn +#else +#define PRESERVES_REGS(...) +#define NAKED +#define SFR +#define AT(A) +#define NORETURN +#endif + +#ifndef NONBANKED +#define NONBANKED +#endif +#ifndef BANKED +#define BANKED +#endif +#ifndef CRITICAL +#define CRITICAL +#endif +#ifndef INTERRUPT +#define INTERRUPT +#endif + +/** TRUE or FALSE. + @anchor file_asm_types_h + */ +typedef INT8 BOOLEAN; + +/** Signed 8 bit. + */ +typedef INT8 BYTE; +/** Unsigned 8 bit. + */ +typedef UINT8 UBYTE; +/** Signed 16 bit */ +typedef INT16 WORD; +/** Unsigned 16 bit */ +typedef UINT16 UWORD; +/** Signed 32 bit */ +typedef INT32 LWORD; +/** Unsigned 32 bit */ +typedef UINT32 ULWORD; +/** Signed 32 bit */ +typedef INT32 DWORD; +/** Unsigned 32 bit */ +typedef UINT32 UDWORD; + +/** Useful definition for working with 8 bit + 8 bit fixed point values + + Use `.w` to access the variable as unsigned 16 bit type. + + Use `.b.h` and `.b.l` (or just `.h` and `.l`) to directly access it's high and low unsigned 8 bit values. + */ +typedef union _fixed { + struct { + UBYTE l; + UBYTE h; + }; + struct { + UBYTE l; + UBYTE h; + } b; + UWORD w; +} fixed; + +#endif diff --git a/ext/include/asm/z80/provides.h b/ext/include/asm/z80/provides.h new file mode 100644 index 0000000..d7aa195 --- /dev/null +++ b/ext/include/asm/z80/provides.h @@ -0,0 +1,4 @@ +#define USE_C_MEMCPY 0 +#define USE_C_STRCPY 0 +#define USE_C_STRCMP 1 + diff --git a/ext/include/asm/z80/stdarg.h b/ext/include/asm/z80/stdarg.h new file mode 100644 index 0000000..a82642f --- /dev/null +++ b/ext/include/asm/z80/stdarg.h @@ -0,0 +1,18 @@ +#ifndef ASM_Z80_STDARG_INCLUDE +#define ASM_Z80_STDARG_INCLUDE + +/* sdcc pushes right to left with the real sizes, not cast up + to an int. + so printf(int, char, long) + results in push long, push char, push int + On the z80 the stack grows down, so the things seem to be in + the correct order. + */ + +typedef unsigned char * va_list; +#define va_start(list, last) list = (unsigned char *)&last + sizeof(last) +#define va_arg(list, type) *((type *)((list += sizeof(type)) - sizeof(type))) + +#define va_end(list) + +#endif diff --git a/ext/include/asm/z80/string.h b/ext/include/asm/z80/string.h new file mode 100644 index 0000000..0d4b2e0 --- /dev/null +++ b/ext/include/asm/z80/string.h @@ -0,0 +1,144 @@ +/** @file string.h + Generic string functions. + */ +#ifndef STRING_INCLUDE +#define STRING_INCLUDE + +#include + +/** Copies the string pointed to by __src__ (including the terminating + `\0' character) to the array pointed to by __dest__. + + The strings may not overlap, and the destination string dest must + be large enough to receive the copy. + + @param dest Array to copy into + @param src Array to copy from + + @return A pointer to dest +*/ +char *strcpy(char *dest, const char *src) OLDCALL; + +/** Compares strings + + @param s1 First string to compare + @param s2 Second string to compare + + Returns: + \li > 0 if __s1__ > __s2__ + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ +*/ +int strcmp(const char *s1, const char *s2); + +/** Copies n bytes from memory area src to memory area dest. + + The memory areas may not overlap. + + @param dest Buffer to copy into + @param src Buffer to copy from + @param len Number of Bytes to copy +*/ +void *memcpy(void *dest, const void *src, size_t len); + +/** Copies n bytes from memory area src to memory area dest, areas may overlap + */ +void *memmove (void *dest, const void *src, size_t n) OLDCALL; + +/** Fills the memory region __s__ with __n__ bytes using value __c__ + + @param s Buffer to fill + @param c char value to fill with (truncated from int) + @param n Number of bytes to fill +*/ +void *memset (void *s, int c, size_t n) Z88DK_CALLEE; + +/** Reverses the characters in a string + + @param s Pointer to string to reverse. + + For example 'abcdefg' will become 'gfedcba'. + + Banked as the string must be modifiable. + + Returns: Pointer to __s__ +*/ +char *reverse(char *s) NONBANKED; + +/** Concatenate Strings. Appends string __s2__ to the end of string __s1__ + + @param s1 String to append onto + @param s2 String to copy from + + For example 'abc' and 'def' will become 'abcdef'. + + String __s1__ must be large enough to store both __s1__ and __s2__. + + Returns: Pointer to __s1__ +*/ +char *strcat(char *s1, const char *s2) NONBANKED; + +/** Calculates the length of a string + + @param s String to calculate length of + + Returns: Length of string not including the terminating `\0' character. +*/ +int strlen(const char *s) OLDCALL; + +/**Concatenate at most __n__ characters from string __s2__ onto the end of __s1__. + + @param s1 String to append onto + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + String __s1__ must be large enough to store both __s1__ and __n__ characters of __s2__ + + Returns: Pointer to __s1__ +*/ +char *strncat(char *s1, const char *s2, int n) NONBANKED; + +/** Compare strings (at most n characters): + + @param s1 First string to compare + @param s2 Second string to compare + @param n Max number of characters to compare + + Returns: + \li > 0 if __s1__ > __s2__ + \li 0 if __s1__ == __s2__ + \li < 0 if __s1__ < __s2__ +*/ +int strncmp(const char *s1, const char *s2, int n) NONBANKED; + +/** Copy __n__ characters from string __s2__ to __s1__ + + + @param s1 String to copy into + @param s2 String to copy from + @param n Max number of characters to copy from __s2__ + + If __s2__ is shorter than __n__, the remaining + bytes in __s1__ are filled with \0. + + Warning: If there is no \0 in the first __n__ bytes of __s2__ then __s1__ + will not be null terminated. + + Returns: Pointer to __s1__ +*/ +char *strncpy(char *s1, const char *s2, int n) NONBANKED; + +/** Compares buffers + + @param buf1 First buffer to compare + @param buf2 Second buffer to compare + @param count Buffer length + + Returns: + \li > 0 if __buf1__ > __buf2__ + \li 0 if __buf1__ == __buf2__ + \li < 0 if __buf1__ < __buf2__ +*/ +int memcmp(const void *buf1, const void *buf2, size_t count) Z88DK_CALLEE; + +#endif diff --git a/ext/include/asm/z80/types.h b/ext/include/asm/z80/types.h new file mode 100644 index 0000000..2984299 --- /dev/null +++ b/ext/include/asm/z80/types.h @@ -0,0 +1,80 @@ +/** @file asm/z80/types.h + @anchor file_asm_z80_types_h + Types definitions for the gb. +*/ +#ifndef ASM_Z80_TYPES_INCLUDE +#define ASM_Z80_TYPES_INCLUDE + +#ifndef __PORT_z80 + #error z80 only. +#endif + +#ifdef __SDCC + +#define Z88DK_CALLEE __sdcccall(0) __z88dk_callee +#define Z88DK_FASTCALL __z88dk_fastcall + +#define NONBANKED __nonbanked /**< Placed in the non-banked lower 16K region (bank 0), regardless of the bank selected by it's source file. */ +#define BANKED __banked /**< The function will use banked sdcc calls, and is placed in the bank selected by it's source file (or compiler switches). */ +#define REENTRANT /**< Needed for mos6502 target when functions take too many parameters. */ +#define NO_OVERLAY_LOCALS /**< Optimization for mos6502 target, indicating locals won't conflict with compiler's overlay segment */ + +/** Use to create a block of code which should execute with interrupts temporarily turned off. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. + + @see enable_interrupts, disable_interrupts +*/ +#define CRITICAL __critical + +/** Indicate to the compiler the function will be used as an interrupt handler. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + These attributes are only required when constructing + a bare jump from the interrupt vector itself. +*/ +#define INTERRUPT __interrupt + +#else + +#define Z88DK_CALLEE +#define Z88DK_FASTCALL + +#endif + +/** Signed eight bit. + */ +typedef signed char INT8; +/** Unsigned eight bit. + */ +typedef unsigned char UINT8; +/** Signed sixteen bit. + */ +typedef signed int INT16; +/** Unsigned sixteen bit. + */ +typedef unsigned int UINT16; +/** Signed 32 bit. + */ +typedef signed long INT32; +/** Unsigned 32 bit. + */ +typedef unsigned long UINT32; + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED +typedef unsigned int size_t; +#endif + +/** Returned from clock + @see clock +*/ +typedef unsigned int clock_t; + +#endif diff --git a/ext/include/assert.h b/ext/include/assert.h new file mode 100644 index 0000000..2d0995d --- /dev/null +++ b/ext/include/assert.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + assert.h - header file for assert ANSI routine + + Copyright (C) 2018, Philipp Klaus Krause . pkk@spth.de + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#undef assert + +#ifdef NDEBUG + +/* Debugging disabled -- do not evaluate assertions. */ +#define assert(x) ((void)0) + +#else + +/* Debugging enabled -- verify assertions at run time. */ +void __assert(const char *expression, const char *functionname, const char *filename, unsigned int linenumber); +#define assert(x) ((x) ? (void)0 : __assert(#x, __func__, __FILE__, __LINE__)) + +#if __STDC_VERSION__ >= 201112L +#define static_assert _Static_assert +#endif + +#endif + diff --git a/ext/include/ctype.h b/ext/include/ctype.h new file mode 100644 index 0000000..91f9c8e --- /dev/null +++ b/ext/include/ctype.h @@ -0,0 +1,45 @@ +/** @file ctype.h + Character type functions. +*/ +#ifndef _CTYPE_H +#define _CTYPE_H + +#include +#include + +/** Returns TRUE if the character __c__ is a letter (a-z, A-Z), otherwise FALSE + @param c Character to test +*/ +bool isalpha(char c); + +/** Returns TRUE if the character __c__ is an uppercase letter (A-Z), otherwise FALSE + @param c Character to test +*/ +bool isupper(char c); + +/** Returns TRUE if the character __c__ is a lowercase letter (a-z), otherwise FALSE + @param c Character to test +*/ +bool islower(char c); + +/** Returns TRUE if the character __c__ is a digit (0-9), otherwise FALSE + @param c Character to test +*/ +bool isdigit(char c); + +/** Returns TRUE if the character __c__ is a space (' '), tab (\\t), or newline (\\n) character, otherwise FALSE + @param c Character to test +*/ +bool isspace(char c); + +/** Returns uppercase version of character __c__ if it is a letter (a-z), otherwise it returns the input value unchanged. + @param c Character to test +*/ +char toupper(char c); + +/** Returns lowercase version of character __c__ if it is a letter (A-Z), otherwise it returns the input value unchanged. + @param c Character to test +*/ +char tolower(char c); + +#endif /* _CTYPE_H */ diff --git a/ext/include/gb/bcd.h b/ext/include/gb/bcd.h new file mode 100644 index 0000000..4f3f004 --- /dev/null +++ b/ext/include/gb/bcd.h @@ -0,0 +1,61 @@ +#ifndef __BCD_H_INCLUDE +#define __BCD_H_INCLUDE + +#include +#include + +/** @file bcd.h + Support for working with BCD (Binary Coded Decimal) + + See the example BCD project for additional details. +*/ + +// macro for creating BCD constants +#define BCD_HEX(v) ((BCD)(v)) + +/** Converts an integer value into BCD format + + A maximum of 8 digits may be used +*/ +#define MAKE_BCD(v) BCD_HEX(0x ## v) + +typedef uint32_t BCD; + +/** Converts integer __i__ into BCD format (Binary Coded Decimal) + @param i Numeric value to convert + @param value Pointer to a BCD variable to store the converted result +*/ +void uint2bcd(uint16_t i, BCD * value) OLDCALL; + +/** Adds two numbers in BCD format: __sour__ += __value__ + @param sour Pointer to a BCD value to add to (and where the result is stored) + @param value Pointer to the BCD value to add to __sour__ +*/ +void bcd_add(BCD * sour, const BCD * value) OLDCALL; + +/** Subtracts two numbers in BCD format: __sour__ -= __value__ + @param sour Pointer to a BCD value to subtract from (and where the result is stored) + @param value Pointer to the BCD value to subtract from __sour__ +*/ +void bcd_sub(BCD * sour, const BCD * value) OLDCALL; + +/** Convert a BCD number into an asciiz (null terminated) string and return the length + @param bcd Pointer to BCD value to convert + @param tile_offset Optional per-character offset value to add (use 0 for none) + @param buffer Buffer to store the result in + + Returns: Length in characters (always 8) + + __buffer__ should be large enough to store the converted string + (9 bytes: 8 characters + 1 for terminator) + + There are a couple different ways to use __tile_offset__. + For example: + \li It can be the Index of the Font Tile '0' in VRAM to + allow the buffer to be used directly with @ref set_bkg_tiles. + \li It can also be set to the ascii value for character '0' + so that the buffer is a normal string that can be passed to @ref printf. +*/ +uint8_t bcd2text(const BCD * bcd, uint8_t tile_offset, uint8_t * buffer) OLDCALL; + +#endif diff --git a/ext/include/gb/bgb_emu.h b/ext/include/gb/bgb_emu.h new file mode 100644 index 0000000..77f204b --- /dev/null +++ b/ext/include/gb/bgb_emu.h @@ -0,0 +1,13 @@ +/** @file gb/bgb_emu.h + + Shim for legacy use of @ref bgb_emu.h which has been + migrated to @ref emu_debug.h + + See the `emu_debug` example project included with gbdk. +*/ +#ifndef __BGB_EMU_INCLUDE +#define __BGB_EMU_INCLUDE + +#include + +#endif diff --git a/ext/include/gb/cgb.h b/ext/include/gb/cgb.h new file mode 100644 index 0000000..543889f --- /dev/null +++ b/ext/include/gb/cgb.h @@ -0,0 +1,190 @@ +/** @file gb/cgb.h + Support for the Color GameBoy (CGB). + + __Enabling CGB features__ + + To unlock and use CGB features and registers you need to + change byte 0143h in the cartridge header. Otherwise, the CGB + will operate in monochrome "Non CGB" compatibility mode. + \li Use a value of __80h__ for games that support CGB and monochrome gameboys + \n (with Lcc: __-Wm-yc__, or makebin directly: __-yc__) + \li Use a value of __C0h__ for CGB only games. + \n (with Lcc: __-Wm-yC__, or makebin directly: __-yC__) + + See the Pan Docs for more information CGB features. +*/ + +#ifndef _CGB_H +#define _CGB_H + +#include +#include + +/** Macro to create a CGB palette color entry out of 5-bit color components. + + @param r 5-bit Red Component, range 0 - 31 (31 brightest) + @param g 5-bit Green Component, range 0 - 31 (31 brightest) + @param b 5-bit Blue Component, range 0 - 31 (31 brightest) + + The resulting format is bitpacked BGR-555 in a uint16_t. + + @see set_bkg_palette(), set_sprite_palette(), RGB8(), RGBHTML() + */ +#define RGB(r, g, b) ((uint16_t)((((b) & 0x1f) << 10) | ((uint16_t)(((g) & 0x1f) << 5)) | ((r) & 0x1f))) + +/** Macro to create a CGB palette color entry out of 8-bit color components. + + @param r 8-bit Red Component, range 0 - 255 (255 brightest) + @param g 8-bit Green Component, range 0 - 255 (255 brightest) + @param b 8-bit Blue Component, range 0 - 255 (255 brightest) + + The resulting format is bitpacked BGR-555 in a uint16_t. + + The lowest 3 bits of each color component are dropped during conversion. + + @see set_bkg_palette(), set_sprite_palette(), RGB(), RGBHTML() + */ +#define RGB8(r, g, b) (((uint16_t)((((b) >> 3) & 0x1f) << 10)) | ((uint16_t)((((g) >> 3) & 0x1f) << 5)) | (((r) >> 3) & 0x1f)) + +/** Macro to convert a 24 Bit RGB color to a CGB palette color entry. + + @param RGB24bit Bit packed RGB-888 color (0-255 for each color component). + + The resulting format is bitpacked BGR-555 in a uint16_t. + + The lowest 3 bits of each color component are dropped during conversion. + + @see set_bkg_palette(), set_sprite_palette(), RGB(), RGB8() + */ +#define RGBHTML(RGB24bit) (RGB8((((RGB24bit) >> 16) & 0xff), (((RGB24bit) >> 8) & 0xff), ((RGB24bit) & 0xff))) + +/** Common colors based on the EGA default palette. + */ +#define RGB_RED RGB(31, 0, 0) +#define RGB_DARKRED RGB(15, 0, 0) +#define RGB_GREEN RGB( 0, 31, 0) +#define RGB_DARKGREEN RGB( 0, 15, 0) +#define RGB_BLUE RGB( 0, 0, 31) +#define RGB_DARKBLUE RGB( 0, 0, 15) +#define RGB_YELLOW RGB(31, 31, 0) +#define RGB_DARKYELLOW RGB(21, 21, 0) +#define RGB_CYAN RGB( 0, 31, 31) +#define RGB_AQUA RGB(28, 5, 22) +#define RGB_PINK RGB(31, 0, 31) +#define RGB_PURPLE RGB(21, 0, 21) +#define RGB_BLACK RGB( 0, 0, 0) +#define RGB_DARKGRAY RGB(10, 10, 10) +#define RGB_LIGHTGRAY RGB(21, 21, 21) +#define RGB_WHITE RGB(31, 31, 31) + +#define RGB_LIGHTFLESH RGB(30, 20, 15) +#define RGB_BROWN RGB(10, 10, 0) +#define RGB_ORANGE RGB(30, 20, 0) +#define RGB_TEAL RGB(15, 15, 0) + +typedef uint16_t palette_color_t; /**< 16 bit color entry */ + +/** Set CGB background palette(s). + + @param first_palette Index of the first palette to write (0-7) + @param nb_palettes Number of palettes to write (1-8, max depends on first_palette) + @param rgb_data Pointer to source palette data + + Writes __nb_palettes__ to background palette data starting + at __first_palette__, Palette data is sourced from __rgb_data__. + + \li Each Palette is 8 bytes in size: 4 colors x 2 bytes per palette color entry. + \li Each color (4 per palette) is packed as BGR-555 format (1:5:5:5, MSBit [15] is unused). + \li Each component (R, G, B) may have values from 0 - 31 (5 bits), 31 is brightest. + + @see RGB(), set_bkg_palette_entry() + @see BKGF_CGB_PAL0, BKGF_CGB_PAL1, BKGF_CGB_PAL2, BKGF_CGB_PAL3 + @see BKGF_CGB_PAL4, BKGF_CGB_PAL5, BKGF_CGB_PAL6, BKGF_CGB_PAL7 + */ +void set_bkg_palette(uint8_t first_palette, uint8_t nb_palettes, const palette_color_t *rgb_data) OLDCALL; + +/** Set CGB sprite palette(s). + + @param first_palette Index of the first palette to write (0-7) + @param nb_palettes Number of palettes to write (1-8, max depends on first_palette) + @param rgb_data Pointer to source palette data + + Writes __nb_palettes__ to sprite palette data starting + at __first_palette__, Palette data is sourced from __rgb_data__. + + \li Each Palette is 8 bytes in size: 4 colors x 2 bytes per palette color entry. + \li Each color (4 per palette) is packed as BGR-555 format (1:5:5:5, MSBit [15] is unused). + \li Each component (R, G, B) may have values from 0 - 31 (5 bits), 31 is brightest. + + @see RGB(), set_sprite_palette_entry() + @see OAMF_CGB_PAL0, OAMF_CGB_PAL1, OAMF_CGB_PAL2, OAMF_CGB_PAL3 + @see OAMF_CGB_PAL4, OAMF_CGB_PAL5, OAMF_CGB_PAL6, OAMF_CGB_PAL7 + */ +void set_sprite_palette(uint8_t first_palette, uint8_t nb_palettes, const palette_color_t *rgb_data) OLDCALL; + +/** Sets a single color in the specified CGB background palette. + + @param palette Index of the palette to modify (0-7) + @param entry Index of color in palette to modify (0-3) + @param rgb_data New color data in BGR 15bpp format. + + @see set_bkg_palette(), RGB() + @see BKGF_CGB_PAL0, BKGF_CGB_PAL1, BKGF_CGB_PAL2, BKGF_CGB_PAL3 + @see BKGF_CGB_PAL4, BKGF_CGB_PAL5, BKGF_CGB_PAL6, BKGF_CGB_PAL7 + */ + +void set_bkg_palette_entry(uint8_t palette, uint8_t entry, uint16_t rgb_data) OLDCALL; + +/** Sets a single color in the specified CGB sprite palette. + + @param palette Index of the palette to modify (0-7) + @param entry Index of color in palette to modify (0-3) + @param rgb_data New color data in BGR 15bpp format. + + @see set_sprite_palette(), RGB() + @see OAMF_CGB_PAL0, OAMF_CGB_PAL1, OAMF_CGB_PAL2, OAMF_CGB_PAL3 + @see OAMF_CGB_PAL4, OAMF_CGB_PAL5, OAMF_CGB_PAL6, OAMF_CGB_PAL7 + */ +void set_sprite_palette_entry(uint8_t palette, uint8_t entry, uint16_t rgb_data) OLDCALL; + +/** Set CPU speed to slow (Normal Speed) operation. + + Interrupts are temporarily disabled and then re-enabled during this call. + + In this mode the CGB operates at the same speed as the DMG/Pocket/SGB models. + + \li You can check to see if @ref _cpu == @ref CGB_TYPE before using this function. + + @see cpu_fast() + */ +void cpu_slow(void); + +/** Set CPU speed to fast (CGB Double Speed) operation. + + On startup the CGB operates in Normal Speed Mode and can be switched + into Double speed mode (faster processing but also higher power consumption). + See the Pan Docs for more information about which hardware features + operate faster and which remain at Normal Speed. + + \li Interrupts are temporarily disabled and then re-enabled during this call. + \li You can check to see if @ref _cpu == @ref CGB_TYPE before using this function. + + @see cpu_slow(), _cpu +*/ +void cpu_fast(void); + +/** Sets CGB palette 0 to be compatible with the DMG/GBP. + + The default/first CGB palettes for sprites and backgrounds are + set to a similar default appearance as on the DMG/Pocket/SGB models. + (White, Light Gray, Dark Gray, Black) + + \li You can check to see if @ref _cpu == @ref CGB_TYPE before using this function. + */ +void set_default_palette(void); + +/** Obsolete. This function has been replaced by set_default_palette(), which has identical behavior. + */ +void cgb_compatibility(void); + +#endif /* _CGB_H */ diff --git a/ext/include/gb/crash_handler.h b/ext/include/gb/crash_handler.h new file mode 100644 index 0000000..3b78b55 --- /dev/null +++ b/ext/include/gb/crash_handler.h @@ -0,0 +1,25 @@ +/** @file gb/crash_handler.h + + When crash_handler.h is included, a crash dump screen + will be displayed if the CPU executes uninitalized + memory (with a value of 0xFF, the opcode for RST 38). + A handler is installed for RST 38 that calls + @ref __HandleCrash(). + + \code{.c} + #include + \endcode + + Also see the `crash` example project included with gbdk. +*/ +#ifndef __CRASH_HANDLER_INCLUDE +#define __CRASH_HANDLER_INCLUDE + +/** Display the crash dump screen. + + See the intro for this file for more details. +*/ +void __HandleCrash(void); +static void * __CRASH_HANDLER_INIT = &__HandleCrash; + +#endif \ No newline at end of file diff --git a/ext/include/gb/drawing.h b/ext/include/gb/drawing.h new file mode 100644 index 0000000..ca6ec7d --- /dev/null +++ b/ext/include/gb/drawing.h @@ -0,0 +1,158 @@ +/** @file gb/drawing.h + All Points Addressable (APA) mode drawing library. + + Drawing routines originally by Pascal Felber + Legendary overhall by Jon Fuge : https://github.com/jf1452 + Commenting by Michael Hope + + Note: The standard text printf() and putchar() cannot be used + in APA mode - use gprintf() and wrtchr() instead. + + Note: Using drawing.h will cause it's custom VBL and LCD ISRs + (`drawing_vbl` and `drawing_lcd`) to be installed. Changing + the mode (`mode(M_TEXT_OUT);`) will cause them to be de-installed. + + The valid coordinate ranges are from (x,y) 0,0 to 159,143. + There is no built-in clipping, so drawing outside valid + coordinates will likely produce undesired results (wrapping/etc). + + ---- + + __Important note for the drawing API :__ + + The Game Boy graphics hardware is not well suited to frame-buffer + style graphics such as the kind provided in `drawing.h`. + Due to that, __most drawing functions (rectangles, circles, etc) will + be slow__ . When possible it's much faster and more efficient + to work with the tiles and tile maps that the Game Boy hardware is + built around. +*/ +#ifndef __DRAWING_H +#define __DRAWING_H + +#include +#include + +/** Size of the screen in pixels */ +#define GRAPHICS_WIDTH 160 +#define GRAPHICS_HEIGHT 144 + +#define SOLID 0x00 /* Overwrites the existing pixels */ +#define OR 0x01 /* Performs a logical OR */ +#define XOR 0x02 /* Performs a logical XOR */ +#define AND 0x03 /* Performs a logical AND */ + +/** Possible drawing colours */ +#define WHITE 0 +#define LTGREY 1 +#define DKGREY 2 +#define BLACK 3 + +/** Possible fill styles for box() and circle() */ +#define M_NOFILL 0 +#define M_FILL 1 + +/** Possible values for signed_value in gprintln() and gprintn() */ +#define SIGNED 1 +#define UNSIGNED 0 + +#include + +/** Print the string 'str' with no interpretation + @see gotogxy() +*/ +void gprint(char *str) NONBANKED; + +/** Print 16 bit __number__ in __radix__ (base) in the default font at the current text position. + + @param number number to print + @param radix radix (base) to print with + @param signed_value should be set to SIGNED or UNSIGNED depending on whether the number is signed or not + + The current position is advanced by the numer of characters printed. + @see gotogxy() +*/ +void gprintln(int16_t number, int8_t radix, int8_t signed_value) NONBANKED; + +/** Print 8 bit __number__ in __radix__ (base) in the default font at the current text position. + + @see gprintln(), gotogxy() +*/ +void gprintn(int8_t number, int8_t radix, int8_t signed_value) NONBANKED; + +/** Print the string and arguments given by __fmt__ with arguments __...__ + + @param fmt The format string as per printf + @param ... params + + Currently supported: + \li \%c (character) + \li \%u (int) + \li \%d (int8_t) + \li \%o (int8_t as octal) + \li \%x (int8_t as hex) + \li \%s (string) + + @return Returns the number of items printed, or -1 if there was an error. + @see gotogxy() +*/ +int8_t gprintf(char *fmt,...) NONBANKED; + +/** Old style plot - try @ref plot_point() */ +void plot(uint8_t x, uint8_t y, uint8_t colour, uint8_t mode) OLDCALL; + +/** Plot a point in the current drawing mode and colour at __x,y__ */ +void plot_point(uint8_t x, uint8_t y) OLDCALL; + +/** Exchanges the tile on screen at x,y with the tile pointed by src, original tile + is saved in dst. Both src and dst may be NULL - saving or copying to screen is + not performed in this case. */ +void switch_data(uint8_t x, uint8_t y, uint8_t *src, uint8_t *dst) OLDCALL; + +/** Draw a full screen image at __data__ */ +void draw_image(uint8_t *data); + +/** Draw a line in the current drawing mode and colour from __x1,y1__ to __x2,y2__ */ +void line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) OLDCALL; + +/** Draw a box (rectangle) with corners __x1,y1__ and __x2,y2__ using fill mode + __style__ (one of NOFILL or FILL) */ +void box(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t style) OLDCALL; + +/** Draw a circle with centre at __x,y__ and __radius__ using fill mode + __style__ (one of NOFILL or FILL)*/ +void circle(uint8_t x, uint8_t y, uint8_t radius, uint8_t style) OLDCALL; + +/** Returns the current colour of the pixel at __x,y__ */ +uint8_t getpix(uint8_t x, uint8_t y) OLDCALL; + +/** Prints the character __chr__ in the default font at the current text position. + + The current position is advanced by 1 after the character is printed. + @see gotogxy() */ +void wrtchr(char chr) OLDCALL; + +/** Sets the current text position to __x,y__. + + Note: __x__ and __y__ have units of tiles (8 pixels per unit) + @see wrtchr() */ +void gotogxy(uint8_t x, uint8_t y) OLDCALL; + +/** Set the current __forecolor__ colour, __backcolor__ colour, and + draw __mode__ + + @param forecolor The primary drawing color (outlines of + rectangles with @ref box(), letter color + with @ref gprintf(), etc). + @param backcolor Secondary or background color where applicable + (fill color of rectangles with @ref box() when + @ref M_FILL is specifed, background color of text + with @ref gprintf(), etc). + @param mode Drawing style to use. Several settings are available + `SOLID`, `OR`, `XOR`, `AND`. + + In order to completely overwrite existing pixels use `SOLID` for __mode__ +*/ +void color(uint8_t forecolor, uint8_t backcolor, uint8_t mode) OLDCALL; + +#endif /* __DRAWING_H */ diff --git a/ext/include/gb/emu_debug.h b/ext/include/gb/emu_debug.h new file mode 100644 index 0000000..69d7632 --- /dev/null +++ b/ext/include/gb/emu_debug.h @@ -0,0 +1,13 @@ +/** @file gb/emu_debug.h + + Shim for legacy use of @ref gb/emu_debug.h which has been + migrated to @ref gbdk/emu_debug.h + + See the `emu_debug` example project included with gbdk. +*/ +#ifndef __EMU_DEBUG_INCLUDE +#define __EMU_DEBUG_INCLUDE + +#include + +#endif diff --git a/ext/include/gb/gb.h b/ext/include/gb/gb.h new file mode 100644 index 0000000..9d3bf4e --- /dev/null +++ b/ext/include/gb/gb.h @@ -0,0 +1,2222 @@ +/** @file gb/gb.h + Gameboy specific functions. +*/ +#ifndef _GB_H +#define _GB_H + +#include +#include +#include +#include + +// Here NINTENDO means Game Boy & related clones +#define NINTENDO + +#ifdef SEGA +#undef SEGA +#endif + +#ifdef NINTENDO_NES +#undef NINTENDO_NES +#endif + +#ifdef MSX +#undef MSX +#endif + +#define SYSTEM_60HZ 0x00 +#define SYSTEM_50HZ 0x01 + +#if defined(__TARGET_ap) +#define ANALOGUEPOCKET +#elif defined(__TARGET_gb) +#define GAMEBOY +#elif defined(__TARGET_duck) +#define MEGADUCK +#endif + + +/** 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 0x04U +#define J_DOWN 0x08U +#define J_LEFT 0x02U +#define J_RIGHT 0x01U +#define J_A 0x10U +#define J_B 0x20U +#define J_SELECT 0x40U +#define J_START 0x80U + +/** Screen modes. + Normally used by internal functions only. + @see mode() + */ +#define M_DRAWING 0x01U +#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 + +/** If this bit set clear, the tile from the second + VRAM bank is used + @see set_sprite_prop() +*/ +#define S_BANK 0x08U +/** If this is set, sprite colours come from OBJ1PAL. Else + they come from OBJ0PAL + @see set_sprite_prop(). +*/ +#define S_PALETTE 0x10U +/** If set the sprite will be flipped horizontally. + @see set_sprite_prop() + */ +#define S_FLIPX 0x20U +/** If set the sprite will be flipped vertically. + @see set_sprite_prop() + */ +#define S_FLIPY 0x40U +/** If this bit is clear, then the sprite will be displayed + on top of the background and window. + @see set_sprite_prop() +*/ +#define S_PRIORITY 0x80U +/** Defines how palette number is encoded in OAM. + Required for the png2asset tool's metasprite output. +*/ +#define S_PAL(n) n + +/* 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 +/** Timer Interrupt when the timer @ref TIMA_REG overflows. + @see set_interrupts(), @see add_TIM + */ +#define TIM_IFLAG 0x04U +/** Serial Link Interrupt occurs when the serial transfer has completed. + @see set_interrupts(), @see add_SIO + */ +#define SIO_IFLAG 0x08U +/** Joypad Interrupt occurs on a transition of the keypad. + @see set_interrupts(), @see add_JOY + */ +#define JOY_IFLAG 0x10U + + +/* DMG Palettes */ +#define DMG_BLACK 0x03 +#define DMG_DARK_GRAY 0x02 +#define DMG_LITE_GRAY 0x01 +#define DMG_WHITE 0x00 +/** Macro to create a DMG palette from 4 colors + + @param C0 Color for Index 0 + @param C1 Color for Index 1 + @param C2 Color for Index 2 + @param C3 Color for Index 3 + + The resulting format is four greyscale colors + packed into a single unsigned byte. + + Example: + \code{.c} + BGP_REG = DMG_PALETTE(DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE); + \endcode + + @see OBP0_REG, OBP1_REG, BGP_REG + @see DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE + + */ +#define DMG_PALETTE(C0, C1, C2, C3) ((uint8_t)((((C3) & 0x03) << 6) | (((C2) & 0x03) << 4) | (((C1) & 0x03) << 2) | ((C0) & 0x03))) + +/* 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 DEVICE_WINDOW_PX_OFFSET_X +/** The Minimum Y position of the Window Layer (Top edge of screen) @see move_win() + */ +#define MINWNDPOSY DEVICE_WINDOW_PX_OFFSET_Y +/** The Maximum X position of the Window Layer (Right edge of screen) @see move_win() + */ +#define MAXWNDPOSX (DEVICE_WINDOW_PX_OFFSET_X + DEVICE_SCREEN_PX_WIDTH - 1) +/** The Maximum Y position of the Window Layer (Bottom edge of screen) @see move_win() + */ +#define MAXWNDPOSY (DEVICE_WINDOW_PX_OFFSET_Y + DEVICE_SCREEN_PX_HEIGHT - 1) + + +/** Interrupt handlers + */ +typedef void (*int_handler)(void) NONBANKED; + +/** The remove functions will remove any interrupt handler. + + A handler of NULL will cause bad things + to happen if the given interrupt is enabled. + + Removes the VBL interrupt handler. @see add_VBL() +*/ +void remove_VBL(int_handler h); + +/** Removes the LCD interrupt handler. + @see add_LCD(), remove_VBL() +*/ +void remove_LCD(int_handler h); + +/** Removes the TIM interrupt handler. + @see add_TIM(), remove_VBL() +*/ +void remove_TIM(int_handler h); + +/** Removes the Serial Link / SIO interrupt handler. + @see add_SIO(), @see remove_VBL() + + The default SIO ISR gets installed automatically if + any of the standard SIO calls are used + (@ref send_byte(), @ref receive_byte()). + + Once installed the default SIO ISR cannot be removed. + Only secondary chained SIO ISRs (added with add_SIO()) + can be removed. +*/ +void remove_SIO(int_handler h); + +/** Removes the JOY interrupt handler. + @see add_JOY(), remove_VBL() +*/ +void remove_JOY(int_handler h); + +/** Adds a Vertical Blanking interrupt handler. + + @param h The handler to be called whenever a V-blank + interrupt occurs. + + Up to 4 handlers may be added, with the last added + being called last. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + Those attributes are only required when constructing + a bare jump from the interrupt vector itself (such as + with @ref ISR_VECTOR()). + + ISR handlers added using add_VBL()/etc are instead + called via the GBDK ISR dispatcher which makes + the extra function attributes unecessary. + + @note The default GBDK VBL is installed automatically. + + @see ISR_VECTOR() +*/ +void add_VBL(int_handler h); + +/** Adds a LCD interrupt handler. + + Called when the LCD interrupt occurs. + + Up to 3 handlers may be added, with the last added + being called last. + + There are various sources controlled by the + @ref STAT_REG register ($FF41) which can trigger + this interrupt. Common examples include triggering + on specific scanlines using @ref LY_REG == @ref LYC_REG. + Another is applying graphics effects on a per-scanline + basis such as modifying the X and Y scroll registers + (@ref SCX_REG / @ref SCY_REG registers). + + @note LYC may not trigger with scanline 0 in the same + way as other scanlines due to particular behavior + with scanlines 153 and 0. Instead, using an add_VBL() + interrupt handler for start of frame behavior may be + more suitable. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + Those attributes are only required when constructing + a bare jump from the interrupt vector itself (such as + with @ref ISR_VECTOR()). + + ISR handlers added using add_VBL/LCD/etc are instead + called via the GBDK ISR dispatcher which makes + the extra function attributes unecessary. + + If this ISR is to be called once per each scanline then + make sure that the time it takes to execute is less + than the duration of a scanline. + + @see add_VBL, nowait_int_handler, ISR_VECTOR() +*/ +void add_LCD(int_handler h); + +/** Adds a timer interrupt handler. + + Can not be used together with @ref add_low_priority_TIM + + This interrupt occurs when the @ref TIMA_REG + register ($FF05) changes from $FF to $00. + + Up to 4 handlers may be added, with the last added + being called last. + + @see add_VBL + @see set_interrupts() with TIM_IFLAG, ISR_VECTOR() +*/ +void add_TIM(int_handler h); + +/** Adds a timer interrupt handler, that could be + interrupted by the other interrupts, + as well as itself, if it runs too slow. + + Can not be used together with @ref add_TIM + + This interrupt occurs when the @ref TIMA_REG + register ($FF05) changes from $FF to $00. + + Up to 4 handlers may be added, with the last added + being called last. + + @see add_VBL + @see set_interrupts() with TIM_IFLAG, ISR_VECTOR() +*/ +void add_low_priority_TIM(int_handler h); + +/** Adds a Serial Link transmit complete interrupt handler. + + This interrupt occurs when a serial transfer has + completed on the game link port. + + Up to 4 handlers may be added, with the last added + being called last. + + The default SIO ISR gets installed automatically if + any of the standard SIO calls are used + (@ref send_byte(), @ref receive_byte()). + + @see send_byte, receive_byte(), add_VBL() + @see set_interrupts() with SIO_IFLAG +*/ +void add_SIO(int_handler h); + + +/** Adds a joypad button change interrupt handler. + + This interrupt occurs on a transition of any of the + keypad input lines from high to low, if the relevant + @ref P1_REG bits 4 or 5 are set. + + For details about configuring flags or reading the data see: + https://gbdev.io/pandocs/Interrupt_Sources.html#int-60--joypad-interrupt + https://gbdev.io/pandocs/Joypad_Input.html#ff00--p1joyp-joypad + + Due to the fact that keypad "bounce" is virtually always + present, software should expect this interrupt to occur + one or more times for every button press and one or more + times for every button release. + + Up to 4 handlers may be added, with the last added + being called last. + + An example use of this is allowing the user to trigger an + exit from the lower-power STOP cpu state. + + @see joypad(), add_VBL(), IEF_HILO, P1F_5, P1F_4, P1F_3, P1F_2, P1F_1, P1F_0, P1F_GET_DPAD, P1F_GET_BTN, P1F_GET_NONE +*/ +void add_JOY(int_handler h); + + +/** Interrupt handler chain terminator that does __not__ wait for .STAT + + You must add this handler last in every interrupt handler + chain if you want to change the default interrupt handler + behaviour that waits for LCD controller mode to become 1 or 0 + before return from the interrupt. + + Example: + \code{.c} + CRITICAL { + add_SIO(nowait_int_handler); // Disable wait on VRAM state before returning from SIO interrupt + } + \endcode + @see wait_int_handler() +*/ +void nowait_int_handler(void); + + +/** Default Interrupt handler chain terminator that waits for + @see STAT_REG and __only__ returns at the BEGINNING of + either Mode 0 or Mode 1. + + Used by default at the end of interrupt chains to help + prevent graphical glitches. The glitches are 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. + + @see nowait_int_handler() +*/ +void wait_int_handler(void); + +/** Cancel pending interrupts + */ +inline uint8_t cancel_pending_interrupts(void) { + return IF_REG = 0; +} + +/** Set the current screen mode - one of M_* modes + + Normally used by internal functions only. + + @see M_DRAWING, M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP +*/ +void mode(uint8_t m); + +/** Returns the current mode + + @see M_DRAWING, M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP +*/ +uint8_t get_mode(void) PRESERVES_REGS(b, c, d, e, h, l); + +/** Returns the system gbdk is running on. + + @see SYSTEM_50HZ, SYSTEM_60HZ, SYSTEM_BITS_DENDY, SYSTEM_BITS_NTSC, SYSTEM_BITS_PAL, SYSTEM_NTSC +SYSTEM_PAL +*/ +inline uint8_t get_system(void) { + return SYSTEM_60HZ; +} + +/** GB CPU type + + @see DMG_TYPE, MGB_TYPE, CGB_TYPE, cpu_fast(), cpu_slow(), _is_GBA +*/ +extern uint8_t _cpu; + +/** Hardware Model: Original GB or Super GB. @see _cpu +*/ +#define DMG_TYPE 0x01 +/** Hardware Model: Pocket GB or Super GB 2. @see _cpu +*/ +#define MGB_TYPE 0xFF +/** Hardware Model: Color GB. @see _cpu +*/ +#define CGB_TYPE 0x11 + +/** GBA detection + + @see GBA_DETECTED, GBA_NOT_DETECTED, _cpu +*/ +extern uint8_t _is_GBA; + +/** Hardware Model: DMG, CGB or MGB. @see _cpu, _is_GBA +*/ +#define GBA_NOT_DETECTED 0x00 +/** Hardware Model: GBA. @see _cpu, _is_GBA +*/ +#define GBA_DETECTED 0x01 + +/** Macro returns TRUE if device supports color + */ +#define DEVICE_SUPPORTS_COLOR (_cpu == CGB_TYPE) + +/** 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; + + + +/** Serial Link: Send the byte in @ref _io_out out through the serial port + + Make sure to enable interrupts for the + Serial Link before trying to transfer data. + @see add_SIO(), remove_SIO() + @see set_interrupts() with @ref SIO_IFLAG +*/ +void send_byte(void); + +/** Serial Link: Receive a byte from the serial port into @ref _io_in + + Make sure to enable interrupts for the + Serial Link before trying to transfer data. + @see add_SIO(), remove_SIO() + @see set_interrupts() with @ref SIO_IFLAG +*/ +void receive_byte(void); + +/** Serial Link: Current IO Status. An OR of IO_* */ +extern volatile uint8_t _io_status; + +/** Serial Link: Byte just read after calling @ref receive_byte() +*/ +extern volatile uint8_t _io_in; + +/** Serial Link: Write byte to send here before calling @ref send_byte() +*/ +extern volatile uint8_t _io_out; + +/* Status codes */ +/** Serial Link IO is completed */ +#define IO_IDLE 0x00U +/** Serial Link Sending data */ +#define IO_SENDING 0x01U +/** Serial Link Receiving data */ +#define IO_RECEIVING 0x02U +/** Serial Link Error */ +#define IO_ERROR 0x04U + + + +/** Tracks current active ROM bank + + In most cases the @ref CURRENT_BANK macro for this variable + is recommended for use instead of the variable itself. + + The active bank number is not tracked by @ref _current_bank when + @ref SWITCH_ROM_MBC5_8M is used. + + This variable is updated automatically when you call SWITCH_ROM_MBC1 or + SWITCH_ROM_MBC5, SWITCH_ROM(), or call a BANKED function. + + @see SWITCH_ROM_MBC1(), SWITCH_ROM_MBC5(), SWITCH_ROM() +*/ +__REG _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 default platform MBC switch the active ROM bank + @param b ROM bank to switch to (max 255) + + \li When used with MBC1 the max bank is Bank 31 (512K). + \li When used with MBC5 the max bank is Bank 255 (4MB). + \li To use the full 8MB size of MBC5 see @ref SWITCH_ROM_MBC5_8M(). + + \li For MBC1 some banks in it's range are unavailable + (typically 0x20, 0x40, 0x60). + + @note Using @ref SWITCH_ROM_MBC5_8M() should not be mixed with using + @ref SWITCH_ROM_MBC5() and @ref SWITCH_ROM(). + + @see SWITCH_ROM_MBC1, SWITCH_ROM_MBC5, SWITCH_ROM_MEGADUCK +*/ +#define SWITCH_ROM(b) (_current_bank = (b), rROMB0 = (b)) + +#if defined(__TARGET_duck) + +#define SWITCH_RAM(b) (0) + +#define ENABLE_RAM + +#define DISABLE_RAM + +#else + +/** Switches SRAM bank on MBC1 and other compatible MBCs + @param b SRAM bank to switch to + + Before switching SRAM banks enable it using @ref ENABLE_RAM + + @see SWITCH_RAM_MBC1, SWITCH_RAM_MBC5 +*/ +#define SWITCH_RAM(b) (rRAMB = (b)) + +/** Enables SRAM on MBC1 and other compatible MBCs +*/ +#define ENABLE_RAM (rRAMG = 0x0A) + +/** Disables SRAM on MBC1 and other compatible MBCs +*/ +#define DISABLE_RAM (rRAMG = 0x00) + +#endif + +/** Makes MEGADUCK MBC switch the active ROM bank + @param b ROM bank to switch to (max `3` for 64K, or `7` for 128K) +*/ +#define SWITCH_ROM_MEGADUCK(b) SWITCH_ROM(b) + +/** Makes MBC1 and other compatible MBCs switch the active ROM bank + @param b ROM bank to switch to + + For MBC1 some banks in it's range are unavailable + (typically 0x20, 0x40, 0x60). + + See pandocs for more details https://gbdev.io/pandocs/MBC1 +*/ +#define SWITCH_ROM_MBC1(b) SWITCH_ROM(b) + +/** Switches SRAM bank on MBC1 and other compatible MBCs + @param b SRAM bank to switch to + + Before switching SRAM banks enable it using @ref ENABLE_RAM + + @see SWITCH_RAM, SWITCH_RAM_MBC5 +*/ +#define SWITCH_RAM_MBC1(b) SWITCH_RAM(b) + +/** Enables SRAM on MBC1 +*/ +#define ENABLE_RAM_MBC1 ENABLE_RAM + +/** Disables SRAM on MBC1 +*/ +#define DISABLE_RAM_MBC1 DISABLE_RAM + +#define SWITCH_16_8_MODE_MBC1 (*(volatile uint8_t *)0x6000 = 0x00) + +#define SWITCH_4_32_MODE_MBC1 (*(volatile uint8_t *)0x6000 = 0x01) + +/** Makes MBC5 switch to the active ROM bank + @param b ROM bank to switch to (max 255) + + Supports up to ROM bank 255 (4 MB). + + @ref SWITCH_ROM_MBC5_8M may be used if the full 8MB size is needed. + + @note Using @ref SWITCH_ROM_MBC5_8M() should not be mixed with using + @ref SWITCH_ROM_MBC5() and @ref SWITCH_ROM(). + + Note the order used here. Writing the other way around on a MBC1 always selects bank 1 +*/ +#define SWITCH_ROM_MBC5(b) (_current_bank = (b), rROMB1 = 0, rROMB0 = (b)) + +/** Makes MBC5 to switch the active ROM bank using the full 8MB size. + @see CURRENT_BANK + @param b ROM bank to switch to + + This is an alternate to @ref SWITCH_ROM_MBC5 which is limited to 4MB. + + Note: + \li Banked SDCC calls are not supported if you use this macro. + \li The active bank number is not tracked by @ref CURRENT_BANK if you use this macro. + \li Using @ref SWITCH_ROM_MBC5_8M() should not be mixed with using @ref SWITCH_ROM_MBC5() and @ref SWITCH_ROM(). + + Note the order used here. Writing the other way around on a MBC1 always selects bank 1 +*/ +#define SWITCH_ROM_MBC5_8M(b) (rROMB1 = ((uint16_t)(b) >> 8), rROMB0 = (b)) + +/** Switches SRAM bank on MBC5 + @param b SRAM bank to switch to + + Before switching SRAM banks enable it using @ref ENABLE_RAM +*/ +#define SWITCH_RAM_MBC5(b) SWITCH_RAM(b) + +/** Enables SRAM on MBC5 +*/ +#define ENABLE_RAM_MBC5 ENABLE_RAM + +/** Disables SRAM on MBC5 +*/ +#define DISABLE_RAM_MBC5 DISABLE_RAM + + + +/** Delays the given number of milliseconds. + Uses no timers or interrupts, and can be called with + interrupts disabled + */ +void delay(uint16_t d) PRESERVES_REGS(h, l); + + + +/** Reads and returns the current state of the joypad. + Follows Nintendo's guidelines for reading the pad. + Return value is an OR of J_* + + When testing for multiple different buttons, it's + best to read the joypad state *once* into a variable + and then test using that variable. + + @see J_START, J_SELECT, J_A, J_B, J_UP, J_DOWN, J_LEFT, J_RIGHT +*/ +uint8_t joypad(void) PRESERVES_REGS(b, c, h, l); + +/** Waits until at least one of the buttons given in mask are pressed. + + @param mask Bitmask indicating which buttons to wait for + + Normally only used for checking one key, but it will + support many, even J_LEFT at the same time as J_RIGHT. :) + + @note Checks in a loop that doesn't HALT at all, so the CPU + will be maxed out until this call returns. + @see joypad + @see J_START, J_SELECT, J_A, J_B, J_UP, J_DOWN, J_LEFT, J_RIGHT +*/ +uint8_t waitpad(uint8_t mask) PRESERVES_REGS(b, c, h, l); + +/** 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(a, b, c, d, e, h, l); + +/** 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 + (for the GB and ones connected via SGB) + @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) OLDCALL; + +/** Polls all avaliable joypads (for the GB and ones connected via SGB) + @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) PRESERVES_REGS(b, c); + + + +/** 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) { + __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) { + __asm__("di"); +} + +/** Clears any pending interrupts and sets the interrupt mask + register IO to flags. + @param flags A logical OR of *_IFLAGS + + @note This disables and then re-enables interrupts so it + must be used outside of a critical section. + + @see enable_interrupts(), disable_interrupts() + @see VBL_IFLAG, LCD_IFLAG, TIM_IFLAG, SIO_IFLAG, JOY_IFLAG +*/ +void set_interrupts(uint8_t flags) PRESERVES_REGS(b, c, d, e, h, l); + +/** Performs a soft reset. + + For the Game Boy and related it does this by jumping to address 0x0150 + which is in crt0.s (the c-runtime that executes before main() is called). + + This performs various startup steps such as resetting the stack, + clearing WRAM and OAM, resetting initialized variables and some + display registers (scroll, window, LCDC), etc. + + This is not the same a hard power reset. +*/ +void reset(void); + +/** HALTs the CPU and waits for the vertical blank interrupt and then + returns when all registered VBL ISRs have completed. + + 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); + +/** 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); + +/** Turns the display off. + + Waits until the VBL before turning the display off. + @see DISPLAY_ON +*/ +void display_off(void) PRESERVES_REGS(b, c, d, e, h, l); + +/** Copies data from shadow OAM to OAM + */ +void refresh_OAM(void) PRESERVES_REGS(b, c, d, e, h, l); + + +/** Copies data from somewhere in the lower address space to part of hi-ram. + @param dst Offset in high ram (0xFF00 and above) to copy to. + @param src Area to copy from + @param n Number of bytes to copy. +*/ +void hiramcpy(uint8_t dst, const void *src, uint8_t n) OLDCALL PRESERVES_REGS(b, c); + + +/** Turns the display back on. + @see display_off, DISPLAY_OFF +*/ +#define DISPLAY_ON \ + LCDC_REG|=LCDCF_ON + +/** Turns the display off + + Waits until the VBL before turning the display off. + @see display_off, DISPLAY_ON +*/ +#define DISPLAY_OFF \ + display_off(); + +/** Does nothing for GB + */ +#define HIDE_LEFT_COLUMN + +/** Does nothing for GB + */ +#define SHOW_LEFT_COLUMN + +/** Does nothing for GB + */ +#define SET_BORDER_COLOR(C) + +/** Turns on the background layer. + Sets bit 0 of the LCDC register to 1. + + Doesn't work in CGB mode - the bit is reused to control sprite priority + over background and window layers instead. + \li If 1 (SHOW_BKG), everything works as usual. + \li If 0 (HIDE_BKG), all sprites are always drawn over background and window, + ignoring any other priority settings. +*/ +#define SHOW_BKG \ + LCDC_REG|=LCDCF_BGON + +/** Turns off the background layer. + Sets bit 0 of the LCDC register to 0. + + Doesn't work in CGB mode - the bit is reused to control sprite priority + over background and window layers instead. + \li If 1 (SHOW_BKG), everything works as usual. + \li If 0 (HIDE_BKG), all sprites are always drawn over background and window, + ignoring any other priority settings. +*/ +#define HIDE_BKG \ + LCDC_REG&=~LCDCF_BGON + +/** Turns on the Window layer + Sets bit 5 of the LCDC register to 1. + + This only controls Window visibility. If either + the Background layer (which the window is part of) + or the Display are not turned then the Window contents + will not be visible. Those can be turned on using + @ref SHOW_BKG and @ref DISPLAY_ON. +*/ +#define SHOW_WIN \ + LCDC_REG|=LCDCF_WINON + +/** Turns off the window layer. + Clears bit 5 of the LCDC register to 0. +*/ +#define HIDE_WIN \ + LCDC_REG&=~LCDCF_WINON + +/** Turns on the sprites layer. + Sets bit 1 of the LCDC register to 1. +*/ +#define SHOW_SPRITES \ + LCDC_REG|=LCDCF_OBJON + +/** Turns off the sprites layer. + Clears bit 1 of the LCDC register to 0. + + @see hide_sprite, hide_sprites_range +*/ +#define HIDE_SPRITES \ + LCDC_REG&=~LCDCF_OBJON + +/** Sets sprite size to 8x16 pixels, two tiles one above the other. + Sets bit 2 of the LCDC register to 1. +*/ +#define SPRITES_8x16 \ + LCDC_REG|=LCDCF_OBJ16 + +/** Sets sprite size to 8x8 pixels, one tile. + Clears bit 2 of the LCDC register to 0. +*/ +#define SPRITES_8x8 \ + LCDC_REG&=~LCDCF_OBJ16 + + + +/** + * 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) PRESERVES_REGS(b, c); + +/** + * Get byte from vram at given memory location + * @param addr address to read from + * @return read value + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + */ +uint8_t get_vram_byte(uint8_t * addr) PRESERVES_REGS(b, c, h, l); + + +/** + * Get address of X,Y tile of background map + */ +uint8_t * get_bkg_xy_addr(uint8_t x, uint8_t y) OLDCALL PRESERVES_REGS(b, c); + +#define COMPAT_PALETTE(C0,C1,C2,C3) ((uint8_t)(((C3) << 6) | ((C2) << 4) | ((C1) << 2) | (C0))) + +/** Sets palette for 2bpp color translation for GG/SMS, does nothing on GB + */ +inline void set_2bpp_palette(uint16_t palette) { + palette; +} + +extern uint16_t _current_1bpp_colors; + +/** Sets the Foreground and Background colors used by the set_*_1bpp_*() functions + @param fgcolor Foreground color + @param bgcolor Background color + @param mode Draw Mode + + See @ref set_1bpp_colors for details. +*/ +void set_1bpp_colors_ex(uint8_t fgcolor, uint8_t bgcolor, uint8_t mode) OLDCALL; + +/** Sets the Foreground and Background colors used by the set_*_1bpp_*() functions + @param fgcolor Foreground color to use + @param bgcolor Background color to use + + The default colors are: + \li Foreground: DMG_BLACK + \li Background: DMG_WHITE + + Example: + \code{.c} + // Use DMG_BLACK as the Foreground color and DMG_LITE_GRAY + // as the Background color when loading 1bpp tile data. + set_1bpp_colors(DMG_BLACK, DMG_LITE_GRAY); + \endcode + + + @see DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE + @see set_bkg_1bpp_data, set_win_1bpp_data, set_sprite_1bpp_data +*/ +inline void set_1bpp_colors(uint8_t fgcolor, uint8_t bgcolor) { + set_1bpp_colors_ex(fgcolor, bgcolor, 0); +} + +/** Sets VRAM Tile Pattern data for the Background / Window + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (2 bpp) source tile data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. Each Tile is 16 bytes in size (8x8 pixels, 2 bits-per-pixel). + + @note Sprite Tiles 128-255 share the same memory region as Background Tiles 128-255. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second + + @see set_win_data, set_tile_data +*/ +void set_bkg_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); +#define set_bkg_2bpp_data set_bkg_data + +/** Sets VRAM Tile Pattern data for the Background / Window using 1bpp source data + + @param first_tile Index of the first Tile to write + @param nb_tiles Number of Tiles to write + @param data Pointer to (1bpp) source Tile Pattern data + + Similar to @ref set_bkg_data, except source data is 1 bit-per-pixel + which gets expanded into 2 bits-per-pixel. + + For a given bit that represent a pixel: + \li 0 will be expanded into the Background color + \li 1 will be expanded into the Foreground color + + See @ref set_1bpp_colors for details about setting the Foreground and Background colors. + + @see SHOW_BKG, HIDE_BKG, set_bkg_tiles + @see set_win_1bpp_data, set_sprite_1bpp_data +*/ +void set_bkg_1bpp_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + +/** Copies from Background / Window VRAM Tile Pattern data into a buffer + + @param first_tile Index of the first Tile to read from + @param nb_tiles Number of Tiles to read + @param data Pointer to destination buffer for Tile Pattern data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Copies __nb_tiles__ tiles from VRAM starting at __first_tile__, Tile data + is copied into __data__. + + Each Tile is 16 bytes, so the buffer pointed to by __data__ + should be at least __nb_tiles__ x 16 bytes in size. + + @see get_win_data, get_data +*/ +void get_bkg_data(uint8_t first_tile, uint8_t nb_tiles, uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + + +/** Sets a rectangular region of Background Tile Map. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map data + + Entries are copied from map at __tiles__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + Use @ref set_bkg_submap() instead when: + \li Source map is wider than 32 tiles. + \li Writing a width that does not match the source map width __and__ more + than one row high at a time. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + @note Patterns 128-255 overlap with patterns 128-255 of the sprite Tile Pattern table. + + GBC only: @ref VBK_REG determines whether Tile Numbers or Tile Attributes get set. + \li VBK_REG = @ref VBK_TILES Tile Numbers are written + \li VBK_REG = @ref VBK_ATTRIBUTES Tile Attributes are written + + GBC Tile Attributes are defined as: + \li Bit 7 - Priority flag. When this is set, it puts the tile above the sprites + with colour 0 being transparent. + \n 0: Below sprites + \n 1: Above sprites + \n Note: @ref SHOW_BKG needs to be set for these priorities to take place. + \li Bit 6 - Vertical flip. Dictates which way up the tile is drawn vertically. + \n 0: Normal + \n 1: Flipped Vertically + \li Bit 5 - Horizontal flip. Dictates which way up the tile is drawn horizontally. + \n 0: Normal + \n 1: Flipped Horizontally + \li Bit 4 - Not used + \li Bit 3 - Character Bank specification. Dictates from which bank of + Background Tile Patterns the tile is taken. + \n 0: Bank 0 + \n 1: Bank 1 + \li Bit 2 - See bit 0. + \li Bit 1 - See bit 0. + \li Bit 0 - Bits 0-2 indicate which of the 7 BKG colour palettes the tile is + assigned. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_submap, set_win_tiles, set_tiles +*/ +void set_bkg_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) OLDCALL PRESERVES_REGS(b, c); +#define set_tile_map set_bkg_tiles + + +extern uint8_t _map_tile_offset; + +/** Sets a rectangular region of Background Tile Map. + The offset value in __base_tile__ is added to + the tile ID for each map entry. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map data + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_bkg_tiles() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_bkg_tiles for more details +*/ +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_bkg_tiles(x, y, w, h, tiles); + _map_tile_offset = 0; +} + + +/** Sets a rectangular region of Background Tile Map Attributes. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map attribute data + + Entries are copied from map at __tiles__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + Use @ref set_bkg_submap_attributes() instead when: + \li Source map is wider than 32 tiles. + \li Writing a width that does not match the source map width __and__ more + than one row high at a time. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + GBC Tile Attributes are defined as: + \li Bit 7 - Priority flag. When this is set, it puts the tile above the sprites + with colour 0 being transparent. + \n 0: Below sprites + \n 1: Above sprites + \n Note: @ref SHOW_BKG needs to be set for these priorities to take place. + \li Bit 6 - Vertical flip. Dictates which way up the tile is drawn vertically. + \n 0: Normal + \n 1: Flipped Vertically + \li Bit 5 - Horizontal flip. Dictates which way up the tile is drawn horizontally. + \n 0: Normal + \n 1: Flipped Horizontally + \li Bit 4 - Not used + \li Bit 3 - Character Bank specification. Dictates from which bank of + Background Tile Patterns the tile is taken. + \n 0: Bank 0 + \n 1: Bank 1 + \li Bit 2 - See bit 0. + \li Bit 1 - See bit 0. + \li Bit 0 - Bits 0-2 indicate which of the 7 BKG colour palettes the tile is + assigned. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_submap_attributes, set_win_tiles, set_tiles + + @note On the Game Boy this is only usable in Game Boy Color mode +*/ +inline void set_bkg_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) +{ + VBK_REG = VBK_ATTRIBUTES; + set_bkg_tiles(x, y, w, h, tiles); + VBK_REG = VBK_TILES; +} + + +/** Sets a rectangular area of the Background Tile Map using a sub-region + from a source tile map. Useful for scrolling implementations of maps + larger than 32 x 32 tiles. + + @param x X Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param y Y Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 255 + + Entries are copied from __map__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles, + using __map_w__ as the rowstride for the source tile map. + + The __x__ and __y__ parameters are in Source Tile Map tile + coordinates. The location tiles will be written to on the + hardware Background Map is derived from those, but only uses + the lower 5 bits of each axis, for range of 0-31 (they are + bit-masked: `x & 0x1F` and `y & 0x1F`). As a result the two + coordinate systems are aligned together. + + In order to transfer tile map data in a way where the + coordinate systems are not aligned, an offset from the + Source Tile Map pointer can be passed in: + `(map_ptr + x + (y * map_width))`. + + For example, if you want the tile id at `1,2` from the source map to + show up at `0,0` on the hardware Background Map (instead of at `1,2`) + then modify the pointer address that is passed in: + `map_ptr + 1 + (2 * map_width)` + + Use this instead of @ref set_bkg_tiles when the source map is wider than + 32 tiles or when writing a width that does not match the source map width. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + See @ref set_bkg_tiles for setting CGB attribute maps with @ref VBK_REG. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_tiles, set_win_submap, set_tiles +*/ +void set_bkg_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) OLDCALL; +#define set_tile_submap set_bkg_submap + + +extern uint8_t _submap_tile_offset; + +/** Sets a rectangular area of the Background Tile Map using a sub-region + from a source tile map. The offset value in __base_tile__ is added to + the tile ID for each map entry. + + @param x X Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param y Y Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 255 + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_bkg_submap() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_bkg_submap for more details +*/ +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_bkg_submap(x, y, w, h, map, map_w); + _submap_tile_offset = 0; +} + + +/** Sets a rectangular area of the Background Tile Map Attributes using a sub-region + from a source tile attribute map. Useful for scrolling implementations of maps + larger than 32 x 32 tiles. + + @param x X Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param y Y Start position in both the Source Tile Map and hardware Background Map tile coordinates. Range 0 - 255 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map attribute data + @param map_w Width of source tile map in tiles. Range 1 - 255 + + Entries are copied from __map__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles, + using __map_w__ as the rowstride for the source tile map. + + The __x__ and __y__ parameters are in Source Tile Map tile + coordinates. The location tiles will be written to on the + hardware Background Map is derived from those, but only uses + the lower 5 bits of each axis, for range of 0-31 (they are + bit-masked: `x & 0x1F` and `y & 0x1F`). As a result the two + coordinate systems are aligned together. + + In order to transfer tile map data in a way where the + coordinate systems are not aligned, an offset from the + Source Tile Map pointer can be passed in: + `(map_ptr + x + (y * map_width))`. + + For example, if you want the tile id at `1,2` from the source map to + show up at `0,0` on the hardware Background Map (instead of at `1,2`) + then modify the pointer address that is passed in: + `map_ptr + 1 + (2 * map_width)` + + Use this instead of @ref set_bkg_tiles when the source map is wider than + 32 tiles or when writing a width that does not match the source map width. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + See @ref set_bkg_tiles for setting CGB attribute maps with @ref VBK_REG. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_attributes, set_win_submap, set_tiles + + @note On the Game Boy this is only usable in Game Boy Color mode +*/ +inline void set_bkg_submap_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) +{ + VBK_REG = VBK_ATTRIBUTES; + set_bkg_submap(x, y, w, h, map, map_w); + VBK_REG = VBK_TILES; +} + + +/** Copies a rectangular region of Background Tile Map entries into a buffer. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to copy in tiles. Range 0 - 31 + @param h Height of area to copy in tiles. Range 0 - 31 + @param tiles Pointer to destination buffer for Tile Map data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Entries are copied into __tiles__ from the Background Tile Map starting at + __x__, __y__ reading across for __w__ tiles and down for __h__ tiles. + + One byte per tile. + + The buffer pointed to by __tiles__ should be at least __x__ x __y__ bytes in size. + + @see get_win_tiles, get_bkg_tile_xy, get_tiles, get_vram_byte +*/ +void get_bkg_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *tiles) OLDCALL PRESERVES_REGS(b, c); + + +/** 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_bkg_tile_xy(uint8_t x, uint8_t y, uint8_t t); +#define set_tile_xy set_bkg_tile_xy + +/** Set single attribute data a on background layer at x,y + @param x X-coordinate + @param y Y-coordinate + @param a tile attributes + @return returns the address of tile attribute, so you may use faster set_vram_byte() later + + @note On the Game Boy this is only usable in Game Boy Color mode +*/ +inline uint8_t * set_bkg_attribute_xy(uint8_t x, uint8_t y, uint8_t a) +{ + uint8_t* addr; + VBK_REG = VBK_ATTRIBUTES; + addr = set_bkg_tile_xy(x, y, a); + VBK_REG = VBK_TILES; + return addr; +} +#define set_attribute_xy set_bkg_attribute_xy + +/** + Get single tile t on background layer at x,y + @param x X-coordinate + @param y Y-coordinate + + @return returns tile index + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + +*/ +uint8_t get_bkg_tile_xy(uint8_t x, uint8_t y) OLDCALL PRESERVES_REGS(b, c); + + +/** Moves the Background Layer to the position specified in __x__ and __y__ in pixels. + + @param x X axis screen coordinate for Left edge of the Background + @param y Y axis screen coordinate for Top edge of the Background + + 0,0 is the top left corner of the GB screen. The Background Layer wraps around the screen, + so when part of it goes off the screen it appears on the opposite side (factoring in the + larger size of the Background Layer versus the screen size). + + The background layer is always under the Window Layer. + + @see SHOW_BKG, HIDE_BKG +*/ +inline void move_bkg(uint8_t x, uint8_t y) { + SCX_REG=x, SCY_REG=y; +} + + +/** Moves the Background relative to it's current position. + + @param x Number of pixels to move the Background on the __X axis__ + \n Range: -128 - 127 + @param y Number of pixels to move the Background on the __Y axis__ + \n Range: -128 - 127 + + @see move_bkg +*/ +inline void scroll_bkg(int8_t x, int8_t y) { + SCX_REG+=x, SCY_REG+=y; +} + + + +/** + * Get address of X,Y tile of window map + */ +uint8_t * get_win_xy_addr(uint8_t x, uint8_t y) OLDCALL PRESERVES_REGS(b, c); + +/** Sets VRAM Tile Pattern data for the Window / Background + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (2 bpp) source Tile Pattern data. + + This is the same as @ref set_bkg_data, since the Window Layer and + Background Layer share the same Tile pattern data. + + @see set_bkg_data + @see set_win_tiles, set_bkg_data, set_data + @see SHOW_WIN, HIDE_WIN +*/ +void set_win_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + + +/** Sets VRAM Tile Pattern data for the Window / Background using 1bpp source data + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (1bpp) source Tile Pattern data + + This is the same as @ref set_bkg_1bpp_data, since the Window Layer and + Background Layer share the same Tile pattern data. + + For a given bit that represent a pixel: + \li 0 will be expanded into the Background color + \li 1 will be expanded into the Foreground color + + See @ref set_1bpp_colors for details about setting the Foreground and Background colors. + + @see set_bkg_data, set_win_data, set_1bpp_colors + @see set_bkg_1bpp_data, set_sprite_1bpp_data +*/ +void set_win_1bpp_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + + +/** Copies from Window / Background VRAM Tile Pattern data into a buffer + + @param first_tile Index of the first Tile to read from + @param nb_tiles Number of Tiles to read + @param data Pointer to destination buffer for Tile Pattern Data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + This is the same as @ref get_bkg_data, since the Window Layer and + Background Layer share the same Tile pattern data. + + @see get_bkg_data, get_data +*/ +void get_win_data(uint8_t first_tile, uint8_t nb_tiles, uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + + +/** Sets a rectangular region of the Window Tile Map. + + @param x X Start position in Window Map tile coordinates. Range 0 - 31 + @param y Y Start position in Window Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map data + + Entries are copied from map at __tiles__ to the Window Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + Use @ref set_win_submap() instead when: + \li Source map is wider than 32 tiles. + \li Writing a width that does not match the source map width __and__ more + than one row high at a time. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + @note Patterns 128-255 overlap with patterns 128-255 of the sprite Tile Pattern table. + + GBC only: @ref VBK_REG determines whether Tile Numbers or Tile Attributes get set. + \li VBK_REG = @ref VBK_TILES Tile Numbers are written + \li VBK_REG = @ref VBK_ATTRIBUTES Tile Attributes are written + + For more details about GBC Tile Attributes see @ref set_bkg_tiles. + + @see SHOW_WIN, HIDE_WIN, set_win_submap, set_bkg_tiles, set_bkg_data, set_tiles +*/ +void set_win_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) OLDCALL PRESERVES_REGS(b, c); + + +/** Sets a rectangular region of the Window Tile Map. + The offset value in __base_tile__ is added to + the tile ID for each map entry. + + @param x X Start position in Window Map tile coordinates. Range 0 - 31 + @param y Y Start position in Window Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map data + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_win_tiles() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_win_tiles for more details +*/ +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_win_tiles(x, y, w, h, tiles); + _map_tile_offset = 0; +} + +/** Sets a rectangular area of the Window Tile Map using a sub-region + from a source tile map. + + @param x X Start position in both the Source Tile Map and hardware Window Map tile coordinates. Range 0 - 255 + @param y Y Start position in both the Source Tile Map and hardware Window Map tile coordinates. Range 0 - 255 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 255 + + Entries are copied from __map__ to the Window Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles, + using __map_w__ as the rowstride for the source tile map. + + The __x__ and __y__ parameters are in Source Tile Map tile + coordinates. The location tiles will be written to on the + hardware Background Map is derived from those, but only uses + the lower 5 bits of each axis, for range of 0-31 (they are + bit-masked: `x & 0x1F` and `y & 0x1F`). As a result the two + coordinate systems are aligned together. + + In order to transfer tile map data in a way where the + coordinate systems are not aligned, an offset from the + Source Tile Map pointer can be passed in: + `(map_ptr + x + (y * map_width))`. + + For example, if you want the tile id at `1,2` from the source map to + show up at `0,0` on the hardware Background Map (instead of at `1,2`) + then modify the pointer address that is passed in: + `map_ptr + 1 + (2 * map_width)` + + Use this instead of @ref set_win_tiles when the source map is wider than + 32 tiles or when writing a width that does not match the source map width. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + GBC only: @ref VBK_REG determines whether Tile Numbers or Tile Attributes get set. + \li VBK_REG = @ref VBK_TILES Tile Numbers are written + \li VBK_REG = @ref VBK_ATTRIBUTES Tile Attributes are written + + See @ref set_bkg_tiles for details about CGB attribute maps with @ref VBK_REG. + + @see SHOW_WIN, HIDE_WIN, set_win_tiles, set_bkg_submap, set_bkg_tiles, set_bkg_data, set_tiles +**/ +void set_win_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) OLDCALL; + + +/** Sets a rectangular area of the Window Tile Map using a sub-region + from a source tile map. The offset value in __base_tile__ is added + to the tile ID for each map entry. + + @param x X Start position in both the Source Tile Map and hardware Window Map tile coordinates. Range 0 - 255 + @param y Y Start position in both the Source Tile Map and hardware Window Map tile coordinates. Range 0 - 255 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 255 + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_win_submap() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_win_submap for more details +**/ +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_win_submap(x, y, w, h, map, map_w); + _submap_tile_offset = 0; +} + + +/** Copies a rectangular region of Window Tile Map entries into a buffer. + + @param x X Start position in Window Map tile coordinates. Range 0 - 31 + @param y Y Start position in Window Map tile coordinates. Range 0 - 31 + @param w Width of area to copy in tiles. Range 0 - 31 + @param h Height of area to copy in tiles. Range 0 - 31 + @param tiles Pointer to destination buffer for Tile Map data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Entries are copied into __tiles__ from the Window Tile Map starting at + __x__, __y__ reading across for __w__ tiles and down for __h__ tiles. + + One byte per tile. + + The buffer pointed to by __tiles__ should be at least __x__ x __y__ bytes in size. + + @see get_bkg_tiles, get_bkg_tile_xy, get_tiles, get_vram_byte +*/ +void get_win_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *tiles) OLDCALL PRESERVES_REGS(b, c); + + +/** + * Set single tile t on window 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_win_tile_xy(uint8_t x, uint8_t y, uint8_t t); + + +/** + * Get single tile t on window layer at x,y + * @param x X-coordinate + * @param y Y-coordinate + * @return returns the tile index + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. +*/ +uint8_t get_win_tile_xy(uint8_t x, uint8_t y) OLDCALL PRESERVES_REGS(b, c); + + +/** Moves the Window to the __x__, __y__ position on the screen. + + @param x X coordinate for Left edge of the Window (actual displayed location will be X - 7) + @param y Y coordinate for Top edge of the Window + + 7,0 is the top left corner of the screen in Window coordinates. The Window is locked to the bottom right corner. + + The Window is always over the Background layer. + + @see SHOW_WIN, HIDE_WIN +*/ +inline void move_win(uint8_t x, uint8_t y) { + WX_REG=x, WY_REG=y; +} + + +/** Move the Window relative to its current position. + + @param x Number of pixels to move the window on the __X axis__ + \n Range: -128 - 127 + @param y Number of pixels to move the window on the __Y axis__ + \n Range: -128 - 127 + + @see move_win +*/ +inline void scroll_win(int8_t x, int8_t y) { + WX_REG+=x, WY_REG+=y; +} + + + +/** Sets VRAM Tile Pattern data for Sprites + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (2 bpp) source Tile Pattern data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. Each Tile is 16 bytes in size (8x8 pixels, 2 bits-per-pixel). + + @note Sprite Tiles 128-255 share the same memory region as Background Tiles 128-255. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second +*/ +void set_sprite_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); +#define set_sprite_2bpp_data set_sprite_data + +/** Sets VRAM Tile Pattern data for Sprites using 1bpp source data + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (1bpp) source Tile Pattern data + + Similar to @ref set_sprite_data, except source data is 1 bit-per-pixel + which gets expanded into 2 bits-per-pixel. + + For a given bit that represent a pixel: + \li 0 will be expanded into the Background color + \li 1 will be expanded into the Foreground color + + See @ref set_1bpp_colors for details about setting the Foreground and Background colors. + + @see SHOW_SPRITES, HIDE_SPRITES, set_sprite_tile + @see set_bkg_1bpp_data, set_win_1bpp_data +*/ +void set_sprite_1bpp_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + +/** Copies from Sprite VRAM Tile Pattern data into a buffer + + @param first_tile Index of the first tile to read from + @param nb_tiles Number of tiles to read + @param data Pointer to destination buffer for Tile Pattern data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Copies __nb_tiles__ tiles from VRAM starting at __first_tile__, tile data + is copied into __data__. + + Each Tile is 16 bytes, so the buffer pointed to by __data__ + should be at least __nb_tiles__ x 16 bytes in size. +*/ +void get_sprite_data(uint8_t first_tile, uint8_t nb_tiles, uint8_t *data) OLDCALL PRESERVES_REGS(b, c); + + +/** 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 DMA copying routine +*/ +__REG _shadow_OAM_base; + +#define DISABLE_OAM_DMA \ + _shadow_OAM_base = 0 + +/** Disable OAM DMA copy each VBlank +*/ +#define DISABLE_VBL_TRANSFER DISABLE_OAM_DMA + +#define ENABLE_OAM_DMA \ + _shadow_OAM_base = (uint8_t)((uint16_t)&shadow_OAM >> 8) + +/** Enable OAM DMA copy each VBlank and set it to transfer default shadow_OAM array +*/ +#define ENABLE_VBL_TRANSFER ENABLE_OAM_DMA + +/** Amount of hardware sprites in OAM +*/ +#define MAX_HARDWARE_SPRITES 40 + +/** True if sprite hardware can flip sprites by X (horizontally) +*/ +#define HARDWARE_SPRITE_CAN_FLIP_X 1 + +/** True if sprite hardware can flip sprites by Y (vertically) +*/ +#define HARDWARE_SPRITE_CAN_FLIP_Y 1 + +/** Enable OAM DMA copy each VBlank and set it to transfer any 256-byte aligned array +*/ +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; +} + + +/** Sets the OAM Property Flags of sprite number __nb__ to those defined in __prop__. + + @param nb Sprite number, range 0 - 39 + @param prop Property setting (see bitfield description) + + The bits in __prop__ represent: + \li Bit 7 - Priority flag. When this is set the sprites appear behind the + background and window layer. + \n 0: infront + \n 1: behind + \li Bit 6 - Vertical flip. Dictates which way up the sprite is drawn + vertically. + \n 0: normal + \n 1:upside down + \li Bit 5 - Horizontal flip. Dictates which way up the sprite is + drawn horizontally. + \n 0: normal + \n 1:back to front + \li Bit 4 - DMG/Non-CGB Mode Only. Assigns either one of the two b/w palettes to the sprite. + \n 0: OBJ palette 0 + \n 1: OBJ palette 1 + \li Bit 3 - GBC only. Dictates from which bank of Sprite Tile Patterns the tile + is taken. + \n 0: Bank 0 + \n 1: Bank 1 + \li Bit 2 - See bit 0. + \li Bit 1 - See bit 0. + \li Bit 0 - GBC only. Bits 0-2 indicate which of the 7 OBJ colour palettes the + sprite is assigned. + + It's recommended to use GBDK constants (eg: S_FLIPY) to configure sprite properties as these are crossplatform. + + \code{.c} + // Load palette data into the first palette + set_sprite_palette(4, 1, exampleSprite_palettes) + + // Set the OAM value for the sprite + // These flags tell the sprite to flip both vertically and horizontally. + set_sprite_prop(0, S_FLIPY | S_FLIPX); + \endcode + + @see S_PALETTE, S_FLIPX, S_FLIPY, S_PRIORITY +*/ +inline void set_sprite_prop(uint8_t nb, uint8_t prop) { + shadow_OAM[nb].prop=prop; +} + + +/** Returns the OAM Property Flags of sprite number __nb__. + + @param nb Sprite number, range 0 - 39 + @see set_sprite_prop for property bitfield settings +*/ +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 + + @see hide_sprites_range, HIDE_SPRITES + */ +inline void hide_sprite(uint8_t nb) { + shadow_OAM[nb].y = 0; +} + + + +/** Copies arbitrary data to an address in VRAM + without taking into account the state of LCDC bits 3 or 4. + + @param vram_addr Pointer to destination VRAM Address + @param data Pointer to source buffer + @param len Number of bytes to copy + + Copies __len__ bytes from a buffer at __data__ to VRAM starting at __vram_addr__. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second + + @see set_bkg_data, set_win_data, set_bkg_tiles, set_win_tiles, set_tile_data, set_tiles +*/ +void set_data(uint8_t *vram_addr, const uint8_t *data, uint16_t len); + + +/** Copies arbitrary data from an address in VRAM into a buffer + without taking into account the state of LCDC bits 3 or 4. + + @param vram_addr Pointer to source VRAM Address + @param data Pointer to destination buffer + @param len Number of bytes to copy + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Copies __len__ bytes from VRAM starting at __vram_addr__ into a buffer at __data__. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second + + @see get_bkg_data, get_win_data, get_bkg_tiles, get_win_tiles, get_tiles +*/ +void get_data(uint8_t *data, uint8_t *vram_addr, uint16_t len); + +/** Copies arbitrary data from an address in VRAM into a buffer + + @param dest Pointer to destination buffer (may be in VRAM) + @param sour Pointer to source buffer (may be in VRAM) + @param len Number of bytes to copy + + Copies __len__ bytes from or to VRAM starting at __sour__ into a buffer or to VRAM at __dest__. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second +*/ +void vmemcpy(uint8_t *dest, uint8_t *sour, uint16_t len); + + + +/** Sets a rectangular region of Tile Map entries at a given VRAM Address + without taking into account the state of LCDC bit 3. + + @param x X Start position in Map tile coordinates. Range 0 - 31 + @param y Y Start position in Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param vram_addr Pointer to destination VRAM Address + @param tiles Pointer to source Tile Map data + + Entries are copied from __tiles__ to Tile Map at address vram_addr starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + One byte per source tile map entry. + + There are two 32x32 Tile Maps in VRAM at addresses 9800h-9BFFh and 9C00h-9FFFh. + + GBC only: @ref VBK_REG determines whether Tile Numbers or Tile Attributes get set. + \li VBK_REG = @ref VBK_TILES Tile Numbers are written + \li VBK_REG = @ref VBK_ATTRIBUTES Tile Attributes are written + + @see set_bkg_tiles, set_win_tiles +*/ +void set_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *vram_addr, const uint8_t *tiles) OLDCALL; + +/** Sets VRAM Tile Pattern data starting from given base address + without taking into account the state of LCDC bit 4. + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to (2 bpp) source Tile Pattern data. + @param base MSB of the destination address in VRAM (usually 0x80 or 0x90 which gives 0x8000 or 0x9000) + + @see set_bkg_data, set_win_data, set_data +*/ +void set_tile_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data, uint8_t base) OLDCALL PRESERVES_REGS(b, c); + +/** Copies a rectangular region of Tile Map entries from a given VRAM Address into a buffer + without taking into account the state of LCDC bit 3. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to copy in tiles. Range 0 - 31 + @param h Height of area to copy in tiles. Range 0 - 31 + @param vram_addr Pointer to source VRAM Address + @param tiles Pointer to destination buffer for Tile Map data + + @note In general **avoid reading from VRAM** + since that memory is not accessible at all times. + It is also not supported by GBDK on the NES platform. + See @ref best_practice_dont_read_vram "coding guidelines" + for more details. + + Entries are copied into __tiles__ from the Background Tile Map starting at + __x__, __y__ reading across for __w__ tiles and down for __h__ tiles. + + One byte per tile. + + There are two 32x32 Tile Maps in VRAM at addresses 9800h - 9BFFh and 9C00h - 9FFFh. + + The buffer pointed to by __tiles__ should be at least __x__ x __y__ bytes in size. + + @see get_bkg_tiles, get_win_tiles +*/ +void get_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *vram_addr, uint8_t *tiles) OLDCALL; + + +/** Sets VRAM Tile Pattern data in the native format + + @param first_tile Index of the first tile to write (0 - 511) + @param nb_tiles Number of tiles to write + @param data Pointer to source Tile Pattern data. + + When `first_tile` is larger than 256 on the GB/AP, it + will write to sprite data instead of background data. + + The bit depth of the source Tile Pattern data depends + on which console is being used: + \li Game Boy/Analogue Pocket: loads 2bpp tiles data + \li SMS/GG: loads 4bpp tile data + */ +inline void set_native_tile_data(uint16_t first_tile, uint8_t nb_tiles, const uint8_t *data) { + if (first_tile < 256) { + set_bkg_data(first_tile, nb_tiles, data); + } else { + set_sprite_data(first_tile - 256, nb_tiles, data); + } +} + +/** Sets VRAM Tile Pattern data for the Background / Window in the native format + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to source tile data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second + + @see set_win_data, set_tile_data +*/ +inline void set_bkg_native_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) { + set_bkg_data(first_tile, nb_tiles, data); +} + +/** Sets VRAM Tile Pattern data for Sprites in the native format + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to source tile data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG = @ref VBK_BANK_0 indicates the first bank + \li VBK_REG = @ref VBK_BANK_1 indicates the second +*/ +inline void set_sprite_native_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) { + set_sprite_data(first_tile, nb_tiles, data); +} + +/** Initializes the entire Window Tile Map with Tile Number __c__ + @param c Tile number to fill with + + @note This function avoids writes during modes 2 & 3 +*/ +void init_win(uint8_t c) OLDCALL PRESERVES_REGS(b, c); + +/** Initializes the entire Background Tile Map with Tile Number __c__ + @param c Tile number to fill with + + @note This function avoids writes during modes 2 & 3 +*/ +void init_bkg(uint8_t c) OLDCALL PRESERVES_REGS(b, c); + +/** Fills the VRAM memory region __s__ of size __n__ with Tile Number __c__ + @param s Start address in VRAM + @param c Tile number to fill with + @param n Size of memory region (in bytes) to fill + + @note This function avoids writes during modes 2 & 3 +*/ +void vmemset (void *s, uint8_t c, size_t n) OLDCALL PRESERVES_REGS(b, c); + + + +/** Fills a rectangular region of Tile Map entries for the Background layer with tile. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 0 - 31 + @param h Height of area to set in tiles. Range 0 - 31 + @param tile Fill value +*/ +void fill_bkg_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tile) OLDCALL PRESERVES_REGS(b, c); +#define fill_rect fill_bkg_rect + +/** Fills a rectangular region of Tile Map entries for the Window layer with tile. + + @param x X Start position in Window Map tile coordinates. Range 0 - 31 + @param y Y Start position in Window Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 0 - 31 + @param h Height of area to set in tiles. Range 0 - 31 + @param tile Fill value +*/ +void fill_win_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tile) OLDCALL PRESERVES_REGS(b, c); + +#endif /* _GB_H */ diff --git a/ext/include/gb/gbdecompress.h b/ext/include/gb/gbdecompress.h new file mode 100644 index 0000000..c84c298 --- /dev/null +++ b/ext/include/gb/gbdecompress.h @@ -0,0 +1,82 @@ +/** @file gb/gbdecompress.h + + GB-Compress decompressor + Compatible with the compression used in GBTD + @see utility_gbcompress "gbcompress" +*/ + +#ifndef __GBDECOMPRESS_H_INCLUDE +#define __GBDECOMPRESS_H_INCLUDE + +#include +#include + +/** gb-decompress data from sour into dest + + @param sour Pointer to source gb-compressed data + @param dest Pointer to destination buffer/address + + Will decompress __all__ of it's data to destination without + stopping until the end of compressed data is reached. It is + not possible to set a limit, so ensure the destination buffer + has sufficient space to avoid an overflow. + + @see gb_decompress_bkg_data, gb_decompress_win_data, gb_decompress_sprite_data, rle_decompress + */ +uint16_t gb_decompress(const uint8_t * sour, uint8_t * dest); + + +/** gb-decompress background tiles into VRAM + + @param first_tile Index of the first tile to write + @param sour Pointer to (gb-compressed 2 bpp) source Tile Pattern data. + + Note: This function avoids writes during modes 2 & 3 + + Will decompress __all__ of it's data to destination without + stopping until the end of compressed data is reached. It is + not possible to set a limit, so ensure the destination buffer + has sufficient space to avoid an overflow. + + @see gb_decompress_bkg_data, gb_decompress_win_data, gb_decompress_sprite_data +*/ +void gb_decompress_bkg_data(uint8_t first_tile, const uint8_t * sour); + + +/** gb-decompress window tiles into VRAM + + @param first_tile Index of the first tile to write + @param sour Pointer to (gb-compressed 2 bpp) source Tile Pattern data. + + This is the same as @ref gb_decompress_bkg_data, since the Window Layer and + Background Layer share the same Tile pattern data. + + Note: This function avoids writes during modes 2 & 3 + + Will decompress __all__ of it's data to destination without + stopping until the end of compressed data is reached. It is + not possible to set a limit, so ensure the destination buffer + has sufficient space to avoid an overflow. + + @see gb_decompress, gb_decompress_bkg_data, gb_decompress_sprite_data + */ +void gb_decompress_win_data(uint8_t first_tile, const uint8_t * sour); + + +/** gb-decompress sprite tiles into VRAM + + @param first_tile Index of the first tile to write + @param sour Pointer to source compressed data + + Note: This function avoids writes during modes 2 & 3 + + Will decompress __all__ of it's data to destination without + stopping until the end of compressed data is reached. It is + not possible to set a limit, so ensure the destination buffer + has sufficient space to avoid an overflow. + + @see gb_decompress, gb_decompress_bkg_data, gb_decompress_win_data + */ +void gb_decompress_sprite_data(uint8_t first_tile, const uint8_t * sour); + +#endif \ No newline at end of file diff --git a/ext/include/gb/hardware.h b/ext/include/gb/hardware.h new file mode 100644 index 0000000..8627b29 --- /dev/null +++ b/ext/include/gb/hardware.h @@ -0,0 +1,448 @@ +/** @file gb/hardware.h + Defines that let the GB's hardware registers be accessed + from C. + + See the @ref Pandocs for more details on each register. +*/ +#ifndef _HARDWARE_H +#define _HARDWARE_H + +#include + +#define __BYTES extern UBYTE +#define __BYTE_REG extern volatile UBYTE +#define __REG extern volatile SFR + +/** Memory map */ + +__BYTES _VRAM[]; +__BYTES _VRAM8000[]; +__BYTES _VRAM8800[]; +__BYTES _VRAM9000[]; +__BYTES _SCRN0[]; +__BYTES _SCRN1[]; +__BYTES _SRAM[]; +__BYTES _RAM[]; +__BYTES _RAMBANK[]; +__BYTES _OAMRAM[]; +__BYTE_REG _IO[]; +__BYTE_REG _AUD3WAVERAM[]; +__BYTE_REG _HRAM[]; + +/** MBC5 registers */ + +__BYTE_REG rRAMG; +__BYTE_REG rROMB0; +__BYTE_REG rROMB1; +__BYTE_REG rRAMB; + +/** IO Registers */ + +__REG P1_REG; /**< Joystick register @see joypad(), add_JOY(), IEF_HILO, P1F_5, P1F_4, P1F_3, P1F_2, P1F_1, P1F_0, P1F_GET_DPAD, P1F_GET_BTN, P1F_GET_NONE */ +#define rP1 P1_REG + +#define P1F_5 0b00100000 +#define P1F_4 0b00010000 +#define P1F_3 0b00001000 +#define P1F_2 0b00000100 +#define P1F_1 0b00000010 +#define P1F_0 0b00000001 + +#define P1F_GET_DPAD P1F_5 +#define P1F_GET_BTN P1F_4 +#define P1F_GET_NONE (P1F_4 | P1F_5) + +__REG SB_REG; /**< Serial IO data buffer */ +#define rSB SB_REG +__REG SC_REG; /**< Serial IO control register */ +#define rSC SC_REG + +#define SIOF_XFER_START 0b10000000 /**< Serial IO: Start Transfer. Automatically cleared at the end of transfer */ +#define SIOF_CLOCK_INT 0b00000001 /**< Serial IO: Use Internal clock */ +#define SIOF_CLOCK_EXT 0b00000000 /**< Serial IO: Use External clock */ +#define SIOF_SPEED_1X 0b00000000 /**< Serial IO: If internal clock then 8KHz mode, 1KB/s (16Khz in CGB high-speed mode, 2KB/s) */ +#define SIOF_SPEED_32X 0b00000010 /**< Serial IO: **CGB-Mode ONLY** If internal clock then 256KHz mode, 32KB/s (512KHz in CGB high-speed mode, 64KB/s) */ +#define SIOF_B_CLOCK 0 +#define SIOF_B_SPEED 1 +#define SIOF_B_XFER_START 7 +#define SCF_START SIOF_XFER_START +#define SCF_SOURCE SIOF_CLOCK_INT +#define SCF_SPEED SIOF_SPEED_32X + +__REG DIV_REG; /**< Divider register */ +#define rDIV DIV_REG +__REG TIMA_REG; /**< Timer counter */ +#define rTIMA TIMA_REG +__REG TMA_REG; /**< Timer modulo */ +#define rTMA TMA_REG +__REG TAC_REG; /**< Timer control */ +#define rTAC TAC_REG + +#define TACF_START 0b00000100 +#define TACF_STOP 0b00000000 +#define TACF_4KHZ 0b00000000 +#define TACF_16KHZ 0b00000011 +#define TACF_65KHZ 0b00000010 +#define TACF_262KHZ 0b00000001 + +__REG IF_REG; /**< Interrupt flags: @ref IEF_HILO, @ref IEF_SERIAL, @ref IEF_TIMER, @ref IEF_STAT, @ref IEF_VBLANK */ +#define rIF IF_REG + +__REG NR10_REG; /**< Sound Channel 1, NR10: Sweep */ +#define rAUD1SWEEP NR10_REG /**< Sound Channel 1, NR10: Sweep */ +#define AUD1SWEEP_UP 0b00000000 /**< For Sound Channel 1, NR10: Sweep Addition, period increases */ +#define AUD1SWEEP_DOWN 0b00001000 /**< For Sound Channel 1, NR10: Sweep Subtraction, period decreases */ +#define AUD1SWEEP_TIME(x) ((x) << 4) /**< For Sound Channel 1, NR10: Sweep Time/Pace, Range: 0-7 */ +#define AUD1SWEEP_LENGTH(x) (x) /**< For Sound Channel 1, NR10: Sweep Length/Individual step, Range: 0-7 */ +__REG NR11_REG; /**< Sound Channel 1, NR11: Sound length/Wave pattern duty */ +#define rAUD1LEN NR11_REG /**< Sound Channel 1, NR11: Sound length/Wave pattern duty */ +__REG NR12_REG; /**< Sound Channel 1, NR12: Volume Envelope */ +#define rAUD1ENV NR12_REG /**< Sound Channel 1, NR12: Volume Envelope */ +__REG NR13_REG; /**< Sound Channel 1, NR13: Frequency Low */ +#define rAUD1LOW NR13_REG /**< Sound Channel 1, NR13: Frequency Low */ +__REG NR14_REG; /**< Sound Channel 1, NR14: Frequency High */ +#define rAUD1HIGH NR14_REG /**< Sound Channel 1, NR14: Frequency High */ + +__REG NR21_REG; /**< Sound Channel 2, NR21_REG: Tone */ +#define rAUD2LEN NR21_REG /**< Sound Channel 2, NR21_REG: Tone */ +__REG NR22_REG; /**< Sound Channel 2, NR22_REG: Volume Envelope */ +#define rAUD2ENV NR22_REG /**< Sound Channel 2, NR22_REG: Volume Envelope */ +__REG NR23_REG; /**< Sound Channel 2, NR23_REG: Frequency data Low */ +#define rAUD2LOW NR23_REG /**< Sound Channel 2, NR23_REG: Frequency data Low */ +__REG NR24_REG; /**< Sound Channel 2, NR24_REG: Frequency data High */ +#define rAUD2HIGH NR24_REG /**< Sound Channel 2, NR24_REG: Frequency data High */ + +__REG NR30_REG; /**< Sound Channel 3, NR30_REG: Sound on/off */ +#define rAUD3ENA NR30_REG /**< Sound Channel 3, NR30_REG: Sound on/off */ +__REG NR31_REG; /**< Sound Channel 3, NR31_REG: Sound Length */ +#define rAUD3LEN NR31_REG /**< Sound Channel 3, NR31_REG: Sound Length */ +__REG NR32_REG; /**< Sound Channel 3, NR32_REG: Select output level */ +#define rAUD3LEVEL NR32_REG/**< Sound Channel 3, NR32_REG: Select output level */ +__REG NR33_REG; /**< Sound Channel 3, NR33_REG: Frequency data Low */ +#define rAUD3LOW NR33_REG /**< Sound Channel 3, NR33_REG: Frequency data Low */ +__REG NR34_REG; /**< Sound Channel 3, NR34_REG: Frequency data High */ +#define rAUD3HIGH NR34_REG /**< Sound Channel 3, NR34_REG: Frequency data High */ + +__REG NR41_REG; /**< Sound Channel 4, NR41_REG: Sound Length */ +#define rAUD4LEN NR41_REG /**< Sound Channel 4, NR41_REG: Sound Length */ +__REG NR42_REG; /**< Sound Channel 4, NR42_REG: Volume Envelope */ +#define rAUD4ENV NR42_REG /**< Sound Channel 4, NR42_REG: Volume Envelope */ +__REG NR43_REG; /**< Sound Channel 4, NR43_REG: Polynomial Counter */ +#define rAUD4POLY NR43_REG /**< Sound Channel 4, NR43_REG: Polynomial Counter */ +#define AUD4POLY_WIDTH_15BIT 0x00 /**< For Sound Channel 4, NR43_REG: Polynomial counter use 15 steps */ +#define AUD4POLY_WIDTH_7BIT 0x08 /**< For Sound Channel 4, NR43_REG: Polynomial counter use 7 steps */ +__REG NR44_REG; /**< Sound Channel 4, NR44_REG: Counter / Consecutive and Initial */ +#define rAUD4GO NR44_REG /**< Sound Channel 4, NR44_REG: Counter / Consecutive and Initial */ + +__REG NR50_REG; /**< Sound Master Volume, NR50: Volume and Cart external sound input (VIN) */ +#define rAUDVOL NR50_REG /**< Sound Master Volume, NR50: Volume and Cart external sound input (VIN) */ + +#define AUDVOL_VOL_LEFT(x) ((x) << 4) /**< For Sound Master Volume, NR50: Left Volume, Range: 0-7 */ +#define AUDVOL_VOL_RIGHT(x) ((x)) /**< For Sound Master Volume, NR50: Right Volume, Range: 0-7 */ +#define AUDVOL_VIN_LEFT 0b10000000 /**< For Sound Master Volume, NR50: Cart external sound input (VIN) Left bit, 1 = ON, 0 = OFF */ +#define AUDVOL_VIN_RIGHT 0b00001000 /**< For Sound Master Volume, NR50: Cart external sound input (VIN) Right bit, 1 = ON, 0 = OFF */ + +__REG NR51_REG; /**< Sound Panning, NR51: Enable/disable left and right output for sound channels */ +#define rAUDTERM NR51_REG /**< Sound Panning, NR51: Enable/disable left and right output for sound channels */ + +#define AUDTERM_4_LEFT 0b10000000 /**< For Sound Panning, NR51: Channel 4 Left bit, 1 = ON, 0 = OFF */ +#define AUDTERM_3_LEFT 0b01000000 /**< For Sound Panning, NR51: Channel 3 Left bit, 1 = ON, 0 = OFF */ +#define AUDTERM_2_LEFT 0b00100000 /**< For Sound Panning, NR51: Channel 2 Left bit, 1 = ON, 0 = OFF */ +#define AUDTERM_1_LEFT 0b00010000 /**< For Sound Panning, NR51: Channel 1 Left bit, 1 = ON, 0 = OFF */ +#define AUDTERM_4_RIGHT 0b00001000 /**< For Sound Panning, NR51: Channel 4 Right bit, 1 = ON, 0 = OFF */ +#define AUDTERM_3_RIGHT 0b00000100 /**< For Sound Panning, NR51: Channel 4 Right bit, 1 = ON, 0 = OFF */ +#define AUDTERM_2_RIGHT 0b00000010 /**< For Sound Panning, NR51: Channel 4 Right bit, 1 = ON, 0 = OFF */ +#define AUDTERM_1_RIGHT 0b00000001 /**< For Sound Panning, NR51: Channel 4 Right bit, 1 = ON, 0 = OFF */ + +__REG NR52_REG; /**< Sound Master Control, NR52: ON / OFF */ +#define rAUDENA NR52_REG /**< Sound Master Control, NR52: ON / OFF */ + +#define AUDENA_ON 0b10000000 /**< For Sound Master Control, NR52: Sound ON */ +#define AUDENA_OFF 0b00000000 /**< For Sound Master Control, NR52: Sound OFF */ + +__BYTE_REG AUD3WAVE[16]; +__BYTE_REG PCM_SAMPLE[16]; + +__REG LCDC_REG; /**< LCD control */ +#define rLCDC LCDC_REG + +#if defined(__TARGET_ap) +#define LCDCF_OFF 0b00000000 +#define LCDCF_ON 0b00000001 +#define LCDCF_WIN9800 0b00000000 +#define LCDCF_WIN9C00 0b00000010 +#define LCDCF_WINOFF 0b00000000 +#define LCDCF_WINON 0b00000100 +#define LCDCF_BG8800 0b00000000 +#define LCDCF_BG8000 0b00001000 +#define LCDCF_BG9800 0b00000000 +#define LCDCF_BG9C00 0b00010000 +#define LCDCF_OBJ8 0b00000000 +#define LCDCF_OBJ16 0b00100000 +#define LCDCF_OBJOFF 0b00000000 +#define LCDCF_OBJON 0b01000000 +#define LCDCF_BGOFF 0b00000000 +#define LCDCF_BGON 0b10000000 +#define LCDCF_B_ON 0 +#define LCDCF_B_WIN9C00 1 +#define LCDCF_B_WINON 2 +#define LCDCF_B_BG8000 3 +#define LCDCF_B_BG9C00 4 +#define LCDCF_B_OBJ16 5 +#define LCDCF_B_OBJON 6 +#define LCDCF_B_BGON 7 +#elif defined(__TARGET_duck) +#define LCDCF_OFF 0b00000000 +#define LCDCF_ON 0b10000000 +#define LCDCF_WIN9800 0b00000000 +#define LCDCF_WIN9C00 0b00001000 +#define LCDCF_WINOFF 0b00000000 +#define LCDCF_WINON 0b00100000 +#define LCDCF_BG8800 0b00000000 +#define LCDCF_BG8000 0b00010000 +#define LCDCF_BG9800 0b00000000 +#define LCDCF_BG9C00 0b00000100 +#define LCDCF_OBJ8 0b00000000 +#define LCDCF_OBJ16 0b00000010 +#define LCDCF_OBJOFF 0b00000000 +#define LCDCF_OBJON 0b00000001 +#define LCDCF_BGOFF 0b00000000 +#define LCDCF_BGON 0b01000000 +#define LCDCF_B_ON 7 +#define LCDCF_B_WIN9C00 3 +#define LCDCF_B_WINON 5 +#define LCDCF_B_BG8000 4 +#define LCDCF_B_BG9C00 2 +#define LCDCF_B_OBJ16 1 +#define LCDCF_B_OBJON 0 +#define LCDCF_B_BGON 6 +#else +#define LCDCF_OFF 0b00000000 /**< LCD Control: Off */ +#define LCDCF_ON 0b10000000 /**< LCD Control: On */ +#define LCDCF_WIN9800 0b00000000 /**< Window Tile Map: Use 9800 Region */ +#define LCDCF_WIN9C00 0b01000000 /**< Window Tile Map: Use 9C00 Region */ +#define LCDCF_WINOFF 0b00000000 /**< Window Display: Hidden */ +#define LCDCF_WINON 0b00100000 /**< Window Display: Visible */ +#define LCDCF_BG8800 0b00000000 /**< BG & Window Tile Data: Use 8800 Region */ +#define LCDCF_BG8000 0b00010000 /**< BG & Window Tile Data: Use 8000 Region */ +#define LCDCF_BG9800 0b00000000 /**< BG Tile Map: use 9800 Region */ +#define LCDCF_BG9C00 0b00001000 /**< BG Tile Map: use 9C00 Region */ +#define LCDCF_OBJ8 0b00000000 /**< Sprites Size: 8x8 pixels */ +#define LCDCF_OBJ16 0b00000100 /**< Sprites Size: 8x16 pixels */ +#define LCDCF_OBJOFF 0b00000000 /**< Sprites Display: Hidden */ +#define LCDCF_OBJON 0b00000010 /**< Sprites Display: Visible */ +#define LCDCF_BGOFF 0b00000000 /**< Background Display: Hidden */ +#define LCDCF_BGON 0b00000001 /**< Background Display: Visible */ +#define LCDCF_B_ON 7 /**< Bit for LCD On/Off Select */ +#define LCDCF_B_WIN9C00 6 /**< Bit for Window Tile Map Region Select */ +#define LCDCF_B_WINON 5 /**< Bit for Window Display On/Off Control */ +#define LCDCF_B_BG8000 4 /**< Bit for BG & Window Tile Data Region Select */ +#define LCDCF_B_BG9C00 3 /**< Bit for BG Tile Map Region Select */ +#define LCDCF_B_OBJ16 2 /**< Bit for Sprites Size Select */ +#define LCDCF_B_OBJON 1 /**< Bit for Sprites Display Visible/Hidden Select */ +#define LCDCF_B_BGON 0 /**< Bit for Background Display Visible/Hidden Select */ +#endif + +__REG STAT_REG; /**< LCD status */ +#define rSTAT STAT_REG + +#if defined(__TARGET_ap) +#define STATF_LYC 0b00000010 +#define STATF_MODE10 0b00000100 +#define STATF_MODE01 0b00001000 +#define STATF_MODE00 0b00010000 +#define STATF_LYCF 0b00100000 +#define STATF_HBL 0b00000000 +#define STATF_VBL 0b10000000 +#define STATF_OAM 0b01000000 +#define STATF_LCD 0b11000000 +#define STATF_BUSY 0b01000000 +#define STATF_B_LYC 1 +#define STATF_B_MODE10 2 +#define STATF_B_MODE01 3 +#define STATF_B_MODE00 4 +#define STATF_B_LYCF 5 +#define STATF_B_VBL 7 +#define STATF_B_OAM 6 +#define STATF_B_BUSY 6 +#else +#define STATF_LYC 0b01000000 /**< STAT Interrupt: LYC=LY Coincidence Source Enable */ +#define STATF_MODE10 0b00100000 /**< STAT Interrupt: Mode 2 OAM Source Enable */ +#define STATF_MODE01 0b00010000 /**< STAT Interrupt: Mode 1 VBlank Source Enable */ +#define STATF_MODE00 0b00001000 /**< STAT Interrupt: Mode 0 HBlank Source Enable */ +#define STATF_LYCF 0b00000100 /**< LYC=LY Coincidence Status Flag, Set when LY contains the same value as LYC */ +#define STATF_HBL 0b00000000 /**< Current LCD Mode is: 0, in H-Blank */ +#define STATF_VBL 0b00000001 /**< Current LCD Mode is: 1, in V-Blank */ +#define STATF_OAM 0b00000010 /**< Current LCD Mode is: 2, in OAM-RAM is used by system (Searching OAM) */ +#define STATF_LCD 0b00000011 /**< Current LCD Mode is: 3, both OAM and VRAM used by system (Transferring Data to LCD Controller) */ +#define STATF_BUSY 0b00000010 /**< When set, VRAM access is unsafe */ +#define STATF_B_LYC 6 /**< Bit for STAT Interrupt: LYC=LY Coincidence Source Enable */ +#define STATF_B_MODE10 5 /**< Bit for STAT Interrupt: Mode 2 OAM Source Enable */ +#define STATF_B_MODE01 4 /**< Bit for STAT Interrupt: Mode 1 VBlank Source Enable */ +#define STATF_B_MODE00 3 /**< Bit for STAT Interrupt: Mode 0 HBlank Source Enable */ +#define STATF_B_LYCF 2 /**< Bit for LYC=LY Coincidence Status Flag */ +#define STATF_B_VBL 0 /**< */ +#define STATF_B_OAM 1 /**< */ +#define STATF_B_BUSY 1 /**< Bit for when VRAM access is unsafe */ +#endif + +__REG SCY_REG; /**< Scroll Y */ +#define rSCY +__REG SCX_REG; /**< Scroll X */ +#define rSCX SCX_REG +__REG LY_REG; /**< LCDC Y-coordinate */ +#define rLY LY_REG +__REG LYC_REG; /**< LY compare */ +#define rLYC LYC_REG +__REG DMA_REG; /**< DMA transfer */ +#define rDMA DMA_REG +__REG BGP_REG; /**< Set and Read the Background palette. \n \n Example with the DMG_PALETTE() helper function and constants: \n BGP_REG = DMG_PALETTE(DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE); */ +#define rBGP BGP_REG +__REG OBP0_REG; /**< Set and Read the OBJ (Sprite) palette 0. \n \n The first color entry is always transparent. \n \n Example with the DMG_PALETTE() helper function and constants: \n OBP0_REG = DMG_PALETTE(DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE); */ +#define rOBP0 OBP0_REG +__REG OBP1_REG; /**< Set and Read the OBJ (Sprite) palette 1. \n \n The first color entry is always transparent. \n \n Example with the DMG_PALETTE() helper function and constants: \n OBP1_REG = DMG_PALETTE(DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE); */ +#define rOBP1 OBP1_REG +__REG WY_REG; /**< Window Y coordinate */ +#define rWY WY_REG +__REG WX_REG; /**< Window X coordinate */ +#define rWX WX_REG +__REG KEY1_REG; /**< CPU speed */ +#define rKEY1 KEY1_REG +#define rSPD KEY1_REG + +#define KEY1F_DBLSPEED 0b10000000 +#define KEY1F_PREPARE 0b00000001 + +__REG VBK_REG; /**< VRAM bank select (CGB only) @see VBK_BANK_0, VBK_TILES, VBK_BANK_1, VBK_ATTRIBUTES */ +#define rVBK VBK_REG + +#define VBK_BANK_0 0 /**< Select Regular Map and Normal Tiles (CGB Mode Only) */ +#define VBK_TILES 0 /**< Select Regular Map and Normal Tiles (CGB Mode Only) */ +#define VBK_BANK_1 1 /**< Select Map Attributes and Extra Tile Bank (CGB Mode Only)*/ +#define VBK_ATTRIBUTES 1 /**< Select Map Attributes and Extra Tile Bank (CGB Mode Only) */ + +#define BKGF_PRI 0b10000000 /**< Background CGB BG and Window over Sprite priority Enabled */ +#define BKGF_YFLIP 0b01000000 /**< Background CGB Y axis flip: Vertically mirrored */ +#define BKGF_XFLIP 0b00100000 /**< Background CGB X axis flip: Horizontally mirrored */ +#define BKGF_BANK0 0b00000000 /**< Background CGB Tile VRAM-Bank: Use Bank 0 (CGB Mode Only) */ +#define BKGF_BANK1 0b00001000 /**< Background CGB Tile VRAM-Bank: Use Bank 1 (CGB Mode Only) */ + +#define BKGF_CGB_PAL0 0b00000000 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL1 0b00000001 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL2 0b00000010 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL3 0b00000011 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL4 0b00000100 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL5 0b00000101 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL6 0b00000110 /**< Background CGB Palette number (CGB Mode Only) */ +#define BKGF_CGB_PAL7 0b00000111 /**< Background CGB Palette number (CGB Mode Only) */ + +__REG HDMA1_REG; /**< DMA control 1 */ +#define rHDMA1 HDMA1_REG +__REG HDMA2_REG; /**< DMA control 2 */ +#define rHDMA2 HDMA2_REG +__REG HDMA3_REG; /**< DMA control 3 */ +#define rHDMA3 HDMA3_REG +__REG HDMA4_REG; /**< DMA control 4 */ +#define rHDMA4 HDMA4_REG +__REG HDMA5_REG; /**< DMA control 5 */ +#define rHDMA5 HDMA5_REG + +#define HDMA5F_MODE_GP 0b00000000 +#define HDMA5F_MODE_HBL 0b10000000 + +#define HDMA5F_BUSY 0b10000000 + +__REG RP_REG; /**< IR port */ +#define rRP RP_REG + +#define RPF_ENREAD 0b11000000 +#define RPF_DATAIN 0b00000010 +#define RPF_WRITE_HI 0b00000001 +#define RPF_WRITE_LO 0b00000000 + +__REG BCPS_REG; /**< BG color palette specification */ +#define rBCPS BCPS_REG + +#define BCPSF_AUTOINC 0b10000000 +__REG BCPD_REG; /**< BG color palette data */ +#define rBCPD BCPD_REG + +__REG OCPS_REG; /**< OBJ color palette specification */ +#define rOCPS OCPS_REG + +#define OCPSF_AUTOINC 0b10000000 +__REG OCPD_REG; /**< OBJ color palette data */ +#define rOCPD OCPD_REG +__REG SVBK_REG; /**< Selects the WRAM upper region bank (CGB Only). WRAM Banking is NOT officially supported in GBDK and SDCC. The stack must be moved and other special care taken. */ +#define rSVBK SVBK_REG +#define rSMBK SVBK_REG + +__REG PCM12_REG; /**< Sound channel 1&2 PCM amplitude (R) */ +#define rPCM12 PCM12_REG + +__REG PCM34_REG; /**< Sound channel 3&4 PCM amplitude (R) */ +#define rPCM34 PCM34_REG + +__REG IE_REG; /**< Interrupt enable */ +#define rIE IE_REG + +#define IEF_HILO 0b00010000 /**< Joypad interrupt enable flag */ +#define IEF_SERIAL 0b00001000 /**< Serial interrupt enable flag */ +#define IEF_TIMER 0b00000100 /**< Timer interrupt enable flag */ +#define IEF_STAT 0b00000010 /**< Stat interrupt enable flag */ +#define IEF_VBLANK 0b00000001 /**< VBlank interrupt enable flag */ + + +/* Square wave duty cycle */ +#define AUDLEN_DUTY_12_5 0b00000000 +#define AUDLEN_DUTY_25 0b01000000 +#define AUDLEN_DUTY_50 0b10000000 +#define AUDLEN_DUTY_75 0b11000000 +#define AUDLEN_LENGTH(x) (x) + +/* Audio envelope flags */ +#define AUDENV_VOL(x) ((x) << 4) +#define AUDENV_UP 0b00001000 +#define AUDENV_DOWN 0b00000000 +#define AUDENV_LENGTH(x) (x) + +/* Audio trigger flags */ +#define AUDHIGH_RESTART 0b10000000 +#define AUDHIGH_LENGTH_ON 0b01000000 +#define AUDHIGH_LENGTH_OFF 0b00000000 + +/* OAM attributes flags */ +#define OAMF_PRI 0b10000000 /**< BG and Window over Sprite Enabled */ +#define OAMF_YFLIP 0b01000000 /**< Sprite Y axis flip: Vertically mirrored */ +#define OAMF_XFLIP 0b00100000 /**< Sprite X axis flip: Horizontally mirrored */ +#define OAMF_PAL0 0b00000000 /**< Sprite Palette number: use OBP0 (Non-CGB Mode Only) */ +#define OAMF_PAL1 0b00010000 /**< Sprite Palette number: use OBP1 (Non-CGB Mode Only) */ +#define OAMF_BANK0 0b00000000 /**< Sprite Tile VRAM-Bank: Use Bank 0 (CGB Mode Only) */ +#define OAMF_BANK1 0b00001000 /**< Sprite Tile VRAM-Bank: Use Bank 1 (CGB Mode Only) */ + +#define OAMF_CGB_PAL0 0b00000000 /**< Sprite CGB Palette number: use OCP0 (CGB Mode Only) */ +#define OAMF_CGB_PAL1 0b00000001 /**< Sprite CGB Palette number: use OCP1 (CGB Mode Only) */ +#define OAMF_CGB_PAL2 0b00000010 /**< Sprite CGB Palette number: use OCP2 (CGB Mode Only) */ +#define OAMF_CGB_PAL3 0b00000011 /**< Sprite CGB Palette number: use OCP3 (CGB Mode Only) */ +#define OAMF_CGB_PAL4 0b00000100 /**< Sprite CGB Palette number: use OCP4 (CGB Mode Only) */ +#define OAMF_CGB_PAL5 0b00000101 /**< Sprite CGB Palette number: use OCP5 (CGB Mode Only) */ +#define OAMF_CGB_PAL6 0b00000110 /**< Sprite CGB Palette number: use OCP6 (CGB Mode Only) */ +#define OAMF_CGB_PAL7 0b00000111 /**< Sprite CGB Palette number: use OCP7 (CGB Mode Only) */ + +#define OAMF_PALMASK 0b00000111 /**< Mask for Sprite CGB Palette number (CGB Mode Only) */ + +#define DEVICE_SCREEN_X_OFFSET 0 /**< Offset of visible screen (in tile units) from left edge of hardware map */ +#define DEVICE_SCREEN_Y_OFFSET 0 /**< Offset of visible screen (in tile units) from top edge of hardware map */ +#define DEVICE_SCREEN_WIDTH 20 /**< Width of visible screen in tile units */ +#define DEVICE_SCREEN_HEIGHT 18 /**< Height of visible screen in tile units */ +#define DEVICE_SCREEN_BUFFER_WIDTH 32 /**< Width of hardware map buffer in tile units */ +#define DEVICE_SCREEN_BUFFER_HEIGHT 32 /**< Height of hardware map buffer in tile units */ +#define DEVICE_SCREEN_MAP_ENTRY_SIZE 1 /**< Number of bytes per hardware map entry */ +#define DEVICE_SPRITE_PX_OFFSET_X 8 /**< Offset of sprite X coordinate origin (in pixels) from left edge of visible screen */ +#define DEVICE_SPRITE_PX_OFFSET_Y 16 /**< Offset of sprite Y coordinate origin (in pixels) from top edge of visible screen */ +#define DEVICE_WINDOW_PX_OFFSET_X 7 /**< Minimal X coordinate of the window layer */ +#define DEVICE_WINDOW_PX_OFFSET_Y 0 /**< Minimal Y coordinate of the window layer */ +#define DEVICE_SCREEN_PX_WIDTH (DEVICE_SCREEN_WIDTH * 8) /**< Width of visible screen in pixels */ +#define DEVICE_SCREEN_PX_HEIGHT (DEVICE_SCREEN_HEIGHT * 8) /**< Height of visible screen in pixels */ + +#endif diff --git a/ext/include/gb/hblankcpy.h b/ext/include/gb/hblankcpy.h new file mode 100644 index 0000000..291ddef --- /dev/null +++ b/ext/include/gb/hblankcpy.h @@ -0,0 +1,53 @@ +#ifndef __HBLANKCPY_H_INCLUDE__ +#define __HBLANKCPY_H_INCLUDE__ + +#include + +/** HBlank stack copy routine + @param sour Source address to copy from + @param count Number of 16 byte chunks to copy + + Performs the required STAT_REG, IE_REG, IF_REG manipulation + when called and restores STAT_REG and IE_REG on exit + (unlike @ref hblank_cpy_vram()). + + Before calling: + - Set the destination using @ref hblank_copy_destination + - Interrupts must be disabled + + @see hblank_cpy_vram, hblank_copy_destination, hblank_copy +*/ +void hblank_copy_vram(const uint8_t * sour, uint8_t count); + +/** HBlank stack copy routine + @param sour Source address to copy from + @param count Number of 16 byte chunks to copy + + Unlike @ref hblank_copy_vram() does not perform the required + STAT_REG, IE_REG, IF_REG manipulation, nor does it restore + STAT_REG and IE_REG on exit. + + Before calling: + - Set the destination using @ref hblank_copy_destination + - Interrupts must be properly configured + - Interrupts must be disabled + + @see hblank_copy_vram, hblank_copy_destination, hblank_copy +*/ +void hblank_cpy_vram(const uint8_t * sour, uint8_t count); + +extern uint8_t * hblank_copy_destination; /**< Destination address for hblank copy routine */ + +/** HBlank stack copy routine (must be called with interrupts disabled!) + @param dest destination pointer + @param sour source pointer + @param size number of bytes to copy (rounded to 16-byte chunks) + + Performs a fast vram safe copy of data during HBlank. +*/ +inline void hblank_copy(uint8_t * dest, const uint8_t * sour, uint16_t size) { + hblank_copy_destination = dest; + hblank_copy_vram(sour, size >> 4); +} + +#endif \ No newline at end of file diff --git a/ext/include/gb/isr.h b/ext/include/gb/isr.h new file mode 100644 index 0000000..d7c2dc6 --- /dev/null +++ b/ext/include/gb/isr.h @@ -0,0 +1,78 @@ +/** @file gb/isr.h + + Macros for creating raw interrupt service routines (ISRs) + which do not use the default GBDK ISR dispatcher. + + Handlers installed this way will have less overhead than + ones which use the GBDK ISR dispatcher. +*/ +#ifndef _ISR_H_INCLUDE_ +#define _ISR_H_INCLUDE_ + +#include +#include + +// #define VECTOR_VBL 0x40 // you can not define raw vector for VBlank interrupt +#define VECTOR_STAT 0x48 /**< Address for the STAT interrupt vector */ +#define VECTOR_TIMER 0x50 /**< Address for the TIMER interrupt vector */ +#define VECTOR_SERIAL 0x58 /**< Address for the SERIAL interrupt vector */ +#define VECTOR_JOYPAD 0x60 /**< Address for the JOYPAD interrupt vector */ + +typedef struct isr_vector_t { + uint8_t opcode; + void * func; +} isr_vector_t; + +/** Creates an interrupt vector at the given address for a raw + interrupt service routine (which does not use the GBDK ISR dispatcher) + + @param ADDR Address of the interrupt vector, any of: @ref VECTOR_STAT, @ref VECTOR_TIMER, @ref VECTOR_SERIAL, @ref VECTOR_JOYPAD + @param FUNC ISR function supplied by the user + + This cannot be used with the VBLANK interrupt. + + Do not use this in combination with interrupt installers + that rely on the default GBDK ISR dispatcher such as + @ref add_TIM(), @ref remove_TIM() + (and the same for all other interrupts). + + Example: + \code{.c} + #include + + void TimerISR() __critical __interrupt { + // some ISR code here + } + + ISR_VECTOR(VECTOR_TIMER, TimerISR) + \endcode + + @see ISR_NESTED_VECTOR, set_interrupts +*/ +#define ISR_VECTOR(ADDR, FUNC) \ +static const isr_vector_t AT((ADDR)) __ISR_ ## ADDR = {0xc3, (void *)&(FUNC)}; + +typedef struct isr_nested_vector_t { + uint8_t opcode[2]; + void * func; +} isr_nested_vector_t; + +/** Creates an interrupt vector at the given address for a raw + interrupt service routine allowing nested interrupts + + @param ADDR Address of the interrupt vector, any of: @ref VECTOR_STAT, @ref VECTOR_TIMER, @ref VECTOR_SERIAL, @ref VECTOR_JOYPAD + @param FUNC ISR function + + This cannot be used with the VBLANK interrupt + + The LCD STAT vector (@ref VECTOR_STAT) cannot be used + in the same program as `stdio.h` since they install + an ISR vector to the same location. + + @see ISR_VECTOR +*/ +#define ISR_NESTED_VECTOR(ADDR, FUNC) \ +static const isr_nested_vector_t AT((ADDR)) __ISR_ ## ADDR = {{0xfb, 0xc3}, (void *)&(FUNC)}; + + +#endif // _ISR_H_INCLUDE_ diff --git a/ext/include/gb/metasprites.h b/ext/include/gb/metasprites.h new file mode 100644 index 0000000..07597cb --- /dev/null +++ b/ext/include/gb/metasprites.h @@ -0,0 +1,310 @@ +/** @file gb/metasprites.h + + @anchor metasprite_main_docs + # Metasprite support + + A metasprite is a larger sprite made up from a + collection of smaller individual hardware sprites. + Different frames of the same metasprites can share + tile data. + + The api supports metasprites in both + @ref SPRITES_8x8 and @ref SPRITES_8x16 mode. If + 8x16 mode is used then the height of the metasprite + must be a multiple of 16. + + The origin (pivot) for the metasprite is not required + to be in the upper left-hand corner as with regular + hardware sprites. + + Use the @ref utility_png2asset tool to convert single + or multiple frames of graphics into metasprite + structured data for use with the ...metasprite...() + functions. + + # Metasprites composed of variable numbers of sprites + + When using png2asset, it's common for the output of + different frames to be composed of different numbers + of hardware sprites (since it's trying to create each + frame as efficiently as possible). Due to that, it's + good practice to clear out (hide) unused sprites in the + shadow_OAM that have been set by previous frames. + + \code + // Example: + // Hide rest of the hardware sprites, because amount + // of sprites differ between animation frames. + // (where hiwater == last hardware sprite used + 1) + hide_sprites_range(hiwater, MAX_HARDWARE_SPRITES); + \endcode + + @anchor metasprite_and_sprite_properties + # Metasprites and sprite properties (including cgb palette) + + When the move_metasprite_*() functions are called they + update all properties for the affected sprites in the + Shadow OAM. This means any existing property flags set + for a sprite (CGB palette, BG/WIN priority, Tile VRAM Bank) + will get overwritten. + + How to use sprite property flags with metasprites: + - Primary method: Use the `base_prop` parameter for the + move_metasprite_*() functions. + - For more details about the properties on the Game Boy see: https://gbdev.io/pandocs/OAM.html#byte-3--attributesflags + - This can be left at zero for defaults + - Various `OAMF_*` flags can be used depending on the platform: + - @ref OAMF_BANK0, @ref OAMF_BANK1 + - @ref OAMF_CGB_PAL0, @ref OAMF_CGB_PAL1, @ref OAMF_CGB_PAL2, @ref OAMF_CGB_PAL3, + @ref OAMF_CGB_PAL4, @ref OAMF_CGB_PAL5, @ref OAMF_CGB_PAL6, @ref OAMF_CGB_PAL7, + - @ref OAMF_PAL0, @ref OAMF_PAL1, + - @ref OAMF_PALMASK, @ref OAMF_PRI, @ref OAMF_XFLIP, @ref OAMF_YFLIP + + - Alternate method: The metasprite structures can have the + property flags modified before compilation (such as with + `-sp ` in the @ref utility_png2asset "png2asset" tool). + + The following functions only support hardware sprite flipping + on the Game Boy / Mega Duck and NES. For other consoles which + do not have hardware sprite flipping see the cross-platform + metasprite example for a workaround (with some performance penalty). + + - @ref move_metasprite_flipx() + - @ref move_metasprite_flipy() + - @ref move_metasprite_flipxy() + + To test for hardware support see + @ref HARDWARE_SPRITE_CAN_FLIP_X and @ref HARDWARE_SPRITE_CAN_FLIP_Y. + Also see @ref docs_consoles_supported_list for a brief summary of + console capabilities. +*/ + +#ifndef _METASPRITES_H_INCLUDE +#define _METASPRITES_H_INCLUDE + +#include +#include +#include + +/** Metasprite sub-item structure + @param dy (int8_t) Y coordinate of the sprite relative to the metasprite origin (pivot) + @param dx (int8_t) X coordinate of the sprite relative to the metasprite origin (pivot) + @param dtile (uint8_t) Start tile relative to the metasprites own set of tiles + @param props (uint8_t) Property Flags + + Metasprites are built from multiple metasprite_t items (one for each sub-sprite) + and a pool of tiles they reference. If a metasprite has multiple frames then each + frame will be built from some number of metasprite_t items (which may vary based + on how many sprites are required for that particular frame). + + A metasprite frame is terminated with a {metasprite_end} entry. +*/ +typedef struct metasprite_t { + int8_t dy, dx; + uint8_t dtile; + uint8_t props; +} metasprite_t; + +#define metasprite_end -128 +#define METASPR_ITEM(dy,dx,dt,a) {(dy),(dx),(dt),(a)} +#define METASPR_TERM {metasprite_end} + +extern const void * __current_metasprite; +extern uint8_t __current_base_tile; +extern uint8_t __current_base_prop; +extern uint8_t __render_shadow_OAM; + + +static uint8_t __move_metasprite(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_flipx(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_flipy(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_flipxy(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_vflip(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_hflip(uint8_t id, uint16_t yx); +static uint8_t __move_metasprite_hvflip(uint8_t id, uint16_t yx); +static void __hide_metasprite(uint8_t id); + +/** + Hides all hardware sprites in range from <= X < to + @param from start OAM index + @param to finish OAM index (must be <= MAX_HARDWARE_SPRITES) + + @see hide_sprite, MAX_HARDWARE_SPRITES + */ +void hide_sprites_range(uint8_t from, uint8_t to); + +/** Moves metasprite to the absolute position x and y + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (can be used to set palette, etc) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Moves __metasprite__ to the absolute position __x__ and __y__ + (with __no flip__ on the X or Y axis). Hardware sprites are + allocated starting from __base_sprite__, using tiles + starting from __base_tile__. + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as CGB Palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + */ +inline uint8_t move_metasprite_ex(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite(base_sprite, (y << 8) | (uint8_t)x); +} + +/** Obsolete. This function has been replaced by move_metasprite_ex() +*/ +inline uint8_t move_metasprite(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite(base_sprite, (y << 8) | (uint8_t)x); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X (horizontally)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (can be used to set palette, etc) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X (horizontally). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as CGB palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + This function is only available on Game Boy and related clone consoles. + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipx(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipx(base_sprite, (y << 8) | (uint8_t)(x - 8u)); +} + +/** Obsolete. This function has been replaced by move_metasprite_flipx() +*/ +inline uint8_t move_metasprite_vflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_vflip(base_sprite, (y << 8) | (uint8_t)(x - 8u)); +} + + +/** Moves metasprite to the absolute position x and y, __flipped by Y (vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (can be used to set palette, etc) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by Y (vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as CGB palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + This function is only available on Game Boy and related clone consoles. + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipy(base_sprite, ((y - ((LCDC_REG & LCDCF_OBJ16) ? 16u : 8u)) << 8) | x); +} + +/** Obsolete. This function has been replaced by move_metasprite_flipy() +*/ +inline uint8_t move_metasprite_hflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_hflip(base_sprite, ((y - ((LCDC_REG & LCDCF_OBJ16) ? 16u : 8u)) << 8) | x); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X and Y (horizontally and vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (can be used to set palette, etc) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X and Y (horizontally and vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as CGB palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + This function is only available on Game Boy and related clone consoles. + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipxy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipxy(base_sprite, ((y - ((LCDC_REG & LCDCF_OBJ16) ? 16u : 8u)) << 8) | (uint8_t)(x - 8)); +} + +/** Obsolete. This function has been replaced by move_metasprite_flipxy() +*/ +inline uint8_t move_metasprite_hvflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_hvflip(base_sprite, ((y - ((LCDC_REG & LCDCF_OBJ16) ? 16u : 8u)) << 8) | (uint8_t)(x - 8)); +} + +/** Hides a metasprite from the screen + + @param metasprite Pointer to first struct of the desired metasprite frame + @param base_sprite Number of hardware sprite to start with + + Sets: + \li __current_metasprite = metasprite; + + **/ +inline void hide_metasprite(const metasprite_t * metasprite, uint8_t base_sprite) { + __current_metasprite = metasprite; + __hide_metasprite(base_sprite); +} + +#endif diff --git a/ext/include/gb/sgb.h b/ext/include/gb/sgb.h new file mode 100644 index 0000000..c524774 --- /dev/null +++ b/ext/include/gb/sgb.h @@ -0,0 +1,70 @@ +/** @file gb/sgb.h + Super Gameboy definitions. + + See the example SGB project for additional details. +*/ +#ifndef _SGB_H +#define _SGB_H + +#include +#include + +#define SGB_PAL_01 0x00U /**< SGB Command: Set SGB Palettes 0 & 1 */ +#define SGB_PAL_23 0x01U /**< SGB Command: Set SGB Palettes 2 & 3 */ +#define SGB_PAL_03 0x02U /**< SGB Command: Set SGB Palettes 0 & 3 */ +#define SGB_PAL_12 0x03U /**< SGB Command: Set SGB Palettes 1 & 2 */ +#define SGB_ATTR_BLK 0x04U /**< SGB Command: Set color attributes for rectangular regions */ +#define SGB_ATTR_LIN 0x05U /**< SGB Command: Set color attributes for horizontal or vertical character lines */ +#define SGB_ATTR_DIV 0x06U /**< SGB Command: Split screen in half and assign separate color attribes to each side and the divider */ +#define SGB_ATTR_CHR 0x07U /**< SGB Command: Set color attributes for separate charactersSet SGB Palette 0,1 Data */ +#define SGB_SOUND 0x08U /**< SGB Command: Start and stop a internal sound effect, and sounds using internal tone data */ +#define SGB_SOU_TRN 0x09U /**< SGB Command: Transfer sound code or data to the SNES APU RAM */ +#define SGB_PAL_SET 0x0AU /**< SGB Command: Apply (previously transferred) SGB system color palettes to actual SNES palettes */ +#define SGB_PAL_TRN 0x0BU /**< SGB Command: Transfer palette data into SGB system color palettes */ +#define SGB_ATRC_EN 0x0CU /**< SGB Command: Enable/disable Attraction mode. It is enabled by default */ +#define SGB_TEST_EN 0x0DU /**< SGB Command: Enable/disable test mode for "SGB-CPU variable clock speed function" */ +#define SGB_ICON_EN 0x0EU /**< SGB Command: Enable/disable ICON functionality */ +#define SGB_DATA_SND 0x0FU /**< SGB Command: Write one or more bytes into SNES Work RAM */ +#define SGB_DATA_TRN 0x10U /**< SGB Command: Transfer code or data into SNES RAM */ +#define SGB_MLT_REQ 0x11U /**< SGB Command: Request multiplayer mode (input from more than one joypad) */ +#define SGB_JUMP 0x12U /**< SGB Command: Set the SNES program counter and NMI (vblank interrupt) handler to specific addresses */ +#define SGB_CHR_TRN 0x13U /**< SGB Command: Transfer tile data (characters) to SNES Tile memory */ +#define SGB_PCT_TRN 0x14U /**< SGB Command: Transfer tile map and palette data to SNES BG Map memory */ +#define SGB_ATTR_TRN 0x15U /**< SGB Command: Transfer data to (color) Attribute Files (ATFs) in SNES RAM */ +#define SGB_ATTR_SET 0x16U /**< SGB Command: Transfer attributes from (color) Attribute Files (ATF) to the Game Boy window */ +#define SGB_MASK_EN 0x17U /**< SGB Command: Modify Game Boy window mask settings */ +#define SGB_OBJ_TRN 0x18U /**< SGB Command: Transfer OBJ attributes to SNES OAM memory */ + + +/** Returns a non-zero value if running on a Super GameBoy + + Since sgb_check() uses @ref sgb_transfer(), the same + delay at startup requirement applies to ensure correct + operation on PAL SNES. See @ref sgb_transfer() for details. + * */ +uint8_t sgb_check(void) OLDCALL PRESERVES_REGS(b, c); + +/** Transfer a SGB packet + + @param packet Pointer to buffer with SGB packet data. + + The first byte of __packet__ should be a SGB command, + then up to 15 bytes of command parameter data. + + See the `sgb_border` GBDK example project for a + demo of how to use these the sgb functions. + + When using the SGB with a PAL SNES, a delay should be added + just after program startup such as: + + \code{.c} + // Wait 4 frames + // For PAL SNES this delay is required on startup + for (uint8_t i = 4; i != 0; i--) wait_vbl_done(); + \endcode + + @see sgb_check() +*/ +void sgb_transfer(uint8_t * packet) OLDCALL PRESERVES_REGS(b, c); + +#endif /* _SGB_H */ diff --git a/ext/include/gbdk/bcd.h b/ext/include/gbdk/bcd.h new file mode 100644 index 0000000..15d8db7 --- /dev/null +++ b/ext/include/gbdk/bcd.h @@ -0,0 +1,14 @@ +#ifndef __GBDK_BCD_H_INCLUDE +#define __GBDK_BCD_H_INCLUDE + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) + #include +#elif defined(__TARGET_sms) || defined(__TARGET_gg) || defined(__TARGET_msxdos) + #include +#elif defined(__TARGET_nes) + #include +#else + #error Unrecognized port +#endif + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/console.h b/ext/include/gbdk/console.h new file mode 100644 index 0000000..d605f8d --- /dev/null +++ b/ext/include/gbdk/console.h @@ -0,0 +1,45 @@ +/** @file gbdk/console.h + Console functions that work like Turbo C's. + + The font is 8x8, making the screen 20x18 characters. +*/ +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#include +#include + +/** Move the cursor to an absolute position at __x, y__. + + __x__ and __y__ have units of tiles (8 pixels per unit) + @see setchar() + */ +void gotoxy(uint8_t x, uint8_t y) OLDCALL; + +/** Returns the current X position of the cursor. + + @see gotoxy() + */ +uint8_t posx(void) OLDCALL; + +/** Returns the current Y position of the cursor. + + @see gotoxy() + */ +uint8_t posy(void) OLDCALL; + +/** Writes out a single character at the current cursor + position. + + Does not update the cursor or interpret the character. + + @see gotoxy() +*/ +void setchar(char c) OLDCALL; + +/** Clears the screen +*/ +void cls(void); + + +#endif /* _CONSOLE_H */ diff --git a/ext/include/gbdk/emu_debug.h b/ext/include/gbdk/emu_debug.h new file mode 100644 index 0000000..6b9cd64 --- /dev/null +++ b/ext/include/gbdk/emu_debug.h @@ -0,0 +1,193 @@ +/** @file gbdk/emu_debug.h + + Debug window logging and profiling support for emulators (BGB, Emulicious, etc). + + Also see the `emu_debug` example project included with gbdk. + + See the BGB Manual for more information + ("expressions, breakpoint conditions, and debug messages") + http://bgb.bircd.org/manual.html#expressions + +*/ + +// Suppress SDCC "info 128" warnings that are a non-issue +#pragma disable_warning 218 + +#ifndef __GBDK_EMU_DEBUG_H_INCLUDE +#define __GBDK_EMU_DEBUG_H_INCLUDE + +#include + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_sms) || defined(__TARGET_gg) + +/** Macro to display a message in the emulator debug message window + + @param message_text Quoted text string to display in the debug message window + + The following special parameters can be + used when bracketed with "%" characters. + \li CPU registers: AF, BC, DE, HL, SP, PC, B, C, D, + E, H, L, A, ZERO, ZF, Z, CARRY, CY, IME, ALLREGS + \li Other state values: ROMBANK, XRAMBANK, SRAMBANK, + WRAMBANK, VRAMBANK, TOTALCLKS, LASTCLKS, CLKS2VBLANK + + Example: print a message along with the currently active ROM bank. + \code{.c} + EMU_MESSAGE("Current ROM Bank is: %ROMBANK%"); + \endcode + + + See the BGB Manual for more information + ("expressions, breakpoint conditions, and debug messages") + http://bgb.bircd.org/manual.html#expressions + + @see EMU_PROFILE_BEGIN(), EMU_PROFILE_END() + */ +#define EMU_MESSAGE(message_text) EMU_MESSAGE1(EMU_MACRONAME(__LINE__), message_text) +#define BGB_MESSAGE(message_text) EMU_MESSAGE(message_text) + +/// \cond DOXYGEN_DO_NOT_DOCUMENT +#define EMU_MACRONAME(A) EMU_MACRONAME1(A) +#define EMU_MACRONAME1(A) EMULOG##A + +#define EMU_MESSAGE1(name, message_text) \ +__asm \ +.MACRO name msg_t, ?llbl \ + ld d, d \ + jr llbl \ + .dw 0x6464 \ + .dw 0x0000 \ + .ascii msg_t \ +llbl: \ +.ENDM \ +name ^/message_text/ \ +__endasm + +#define EMU_MESSAGE_SUFFIX(message_text, message_suffix) EMU_MESSAGE3(EMU_MACRONAME(__LINE__), message_text, message_suffix) +#define EMU_MESSAGE3(name, message_text, message_suffix) \ +__asm \ +.MACRO name msg_t, msg_s, ?llbl \ + ld d, d \ + jr llbl \ + .dw 0x6464 \ + .dw 0x0000 \ + .ascii msg_t \ + .ascii msg_s \ +llbl: \ +.ENDM \ +name ^/message_text/, ^/message_suffix/ \ +__endasm +/// \endcond DOXYGEN_DO_NOT_DOCUMENT + +/** Macro to __Start__ a profiling block for the emulator (BGB, Emulicious, etc) + + @param MSG Quoted text string to display in the + debug message window along with the result + + To complete the profiling block and print + the result call @ref EMU_PROFILE_END. + + @see EMU_PROFILE_END(), EMU_MESSAGE() + */ +#define EMU_PROFILE_BEGIN(MSG) EMU_MESSAGE_SUFFIX(MSG, "%ZEROCLKS%"); +#define BGB_PROFILE_BEGIN(MSG) EMU_PROFILE_BEGIN(MSG) +/** Macro to __End__ a profiling block and print the results in the emulator debug message window + + @param MSG Quoted text string to display in the + debug message window along with the result + + This should only be called after a previous call + to @ref EMU_PROFILE_BEGIN() + + The results are in Emulator clock units, which are + "1 nop in [CGB] doublespeed mode". + + So when running in Normal Speed mode (i.e. non-CGB doublespeed) + the printed result should be __divided by 2__ to get the actual + ellapsed cycle count. + + If running in CB Double Speed mode use the below call instead, + it correctly compensates for the speed difference. In this + scenario, the result does __not need to be divided by 2__ to + get the ellapsed cycle count. + \code{.c} + EMU_MESSAGE("NOP TIME: %-4+LASTCLKS%"); + \endcode + + @see EMU_PROFILE_BEGIN(), EMU_MESSAGE() + */ +#if defined(NINTENDO) +#define EMU_PROFILE_END(MSG) EMU_MESSAGE_SUFFIX(MSG,"%-8+LASTCLKS%"); +#define BGB_PROFILE_END(MSG) EMU_PROFILE_END(MSG) +#elif defined(SEGA) +#define EMU_PROFILE_END(MSG) EMU_MESSAGE_SUFFIX(MSG,"%-16+LASTCLKS%"); +#define BGB_PROFILE_END(MSG) EMU_PROFILE_END(MSG) +#endif + +#define EMU_TEXT(MSG) EMU_MESSAGE(MSG) +#define BGB_TEXT(MSG) EMU_TEXT(MSG) + +#if defined(NINTENDO) +/** Display preset debug information in the Emulator debug messages window. + + This function is equivalent to: + \code{.c} + EMU_MESSAGE("PROFILE,%(SP+$0)%,%(SP+$1)%,%A%,%TOTALCLKS%,%ROMBANK%,%WRAMBANK%"); + \endcode + +*/ +void EMU_profiler_message(void); +#define BGB_profiler_message EMU_profiler_message() +#endif // NINTENDO + +/** Print the string and arguments given by format to the emulator debug message window + + @param format The format string as per printf + + Does not return the number of characters printed. + Currently supported: + \li \%hx (char as hex) + \li \%hu (unsigned char) + \li \%hd (signed char) + \li \%c (character) + \li \%u (unsigned int) + \li \%d (signed int) + \li \%x (unsigned int as hex) + \li \%s (string) + + Warning: to correctly pass chars for printing as chars, they *must* + be explicitly re-cast as such when calling the function. + See @ref docs_chars_varargs for more details. + + Currently supported in the Emulicious emulator + */ +void EMU_printf(const char *format, ...) PRESERVES_REGS(a, b, c); +#define BGB_printf(...) EMU_printf(__VA_ARGS__) + +/** Print the string and arguments in the buffer buffer by the pointer given by format to the emulator debug message window + + @param format The format string as per printf + @param data Buffer containing arguments, for example some struct + + @see EMU_printf for the format string description + + Currently supported in the Emulicious emulator +*/ +void EMU_fmtbuf(const unsigned char * format, void * data) PRESERVES_REGS(a, b, c); + +#ifdef NINTENDO +static void * __EMU_PROFILER_INIT = &EMU_profiler_message; +#endif // NINTENDO + +/** The Emulator will break into debugger when encounters this line + */ +#define EMU_BREAKPOINT __asm__("ld b, b"); +#define BGB_BREAKPOINT EMU_BREAKPOINT + +#elif defined(__TARGET_duck) + #error Not implemented yet +#else + #error Unrecognized port +#endif + +#endif diff --git a/ext/include/gbdk/far_ptr.h b/ext/include/gbdk/far_ptr.h new file mode 100644 index 0000000..80e224d --- /dev/null +++ b/ext/include/gbdk/far_ptr.h @@ -0,0 +1,99 @@ +/** @file gbdk/far_ptr.h + + Far pointers include a segment (bank) selector so they are + able to point to addresses (functions or data) outside + of the current bank (unlike normal pointers which are not + bank-aware). + + See the `banks_farptr` example project included with gbdk. + + @todo Add link to a discussion about banking (such as, how to assign code and variables to banks) +*/ + +#ifndef __FAR_PTR_H_INCLUDE +#define __FAR_PTR_H_INCLUDE + +#include +#include + +/** Macro to obtain a far pointer at compile-time + @param ofs Memory address within the given Segment (Bank) + @param seg Segment (Bank) number + + @returns A far pointer (type @ref FAR_PTR) +*/ +#define TO_FAR_PTR(ofs, seg) (((FAR_PTR)seg << 16) | (FAR_PTR)ofs) + +/** Macro to get the Segment (Bank) number of a far pointer + @param ptr A far pointer (type @ref FAR_PTR) + + @returns Segment (Bank) of the far pointer (type uint16_t) +*/ +#define FAR_SEG(ptr) (((union __far_ptr *)&ptr)->segofs.seg) + +/** Macro to get the Offset (address) of a far pointer + @param ptr A far pointer (type @ref FAR_PTR) + + @returns Offset (address) of the far pointer (type void *) +*/ +#define FAR_OFS(ptr) (((union __far_ptr *)&ptr)->segofs.ofs) + +#define FAR_FUNC(ptr, typ) ((typ)(((union __far_ptr *)&ptr)->segfn.fn)) + +/** Macro to call a function at far pointer __ptr__ of type __typ__ + @param ptr Far pointer of a function to call (type @ref FAR_PTR) + @param typ Type to cast the function far pointer to. + @param ... VA Args list of parameters for the function + + __type__ should match the definition of the function being called. For example: + \code{.c} + // A function in bank 2 + #pragma bank 2 + uint16_t some_function(uint16_t param1, uint16_t param2) __banked { return 1; }; + + ... + // Code elsewhere, such as unbanked main() + // This type declaration should match the above function + typedef uint16_t (*some_function_t)(uint16_t, uint16_t) __banked; + + // Using FAR_CALL() with the above as *ptr*, *typ*, and two parameters. + result = FAR_CALL(some_function, some_function_t, 100, 50); + \endcode + + @returns Value returned by the function (if present) +*/ +#define FAR_CALL(ptr, typ, ...) (__call_banked_ptr=ptr,((typ)(&__call__banked))(__VA_ARGS__)) + +/** Type for storing a FAR_PTR +*/ +typedef uint32_t FAR_PTR; + +/** Union for working with members of a FAR_PTR +*/ +union __far_ptr { + FAR_PTR ptr; + struct { + void * ofs; + uint16_t seg; + } segofs; + struct { + void (*fn)(void); + uint16_t seg; + } segfn; +}; + +extern volatile FAR_PTR __call_banked_ptr; +extern volatile void * __call_banked_addr; +extern volatile uint8_t __call_banked_bank; + +void __call__banked(void); + +/** Obtain a far pointer at runtime + @param ofs Memory address within the given Segment (Bank) + @param seg Segment (Bank) number + + @returns A far pointer (type @ref FAR_PTR) +*/ +uint32_t to_far_ptr(void* ofs, uint16_t seg); + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/font.h b/ext/include/gbdk/font.h new file mode 100644 index 0000000..8b90f1c --- /dev/null +++ b/ext/include/gbdk/font.h @@ -0,0 +1,78 @@ +/** @file gbdk/font.h + Multiple font support for the GameBoy + Michael Hope, 1999 + michaelh@earthling.net +*/ +#ifndef __FONT_H +#define __FONT_H + +#include +#include + +/** Various flags in the font header. + */ +#define FONT_256ENCODING 0 +#define FONT_128ENCODING 1 +#define FONT_NOENCODING 2 + +#define FONT_COMPRESSED 4 + +/* See gb.h/M_NO_SCROLL and gb.h/M_NO_INTERP */ + +/** font_t is a handle to a font loaded by font_load(). + It can be used with @ref font_set() */ +typedef uint16_t font_t; + + +/*! \defgroup gbdk_fonts List of gbdk fonts + @{ +*/ + +/** The default fonts */ +extern uint8_t font_spect[], font_italic[], font_ibm[], font_min[]; + +/** Backwards compatible font */ +extern uint8_t font_ibm_fixed[]; + + /*! @} End of gbdk_fonts */ + + +/** Initializes the font system. + Should be called before other font functions. + */ +void font_init(void); + +/** Load a font and set it as the current font. + @param font Pointer to a font to load (usually a gbdk font) + + @return Handle to the loaded font, which can be used with @ref font_set() + @see font_init(), font_set(), gbdk_fonts + */ +font_t font_load(void *font) OLDCALL; + +/** Set the current font. + @param font_handle handle of a font returned by @ref font_load() + + @return The previously used font handle. + @see font_init(), font_load() +*/ +font_t font_set(font_t font_handle) OLDCALL; + +/* Use mode() and color() to set the font modes and colours */ + +/** Internal representation of a font. + What a font_t really is */ +typedef struct sfont_handle mfont_handle; +typedef struct sfont_handle *pmfont_handle; + +/** Font handle structure +*/ +struct sfont_handle { + uint8_t first_tile; /**< First tile used for font */ + void *font; /**< Pointer to the base of the font */ +}; + +/** Set the current __foreground__ colour (for pixels), __background__ colour */ +void font_color(uint8_t forecolor, uint8_t backcolor) OLDCALL; + +#endif /* __FONT_H */ diff --git a/ext/include/gbdk/gbdecompress.h b/ext/include/gbdk/gbdecompress.h new file mode 100644 index 0000000..5865dd2 --- /dev/null +++ b/ext/include/gbdk/gbdecompress.h @@ -0,0 +1,12 @@ +#ifndef __GB_DECOMPRESS_H_INCLUDE +#define __GB_DECOMPRESS_H_INCLUDE + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) + #include +#elif defined(__TARGET_sms) || defined(__TARGET_gg) + #include +#else + #error Unrecognized port +#endif + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/gbdk-lib.h b/ext/include/gbdk/gbdk-lib.h new file mode 100644 index 0000000..cb0877f --- /dev/null +++ b/ext/include/gbdk/gbdk-lib.h @@ -0,0 +1,28 @@ +/** @file gbdk/gbdk-lib.h + Settings for the greater library system. +*/ +#ifndef GBDK_LIB_INCLUDE +#define GBDK_LIB_INCLUDE + +#if defined(__PORT_sm83) + #include +#elif defined(__PORT_z80) + #include +#elif defined(__PORT_mos6502) + #include +#else + #error Unrecognized port +#endif + + +#ifndef USE_C_MEMCPY +#define USE_C_MEMCPY 1 +#endif +#ifndef USE_C_STRCPY +#define USE_C_STRCPY 1 +#endif +#ifndef USE_C_STRCMP +#define USE_C_STRCMP 1 +#endif + +#endif diff --git a/ext/include/gbdk/incbin.h b/ext/include/gbdk/incbin.h new file mode 100644 index 0000000..f4891f0 --- /dev/null +++ b/ext/include/gbdk/incbin.h @@ -0,0 +1,88 @@ +/** @file gbdk/incbin.h + + Allows binary data from other files to be included + into a C source file. + + It is implemented using asm .incbin and macros. + + See the `incbin` example project for a demo of how to use it. +*/ +#ifndef _INCBIN_H +#define _INCBIN_H + +#include + + +/** Creates extern entries for accessing a INCBIN() generated + variable and it's size in another source file. + + @param VARNAME Name of the variable used with INCBIN + + An entry is created for the variable and it's size variable. + + @ref INCBIN(), INCBIN_SIZE() +*/ +#define INCBIN_EXTERN(VARNAME) extern const uint8_t VARNAME[]; \ +extern const void __size_ ## VARNAME; \ +extern const void __bank_ ## VARNAME; + +/** Obtains the __size in bytes__ of the INCBIN() generated data + + @param VARNAME Name of the variable used with INCBIN + + Requires @ref INCBIN_EXTERN() to have been called earlier in the source file + + @ref INCBIN(), INCBIN_EXTERN() +*/ +#define INCBIN_SIZE(VARNAME) ( (uint16_t) & __size_ ## VARNAME ) + +/** Obtains the __bank number__ of the INCBIN() generated data + + @param VARNAME Name of the variable used with INCBIN + + Requires @ref INCBIN_EXTERN() to have been called earlier in the source file + + @ref INCBIN(), INCBIN_EXTERN() +*/ +#ifndef BANK +#define BANK(VARNAME) ( (uint8_t) & __bank_ ## VARNAME ) +#endif + +/** Includes binary data into a C source file + + @param VARNAME Variable name to use + @param FILEPATH Path to the file which will be binary included into the C source file + + __filepath__ is relative to the working directory of the tool + that is calling it (often a makefile's working directory), __NOT__ + to the file it's being included into. + + The variable name is not modified and can be used as-is. + + The INCBIN() macro will declare the @ref BANK() and @ref INCBIN_SIZE() + helper symbols. Then if @ref INCBIN_EXTERN() is used in the header then + those helper macros can be used in the application code. + - @ref INCBIN_SIZE() for obtaining the size of the included data. + - @ref BANK() for obtaining the bank number of the included data. + + Use @ref INCBIN_EXTERN() within another source file + to make the variable and it's data accessible there. + +============== + +*/ +#define INCBIN(VARNAME, FILEPATH) void __func_ ## VARNAME(void) __banked __naked { \ +__asm \ +_ ## VARNAME:: \ +1$: \ + .incbin FILEPATH \ +2$: \ + ___size_ ## VARNAME = (2$-1$) \ + .globl ___size_ ## VARNAME \ + .local b___func_ ## VARNAME \ + ___bank_ ## VARNAME = b___func_ ## VARNAME \ + .globl ___bank_ ## VARNAME \ +__endasm; \ +} + +#endif // _INCBIN_H \ No newline at end of file diff --git a/ext/include/gbdk/metasprites.h b/ext/include/gbdk/metasprites.h new file mode 100644 index 0000000..a174d66 --- /dev/null +++ b/ext/include/gbdk/metasprites.h @@ -0,0 +1,16 @@ +#ifndef __PLAT_METASPRITES_H_INVCLUDE +#define __PLAT_METASPRITES_H_INVCLUDE + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) + #include +#elif defined(__TARGET_sms) || defined(__TARGET_gg) + #include +#elif defined(__TARGET_msxdos) + #include +#elif defined(__TARGET_nes) + #include +#else + #error Unrecognized port +#endif + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/platform.h b/ext/include/gbdk/platform.h new file mode 100644 index 0000000..c8deb78 --- /dev/null +++ b/ext/include/gbdk/platform.h @@ -0,0 +1,18 @@ +#ifndef __PLATFORM_H_INCLUDE +#define __PLATFORM_H_INCLUDE + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) + #include + #include + #include +#elif defined(__TARGET_sms) || defined(__TARGET_gg) + #include +#elif defined(__TARGET_msxdos) + #include +#elif defined(__TARGET_nes) + #include +#else + #error Unrecognized port +#endif + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/rledecompress.h b/ext/include/gbdk/rledecompress.h new file mode 100644 index 0000000..6cb0816 --- /dev/null +++ b/ext/include/gbdk/rledecompress.h @@ -0,0 +1,48 @@ +/** @file gbdk/rledecompress.h + + Decompressor for RLE encoded data + + Decompresses data which has been compressed with + @ref utility_gbcompress "gbcompress" using the `--alg=rle` argument. +*/ + +#ifndef __RLEDECOMPRESS_H_INCLUDE +#define __RLEDECOMPRESS_H_INCLUDE + +#include +#include + +#define RLE_STOP 0 + +#if defined(__TARGET_gb) || defined(__TARGET_ap) || defined(__TARGET_duck) || defined(__TARGET_nes) +/** Initialize the RLE decompressor with RLE data at address __data__ + + @param data Pointer to start of RLE compressed data + + @see rle_decompress + */ +uint8_t rle_init(void * data); + +/** Decompress RLE compressed data into __dest__ for length __len__ bytes + + @param dest Pointer to destination buffer/address + @param len Number of bytes to decompress + @return Returns `0` if compression is complete, `1` if there is more data to decompress + + Before calling this function @ref rle_init must be called + one time to initialize the RLE decompressor. + + Decompresses data which has been compressed with + @ref utility_gbcompress "gbcompress" using the `--alg=rle` argument. + + @see rle_init + */ +uint8_t rle_decompress(void * dest, uint8_t len); +#elif defined(__TARGET_sms) || defined(__TARGET_gg) +uint8_t rle_init(void * data) Z88DK_FASTCALL; +uint8_t rle_decompress(void * dest, uint8_t len) Z88DK_CALLEE; +#else + #error Unrecognized port +#endif + +#endif \ No newline at end of file diff --git a/ext/include/gbdk/version.h b/ext/include/gbdk/version.h new file mode 100644 index 0000000..f6d075d --- /dev/null +++ b/ext/include/gbdk/version.h @@ -0,0 +1,6 @@ +#ifndef __VERSION_H_INCLUDE__ +#define __VERSION_H_INCLUDE__ + +#define __GBDK_VERSION 430 + +#endif diff --git a/ext/include/limits.h b/ext/include/limits.h new file mode 100644 index 0000000..5cadc13 --- /dev/null +++ b/ext/include/limits.h @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------- + limits.h - ANSI defines constants for sizes of integral types + + Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef __SDC51_LIMITS_H +#define __SDC51_LIMITS_H 1 + +#define CHAR_BIT 8 /* bits in a char */ +#define SCHAR_MAX 127 +#define SCHAR_MIN -128 +#define UCHAR_MAX 0xff + +#ifdef __SDCC_CHAR_UNSIGNED +#define CHAR_MAX UCHAR_MAX +#define CHAR_MIN 0 +#else +#define CHAR_MAX SCHAR_MAX +#define CHAR_MIN SCHAR_MIN +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199409L +#define MB_LEN_MAX 4 +#endif + +#define INT_MIN (-32767 - 1) +#define INT_MAX 32767 +#define SHRT_MAX INT_MAX +#define SHRT_MIN INT_MIN +#define UINT_MAX 0xffff +#define UINT_MIN 0 +#define USHRT_MAX UINT_MAX +#define USHRT_MIN UINT_MIN +#define LONG_MIN (-2147483647L-1) +#define LONG_MAX 2147483647L +#define ULONG_MAX 0xffffffff +#define ULONG_MIN 0 + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define LLONG_MIN (-9223372036854775807LL-1) +#define LLONG_MAX 9223372036854775807LL +#define ULLONG_MAX 18446744073709551615ULL +#endif + +#endif + diff --git a/ext/include/msx/hardware.h b/ext/include/msx/hardware.h new file mode 100644 index 0000000..ecaa01e --- /dev/null +++ b/ext/include/msx/hardware.h @@ -0,0 +1,161 @@ +/** @file msx/hardware.h + Defines that let the MSX hardware registers be accessed + from C. +*/ +#ifndef _HARDWARE_H +#define _HARDWARE_H + +#include + +#define __BYTES extern UBYTE +#define __BYTE_REG extern volatile UBYTE + +static volatile SFR AT(0x7E) VCOUNTER; + +static volatile SFR AT(0x7F) PSG; + +#define PSG_LATCH 0x80 + +#define PSG_CH0 0b00000000 +#define PSG_CH1 0b00100000 +#define PSG_CH2 0b01000000 +#define PSG_CH3 0b01100000 + +#define PSG_VOLUME 0b00010000 + +static volatile SFR AT(0x7F) HCOUNTER; + +static volatile SFR AT(0x98) VDP_DATA; +static volatile SFR AT(0x99) VDP_CMD; +static volatile SFR AT(0x99) VDP_STATUS; + +#define STATF_INT_VBL 0b10000000 +#define STATF_9_SPR 0b01000000 +#define STATF_SPR_COLL 0b00100000 + +#define VDP_REG_MASK 0b10000000 +#define VDP_R0 0b10000000 +extern UBYTE shadow_VDP_R0; + +#define R0_DEFAULT 0b00000000 +#define R0_CB_OUTPUT 0b00000000 +#define R0_CB_INPUT 0b01000000 +#define R0_IE2_OFF 0b00000000 +#define R0_IE2 0b00100000 +#define R0_IE1_OFF 0b00000000 +#define R0_IE1 0b00010000 +#define R0_SCR_MODE1 0b00000000 +#define R0_SCR_MODE2 0b00000010 +#define R0_SCR_MODE3 0b00000100 +#define R0_ES_OFF 0b00000000 +#define R0_ES 0b00000001 + +#define VDP_R1 0b10000001 +extern UBYTE shadow_VDP_R1; + +#define R1_DEFAULT 0b10000000 +#define R1_DISP_OFF 0b00000000 +#define R1_DISP_ON 0b01000000 +#define R1_IE_OFF 0b00000000 +#define R1_IE 0b00100000 +#define R1_SCR_MODE1 0b00010000 +#define R1_SCR_MODE2 0b00000000 +#define R1_SCR_MODE3 0b00000000 +#define R1_SPR_8X8 0b00000000 +#define R1_SPR_16X16 0b00000010 +#define R1_SPR_MAG 0b00000001 +#define R1_SPR_MAG_OFF 0b00000000 + +#define VDP_R2 0b10000010 +extern UBYTE shadow_VDP_R2; + +#define R2_MAP_0x3800 0xFF +#define R2_MAP_0x3000 0xFD +#define R2_MAP_0x2800 0xFB +#define R2_MAP_0x2000 0xF9 +#define R2_MAP_0x1800 0xF7 +#define R2_MAP_0x1000 0xF5 +#define R2_MAP_0x0800 0xF3 +#define R2_MAP_0x0000 0xF1 + +#define VDP_R3 0b10000011 +extern UBYTE shadow_VDP_R3; +#define VDP_R4 0b10000100 +extern UBYTE shadow_VDP_R4; +#define VDP_R5 0b10000101 +extern UBYTE shadow_VDP_R5; + +#define R5_SAT_0x3F00 0xFF +#define R5_SAT_MASK 0b10000001 + +#define VDP_R6 0b10000110 +extern UBYTE shadow_VDP_R6; + +#define R6_BANK0 0xFB +#define R6_DATA_0x0000 0xFB +#define R6_BANK1 0xFF +#define R6_DATA_0x2000 0xFF + +#define VDP_R7 0b10000111 +extern UBYTE shadow_VDP_R7; +#define VDP_RBORDER 0b10000111 +extern UBYTE shadow_VDP_RBORDER; + +#define R7_COLOR_MASK 0b11110000 + +#define VDP_R8 0b10001000 +extern UBYTE shadow_VDP_R8; +#define VDP_RSCX 0b10001000 +extern UBYTE shadow_VDP_RSCX; + +#define VDP_R9 0b10001001 +extern UBYTE shadow_VDP_R9; +#define VDP_RSCY 0b10001001 +extern UBYTE shadow_VDP_RSCY; + +#define VDP_R10 0b10001010 +extern UBYTE shadow_VDP_R10; + +#define R10_INT_OFF 0xFF +#define R10_INT_EVERY 0x00 + +static volatile SFR AT(0xF0) FMADDRESS; +static volatile SFR AT(0xF1) FMDATA; +static volatile SFR AT(0xF2) AUDIOCTRL; + +static volatile SFR AT(0xfc) MAP_FRAME0; +static volatile SFR AT(0xfd) MAP_FRAME1; +static volatile SFR AT(0xfe) MAP_FRAME2; +static volatile SFR AT(0xff) MAP_FRAME3; + +extern const UBYTE _SYSTEM; + +#define SYSTEM_PAL 0x00 +#define SYSTEM_NTSC 0x01 + +extern volatile UBYTE VDP_ATTR_SHIFT; + +#define VBK_TILES 0 +#define VBK_ATTRIBUTES 1 + +#define VDP_SAT_TERM 0xD0 + +#if defined(__TARGET_msxdos) +#define DEVICE_SCREEN_X_OFFSET 0 +#define DEVICE_SCREEN_Y_OFFSET 0 +#define DEVICE_SCREEN_WIDTH 32 +#define DEVICE_SCREEN_HEIGHT 24 +#define DEVICE_SCREEN_BUFFER_WIDTH 32 +#define DEVICE_SCREEN_BUFFER_HEIGHT 28 +#define DEVICE_SCREEN_MAP_ENTRY_SIZE 2 +#define DEVICE_SPRITE_PX_OFFSET_X 0 +#define DEVICE_SPRITE_PX_OFFSET_Y -1 +#define DEVICE_WINDOW_PX_OFFSET_X 0 +#define DEVICE_WINDOW_PX_OFFSET_Y 0 +#else +#error Unrecognized port +#endif +#define DEVICE_SCREEN_PX_WIDTH (DEVICE_SCREEN_WIDTH * 8) +#define DEVICE_SCREEN_PX_HEIGHT (DEVICE_SCREEN_HEIGHT * 8) + +#endif diff --git a/ext/include/msx/metasprites.h b/ext/include/msx/metasprites.h new file mode 100644 index 0000000..832c4cb --- /dev/null +++ b/ext/include/msx/metasprites.h @@ -0,0 +1,109 @@ +/** @file sms/metasprites.h + + # Metasprite support + + A metasprite is a larger sprite made up from a + collection of smaller individual hardware sprites. + Different frames of the same metasprites can share + tile data. + + See the main @ref metasprite_main_docs "metasprite docs" + under the game Boy platform for additional details. +*/ + +#ifndef _METASPRITES_H_INCLUDE +#define _METASPRITES_H_INCLUDE + +#include +#include +#include + +/** Metasprite sub-item structure + @param dy (int8_t) Y coordinate of the sprite relative to the metasprite origin (pivot) + @param dx (int8_t) X coordinate of the sprite relative to the metasprite origin (pivot) + @param dtile (uint8_t) Start tile relative to the metasprites own set of tiles + @param props (uint8_t) Property Flags + + Metasprites are built from multiple metasprite_t items (one for each sub-sprite) + and a pool of tiles they reference. If a metasprite has multiple frames then each + frame will be built from some number of metasprite_t items (which may vary based + on how many sprites are required for that particular frame). + + A metasprite frame is terminated with a {metasprite_end} entry. +*/ +typedef struct metasprite_t { + int8_t dy, dx; + uint8_t dtile; + uint8_t props; +} metasprite_t; + +#define metasprite_end -128 +#define METASPR_ITEM(dy,dx,dt,a) {(dy),(dx),(dt),(a)} +#define METASPR_TERM {metasprite_end} + +extern const void * __current_metasprite; +extern uint8_t __current_base_tile; +extern uint8_t __render_shadow_OAM; + + +static uint8_t __move_metasprite(uint8_t id, uint8_t x, uint8_t y) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl); +static void __hide_metasprite(uint8_t id) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl); + +/** + * Hides all hardware sprites in range from <= X < to + * @param from start OAM index + * @param to finish OAM index + */ +void hide_sprites_range(uint8_t from, uint8_t to) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl); + +/** Moves metasprite to the absolute position x and y + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (unused on this platform) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Moves __metasprite__ to the absolute position __x__ and __y__ + (with __no flip__ on the X or Y axis). Hardware sprites are + allocated starting from __base_sprite__, using tiles + starting from __base_tile__. + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + @return Number of hardware sprites used to draw this metasprite + */ +inline uint8_t move_metasprite_ex(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint8_t x, uint8_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite(base_sprite, x, y); +} + +/** Obsolete +*/ +inline uint8_t move_metasprite(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint8_t x, uint8_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite(base_sprite, x, y); +} + + +/** Hides a metasprite from the screen + + @param metasprite Pointer to first struct of the desired metasprite frame + @param base_sprite Number of hardware sprite to start with + + Sets: + \li __current_metasprite = metasprite; + + **/ +inline void hide_metasprite(const metasprite_t * metasprite, uint8_t base_sprite) { + __current_metasprite = metasprite; + __hide_metasprite(base_sprite); +} + +#endif diff --git a/ext/include/msx/msx.h b/ext/include/msx/msx.h new file mode 100644 index 0000000..b214c64 --- /dev/null +++ b/ext/include/msx/msx.h @@ -0,0 +1,832 @@ +/** @file msx/msx.h + MSX specific functions. +*/ +#ifndef _MSX_H +#define _MSX_H + +#include +#include +#include +#include + +#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; + +/** 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 */ diff --git a/ext/include/nes/bcd.h b/ext/include/nes/bcd.h new file mode 100644 index 0000000..4f3f004 --- /dev/null +++ b/ext/include/nes/bcd.h @@ -0,0 +1,61 @@ +#ifndef __BCD_H_INCLUDE +#define __BCD_H_INCLUDE + +#include +#include + +/** @file bcd.h + Support for working with BCD (Binary Coded Decimal) + + See the example BCD project for additional details. +*/ + +// macro for creating BCD constants +#define BCD_HEX(v) ((BCD)(v)) + +/** Converts an integer value into BCD format + + A maximum of 8 digits may be used +*/ +#define MAKE_BCD(v) BCD_HEX(0x ## v) + +typedef uint32_t BCD; + +/** Converts integer __i__ into BCD format (Binary Coded Decimal) + @param i Numeric value to convert + @param value Pointer to a BCD variable to store the converted result +*/ +void uint2bcd(uint16_t i, BCD * value) OLDCALL; + +/** Adds two numbers in BCD format: __sour__ += __value__ + @param sour Pointer to a BCD value to add to (and where the result is stored) + @param value Pointer to the BCD value to add to __sour__ +*/ +void bcd_add(BCD * sour, const BCD * value) OLDCALL; + +/** Subtracts two numbers in BCD format: __sour__ -= __value__ + @param sour Pointer to a BCD value to subtract from (and where the result is stored) + @param value Pointer to the BCD value to subtract from __sour__ +*/ +void bcd_sub(BCD * sour, const BCD * value) OLDCALL; + +/** Convert a BCD number into an asciiz (null terminated) string and return the length + @param bcd Pointer to BCD value to convert + @param tile_offset Optional per-character offset value to add (use 0 for none) + @param buffer Buffer to store the result in + + Returns: Length in characters (always 8) + + __buffer__ should be large enough to store the converted string + (9 bytes: 8 characters + 1 for terminator) + + There are a couple different ways to use __tile_offset__. + For example: + \li It can be the Index of the Font Tile '0' in VRAM to + allow the buffer to be used directly with @ref set_bkg_tiles. + \li It can also be set to the ascii value for character '0' + so that the buffer is a normal string that can be passed to @ref printf. +*/ +uint8_t bcd2text(const BCD * bcd, uint8_t tile_offset, uint8_t * buffer) OLDCALL; + +#endif diff --git a/ext/include/nes/hardware.h b/ext/include/nes/hardware.h new file mode 100644 index 0000000..330b88d --- /dev/null +++ b/ext/include/nes/hardware.h @@ -0,0 +1,59 @@ +/** @file nes/hardware.h + Defines that let the NES hardware registers be accessed + from C. +*/ +#ifndef _HARDWARE_H +#define _HARDWARE_H + +#include + +#define __SHADOW_REG extern volatile uint8_t +#define __REG(addr) volatile __at (addr) uint8_t + +__REG(0x2000) PPUCTRL; +#define PPUCTRL_NMI 0b10000000 +#define PPUCTRL_SPR_8X8 0b00000000 +#define PPUCTRL_SPR_8X16 0b00100000 +#define PPUCTRL_BG_CHR 0b00010000 +#define PPUCTRL_SPR_CHR 0b00001000 +#define PPUCTRL_INC32 0b00000100 +__SHADOW_REG shadow_PPUCTRL; + +__REG(0x2001) PPUMASK; +#define PPUMASK_BLUE 0b10000000 +#define PPUMASK_RED 0b01000000 +#define PPUMASK_GREEN 0b00100000 +#define PPUMASK_SHOW_SPR 0b00010000 +#define PPUMASK_SHOW_BG 0b00001000 +#define PPUMASK_SHOW_SPR_LC 0b00000100 +#define PPUMASK_SHOW_BG_LC 0b00000010 +#define PPUMASK_MONOCHROME 0b00000001 +__SHADOW_REG shadow_PPUMASK; + +__REG(0x2002) PPUSTATUS; +__REG(0x2003) OAMADDR; +__REG(0x2004) OAMDATA; +__REG(0x2005) PPUSCROLL; +__REG(0x2006) PPUADDR; +__REG(0x2007) PPUDATA; +__REG(0x4014) OAMDMA; + +#define DEVICE_SCREEN_X_OFFSET 0 +#define DEVICE_SCREEN_Y_OFFSET 0 +#define DEVICE_SCREEN_WIDTH 32 +#define DEVICE_SCREEN_HEIGHT 30 +#define DEVICE_SCREEN_BUFFER_WIDTH 32 +#define DEVICE_SCREEN_BUFFER_HEIGHT 30 +#define DEVICE_SCREEN_MAP_ENTRY_SIZE 1 +#define DEVICE_SPRITE_PX_OFFSET_X 0 +#define DEVICE_SPRITE_PX_OFFSET_Y -1 +#define DEVICE_WINDOW_PX_OFFSET_X 0 +#define DEVICE_WINDOW_PX_OFFSET_Y 0 +#define DEVICE_SCREEN_PX_WIDTH (DEVICE_SCREEN_WIDTH * 8) +#define DEVICE_SCREEN_PX_HEIGHT (DEVICE_SCREEN_HEIGHT * 8) + +// Scrolling coordinates (will be written to PPUSCROLL at end-of-vblank by NMI handler) +__SHADOW_REG bkg_scroll_x; +__SHADOW_REG bkg_scroll_y; + +#endif diff --git a/ext/include/nes/metasprites.h b/ext/include/nes/metasprites.h new file mode 100644 index 0000000..03fd4c2 --- /dev/null +++ b/ext/include/nes/metasprites.h @@ -0,0 +1,238 @@ +/** @file nes/metasprites.h + + # Metasprite support + + A metasprite is a larger sprite made up from a + collection of smaller individual hardware sprites. + Different frames of the same metasprites can share + tile data. + + See the main @ref metasprite_main_docs "metasprite docs" + under the game Boy platform for additional details. +*/ + +#ifndef _METASPRITES_H_INCLUDE +#define _METASPRITES_H_INCLUDE + +#include +#include +#include + +/** Metasprite sub-item structure + @param dy (int8_t) Y coordinate of the sprite relative to the metasprite origin (pivot) + @param dx (int8_t) X coordinate of the sprite relative to the metasprite origin (pivot) + @param dtile (uint8_t) Start tile relative to the metasprites own set of tiles + @param props (uint8_t) Property Flags + + Metasprites are built from multiple metasprite_t items (one for each sub-sprite) + and a pool of tiles they reference. If a metasprite has multiple frames then each + frame will be built from some number of metasprite_t items (which may vary based + on how many sprites are required for that particular frame). + + A metasprite frame is terminated with a {metasprite_end} entry. +*/ +typedef struct metasprite_t { + int8_t dy, dx; + uint8_t dtile; + uint8_t props; +} metasprite_t; + +#define metasprite_end -128 +#define METASPR_ITEM(dy,dx,dt,a) {(dy),(dx),(dt),(a)} +#define METASPR_TERM {metasprite_end} + +extern const void * __current_metasprite; +extern uint8_t __current_base_tile; +extern uint8_t __current_base_prop; +extern uint8_t __render_shadow_OAM; + + +static uint8_t __move_metasprite(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_flipx(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_flipy(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_flipxy(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_vflip(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_hflip(uint8_t id, int16_t x, int16_t y) OLDCALL; +static uint8_t __move_metasprite_hvflip(uint8_t id, int16_t x, int16_t y) OLDCALL; +static void __hide_metasprite(uint8_t id) OLDCALL; + +/** + * Hides all hardware sprites in range from <= X < to + * @param from start OAM index + * @param to finish OAM index + */ +void hide_sprites_range(uint8_t from, uint8_t to) OLDCALL; + +/** Moves metasprite to the absolute position x and y + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Moves __metasprite__ to the absolute position __x__ and __y__ + (with __no flip__ on the X or Y axis). Hardware sprites are + allocated starting from __base_sprite__, using tiles + starting from __base_tile__. + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + */ +inline uint8_t move_metasprite_ex(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, int16_t x, int16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite(base_sprite, x, y); +} + +/** Obsolete. Replaced by move_metasprite_ex() +*/ +inline uint8_t move_metasprite(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, int16_t x, int16_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite(base_sprite, x, y); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X (horizontally)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X (horizontally). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipx(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, int16_t x, int16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipx(base_sprite, x - 8, y); +} + +/** Obsolete. Replaced by move_metasprite_flipx() +*/ +inline uint8_t move_metasprite_vflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, int16_t x, int16_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_vflip(base_sprite, x - 8, y); +} + + +/** Moves metasprite to the absolute position x and y, __flipped by Y (vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by Y (vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, int16_t x, int16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipy(base_sprite, x, y - ((shadow_PPUCTRL & PPUCTRL_SPR_8X16) ? 16 : 8) ); +} + +/** Obsolete. Replaced by move_metasprite_flipy() +*/ +inline uint8_t move_metasprite_hflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, int16_t x, int16_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_hflip(base_sprite, x, y - ((shadow_PPUCTRL & PPUCTRL_SPR_8X16) ? 16 : 8) ); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X and Y (horizontally and vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X and Y (horizontally and vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipxy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, int16_t x, int16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = base_prop; + return __move_metasprite_flipxy(base_sprite, x - 8, y - ((shadow_PPUCTRL & PPUCTRL_SPR_8X16) ? 16 : 8)); +} + +/** Obsolete. Replaced by move_metasprite_flipxy() +*/ +inline uint8_t move_metasprite_hvflip(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, int16_t x, int16_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + __current_base_prop = 0; + return __move_metasprite_hvflip(base_sprite, x - 8, y - ((shadow_PPUCTRL & PPUCTRL_SPR_8X16) ? 16 : 8)); +} + +/** Hides a metasprite from the screen + + @param metasprite Pointer to first struct of the desired metasprite frame + @param base_sprite Number of hardware sprite to start with + + Sets: + \li __current_metasprite = metasprite; + + **/ +inline void hide_metasprite(const metasprite_t * metasprite, uint8_t base_sprite) { + __current_metasprite = metasprite; + __hide_metasprite(base_sprite); +} + +#endif diff --git a/ext/include/nes/nes.h b/ext/include/nes/nes.h new file mode 100644 index 0000000..248faa4 --- /dev/null +++ b/ext/include/nes/nes.h @@ -0,0 +1,1253 @@ +/** @file nes/nes.h + NES specific functions. +*/ +#ifndef _NES_H +#define _NES_H + +#include +#include +#include +#include +#include + +#define NINTENDO_NES + +// Here NINTENDO means Game Boy & related clones +#ifdef NINTENDO +#undef NINTENDO +#endif + +#ifdef SEGA +#undef SEGA +#endif + +#ifdef MSX +#undef MSX +#endif + +#define SYSTEM_BITS_NTSC 0x00 +#define SYSTEM_BITS_PAL 0x40 +#define SYSTEM_BITS_DENDY 0x80 +extern const uint8_t _SYSTEM; + +#define SYSTEM_60HZ 0x00 +#define SYSTEM_50HZ 0x01 + +#define RGB(r,g,b) RGB_TO_NES(((r) | ((g) << 2) | ((b) << 4))) +#define RGB8(r,g,b) RGB_TO_NES((((r) >> 6) | (((g) >> 6) << 2) | (((b) >> 6) << 4))) +#define RGBHTML(RGB24bit) RGB_TO_NES((((RGB24bit) >> 22) | ((((RGB24bit) & 0xFFFF) >> 14) << 2) | ((((RGB24bit) & 0xFF) >> 6) << 4))) + +/** Common colors based on the EGA default palette. + * + * Manually entered from https://www.nesdev.org/wiki/PPU_palettes#RGBI + * + */ +#define RGB_RED 0x16 // EGA12 +#define RGB_DARKRED 0x06 // EGA4 +#define RGB_GREEN 0x2A // EGA10 +#define RGB_DARKGREEN 0x1A // EGA2 +#define RGB_BLUE 0x12 // EGA9 +#define RGB_DARKBLUE 0x02 // EGA1 +#define RGB_YELLOW 0x28 // EGA14 +#define RGB_DARKYELLOW 0x18 // EGA6 +#define RGB_CYAN 0x2C // EGA11 +#define RGB_AQUA 0x1C // EGA3 +#define RGB_PINK 0x24 // EGA13 +#define RGB_PURPLE 0x14 // EGA5 +#define RGB_BLACK 0x0F // EGA0 +#define RGB_DARKGRAY 0x00 // EGA8 +#define RGB_LIGHTGRAY 0x10 // EGA7 +#define RGB_WHITE 0x30 // EGA15 + +typedef uint8_t palette_color_t; + +void set_bkg_palette(uint8_t first_palette, uint8_t nb_palettes, const palette_color_t *rgb_data) NO_OVERLAY_LOCALS; + +void set_sprite_palette(uint8_t first_palette, uint8_t nb_palettes, const palette_color_t *rgb_data) NO_OVERLAY_LOCALS; + +void set_bkg_palette_entry(uint8_t palette, uint8_t entry, palette_color_t rgb_data) NO_OVERLAY_LOCALS; + +void set_sprite_palette_entry(uint8_t palette, uint8_t entry, palette_color_t rgb_data) NO_OVERLAY_LOCALS; + +/** 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 0x08U +#define J_DOWN 0x04U +#define J_LEFT 0x02U +#define J_RIGHT 0x01U +#define J_A 0x80U +#define J_B 0x40U +#define J_SELECT 0x20U +#define J_START 0x10U + +/** Screen modes. + Normally used by internal functions only. + @see mode() + */ +#define M_DRAWING 0x01U +#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 + +/** If this is set, sprite colours come from OBJ1PAL. Else + they come from OBJ0PAL + @see set_sprite_prop(). +*/ +#define S_PALETTE 0x10U +/** If set the sprite will be flipped horizontally. + @see set_sprite_prop() + */ +#define S_FLIPX 0x40U +/** If set the sprite will be flipped vertically. + @see set_sprite_prop() + */ +#define S_FLIPY 0x80U +/** If this bit is clear, then the sprite will be displayed + on top of the background and window. + @see set_sprite_prop() +*/ +#define S_PRIORITY 0x20U +/** Defines how palette number is encoded in OAM. + Required for the png2asset tool's metasprite output. +*/ +#define S_PAL(n) n + +/* DMG Palettes */ +#define DMG_BLACK 0x03 +#define DMG_DARK_GRAY 0x02 +#define DMG_LITE_GRAY 0x01 +#define DMG_WHITE 0x00 +/** Macro to create a DMG palette from 4 colors + + @param C0 Color for Index 0 + @param C1 Color for Index 1 + @param C2 Color for Index 2 + @param C3 Color for Index 3 + + The resulting format is four greyscale colors + packed into a single unsigned byte. + + Example: + \code{.c} + REG_BGP = DMG_PALETTE(DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE); + \endcode + + @see OBP0_REG, OBP1_REG, BGP_REG + @see DMG_BLACK, DMG_DARK_GRAY, DMG_LITE_GRAY, DMG_WHITE + + */ +#define DMG_PALETTE(C0, C1, C2, C3) ((uint8_t)((((C3) & 0x03) << 6) | (((C2) & 0x03) << 4) | (((C1) & 0x03) << 2) | ((C0) & 0x03))) + +/* 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 + +/** Interrupt handlers + */ +typedef void (*int_handler)(void) NONBANKED; + +/** The remove functions will remove any interrupt handler. + + A handler of NULL will cause bad things + to happen if the given interrupt is enabled. + + Removes the VBL interrupt handler. @see add_VBL() +*/ +void remove_VBL(int_handler h) NO_OVERLAY_LOCALS; + +/** Removes the LCD interrupt handler. + @see add_LCD(), remove_VBL() +*/ +void remove_LCD(int_handler h) NO_OVERLAY_LOCALS; + +/** Adds a Vertical Blanking interrupt handler. + + @param h The handler to be called whenever a V-blank + interrupt occurs. + + Only a single handler is currently supported for NES. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + Those attributes are only required when constructing + a bare jump from the interrupt vector itself (such as + with @ref ISR_VECTOR()). + + ISR handlers added using add_VBL()/etc are instead + called via the GBDK ISR dispatcher which makes + the extra function attributes unecessary. + + @note The default GBDK VBL is installed automatically. + + @note On the current NES implementation, this handler + is actually faked, and called before vblank occurs, by + @ref vsync(). Writes to PPU registers should be done to + the shadow_ versions, so they are updated by the default + VBL handler only when vblank actually occurs. + + @see ISR_VECTOR() +*/ +void add_VBL(int_handler h) NO_OVERLAY_LOCALS; + +/** Adds a LCD interrupt handler. + + Called when the scanline matches the _lcd_scanline variables. + + Only a single handler is currently supported for NES. + + The use-case is to indicate to the user when the + video hardware is about to redraw a given LCD line. + This can be useful for dynamically controlling the + scrolling registers to perform special video effects. + + __Do not__ use the function definition attributes + @ref CRITICAL and @ref INTERRUPT when declaring + ISR functions added via add_VBL() (or LCD, etc). + Those attributes are only required when constructing + a bare jump from the interrupt vector itself (such as + with @ref ISR_VECTOR()). + + ISR handlers added using add_VBL()/etc are instead + called via the GBDK ISR dispatcher which makes + the extra function attributes unecessary. + + @note On the current NES implementation, this handler + is actually faked, and called by the default VBL handler + after a manual delay loop. Only one such faked "interrupt" + is possible per frame. + This means the CPU cycles wasted in the delay loop increase + with higher values of _lcd_scanline. In practice, it makes + this functionality mostly suited for a top status bar. + + @see add_VBL, nowait_int_handler, ISR_VECTOR() +*/ +void add_LCD(int_handler h) NO_OVERLAY_LOCALS; + +/** The maximum number of times the LCD handler will be called per frame. + */ +#define MAX_LCD_ISR_CALLS 4 + +/** Set the current screen mode - one of M_* modes + + Normally used by internal functions only. + + @see M_DRAWING, M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP +*/ +void mode(uint8_t m) NO_OVERLAY_LOCALS; + +/** Returns the current mode + + @see M_DRAWING, M_TEXT_OUT, M_TEXT_INOUT, M_NO_SCROLL, M_NO_INTERP +*/ +uint8_t get_mode(void) NO_OVERLAY_LOCALS; + +/** Returns the system gbdk is running on. + +*/ +inline uint8_t get_system(void) { + if(_SYSTEM == SYSTEM_BITS_NTSC) + return SYSTEM_60HZ; + else + return SYSTEM_50HZ; +} + +/** 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; + +/** Tracks current active ROM bank + + The active bank number is not tracked by @ref _current_bank when + @ref SWITCH_ROM_MBC5_8M is used. + + This variable is updated automatically when you call SWITCH_ROM_MBC1 or + SWITCH_ROM_MBC5, SWITCH_ROM(), or call a BANKED function. + + @see SWITCH_ROM_MBC1(), SWITCH_ROM_MBC5(), SWITCH_ROM() +*/ +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; + +/** Dummy macro for no-bank-switching WIP prototype + @param b ROM bank to switch to +*/ +#define SWITCH_ROM_DUMMY(b) + +/** Macro for simple UNROM-like switching (write bank# to single 8-bit register) + @param b ROM bank to switch to +*/ +#define SWITCH_ROM_UNROM(b) _switch_prg0(b) + +/** Makes default mapper switch the active ROM bank + @param b ROM bank to switch to (max 255) + + @see SWITCH_ROM_UNROM +*/ +#define SWITCH_ROM SWITCH_ROM_UNROM + +/** No-op at the moment. Placeholder for future mappers / test compatibility. + @param b SRAM bank to switch to + +*/ +#define SWITCH_RAM(b) 0 + +/** No-op at the moment. Placeholder for future mappers / test compatibility. + +*/ +#define ENABLE_RAM + +/** No-op at the moment. Placeholder for future mappers / test compatibility. + +*/ +#define DISABLE_RAM + +/** Delays the given number of milliseconds. + Uses no timers or interrupts, and can be called with + interrupts disabled + */ +void delay(uint16_t d) NO_OVERLAY_LOCALS; + +/** Reads and returns the current state of the joypad. + Return value is an OR of J_* + + When testing for multiple different buttons, it's + best to read the joypad state *once* into a variable + and then test using that variable. + + @see J_START, J_SELECT, J_A, J_B, J_UP, J_DOWN, J_LEFT, J_RIGHT +*/ +uint8_t joypad(void) NO_OVERLAY_LOCALS; + +/** Waits until at least one of the buttons given in mask are pressed. + + Normally only used for checking one key, but it will + support many, even J_LEFT at the same time as J_RIGHT. :) + + @see joypad + @see J_START, J_SELECT, J_A, J_B, J_UP, J_DOWN, J_LEFT, J_RIGHT +*/ +uint8_t waitpad(uint8_t mask) NO_OVERLAY_LOCALS; + +/** Waits for the directional pad and all buttons to be released. + +*/ +void waitpadup(void) NO_OVERLAY_LOCALS; + +/** 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) NO_OVERLAY_LOCALS; + +/** Polls all avaliable joypads + + @see joypad_init(), joypads_t +*/ +void joypad_ex(joypads_t * joypads) NO_OVERLAY_LOCALS; + + + +/** 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) { + __asm__("cli"); +} + +/** 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) { + __asm__("sei"); +} + +/** Waits for the vertical blank interrupt. + + This is often used in main loops to idle the CPU + 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. +*/ +void vsync(void) NO_OVERLAY_LOCALS; + +/** Obsolete. This function has been replaced by vsync(), which has identical behavior. +*/ +void wait_vbl_done(void) NO_OVERLAY_LOCALS; + +/** Turns the display on. + + @see DISPLAY_ON +*/ +void display_on(void) NO_OVERLAY_LOCALS; + +/** Turns the display off immediately. + @see DISPLAY_ON +*/ +void display_off(void) NO_OVERLAY_LOCALS; + +/** Copies data from shadow OAM to OAM + */ +void refresh_OAM(void) NO_OVERLAY_LOCALS; + +/** Turns the display back on. + @see display_off, DISPLAY_OFF +*/ +#define DISPLAY_ON \ + display_on(); + +/** Turns the display off immediately. + @see display_off, DISPLAY_ON +*/ +#define DISPLAY_OFF \ + display_off(); + +/** Blanks leftmost column, so it is not garbaged when you use horizontal scroll + @see SHOW_LEFT_COLUMN +*/ +#define HIDE_LEFT_COLUMN \ + shadow_PPUMASK &= ~(PPUMASK_SHOW_BG_LC | PPUMASK_SHOW_SPR_LC); \ + +/** Shows leftmost column + @see HIDE_LEFT_COLUMN +*/ +#define SHOW_LEFT_COLUMN \ + shadow_PPUMASK |= (PPUMASK_SHOW_BG_LC | PPUMASK_SHOW_SPR_LC); + +/** Does nothing for NES + not implemented yet + */ +#define SET_BORDER_COLOR(C) + +/** Turns on the background layer. + Sets bit 0 of the LCDC register to 1. +*/ +#define SHOW_BKG \ + shadow_PPUMASK |= PPUMASK_SHOW_BG; + +/** Turns off the background layer. + Sets bit 0 of the LCDC register to 0. +*/ +#define HIDE_BKG \ + shadow_PPUMASK &= ~PPUMASK_SHOW_BG; + +/** Turns on the sprites layer. + Sets bit 1 of the LCDC register to 1. +*/ +#define SHOW_SPRITES \ + shadow_PPUMASK |= PPUMASK_SHOW_SPR; + +/** Turns off the sprites layer. + Clears bit 1 of the LCDC register to 0. +*/ +#define HIDE_SPRITES \ + shadow_PPUMASK &= ~PPUMASK_SHOW_SPR; + +/** Sets sprite size to 8x16 pixels, two tiles one above the other. + Sets bit 2 of the LCDC register to 1. +*/ +#define SPRITES_8x16 \ + shadow_PPUCTRL |= PPUCTRL_SPR_8X16; + +/** Sets sprite size to 8x8 pixels, one tile. + Clears bit 2 of the LCDC register to 0. +*/ +#define SPRITES_8x8 \ + shadow_PPUCTRL &= ~PPUCTRL_SPR_8X16; + + + +/** + * 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) NO_OVERLAY_LOCALS; + +/** + * Get address of X,Y tile of background map + */ +uint8_t * get_bkg_xy_addr(uint8_t x, uint8_t y) NO_OVERLAY_LOCALS; + +#define COMPAT_PALETTE(C0,C1,C2,C3) ((uint8_t)(((C3) << 6) | ((C2) << 4) | ((C1) << 2) | (C0))) + +/** Sets palette for 2bpp color translation for GG/SMS, does nothing on GB + */ +inline void set_2bpp_palette(uint16_t palette) { + palette; +} + +extern uint16_t _current_1bpp_colors; +void set_1bpp_colors_ex(uint8_t fgcolor, uint8_t bgcolor, uint8_t mode) NO_OVERLAY_LOCALS; +inline void set_1bpp_colors(uint8_t fgcolor, uint8_t bgcolor) { + set_1bpp_colors_ex(fgcolor, bgcolor, 0); +} + +/** Sets VRAM Tile Pattern data for the Background + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. Each Tile is 16 bytes in size (8x8 pixels, 2 bits-per-pixel). + + Note: Sprite Tiles 128-255 share the same memory region as Background Tiles 128-255. + + @see set_tile_data +*/ +void set_bkg_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; +#define set_bkg_2bpp_data set_bkg_data + +/** Sets VRAM Tile Pattern data for the Background using 1bpp source data + + Similar to @ref set_bkg_data, except source data is 1 bit-per-pixel + which gets expanded into 2 bits-per-pixel. + + For a given bit that represent a pixel: + \li 0 will be expanded into color 0 + \li 1 will be expanded into color 1, 2 or 3 depending on color argument + + @see SHOW_BKG, HIDE_BKG, set_bkg_tiles +*/ +void set_bkg_1bpp_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; + +/** Sets a rectangular region of Background Tile Map. + + Entries are copied from map at __tiles__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + Use @ref set_bkg_submap() instead when: + \li Source map is wider than 32 tiles. + \li Writing a width that does not match the source map width __and__ more + than one row high at a time. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_submap, set_win_tiles, set_tiles +*/ +void set_bkg_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) NO_OVERLAY_LOCALS; +#define set_tile_map set_bkg_tiles + +/** Sets a rectangular region of Background Tile Map Attributes. + + @param x X Start position in Background Map tile coordinates. Range 0 - 15 + @param y Y Start position in Background Map tile coordinates. Range 0 - 14 + @param w Width of area to set in tiles. Range 1 - 16 + @param h Height of area to set in tiles. Range 1 - 15 + @param attributes Pointer to source tile map attribute data + + Entries are copied from map at __tiles__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + NES 16x16 Tile Attributes are tightly packed into 4 attributes per byte, + with each 16x16 area of a 32x32 pixel block using the bits as follows: + D1-D0: Top-left 16x16 pixels + D3-D2: Top-right 16x16 pixels + D5-D4: Bottom-left 16x16 pixels + D7-D6: Bottom-right 16x16 pixels + + https://www.nesdev.org/wiki/PPU_attribute_tables + + @see SHOW_BKG + @see set_bkg_data, set_bkg_submap_attributes, set_win_tiles, set_tiles +*/ +void set_bkg_attributes_nes16x16(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *attributes) NO_OVERLAY_LOCALS; + +/** Sets a rectangular region of Background Tile Map Attributes. + + Entries are copied from map at __tiles__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + Use @ref set_bkg_submap_attributes() instead when: + \li Source map is wider than 32 tiles. + \li Writing a width that does not match the source map width __and__ more + than one row high at a time. + + One byte per source tile map attribute entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + Please note that this is just a wrapper function for set_bkg_attributes_nes16x16() + and divides the coordinates and dimensions by 2 to achieve this. + It is intended to make code more portable by using the same coordinate system + that systems with the much more common 8x8 attribute resolution would use. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_submap_attributes, set_win_tiles, set_tiles +*/ +inline void set_bkg_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *attributes) +{ + set_bkg_attributes_nes16x16(x >> 1, y >> 1, (w + 1) >> 1, (h + 1) >> 1, attributes); +} +/** Sets a rectangular area of the Background Tile Map using a sub-region + from a source tile map. Useful for scrolling implementations of maps + larger than 32 x 30 tiles / 16x15 attributes. + + @param x X Start position in both the Source Attribute Map and hardware Background Map attribute coordinates. Range 0 - 255 + @param y Y Start position in both the Source Attribute Map and hardware Background Map attribute coordinates. Range 0 - 255 + @param w Width of area to set in Attributes. Range 1 - 127 + @param h Height of area to set in Attributes. Range 1 - 127 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 127 + + Entries are copied from __map__ to the Background Attribute Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ attributes, + using __map_w__ as the rowstride for the source attribute map. + + The __x__ and __y__ parameters are in Source Attribute Map Attribute + coordinates. The location tiles will be written to on the + hardware Background Map is derived from those, but only uses + the lower 5 bits of each axis, for range of 0-15 (they are + bit-masked: `x & 0xF` and `y & 0xF`). As a result the two + coordinate systems are aligned together. + + In order to transfer tile map data in a way where the + coordinate systems are not aligned, an offset from the + Source Attribute Map pointer can be passed in: + `(map_ptr + x + (y * map_width))`. + + For example, if you want the tile id at `1,2` from the source map to + show up at `0,0` on the hardware Background Map (instead of at `1,2`) + then modify the pointer address that is passed in: + `map_ptr + 1 + (2 * map_width)` + + Use this instead of @ref set_bkg_tiles when the source map is wider than + 32 tiles or when writing a width that does not match the source map width. + + One byte per source attribute map entry. + + Writes that exceed coordinate 15/14 on the x / y axis will wrap around to + the Left and Top edges. + + See @ref set_bkg_tiles for setting CGB attribute maps with @ref VBK_REG. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_tiles, set_win_submap, set_tiles +*/ +void set_bkg_submap_attributes_nes16x16(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) NO_OVERLAY_LOCALS; + +/** Sets a rectangular area of the Background Tile Map attributes using + a sub-region from a source tile map. Useful for scrolling implementations + of maps larger than 32 x 30 tiles. + + Please note that this is just a wrapper function for set_bkg_submap_attributes_nes16x16() + and divides the coordinates and dimensions by 2 to achieve this. + It is intended to make code more portable by using the same coordinate system + that systems with the much more common 8x8 attribute resolution would use. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_tiles, set_win_submap, set_tiles +*/ +inline void set_bkg_submap_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *attributes, uint8_t map_w) +{ + set_bkg_submap_attributes_nes16x16(x >> 1, y >> 1, (w + 1) >> 1, (h + 1) >> 1, attributes, map_w >> 1); +} + + +extern uint8_t _map_tile_offset; + +/** Sets a rectangular region of Background Tile Map. + The offset value in __base_tile__ is added to + the tile ID for each map entry. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param tiles Pointer to source tile map data + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_bkg_tiles() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_bkg_tiles for more details +*/ +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_bkg_tiles(x, y, w, h, tiles); + _map_tile_offset = 0; +} + + +/** Sets a rectangular area of the Background Tile Map using a sub-region + from a source tile map. Useful for scrolling implementations of maps + larger than 32 x 32 tiles. + + @ param x X Start position in Background Map tile coordinates. Range 0 - 31 + @ param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @ param w Width of area to set in tiles. Range 1 - 255 + @ param h Height of area to set in tiles. Range 1 - 255 + @ param map Pointer to source tile map data + @ param map_w Width of source tile map in tiles. Range 1 - 255 + + Entries are copied from __map__ to the Background Tile Map starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles, + using __map_w__ as the rowstride for the source tile map. + + Use this instead of @ref set_bkg_tiles when the source map is wider than + 32 tiles or when writing a width that does not match the source map width. + + One byte per source tile map entry. + + Writes that exceed coordinate 31 on the x or y axis will wrap around to + the Left and Top edges. + + See @ref set_bkg_tiles for setting CGB attribute maps with @ref VBK_REG. + + @see SHOW_BKG + @see set_bkg_data, set_bkg_tiles, set_win_submap, set_tiles +*/ +void set_bkg_submap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) NO_OVERLAY_LOCALS; +#define set_tile_submap set_bkg_submap + + +extern uint8_t _submap_tile_offset; + +/** Sets a rectangular area of the Background Tile Map using a sub-region + from a source tile map. The offset value in __base_tile__ is added to + the tile ID for each map entry. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 255 + @param h Height of area to set in tiles. Range 1 - 255 + @param map Pointer to source tile map data + @param map_w Width of source tile map in tiles. Range 1 - 255 + @param base_tile Offset each tile ID entry of the source map by this value. Range 1 - 255 + + This is identical to @ref set_bkg_submap() except that it + adds the __base_tile__ parameter for when a tile map's tiles don't + start at index zero. (For example, the tiles used by the map + range from 100 -> 120 in VRAM instead of 0 -> 20). + + @see set_bkg_submap for more details +*/ +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_bkg_submap(x, y, w, h, map, map_w); + _submap_tile_offset = 0; +} + + +/** Copies a rectangular region of Background Tile Map entries into a buffer. + + Entries are copied into __tiles__ from the Background Tile Map starting at + __x__, __y__ reading across for __w__ tiles and down for __h__ tiles. + + One byte per tile. + + The buffer pointed to by __tiles__ should be at least __x__ x __y__ bytes in size. + + @see get_bkg_tile_xy, get_tiles +*/ +void get_bkg_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *tiles) NO_OVERLAY_LOCALS; + + +/** + * 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_bkg_tile_xy(uint8_t x, uint8_t y, uint8_t t) NO_OVERLAY_LOCALS; +#define set_tile_xy set_bkg_tile_xy + +/** + Set single attribute data a on background layer at x,y + + @param x X-coordinate + @param y Y-coordinate + @param a tile attributes + */ +void set_bkg_attribute_xy_nes16x16(uint8_t x, uint8_t y, uint8_t a) NO_OVERLAY_LOCALS; + +/** + Set single attribute data a on background layer at x,y + + Please note that this is just a wrapper function for set_bkg_submap_attributes_nes16x16() + and divides the coordinates and dimensions by 2 to achieve this. + It is intended to make code more portable by using the same coordinate system + that systems with the much more common 8x8 attribute resolution would use. + + @param x X-coordinate + @param y Y-coordinate + @param a tile attributes + */ +inline void set_bkg_attribute_xy(uint8_t x, uint8_t y, uint8_t a) +{ + set_bkg_attribute_xy_nes16x16(x >> 1, y >> 1, a); +} +#define set_attribute_xy set_bkg_attribute_xy + +/** + * Get single tile t on background layer at x,y + * @param x X-coordinate + * @param y Y-coordinate + * @return returns tile index + */ +uint8_t get_bkg_tile_xy(uint8_t x, uint8_t y) NO_OVERLAY_LOCALS; + + +/** Moves the Background Layer to the position specified in __x__ and __y__ in pixels. + + @param x X axis screen coordinate for Left edge of the Background + @param y Y axis screen coordinate for Top edge of the Background + + 0,0 is the top left corner of the GB screen. The Background Layer wraps around the screen, + so when part of it goes off the screen it appears on the opposite side (factoring in the + larger size of the Background Layer versus the screen size). + + The background layer is always under the Window Layer. + + @see SHOW_BKG, HIDE_BKG +*/ +inline void move_bkg(uint8_t x, uint8_t y) { + bkg_scroll_x = x, bkg_scroll_y = y; +} + + +/** Moves the Background relative to it's current position. + + @param x Number of pixels to move the Background on the __X axis__ + \n Range: -128 - 127 + @param y Number of pixels to move the Background on the __Y axis__ + \n Range: -128 - 127 + + @see move_bkg +*/ +inline void scroll_bkg(int8_t x, int8_t y) { + bkg_scroll_x += x, bkg_scroll_y += y; +} + + +/** Sets VRAM Tile Pattern data for Sprites + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. Each Tile is 16 bytes in size (8x8 pixels, 2 bits-per-pixel). + + Note: Sprite Tiles 128-255 share the same memory region as Background Tiles 128-255. + + GBC only: @ref VBK_REG determines which bank of tile patterns are written to. + \li VBK_REG=0 indicates the first bank + \li VBK_REG=1 indicates the second +*/ +void set_sprite_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; +#define set_sprite_2bpp_data set_sprite_data + +/** Sets VRAM Tile Pattern data for Sprites using 1bpp source data + + Similar to @ref set_sprite_data, except source data is 1 bit-per-pixel + which gets expanded into 2 bits-per-pixel. + + For a given bit that represent a pixel: + \li 0 will be expanded into color 0 + \li 1 will be expanded into color 3 + + @see SHOW_SPRITES, HIDE_SPRITES, set_sprite_tile +*/ +void set_sprite_1bpp_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; + +/** Sprite Attributes structure + @param x X Coordinate of the sprite on screen + @param y Y Coordinate of the sprite on screen - 1 + @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; //< Y coordinate of the sprite on screen - 1 + uint8_t tile; //< Sprite tile number + uint8_t prop; //< OAM Property Flags + uint8_t x; //< X coordinate of the sprite on screen +} 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 DMA copying routine +*/ +extern uint8_t _shadow_OAM_base; + +#define DISABLE_OAM_DMA \ + _shadow_OAM_base = 0 + +/** Disable OAM DMA copy each VBlank +*/ +#define DISABLE_VBL_TRANSFER DISABLE_OAM_DMA + +#define ENABLE_OAM_DMA \ + _shadow_OAM_base = (uint8_t)((uint16_t)&shadow_OAM >> 8) + +/** Enable OAM DMA copy each VBlank and set it to transfer default shadow_OAM array +*/ +#define ENABLE_VBL_TRANSFER ENABLE_OAM_DMA + +/** Amount of hardware sprites in OAM +*/ +#define MAX_HARDWARE_SPRITES 64 + +/** True if sprite hardware can flip sprites by X (horizontally) +*/ +#define HARDWARE_SPRITE_CAN_FLIP_X 1 + +/** True if sprite hardware can flip sprites by Y (vertically) +*/ +#define HARDWARE_SPRITE_CAN_FLIP_Y 1 + +/** Enable OAM DMA copy each VBlank and set it to transfer any 256-byte aligned array +*/ +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 - 63 + @param tile Selects a tile (0 - 255) from PPU memory at 0000h - 0FFFh / 1000h - 1FFFh + + 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 +*/ +void set_sprite_tile(uint8_t nb, uint8_t tile) NO_OVERLAY_LOCALS; + + +/** Returns the tile number of sprite number __nb__ in the OAM. + +@param nb Sprite number, range 0 - 63 + +@see set_sprite_tile for more details +*/ +uint8_t get_sprite_tile(uint8_t nb) NO_OVERLAY_LOCALS; + + +/** Sets the OAM Property Flags of sprite number __nb__ to those defined in __prop__. + + @param nb Sprite number, range 0 - 39 + @param prop Property setting (see bitfield description) + + The bits in __prop__ represent: + \li Bit 7 - Vertical flip. Dictates which way up the sprite is drawn + vertically. + \n 0: normal + \n 1: upside down + \li Bit 6 - Horizontal flip. Dictates which way up the sprite is + drawn horizontally. + \n 0: normal + \n 1: back to front + \li Bit 5 - Priority flag. When this is set, the sprites appear behind the + background and window layer. + \n 0: infront + \n 1: behind + \li Bit 4 - Unimplemented + \li Bit 3 - Unimplemented + \li Bit 2 - Unimplemented + \li Bit 1 - See bit 0. + \li Bit 0 - Bits 0-1 indicate which color palette the sprite should use. Note: only palettes 4 to 7 will be available for NES sprites. + + It's recommended to use GBDK constants (eg: S_FLIPY) to configure sprite properties as these are crossplatform. + + \code{.c} + // Load palette data into the first palette + set_sprite_palette(4, 1, exampleSprite_palettes) + + // Set the OAM value for the sprite + // These flags tell the sprite to use the first sprite palette (palette 4) and to flip the sprite both vertically and horizontally. + set_sprite_prop(0, S_FLIPY | S_FLIPX); + \endcode + + @see S_PALETTE, S_FLIPX, S_FLIPY, S_PRIORITY +*/ +void set_sprite_prop(uint8_t nb, uint8_t prop) NO_OVERLAY_LOCALS; + + +/** Returns the OAM Property Flags of sprite number __nb__. + + @param nb Sprite number, range 0 - 39 + @see set_sprite_prop for property bitfield settings +*/ +uint8_t get_sprite_prop(uint8_t nb) NO_OVERLAY_LOCALS; + + +/** Moves sprite number __nb__ to the __x__, __y__ position on the screen. + + @param nb Sprite number, range 0 - 63 + @param x X Position. Specifies the sprites horizontal position on the screen (minus 8). + @param y Y Position. Specifies the sprites vertical position on the screen (minus 16). + \n An offscreen value (Y>=240) hides the sprite. + + Moving the sprite to 0,0 (or similar off-screen location) will hide it. +*/ +void move_sprite(uint8_t nb, uint8_t x, uint8_t y) NO_OVERLAY_LOCALS; + + +/** Moves sprite number __nb__ relative to its current position. + + @param nb Sprite number, range 0 - 63 + @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 + */ +void scroll_sprite(uint8_t nb, int8_t x, int8_t y) NO_OVERLAY_LOCALS; + + +/** Hides sprite number __nb__ by moving it to Y position 240. + + @param nb Sprite number, range 0 - 63 + */ +void hide_sprite(uint8_t nb) NO_OVERLAY_LOCALS; + + + +/** Copies arbitrary data to an address in VRAM + without taking into account the state of LCDC bits 3 or 4. + + Copies __len__ bytes from a buffer at __data__ to VRAM starting at __vram_addr__. + + @see set_bkg_data, set_win_data, set_bkg_tiles, set_win_tiles, set_tile_data, set_tiles +*/ +void set_data(uint8_t *vram_addr, const uint8_t *data, uint16_t len) NO_OVERLAY_LOCALS; + + +/** Sets a rectangular region of Tile Map entries at a given VRAM Address. + + @param x X Start position in Map tile coordinates. Range 0 - 31 + @param y Y Start position in Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 1 - 32 + @param h Height of area to set in tiles. Range 1 - 32 + @param vram_addr Pointer to destination VRAM Address + @param tiles Pointer to source Tile Map data + + Entries are copied from __tiles__ to Tile Map at address vram_addr starting at + __x__, __y__ writing across for __w__ tiles and down for __h__ tiles. + + One byte per source tile map entry. + + There are two 32x30 Tile Maps in VRAM at addresses 2000h-23FFh and 2400h-27FFh. + + @see set_bkg_tiles +*/ +void set_tiles(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t *vram_addr, const uint8_t *tiles) NO_OVERLAY_LOCALS; + +/** Sets VRAM Tile Pattern data starting from given base address + without taking into account the state of PPUMASK. + + @see set_bkg_data, set_data +*/ +inline void set_tile_data(uint16_t first_tile, uint8_t nb_tiles, const uint8_t *data) { + if (first_tile < 256) { + set_bkg_data(first_tile, nb_tiles, data); + if(first_tile + nb_tiles > 256) + set_sprite_data(first_tile - 256, nb_tiles, data); + } else { + set_sprite_data(first_tile - 256, nb_tiles, data); + } +} + +/** Sets VRAM Tile Pattern data for the Background in the native format + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to source tile data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. + + @see set_tile_data +*/ +void set_bkg_native_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; + +/** Sets VRAM Tile Pattern data for Sprites in the native format + + @param first_tile Index of the first tile to write + @param nb_tiles Number of tiles to write + @param data Pointer to source tile data + + Writes __nb_tiles__ tiles to VRAM starting at __first_tile__, tile data + is sourced from __data__. +*/ +void set_sprite_native_data(uint8_t first_tile, uint8_t nb_tiles, const uint8_t *data) NO_OVERLAY_LOCALS; + +/** Sets VRAM Tile Pattern data in the native format + + @param first_tile Index of the first tile to write (0 - 511) + @param nb_tiles Number of tiles to write + @param data Pointer to source Tile Pattern data. + + When `first_tile` is larger than 256 on the GB/AP, it + will write to sprite data instead of background data. + + The bit depth of the source Tile Pattern data depends + on which console is being used: + \li NES: loads 2bpp tiles data + */ +inline void set_native_tile_data(uint16_t first_tile, uint8_t nb_tiles, const uint8_t *data) { + if (first_tile < 256) { + set_bkg_native_data(first_tile, nb_tiles, data); + if(first_tile + nb_tiles > 256) + set_sprite_native_data(first_tile - 256, nb_tiles, data); + } else { + set_sprite_native_data(first_tile - 256, nb_tiles, data); + } +} + +/** Initializes the entire Background Tile Map with Tile Number __c__ + @param c Tile number to fill with + + Note: This function avoids writes during modes 2 & 3 +*/ +void init_bkg(uint8_t c) NO_OVERLAY_LOCALS; + +/** Fills the VRAM memory region __s__ of size __n__ with Tile Number __c__ + @param s Start address in VRAM + @param c Tile number to fill with + @param n Size of memory region (in bytes) to fill + + Note: This function avoids writes during modes 2 & 3 +*/ +void vmemset (void *s, uint8_t c, size_t n) NO_OVERLAY_LOCALS; + +/** Fills a rectangular region of Tile Map entries for the Background layer with tile. + + @param x X Start position in Background Map tile coordinates. Range 0 - 31 + @param y Y Start position in Background Map tile coordinates. Range 0 - 31 + @param w Width of area to set in tiles. Range 0 - 31 + @param h Height of area to set in tiles. Range 0 - 31 + @param tile Fill value +*/ +void fill_bkg_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tile) NO_OVERLAY_LOCALS; +#define fill_rect fill_bkg_rect + +/** "Flushes" the updates to the shadow attributes so they are written + to the transfer buffer, and then written to PPU memory on next vblank. + + This function must be called to see visible changes to attributes + on the NES target. But it will automatically be called by @ref vsync(), + so the use-cases for calling it manually are rare in practice. +*/ +void flush_shadow_attributes(void) NO_OVERLAY_LOCALS; + +uint8_t _switch_prg0(uint8_t bank) NO_OVERLAY_LOCALS; + +#endif /* _NES_H */ diff --git a/ext/include/nes/rgb_to_nes_macro.h b/ext/include/nes/rgb_to_nes_macro.h new file mode 100644 index 0000000..ba2cf19 --- /dev/null +++ b/ext/include/nes/rgb_to_nes_macro.h @@ -0,0 +1,70 @@ +// File auto-generated file by nespal.py +#ifndef __RGB_TO_NES_MACRO_H__ +#define __RGB_TO_NES_MACRO_H__ +#define RGB_TO_NES(c) \ + (c == 0x00) ? 0x1D : \ + (c == 0x01) ? 0x06 : \ + (c == 0x02) ? 0x17 : \ + (c == 0x03) ? 0x16 : \ + (c == 0x04) ? 0x19 : \ + (c == 0x05) ? 0x18 : \ + (c == 0x06) ? 0x17 : \ + (c == 0x07) ? 0x27 : \ + (c == 0x08) ? 0x2A : \ + (c == 0x09) ? 0x29 : \ + (c == 0x0A) ? 0x28 : \ + (c == 0x0B) ? 0x27 : \ + (c == 0x0C) ? 0x2A : \ + (c == 0x0D) ? 0x29 : \ + (c == 0x0E) ? 0x29 : \ + (c == 0x0F) ? 0x28 : \ + (c == 0x10) ? 0x01 : \ + (c == 0x11) ? 0x04 : \ + (c == 0x12) ? 0x15 : \ + (c == 0x13) ? 0x15 : \ + (c == 0x14) ? 0x1C : \ + (c == 0x15) ? 0x00 : \ + (c == 0x16) ? 0x15 : \ + (c == 0x17) ? 0x26 : \ + (c == 0x18) ? 0x2B : \ + (c == 0x19) ? 0x2A : \ + (c == 0x1A) ? 0x10 : \ + (c == 0x1B) ? 0x26 : \ + (c == 0x1C) ? 0x2B : \ + (c == 0x1D) ? 0x2A : \ + (c == 0x1E) ? 0x39 : \ + (c == 0x1F) ? 0x38 : \ + (c == 0x20) ? 0x02 : \ + (c == 0x21) ? 0x13 : \ + (c == 0x22) ? 0x14 : \ + (c == 0x23) ? 0x14 : \ + (c == 0x24) ? 0x11 : \ + (c == 0x25) ? 0x13 : \ + (c == 0x26) ? 0x10 : \ + (c == 0x27) ? 0x25 : \ + (c == 0x28) ? 0x2C : \ + (c == 0x29) ? 0x10 : \ + (c == 0x2A) ? 0x3D : \ + (c == 0x2B) ? 0x36 : \ + (c == 0x2C) ? 0x2C : \ + (c == 0x2D) ? 0x3B : \ + (c == 0x2E) ? 0x3A : \ + (c == 0x2F) ? 0x37 : \ + (c == 0x30) ? 0x12 : \ + (c == 0x31) ? 0x13 : \ + (c == 0x32) ? 0x14 : \ + (c == 0x33) ? 0x24 : \ + (c == 0x34) ? 0x12 : \ + (c == 0x35) ? 0x22 : \ + (c == 0x36) ? 0x23 : \ + (c == 0x37) ? 0x24 : \ + (c == 0x38) ? 0x21 : \ + (c == 0x39) ? 0x22 : \ + (c == 0x3A) ? 0x32 : \ + (c == 0x3B) ? 0x34 : \ + (c == 0x3C) ? 0x2C : \ + (c == 0x3D) ? 0x3C : \ + (c == 0x3E) ? 0x3C : \ + (c == 0x3F) ? 0x20 : \ + 0xFF // out-of-range value - set to 0xFF +#endif diff --git a/ext/include/rand.h b/ext/include/rand.h new file mode 100644 index 0000000..8b2280f --- /dev/null +++ b/ext/include/rand.h @@ -0,0 +1,82 @@ +/** @file rand.h + Random generator using the linear congruential method + + @author Luc Van den Borre +*/ +#ifndef RAND_INCLUDE +#define RAND_INCLUDE + +#include +#include + +/** Initalise the pseudo-random number generator. + + @param seed The value for initializing the random number generator. + + The seed should be different each time, otherwise the same pseudo-random + sequence will be generated. + + One way to do this is sampling (@ref DIV_REG) up to 2 times (high byte of + seed value then the low byte) at variable, non-deterministic points in time + (such as when the player presses buttons on the title screen or in a menu). + + It only needs to be called once to be initialized. + + @see rand(), randw() +*/ +#if defined(__PORT_sm83) || defined(__PORT_mos6502) +void initrand(uint16_t seed) OLDCALL; +#elif defined(__PORT_z80) +void initrand(uint16_t seed) Z88DK_FASTCALL; +#endif + +#define RAND_MAX 255 +#define RANDW_MAX 65535 + +/** The random number seed is stored in __rand_seed and can be + saved and restored if needed. + + \code{.c} + // Save + some_uint16 = __rand_seed; + ... + // Restore + __rand_seed = some_uint16; + \endcode +*/ +extern uint16_t __rand_seed; + +/** Returns a random byte (8 bit) value. + + @ref initrand() should be used to initialize the random number generator before using rand() + */ +uint8_t rand(void) OLDCALL; + +/** Returns a random word (16 bit) value. + + @ref initrand() should be used to initialize the random number generator before using rand() + */ +uint16_t randw(void) OLDCALL; + +/** Random generator using the linear lagged additive method + + @param seed The value for initializing the random number generator. + + Note: initarand() calls @ref initrand() with the same seed value, and + uses @ref rand() to initialize the random generator. + + @see initrand() for suggestions about seed values, arand() +*/ +#if defined(__PORT_sm83) || defined(__PORT_mos6502) +void initarand(uint16_t seed) OLDCALL; +#elif defined(__PORT_z80) +void initarand(uint16_t seed) Z88DK_FASTCALL; +#endif + +/** Returns a random number generated with the linear lagged additive method. + + @ref initarand() should be used to initialize the random number generator before using arand() + */ +uint8_t arand(void) OLDCALL; + +#endif diff --git a/ext/include/setjmp.h b/ext/include/setjmp.h new file mode 100644 index 0000000..e057259 --- /dev/null +++ b/ext/include/setjmp.h @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------- + setjmp.h - header file for setjmp & longjmp ANSI routines + + Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef __SDCC_SETJMP_H +#define __SDCC_SETJMP_H + +#define SP_SIZE 1 + +#ifdef __SDCC_STACK_AUTO +#define BP_SIZE SP_SIZE +#else +#define BP_SIZE 0 +#endif + +#ifdef __SDCC_USE_XSTACK +#define SPX_SIZE 1 +#else +#define SPX_SIZE 0 +#endif + +#define BPX_SIZE SPX_SIZE + +#ifdef __SDCC_MODEL_HUGE +#define RET_SIZE 3 +#else +#define RET_SIZE 2 +#endif + +#if defined (__SDCC_z80) || defined (__SDCC_z180) || defined (__SDCC_r2k) || defined (__SDCC_r3ka) || defined (__SDCC_tlcs90) || defined (__SDCC_ez80_z80) || defined (__SDCC_z80n) +typedef unsigned char jmp_buf[6]; /* 2 for the stack pointer, 2 for the return address, 2 for the frame pointer. */ +#elif defined (__SDCC_ds390) || defined (__SDCC_stm8) && defined (__SDCC_MODEL_LARGE) +typedef unsigned char jmp_buf[5]; /* 2 for the stack pointer, 3 for the return address. */ +#elif defined (__SDCC_stm8) || defined (__SDCC_sm83) || defined (__SDCC_hc08) || defined (__SDCC_s08) +typedef unsigned char jmp_buf[4]; /* 2 for the stack pointer, 2 for the return address. */ +#elif defined (__SDCC_pdk13) || defined (__SDCC_pdk14) || defined (__SDCC_pdk15) +typedef unsigned char jmp_buf[3]; /* 1 for the stack pointer, 2 for the return address. */ +#else +typedef unsigned char jmp_buf[RET_SIZE + SP_SIZE + BP_SIZE + SPX_SIZE + BPX_SIZE]; +#endif + +int __setjmp (jmp_buf) OLDCALL; + +/* C99 might require setjmp to be a macro. The standard seems self-contradicting on this issue. */ +/* However, it is clear that the standards allow setjmp to be a macro. */ +#define setjmp(jump_buf) __setjmp(jump_buf) + +#ifndef __SDCC_HIDE_LONGJMP +_Noreturn void longjmp(jmp_buf, int) OLDCALL; +#endif + +#undef RET_SIZE +#undef SP_SIZE +#undef BP_SIZE +#undef SPX_SIZE +#undef BPX_SIZE + +#endif + diff --git a/ext/include/sms/bcd.h b/ext/include/sms/bcd.h new file mode 100644 index 0000000..4e32c0b --- /dev/null +++ b/ext/include/sms/bcd.h @@ -0,0 +1,61 @@ +#ifndef __BCD_H_INCLUDE +#define __BCD_H_INCLUDE + +#include +#include + +/** @file bcd.h + Support for working with BCD (Binary Coded Decimal) + + See the example BCD project for additional details. +*/ + +// macro for creating BCD constants +#define BCD_HEX(v) ((BCD)(v)) + +/** Converts an integer value into BCD format + + A maximum of 8 digits may be used +*/ +#define MAKE_BCD(v) BCD_HEX(0x ## v) + +typedef uint32_t BCD; + +/** Converts integer __i__ into BCD format (Binary Coded Decimal) + @param i Numeric value to convert + @param value Pointer to a BCD variable to store the converted result +*/ +void uint2bcd(uint16_t i, BCD * value); + +/** Adds two numbers in BCD format: __sour__ += __value__ + @param sour Pointer to a BCD value to add to (and where the result is stored) + @param value Pointer to the BCD value to add to __sour__ +*/ +void bcd_add(BCD * sour, const BCD * value); + +/** Subtracts two numbers in BCD format: __sour__ -= __value__ + @param sour Pointer to a BCD value to subtract from (and where the result is stored) + @param value Pointer to the BCD value to subtract from __sour__ +*/ +void bcd_sub(BCD * sour, const BCD * value); + +/** Convert a BCD number into an asciiz (null terminated) string and return the length + @param bcd Pointer to BCD value to convert + @param tile_offset Optional per-character offset value to add (use 0 for none) + @param buffer Buffer to store the result in + + Returns: Length in characters (always 8) + + __buffer__ should be large enough to store the converted string + (9 bytes: 8 characters + 1 for terminator) + + There are a couple different ways to use __tile_offset__. + For example: + \li It can be the Index of the Font Tile '0' in VRAM to + allow the buffer to be used directly with @ref set_bkg_tiles. + \li It can also be set to the ascii value for character '0' + so that the buffer is a normal string that can be passed to @ref printf. +*/ +uint8_t bcd2text(const BCD * bcd, uint8_t tile_offset, uint8_t * buffer); + +#endif diff --git a/ext/include/sms/gbdecompress.h b/ext/include/sms/gbdecompress.h new file mode 100644 index 0000000..4bcbcc1 --- /dev/null +++ b/ext/include/sms/gbdecompress.h @@ -0,0 +1,24 @@ +/** @file gb/gbdecompress.h + + GB-Compress decompressor + Compatible with the compression used in GBTD +*/ + +#ifndef __GBDECOMPRESS_H_INCLUDE +#define __GBDECOMPRESS_H_INCLUDE + +#include +#include + +/** gb-decompress data from sour into dest + + @param sour Pointer to source gb-compressed data + @param dest Pointer to destination buffer/address + + @return Return value is number of bytes decompressed + + @see gb_decompress_bkg_data, gb_decompress_win_data, gb_decompress_sprite_data + */ +uint16_t gb_decompress(const uint8_t * sour, uint8_t * dest) Z88DK_CALLEE PRESERVES_REGS(b, c); + +#endif \ No newline at end of file diff --git a/ext/include/sms/hardware.h b/ext/include/sms/hardware.h new file mode 100644 index 0000000..d028c45 --- /dev/null +++ b/ext/include/sms/hardware.h @@ -0,0 +1,284 @@ +/** @file sms/hardware.h + Defines that let the SMS/GG hardware registers be accessed + from C. +*/ +#ifndef _HARDWARE_H +#define _HARDWARE_H + +#include + +#define __BYTES extern UBYTE +#define __BYTE_REG extern volatile UBYTE + +static volatile SFR AT(0x00) GG_STATE; /**< Game Gear status register for Start/Pause, Japan vs Overseas mode (NJAP), NTSC/PAL mode */ + +#define GGSTATE_STT 0b10000000 +#define GGSTATE_NJAP 0b01000000 +#define GGSTATE_NNTS 0b00100000 + +static volatile SFR AT(0x01) GG_EXT_7BIT; /**< Game Gear Serial port register used to read/write data when the EXT connector used as 7-bit input/output port */ + +static volatile SFR AT(0x02) GG_EXT_CTL; /**< Game Gear Serial port register for configuring external NMI */ + +#define GGEXT_NINIT 0b10000000 + +static volatile SFR AT(0x03) GG_SIO_SEND; /**< Game Gear Serial Data Send register */ +static volatile SFR AT(0x04) GG_SIO_RECV; /**< Game Gear Serial Data Receive register */ +static volatile SFR AT(0x05) GG_SIO_CTL; /**< Game Gear Serial Port control register */ + +#define SIOCTL_TXFL 0b00000001 +#define SIOCTL_RXRD 0b00000010 +#define SIOCTL_FRER 0b00000100 +#define SIOCTL_INT 0b00001000 +#define SIOCTL_TON 0b00010000 +#define SIOCTL_RON 0b00100000 +#define SIOCTL_BS0 0b01000000 +#define SIOCTL_BS1 0b10000000 + +static volatile SFR AT(0x06) GG_SOUND_PAN; /**< Game Gear Sound panning (left / right) register */ + +#define SOUNDPAN_TN1R 0b00000001 +#define SOUNDPAN_TN2R 0b00000010 +#define SOUNDPAN_TN3R 0b00000100 +#define SOUNDPAN_NOSR 0b00001000 +#define SOUNDPAN_TN1L 0b00010000 +#define SOUNDPAN_TN2L 0b00100000 +#define SOUNDPAN_TN3L 0b01000000 +#define SOUNDPAN_NOSL 0b10000000 + +static volatile SFR AT(0x3E) MEMORY_CTL; + +#define MEMCTL_JOYON 0b00000000 +#define MEMCTL_JOYOFF 0b00000100 +#define MEMCTL_BASEON 0b00000000 +#define MEMCTL_BASEOFF 0b00001000 +#define MEMCTL_RAMON 0b00000000 +#define MEMCTL_RAMOFF 0b00010000 +#define MEMCTL_CROMON 0b00000000 +#define MEMCTL_CROMOFF 0b00100000 +#define MEMCTL_ROMON 0b00000000 +#define MEMCTL_ROMOFF 0b01000000 +#define MEMCTL_EXTON 0b00000000 +#define MEMCTL_EXTOFF 0b10000000 + +static volatile SFR AT(0x3F) JOY_CTL; + +#define JOY_P1_TR_DIR_IN 0b00000001 +#define JOY_P1_TR_DIR_OUT 0b00000000 +#define JOY_P1_TH_DIR_IN 0b00000010 +#define GUN_P1_LATCH JOY_P1_TH_DIR_IN +#define JOY_P1_TH_DIR_OUT 0b00000000 +#define JOY_P2_TR_DIR_IN 0b00000100 +#define JOY_P2_TR_DIR_OUT 0b00000000 +#define JOY_P2_TH_DIR_IN 0b00001000 +#define GUN_P2_LATCH JOY_P2_TH_DIR_IN +#define JOY_P2_TH_DIR_OUT 0b00000000 +#define JOY_P1_TR_OUT_HI 0b00010000 +#define JOY_P1_TR_OUT_LO 0b00000000 +#define JOY_P1_TH_OUT_HI 0b00100000 +#define JOY_P1_TH_OUT_LO 0b00000000 +#define JOY_P2_TR_OUT_HI 0b01000000 +#define JOY_P2_TR_OUT_LO 0b00000000 +#define JOY_P2_TH_OUT_HI 0b10000000 +#define JOY_P2_TH_OUT_LO 0b00000000 + +#define JOY_TH_HI (JOY_P1_TR_DIR_IN | JOY_P1_TH_DIR_OUT | JOY_P2_TR_DIR_IN | JOY_P2_TH_DIR_OUT | JOY_P1_TR_OUT_HI | JOY_P1_TH_OUT_HI | JOY_P2_TR_OUT_HI | JOY_P2_TH_OUT_HI) +#define JOY_TH_LO (JOY_P1_TR_DIR_IN | JOY_P1_TH_DIR_OUT | JOY_P2_TR_DIR_IN | JOY_P2_TH_DIR_OUT | JOY_P1_TR_OUT_HI | JOY_P1_TH_OUT_LO | JOY_P2_TR_OUT_HI | JOY_P2_TH_OUT_LO) + +static volatile SFR AT(0x7E) VCOUNTER; + +static volatile SFR AT(0x7F) PSG; + +#define PSG_LATCH 0b10000000 + +#define PSG_CH0 0b00000000 +#define PSG_CH1 0b00100000 +#define PSG_CH2 0b01000000 +#define PSG_CH3 0b01100000 + +#define PSG_VOLUME 0b00010000 + +static volatile SFR AT(0x7F) HCOUNTER; + +static volatile SFR AT(0xBE) VDP_DATA; +static volatile SFR AT(0xBF) VDP_CMD; +static volatile SFR AT(0xBF) VDP_STATUS; + +#define STATF_INT_VBL 0b10000000 +#define STATF_9_SPR 0b01000000 +#define STATF_SPR_COLL 0b00100000 + +#define VDP_REG_MASK 0b10000000 +#define VDP_R0 0b10000000 +extern UBYTE shadow_VDP_R0; + +#define R0_VSCRL 0b00000000 +#define R0_VSCRL_INH 0b10000000 +#define R0_HSCRL 0b00000000 +#define R0_HSCRL_INH 0b01000000 +#define R0_NO_LCB 0b00000000 +#define R0_LCB 0b00100000 +#define R0_IE1_OFF 0b00000000 +#define R0_IE1 0b00010000 +#define R0_SS_OFF 0b00000000 +#define R0_SS 0b00001000 +#define R0_DEFAULT 0b00000110 +#define R0_ES_OFF 0b00000000 +#define R0_ES 0b00000001 + +#define VDP_R1 0b10000001 +extern UBYTE shadow_VDP_R1; + +#define R1_DEFAULT 0b10000000 +#define R1_DISP_OFF 0b00000000 +#define R1_DISP_ON 0b01000000 +#define R1_IE_OFF 0b00000000 +#define R1_IE 0b00100000 +#define R1_SPR_8X8 0b00000000 +#define R1_SPR_8X16 0b00000010 + +#define VDP_R2 0b10000010 +extern UBYTE shadow_VDP_R2; + +#define R2_MAP_0x3800 0xFF +#define R2_MAP_0x3000 0xFD +#define R2_MAP_0x2800 0xFB +#define R2_MAP_0x2000 0xF9 +#define R2_MAP_0x1800 0xF7 +#define R2_MAP_0x1000 0xF5 +#define R2_MAP_0x0800 0xF3 +#define R2_MAP_0x0000 0xF1 + +#define VDP_R3 0b10000011 +extern UBYTE shadow_VDP_R3; +#define VDP_R4 0b10000100 +extern UBYTE shadow_VDP_R4; +#define VDP_R5 0b10000101 +extern UBYTE shadow_VDP_R5; + +#define R5_SAT_0x3F00 0xFF +#define R5_SAT_0x1F00 0xBF +#define R5_SAT_MASK 0b10000001 + +#define VDP_R6 0b10000110 +extern UBYTE shadow_VDP_R6; + +#define R6_BANK0 0xFB +#define R6_DATA_0x0000 0xFB +#define R6_BANK1 0xFF +#define R6_DATA_0x2000 0xFF + +#define VDP_R7 0b10000111 +extern UBYTE shadow_VDP_R7; +#define VDP_RBORDER 0b10000111 +extern UBYTE shadow_VDP_RBORDER; + +#define R7_COLOR_MASK 0b11110000 + +#define VDP_R8 0b10001000 +extern UBYTE shadow_VDP_R8; +#define VDP_RSCX 0b10001000 +extern UBYTE shadow_VDP_RSCX; + +#define VDP_R9 0b10001001 +extern UBYTE shadow_VDP_R9; +#define VDP_RSCY 0b10001001 +extern UBYTE shadow_VDP_RSCY; + +#define VDP_R10 0b10001010 +extern UBYTE shadow_VDP_R10; + +#define R10_INT_OFF 0xFF +#define R10_INT_EVERY 0x00 + +static volatile SFR AT(0xDC) JOY_PORT1; + +#define JOY_P1_UP 0b00000001 +#define JOY_P1_MD_Z JOY_P1_UP +#define JOY_P1_DOWN 0b00000010 +#define JOY_P1_MD_Y JOY_P1_DOWN +#define JOY_P1_LEFT 0b00000100 +#define JOY_P1_MD_X JOY_P1_LEFT +#define JOY_P1_RIGHT 0b00001000 +#define JOY_P1_MD_MODE JOY_P1_RIGHT +#define JOY_P1_SW1 0b00010000 +#define JOY_P1_TRIGGER JOY_P1_SW1 +#define JOY_P1_MD_A JOY_P1_SW1 +#define JOY_P1_SW2 0b00100000 +#define JOY_P1_MD_START JOY_P1_SW2 +#define JOY_P2_UP 0b01000000 +#define JOY_P2_MD_Z JOY_P2_UP +#define JOY_P2_DOWN 0b10000000 +#define JOY_P2_MD_Y JOY_P2_DOWN + +static volatile SFR AT(0xDD) JOY_PORT2; + +#define JOY_P2_LEFT 0b00000001 +#define JOY_P2_MD_X JOY_P2_LEFT +#define JOY_P2_RIGHT 0b00000010 +#define JOY_P2_MD_MODE JOY_P2_RIGHT +#define JOY_P2_SW1 0b00000100 +#define JOY_P2_TRIGGER JOY_P2_SW1 +#define JOY_P2_MD_A JOY_P2_SW1 +#define JOY_P2_SW2 0b00001000 +#define JOY_P2_MD_START JOY_P2_SW2 +#define JOY_RESET 0b00010000 +#define JOY_P1_LIGHT 0b01000000 +#define JOY_P2_LIGHT 0b10000000 + +static volatile SFR AT(0xF0) FMADDRESS; +static volatile SFR AT(0xF1) FMDATA; +static volatile SFR AT(0xF2) AUDIOCTRL; + +static volatile UBYTE AT(0xfffc) RAM_CONTROL; + +#define RAMCTL_BANK 0b00000100 +#define RAMCTL_ROM 0b00000000 +#define RAMCTL_RAM 0b00001000 +#define RAMCTL_RO 0b00010000 +#define RAMCTL_PROT 0b10000000 + +static volatile UBYTE AT(0xfff8) GLASSES_3D; + +static volatile UBYTE AT(0xfffd) MAP_FRAME0; +static volatile UBYTE AT(0xfffe) MAP_FRAME1; +static volatile UBYTE AT(0xffff) MAP_FRAME2; + +extern volatile UBYTE VDP_ATTR_SHIFT; + +#define VBK_TILES 0 +#define VBK_ATTRIBUTES 1 + +#define VDP_SAT_TERM 0xD0 + +#if defined(__TARGET_sms) +#define DEVICE_SCREEN_X_OFFSET 0 +#define DEVICE_SCREEN_Y_OFFSET 0 +#define DEVICE_SCREEN_WIDTH 32 +#define DEVICE_SCREEN_HEIGHT 24 +#define DEVICE_SCREEN_BUFFER_WIDTH 32 +#define DEVICE_SCREEN_BUFFER_HEIGHT 28 +#define DEVICE_SCREEN_MAP_ENTRY_SIZE 2 +#define DEVICE_SPRITE_PX_OFFSET_X 0 +#define DEVICE_SPRITE_PX_OFFSET_Y -1 +#define DEVICE_WINDOW_PX_OFFSET_X 0 +#define DEVICE_WINDOW_PX_OFFSET_Y 0 +#elif defined(__TARGET_gg) +#define DEVICE_SCREEN_X_OFFSET 6 +#define DEVICE_SCREEN_Y_OFFSET 3 +#define DEVICE_SCREEN_WIDTH 20 +#define DEVICE_SCREEN_HEIGHT 18 +#define DEVICE_SCREEN_BUFFER_WIDTH 32 +#define DEVICE_SCREEN_BUFFER_HEIGHT 28 +#define DEVICE_SCREEN_MAP_ENTRY_SIZE 2 +#define DEVICE_SPRITE_PX_OFFSET_X 48 +#define DEVICE_SPRITE_PX_OFFSET_Y 23 +#define DEVICE_WINDOW_PX_OFFSET_X 0 +#define DEVICE_WINDOW_PX_OFFSET_Y 0 +#else +#error Unrecognized port +#endif +#define DEVICE_SCREEN_PX_WIDTH (DEVICE_SCREEN_WIDTH * 8) +#define DEVICE_SCREEN_PX_HEIGHT (DEVICE_SCREEN_HEIGHT * 8) + +#endif diff --git a/ext/include/sms/metasprites.h b/ext/include/sms/metasprites.h new file mode 100644 index 0000000..5d277e1 --- /dev/null +++ b/ext/include/sms/metasprites.h @@ -0,0 +1,197 @@ +/** @file sms/metasprites.h + + # Metasprite support + + A metasprite is a larger sprite made up from a + collection of smaller individual hardware sprites. + Different frames of the same metasprites can share + tile data. + + See the main @ref metasprite_main_docs "metasprite docs" + under the game Boy platform for additional details. +*/ + +#ifndef _METASPRITES_H_INCLUDE +#define _METASPRITES_H_INCLUDE + +#include +#include +#include +#include + +/** Metasprite sub-item structure + @param dy (int8_t) Y coordinate of the sprite relative to the metasprite origin (pivot) + @param dx (int8_t) X coordinate of the sprite relative to the metasprite origin (pivot) + @param dtile (uint8_t) Start tile relative to the metasprites own set of tiles + + Metasprites are built from multiple metasprite_t items (one for each sub-sprite) + and a pool of tiles they reference. If a metasprite has multiple frames then each + frame will be built from some number of metasprite_t items (which may vary based + on how many sprites are required for that particular frame). + + A metasprite frame is terminated with a {metasprite_end} entry. +*/ +typedef struct metasprite_t { + int8_t dy, dx; + uint8_t dtile; +} metasprite_t; + +#define metasprite_end -128 +#define METASPR_ITEM(dy,dx,dt,a) {(dy),(dx),(dt)} +#define METASPR_TERM {metasprite_end} + +extern const void * __current_metasprite; +extern uint8_t __current_base_tile; +extern uint8_t __render_shadow_OAM; + + +static uint8_t __move_metasprite(uint8_t id, uint16_t x, uint16_t y); +static uint8_t __move_metasprite_flipx(uint8_t id, uint16_t x, uint16_t y); +static uint8_t __move_metasprite_flipy(uint8_t id, uint16_t x, uint16_t y); +static uint8_t __move_metasprite_flipxy(uint8_t id, uint16_t x, uint16_t y); +static void __hide_metasprite(uint8_t id) Z88DK_FASTCALL PRESERVES_REGS(iyh, iyl); + +/** + * Hides all hardware sprites in range from <= X < to + * @param from start OAM index + * @param to finish OAM index + */ +void hide_sprites_range(uint8_t from, uint8_t to) PRESERVES_REGS(iyh, iyl); + +/** Moves metasprite to the absolute position x and y + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (unused on this platform) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Moves __metasprite__ to the absolute position __x__ and __y__ + (with __no flip__ on the X or Y axis). Hardware sprites are + allocated starting from __base_sprite__, using tiles + starting from __base_tile__. + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + @return Number of hardware sprites used to draw this metasprite +*/ +inline uint8_t move_metasprite_ex(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint16_t x, uint16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite(base_sprite, x, y); +} + +/** Obsolete. This function has been replaced by move_metasprite_ex() +*/ +inline uint8_t move_metasprite(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_sprite, uint16_t x, uint16_t y) { + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite(base_sprite, x, y); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X (horizontally)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (unused on this platform) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X (horizontally). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipx(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint16_t x, uint16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite_flipx(base_sprite, x - 8, y); +} + +/** Moves metasprite to the absolute position x and y, __flipped by Y (vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (unused on this platform) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by Y (vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint16_t x, uint16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite_flipy(base_sprite, x, y - ((__READ_VDP_REG(VDP_R1) & R1_SPR_8X16) ? 16 : 8) ); +} + +/** Moves metasprite to the absolute position x and y, __flipped by X and Y (horizontally and vertically)__ + + @param metasprite Pointer to the first struct of the metasprite (for the desired frame) + @param base_tile Number of the first tile where the metasprite's tiles start + @param base_prop Base sprite property flags (unused on this platform) + @param base_sprite Number of the first hardware sprite to be used by the metasprite + @param x Absolute x coordinate of the sprite + @param y Absolute y coordinate of the sprite + + Same as @ref move_metasprite(), but with the metasprite flipped by X and Y (horizontally and vertically). + + Sets: + \li __current_metasprite = metasprite; + \li __current_base_tile = base_tile; + + Note: Overwrites OAM sprite properties (such as palette), see + @ref metasprite_and_sprite_properties "Metasprites and sprite properties". + + @return Number of hardware sprites used to draw this metasprite + + @see move_metasprite() +*/ +inline uint8_t move_metasprite_flipxy(const metasprite_t * metasprite, uint8_t base_tile, uint8_t base_prop, uint8_t base_sprite, uint16_t x, uint16_t y) { + base_prop; + __current_metasprite = metasprite; + __current_base_tile = base_tile; + return __move_metasprite_flipxy(base_sprite, x - 8, y - ((__READ_VDP_REG(VDP_R1) & R1_SPR_8X16) ? 16 : 8)); +} + +/** Hides a metasprite from the screen + + @param metasprite Pointer to first struct of the desired metasprite frame + @param base_sprite Number of hardware sprite to start with + + Sets: + \li __current_metasprite = metasprite; + + **/ +inline void hide_metasprite(const metasprite_t * metasprite, uint8_t base_sprite) { + __current_metasprite = metasprite; + __hide_metasprite(base_sprite); +} + +#endif diff --git a/ext/include/sms/sms.h b/ext/include/sms/sms.h new file mode 100644 index 0000000..025209f --- /dev/null +++ b/ext/include/sms/sms.h @@ -0,0 +1,923 @@ +/** @file sms/sms.h + SMS/GG specific functions. +*/ +#ifndef _SMS_H +#define _SMS_H + +#include +#include +#include +#include + +#define SEGA + +// Here NINTENDO means Game Boy & related clones +#ifdef NINTENDO +#undef NINTENDO +#endif + +#ifdef NINTENDO_NES +#undef NINTENDO_NES +#endif + +#ifdef MSX +#undef MSX +#endif + +#if defined(__TARGET_sms) +#define MASTERSYSTEM +#elif defined(__TARGET_gg) +#define GAMEGEAR +#endif + + +extern const UBYTE _BIOS; + +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 0b00000001 +#define J_DOWN 0b00000010 +#define J_LEFT 0b00000100 +#define J_RIGHT 0b00001000 +#define J_B 0b00010000 +#define J_A 0b00100000 +#define J_START 0b01000000 +#define J_SELECT 0b10000000 + +/** 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 +/** Dummy function used by other platforms. + 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 SMS/GG + */ +#define TIM_IFLAG 0x04U +/** Does nothing on SMS/GG + */ +#define SIO_IFLAG 0x08U +/** Does nothing on SMS/GG + */ +#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 SMS/GG + */ +void add_TIM(int_handler h) Z88DK_FASTCALL; + +/** Does nothing on SMS/GG + */ +void add_SIO(int_handler h) Z88DK_FASTCALL; + +/** Does nothing on SMS/GG + */ +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. +*/ +#define SHOW_SPRITES \ + (_sprites_OFF = 0) + +/** Turns off the sprites layer. +*/ +#define HIDE_SPRITES \ + (_sprites_OFF = 1) + +/** Sets sprite size to 8x16 pixels, two tiles one above the other. +*/ +#define SPRITES_8x16 \ + __WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) |= R1_SPR_8X16) + +/** Sets sprite size to 8x8 pixels, one tile. +*/ +#define SPRITES_8x8 \ + __WRITE_VDP_REG(VDP_R1, __READ_VDP_REG(VDP_R1) &= (~R1_SPR_8X16)) + +/** Macro returns TRUE if device supports color + * (it always does on SMS/GG) + */ +#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; + + +/** 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 +*/ +#define _current_bank MAP_FRAME1 +#define CURRENT_BANK MAP_FRAME1 + +/** 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 b ROM bank to switch to +*/ + +#define SWITCH_ROM(b) MAP_FRAME1=(b) +#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, 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(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(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_sms) + +#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; + +#elif defined(__TARGET_gg) + +#define RGB(r,g,b) ((uint16_t)(r) | (uint16_t)((g) << 4) | (uint16_t)((b) << 8)) +#define RGB8(r,g,b) ((uint16_t)((r) >> 4) | ((uint16_t)((g) >> 4) << 4) | ((uint16_t)((b) >> 4) << 8)) +#define RGBHTML(RGB24bit) (((RGB24bit) >> 20) | ((((RGB24bit) & 0xFFFF) >> 12) << 4)|((((RGB24bit) & 0xFF) >> 4) << 8)) + +/** Common colors based on the EGA default palette. + */ +#define RGB_RED RGB(15, 0, 0) +#define RGB_DARKRED RGB( 7, 0, 0) +#define RGB_GREEN RGB( 0, 15, 0) +#define RGB_DARKGREEN RGB( 0, 7, 0) +#define RGB_BLUE RGB( 0, 0, 15) +#define RGB_DARKBLUE RGB( 0, 0, 7) +#define RGB_YELLOW RGB(15, 15, 0) +#define RGB_DARKYELLOW RGB( 7, 7, 0) +#define RGB_CYAN RGB( 0, 15, 15) +#define RGB_AQUA RGB(14, 2, 11) +#define RGB_PINK RGB(15, 0, 15) +#define RGB_PURPLE RGB(10, 0, 10) +#define RGB_BLACK RGB( 0, 0, 0) +#define RGB_DARKGRAY RGB( 5, 5, 5) +#define RGB_LIGHTGRAY RGB(10, 10, 10) +#define RGB_WHITE RGB(15, 15, 15) + +#define RGB_LIGHTFLESH RGB(15, 10, 7) +#define RGB_BROWN RGB( 5, 5, 0) +#define RGB_ORANGE RGB(15, 10, 0) +#define RGB_TEAL RGB( 7, 7, 0) + +typedef uint16_t palette_color_t; + +#else +#error Unrecognized port +#endif + +void set_default_palette(void); +inline void cgb_compatibility(void) { + set_default_palette(); +} + +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) + + +/** Set color palette(s) + + @param first_palette Index of the first 16 color palette to write (0-1) + @param nb_palettes Number of palettes to write (1-2, max depends on first_palette) + @param rgb_data Pointer to source palette data + + Writes __nb_palettes__ to palette data starting + at __first_palette__, Palette data is sourced from __rgb_data__. + + \li Palette 0 can be used for the Background. + \li Palette 1 is shared between Background and Sprites. + + On the Game Gear + \li Each Palette is 32 bytes in size: 16 colors x 2 bytes per palette color entry. + \li Each color (16 per palette) is packed as BGR-444 format (x:4:4:4, MSBits [15..12] are unused). + \li Each component (R, G, B) may have values from 0 - 15 (4 bits), 15 is brightest. + + On the SMS + \li On SMS each Palette is 16 bytes in size: 16 colors x 1 byte per palette color entry. + \li Each color (16 per palette) is packed as BGR-222 format (x:2:2:2, MSBits [7..6] are unused). + \li Each component (R, G, B) may have values from 0 - 3 (2 bits), 3 is brightest. + + @see RGB(), set_sprite_palette(), set_bkg_palette(), set_palette_entry(), set_sprite_palette_entry(), set_bkg_palette_entry(), set_sprite_palette() +*/ +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) PRESERVES_REGS(iyh, iyl); +void set_bkg_4bpp_data(uint16_t start, uint16_t ntiles, const void *src) PRESERVES_REGS(iyh, iyl); +void set_bkg_native_data(uint16_t start, uint16_t ntiles, const void *src) PRESERVES_REGS(iyh, iyl); + +void set_sprite_4bpp_data(uint8_t start, uint16_t ntiles, const void *src) PRESERVES_REGS(iyh, iyl); +void set_sprite_native_data(uint8_t start, uint16_t ntiles, const void *src) PRESERVES_REGS(iyh, iyl); + +#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_tile_2bpp_data(start, ntiles, src, _current_2bpp_palette); +} +inline void set_sprite_data(uint16_t start, uint16_t ntiles, const void *src) { + set_tile_2bpp_data((uint8_t)(start) + 0x100u, ntiles, src, _current_2bpp_palette); +} +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); +} +inline void set_sprite_1bpp_data(uint16_t start, uint16_t ntiles, const void *src) { + set_tile_1bpp_data((uint8_t)(start) + 0x100u, 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; +void set_tile_map_compat(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) Z88DK_CALLEE; +#define set_bkg_tiles set_tile_map_compat +#define set_win_tiles set_tile_map_compat + +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_compat(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_compat(x, y, w, h, tiles); + _map_tile_offset = 0; +} + +inline void set_bkg_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *tiles) +{ + VBK_REG = VBK_ATTRIBUTES; + set_bkg_tiles(x, y, w, h, tiles); + VBK_REG = VBK_TILES; +} + +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; +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; +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; +} + +inline void set_bkg_submap_attributes(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t map_w) +{ + VBK_REG = VBK_ATTRIBUTES; + set_bkg_submap(x, y, w, h, map, map_w); + VBK_REG = VBK_TILES; +} + +void fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t tile) Z88DK_CALLEE; +void fill_rect_compat(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t tile) Z88DK_CALLEE; +#define fill_bkg_rect fill_rect_compat +#define fill_win_rect fill_rect_compat + +/** Shadow OAM array in WRAM, that is transferred into the real OAM each VBlank +*/ +extern volatile uint8_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 sms/gg 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; + +extern volatile uint8_t _sprites_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 64 + +/** 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[0x41+(nb << 1)] = 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[0x41+(nb << 1)]; +} + +/** Function has no affect on sms. + + This function is only here to enable game portability +*/ + +inline void set_sprite_prop(uint8_t nb, uint8_t prop) { + nb; prop; +} + +inline uint8_t get_sprite_prop(uint8_t nb) { + nb; + return 0; +} + +/** 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) { + shadow_OAM[nb] = (y < VDP_SAT_TERM) ? y : 0xC0; + shadow_OAM[0x40+(nb << 1)] = 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) { + uint8_t new_y = shadow_OAM[nb] + y; + shadow_OAM[nb] = (new_y < VDP_SAT_TERM) ? new_y : 0xC0; + shadow_OAM[0x40+(nb << 1)] += 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] = 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 + +/** + * Set single attribute data a on background layer at x,y + * @param x X-coordinate + * @param y Y-coordinate + * @param a tile attributes + * @return returns the address of tile attribute, so you may use faster set_vram_byte() later + */ +inline uint8_t * set_attribute_xy(uint8_t x, uint8_t y, uint8_t a) Z88DK_CALLEE PRESERVES_REGS(iyh, iyl); +#define set_bkg_attribute_xy set_attribute_xy +#define set_win_attribute_xy set_attribute_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 /* _SMS_H */ diff --git a/ext/include/stdarg.h b/ext/include/stdarg.h new file mode 100644 index 0000000..fe0ea56 --- /dev/null +++ b/ext/include/stdarg.h @@ -0,0 +1,12 @@ +#ifndef STDARG_INCLUDE +#define STDARG_INCLUDE + +#if defined(__PORT_sm83) +#include +#elif defined(__PORT_z80) +#include +#elif defined(__PORT_mos6502) +#include +#endif + +#endif diff --git a/ext/include/stdatomic.h b/ext/include/stdatomic.h new file mode 100644 index 0000000..f33d3fa --- /dev/null +++ b/ext/include/stdatomic.h @@ -0,0 +1,21 @@ +#ifndef __SDCC_STDATOMIC_H +#define __SDCC_STDATOMIC_H 1 + +#include + +typedef struct {unsigned char flag;} atomic_flag; + +#if defined(__SDCC_z80) || defined(__SDCC_z180) || defined(__SDCC_ez80_z80) || defined(__SDCC_sm83) || defined(__SDCC_r2k) || defined(__SDCC_r3ka) || defined(__SDCC_stm8) || defined(__SDCC_hc08) || defined(__SDCC_s08) || defined(__SDCC_mos6502) +#define ATOMIC_FLAG_INIT {1} +//#elif defined(__SDCC_mcs51) +//#define ATOMIC_FLAG_INIT {0} +#else +#error Support for atomic_flag not implemented +#endif + +_Bool atomic_flag_test_and_set(volatile atomic_flag *object) OLDCALL; + +void atomic_flag_clear(volatile atomic_flag *object); + +#endif + diff --git a/ext/include/stdbool.h b/ext/include/stdbool.h new file mode 100644 index 0000000..018bfe6 --- /dev/null +++ b/ext/include/stdbool.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + stdbool.h - ANSI functions forward declarations + + Copyright (C) 2004, Maarten Brock, sourceforge.brock@dse.nl + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef __SDC51_STDBOOL_H +#define __SDC51_STDBOOL_H 1 + +/* Define true and false of type _Bool in a way compatible with the preprocessor (see N 2229 for details). */ +#define true ((_Bool)+1) +#define false ((_Bool)+0) + +#define bool _Bool +#define __bool_true_false_are_defined 1 + +#endif + diff --git a/ext/include/stddef.h b/ext/include/stddef.h new file mode 100644 index 0000000..fa03894 --- /dev/null +++ b/ext/include/stddef.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + stddef.h - ANSI functions forward declarations + + Copyright (C) 2004, Maarten Brock / sourceforge.brock@dse.nl + Copyright (C) 2011, Philipp Klaus Krause / pkk@spth.de + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef __SDCC_STDDEF_H +#define __SDCC_STDDEF_H 1 + +#ifndef NULL + #define NULL (void *)0 +#endif + +#ifndef __PTRDIFF_T_DEFINED +#define __PTRDIFF_T_DEFINED +#if defined (__SDCC_mcs51) || defined (__SDCC_ds390) + typedef long int ptrdiff_t; +#else + typedef int ptrdiff_t; +#endif +#endif + +#ifndef __SIZE_T_DEFINED +#define __SIZE_T_DEFINED + typedef unsigned int size_t; +#endif + +#if __STDC_VERSION__ >= 201112L + typedef unsigned char max_align_t; +#endif + +#ifndef __WCHAR_T_DEFINED +#define __WCHAR_T_DEFINED + typedef unsigned long int wchar_t; +#endif + +/* Bounds-checking interfaces from annex K of the C11 standard. */ +#if defined (__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ + +#ifndef __RSIZE_T_DEFINED +#define __RSIZE_T_DEFINED +typedef size_t rsize_t; +#endif + +#ifndef __ERRNO_T_DEFINED +#define __ERRNO_T_DEFINED +typedef int errno_t; +#endif + +#endif + +#define offsetof(s, m) __builtin_offsetof (s, m) + +#endif + diff --git a/ext/include/stdint.h b/ext/include/stdint.h new file mode 100644 index 0000000..9401212 --- /dev/null +++ b/ext/include/stdint.h @@ -0,0 +1,274 @@ +/*------------------------------------------------------------------------- + stdint.h - ISO C99 7.18 Integer types + + Copyright (C) 2005, Maarten Brock, sourceforge.brock@dse.nl + Copyright (C) 2011, Philipp Klaus Krause, pkk@spth.de + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef _STDINT_H +#define _STDINT_H 1 + +/* Exact integral types. */ + +#if !defined(__SDCC_pic14) && !defined(__SDCC_pic16) +#if __STDC_VERSION__ >= 199901L +#define __SDCC_LONGLONG +#endif +#endif + +/* Signed. */ + +typedef signed char int8_t; +typedef short int int16_t; +typedef long int int32_t; +#ifdef __SDCC_LONGLONG +typedef long long int int64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned long int uint32_t; +#ifdef __SDCC_LONGLONG +typedef unsigned long long int uint64_t; +#endif + +/* Small types. */ + +/* Signed. */ +typedef signed char int_least8_t; +typedef short int int_least16_t; +typedef long int int_least32_t; +#ifdef __SDCC_LONGLONG +typedef long long int int_least64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint_least8_t; +typedef unsigned short int uint_least16_t; +typedef unsigned long int uint_least32_t; +#ifdef __SDCC_LONGLONG +typedef unsigned long long int uint_least64_t; +#endif + +/* Fast types. */ + +/* Signed. */ +typedef signed char int_fast8_t; +typedef int int_fast16_t; +typedef long int int_fast32_t; +#ifdef __SDCC_LONGLONG +typedef long long int int_fast64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint_fast8_t; +typedef unsigned int uint_fast16_t; +typedef unsigned long int uint_fast32_t; +#ifdef __SDCC_LONGLONG +typedef unsigned long long int uint_fast64_t; +#endif + +/* Types for `void *' pointers. */ +#if defined (__SDCC_mcs51) || defined (__SDCC_ds390) + typedef long int intptr_t; + typedef unsigned long int uintptr_t; +#else + typedef int intptr_t; + typedef unsigned int uintptr_t; +#endif + + +/* Largest integral types. */ +#ifndef __SDCC_LONGLONG +typedef long int intmax_t; +typedef unsigned long int uintmax_t; +#else +typedef long long int intmax_t; +typedef unsigned long long int uintmax_t; +#endif + +/* Limits of integral types. */ + +/* Minimum of signed integral types. */ +#define INT8_MIN (-128) +#define INT16_MIN (-32767-1) +#define INT32_MIN (-2147483647L-1) +#ifdef __SDCC_LONGLONG +#define INT64_MIN (-9223372036854775807LL-1) +#endif + +/* Maximum of signed integral types. */ +#define INT8_MAX (127) +#define INT16_MAX (32767) +#define INT32_MAX (2147483647L) +#ifdef __SDCC_LONGLONG +#define INT64_MAX (9223372036854775807LL) +#endif + +/* Maximum of unsigned integral types. */ +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (4294967295UL) +#ifdef __SDCC_LONGLONG +#define UINT64_MAX (18446744073709551615ULL) +#endif + +/* Minimum of signed integral types having a minimum size. */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#ifdef __SDCC_LONGLONG +#define INT_LEAST64_MIN INT64_MIN +#endif + +/* Maximum of signed integral types having a minimum size. */ +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#ifdef __SDCC_LONGLONG +#define INT_LEAST64_MAX INT64_MAX +#endif + +/* Maximum of unsigned integral types having a minimum size. */ +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#ifdef __SDCC_LONGLONG +#define UINT_LEAST64_MAX UINT64_MAX +#endif + +/* Minimum of fast signed integral types having a minimum size. */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#ifdef __SDCC_LONGLONG +#define INT_FAST64_MIN INT64_MIN +#endif + +/* Maximum of fast signed integral types having a minimum size. */ +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#ifdef __SDCC_LONGLONG +#define INT_FAST64_MAX INT64_MAX +#endif + +/* Maximum of fast unsigned integral types having a minimum size. */ +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#ifdef __SDCC_LONGLONG +#define UINT_FAST64_MAX UINT64_MAX +#endif + +/* Values to test for integral types holding `void *' pointer. */ +#if defined (__SDCC_mcs51) || defined (__SDCC_ds390) +#define INTPTR_MIN (-2147483647L-1) +#define INTPTR_MAX (2147483647L) +#define UINTPTR_MAX (4294967295UL) +#else +#define INTPTR_MIN (-32767-1) +#define INTPTR_MAX (32767) +#define UINTPTR_MAX (65535) +#endif + +/* Minimum for largest signed integral type. */ +#ifndef __SDCC_LONGLONG +#define INTMAX_MIN (-2147483647L-1) +#else +#define INTMAX_MIN (-9223372036854775807LL-1) +#endif + +/* Maximum for largest signed integral type. */ +#ifndef __SDCC_LONGLONG +#define INTMAX_MAX (2147483647L) +#else +#define INTMAX_MAX (9223372036854775807LL) +#endif + +/* Maximum for largest unsigned integral type. */ +#ifndef __SDCC_LONGLONG +#define UINTMAX_MAX (4294967295UL) +#else +#define UINTMAX_MAX (18446744073709551615ULL) +#endif + +/* Limits of other integer types. */ + +/* Limits of `ptrdiff_t' type. */ +#if defined (__SDCC_mcs51) || defined (__SDCC_ds390) +#define PTRDIFF_MIN (-2147483647L-1) +#define PTRDIFF_MAX (2147483647L) +#else +#define PTRDIFF_MIN (-32767-1) +#define PTRDIFF_MAX (32767) +#endif + +/* */ +#define SIG_ATOMIC_MIN (0) +#define SIG_ATOMIC_MAX (255) + +/* Limit of `size_t' type. */ +#define SIZE_MAX (65535u) + +/* Signed. */ +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c ## L +#ifdef __SDCC_LONGLONG +#define INT64_C(c) c ## LL +#endif + +/* Unsigned. */ +#define UINT8_C(c) c ## U +#define UINT16_C(c) c ## U +#define UINT32_C(c) c ## UL +#ifdef __SDCC_LONGLONG +#define UINT64_C(c) c ## ULL +#endif + +#define WCHAR_MIN 0 +#define WCHAR_MAX 0xffffffff + +#define WINT_MIN 0 +#define WINT_MAX 0xffffffff + +/* Maximal type. */ +#ifdef __SDCC_LONGLONG +#define INTMAX_C(c) c ## LL +#define UINTMAX_C(c) c ## ULL +#else +#define INTMAX_C(c) c ## L +#define UINTMAX_C(c) c ## UL +#endif + +/* Bounds-checking interfaces from annex K of the C11 standard. */ +#if defined (__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ +#define RSIZE_MAX SIZE_MAX +#endif + +#endif /* stdint.h */ + diff --git a/ext/include/stdio.h b/ext/include/stdio.h new file mode 100644 index 0000000..0405ff8 --- /dev/null +++ b/ext/include/stdio.h @@ -0,0 +1,76 @@ +/** @file stdio.h + Basic file/console input output functions. + + Including stdio.h 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. + */ +#ifndef STDIO_INCLUDE +#define STDIO_INCLUDE + +#include + +/** Print char to stdout. + @param c Character to print + */ + +void putchar(char c) OLDCALL REENTRANT; + +/** Print the string and arguments given by format to stdout. + + @param format The format string as per printf + + Does not return the number of characters printed. + + Currently supported: + \li \%hx (char as hex) + \li \%hu (unsigned char) + \li \%hd (signed char) + \li \%c (character) + \li \%u (unsigned int) + \li \%d (signed int) + \li \%x (unsigned int as hex) + \li \%s (string) + + Warning: to correctly pass parameters (such as chars, ints, etc) + __all of them should always be explicitly cast__ as when calling + the function. + See @ref docs_chars_varargs for more details. + */ +void printf(const char *format, ...); + +/** Print the string and arguments given by format to a buffer. + + @param str The buffer to print into + @param format The format string as per @ref printf + + Does not return the number of characters printed. + + Warning: to correctly pass parameters (such as chars, ints, etc) + __all of them should always be explicitly cast__ as when calling + the function. + See @ref docs_chars_varargs for more details. + */ +void sprintf(char *str, const char *format, ...); + +/** puts() writes the string __s__ and a trailing newline to stdout. +*/ +void puts(const char *s); + +/** gets() Reads a line from stdin into a buffer pointed to by __s__. + + @param s Buffer to store string in + + Reads until either a terminating newline or an EOF, which it replaces with '\0'. No + check for buffer overrun is performed. + + Returns: Buffer pointed to by __s__ +*/ +char *gets(char *s) OLDCALL; + +/** getchar() Reads and returns a single character from stdin. + */ +char getchar(void) OLDCALL; + +#endif diff --git a/ext/include/stdlib.h b/ext/include/stdlib.h new file mode 100644 index 0000000..606182c --- /dev/null +++ b/ext/include/stdlib.h @@ -0,0 +1,151 @@ +/** file stdlib.h + 'Standard library' functions, for whatever that means. +*/ +#ifndef STDLIB_INCLUDE +#define STDLIB_INCLUDE + +#include + +/** Causes normal program termination and the value of status is + returned to the parent. + All open streams are flushed and closed. +*/ +void exit(int status) OLDCALL; + +#if 0 +/** Compatibility function. Not implemented. + */ +int getkey(void) OLDCALL; +#endif + +/** Returns the absolute value of int __i__ + @param i Int to obtain absolute value of + + If i is negative, returns -i; else returns i. +*/ +int abs(int i); + + +/** Returns the absolute value of long int __num__ + + @param num Long integer to obtain absolute value of + */ +long labs(long num) OLDCALL; + + +/** Converts an ASCII string to an int + + @param s String to convert to an int + + The string may be of the format + \code{.c} + [\s]*[+-][\d]+[\D]* + \endcode + i.e. any number of spaces, an optional + or -, then an + arbitrary number of digits. + + The result is undefined if the number doesnt fit in an int. + + Returns: Int value of string + */ +int atoi(const char *s); + + +/** Converts an ASCII string to a long. + @param s String to convert to an long int + @see atoi() + + Returns: Long int value of string + */ +long atol(const char *s); + +/** Converts an int into a base 10 ASCII string. + @param n Int to convert to a string + @param s String to store the converted number + @param radix Numerical base for converted number, ex: 10 is decimal base + (parameter is required but not utilized on Game Boy and Analogue Pocket) + + Can be used with @ref set_bkg_based_tiles() for printing if + the digit character tiles are not ascii-mapped. + + Returns: Pointer to converted string + */ +char *itoa(int n, char *s, unsigned char radix) OLDCALL; + +/** Converts an unsigned int into a base 10 ASCII string. + @param n Unsigned Int to convert to a string + @param s String to store the converted number + @param radix Numerical base for converted number, ex: 10 is decimal base + (parameter is required but not utilized on Game Boy and Analogue Pocket) + + Can be used with @ref set_bkg_based_tiles() for printing if + the digit character tiles are not ascii-mapped. + + Returns: Pointer to converted string + */ +char *uitoa(unsigned int n, char *s, unsigned char radix) OLDCALL; + +/** Converts a long into a base 10 ASCII string. + @param n Long int to convert to a string + @param s String to store the converted number + @param radix Numerical base for converted number, ex: 10 is decimal base + (parameter is required but not utilized on Game Boy and Analogue Pocket) + + Can be used with @ref set_bkg_based_tiles() for printing if + the digit character tiles are not ascii-mapped. + + Returns: Pointer to converted string + */ +char *ltoa(long n, char *s, unsigned char radix) OLDCALL; + +/** Converts an unsigned long into a base 10 ASCII string. + @param n Unsigned Long Int to convert to a string + @param s String to store the converted number + @param radix Numerical base for converted number, ex: 10 is decimal base + (parameter is required but not utilized on Game Boy and Analogue Pocket) + + Can be used with @ref set_bkg_based_tiles() for printing if + the digit character tiles are not ascii-mapped. + + Returns: Pointer to converted string + */ +char *ultoa(unsigned long n, char *s, unsigned char radix) OLDCALL; + + +/** Memory allocation functions + */ +void *calloc (size_t nmemb, size_t size); +void *malloc (size_t size); +void *realloc (void *ptr, size_t size); +#if __STDC_VERSION__ >= 201112L +inline void *aligned_alloc(size_t alignment, size_t size) +{ + (void)alignment; + return malloc(size); +} +#endif +extern void free (void * ptr); + +/* Searching and sorting utilities (ISO C11 7.22.5) */ +/** search a sorted array of __nmemb__ items + @param key Pointer to object that is the key for the search + @param base Pointer to first object in the array to search + @param nmemb Number of elements in the array + @param size Size in bytes of each element in the array + @param compar Function used to compare two elements of the array + + Returns: Pointer to array entry that matches the search key. + If key is not found, NULL is returned. +*/ +extern void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) REENTRANT); + + +/** Sort an array of __nmemb__ items + @param base Pointer to first object in the array to sort + @param nmemb Number of elements in the array + @param size Size in bytes of each element in the array + @param compar Function used to compare and sort two elements of the array +*/ +extern void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) REENTRANT); + +#endif diff --git a/ext/include/stdnoreturn.h b/ext/include/stdnoreturn.h new file mode 100644 index 0000000..992f9b9 --- /dev/null +++ b/ext/include/stdnoreturn.h @@ -0,0 +1,7 @@ +#ifndef __SDCC_STDNORETURN_H +#define __SDCC_STDNORETURN_H 1 + +#define noreturn _Noreturn + +#endif + diff --git a/ext/include/string.h b/ext/include/string.h new file mode 100644 index 0000000..21f8f91 --- /dev/null +++ b/ext/include/string.h @@ -0,0 +1,17 @@ +/** @file string.h + Generic string functions. + */ +#ifndef STD_STRING_INCLUDE +#define STD_STRING_INCLUDE + +#if defined(__PORT_sm83) + #include +#elif defined(__PORT_z80) + #include +#elif defined(__PORT_mos6502) + #include +#else + #error Unrecognized port +#endif + +#endif diff --git a/ext/include/time.h b/ext/include/time.h new file mode 100644 index 0000000..0bd9555 --- /dev/null +++ b/ext/include/time.h @@ -0,0 +1,38 @@ +/** @file time.h + Sort of ANSI compliant time functions. +*/ +#ifndef TIME_INCLUDE +#define TIME_INCLUDE + +#include +#include + +#define CLOCKS_PER_SEC 60 + +typedef uint16_t time_t; + +/** Returns an approximation of processor time used by the program in Clocks + + The value returned is the CPU time (ticks) used so far as a @ref clock_t. + + To get the number of seconds used, divide by @ref CLOCKS_PER_SEC. + + This is based on @ref sys_time, which will wrap around every ~18 minutes. + (unsigned 16 bits = 65535 / 60 / 60 = 18.2) + + @see sys_time, time() +*/ +clock_t clock(void) OLDCALL; + +/** Converts clock() time to Seconds + + @param t If pointer __t__ is not NULL, it's value will be set to the same seconds calculation as returned by the function. + + The calculation is clock() / CLOCKS_PER_SEC + + Returns: time in seconds + @see sys_time, clock() +*/ +time_t time(time_t *t); + +#endif diff --git a/ext/include/typeof.h b/ext/include/typeof.h new file mode 100644 index 0000000..e1f6f97 --- /dev/null +++ b/ext/include/typeof.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + typeof.h - Contains enumerations of values returned by __typeof + + Copyright (C) 2001, Sandeep Dutta . sandeep.dutta@usa.net + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + As a special exception, if you link this library with other files, + some of which are compiled with SDCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. +-------------------------------------------------------------------------*/ + +#ifndef __SDC51_TYPEOF_H +#define __SDC51_TYPEOF_H 1 + +#define TYPEOF_INT 1 +#define TYPEOF_SHORT 2 +#define TYPEOF_CHAR 3 +#define TYPEOF_LONG 4 +#define TYPEOF_FLOAT 5 +#define TYPEOF_FIXED16X16 6 +#define TYPEOF_BIT 7 +#define TYPEOF_BITFIELD 8 +#define TYPEOF_SBIT 9 +#define TYPEOF_SFR 10 +#define TYPEOF_VOID 11 +#define TYPEOF_STRUCT 12 +#define TYPEOF_ARRAY 13 +#define TYPEOF_FUNCTION 14 +#define TYPEOF_POINTER 15 +#define TYPEOF_FPOINTER 16 +#define TYPEOF_CPOINTER 17 +#define TYPEOF_GPOINTER 18 +#define TYPEOF_PPOINTER 19 +#define TYPEOF_IPOINTER 20 +#define TYPEOF_EEPPOINTER 21 + +#endif diff --git a/ext/include/types.h b/ext/include/types.h new file mode 100644 index 0000000..3710bdf --- /dev/null +++ b/ext/include/types.h @@ -0,0 +1,25 @@ +/** @file types.h + Basic types. + Directly include the port specific file. +*/ +#ifndef TYPES_INCLUDE +#define TYPES_INCLUDE + +#include + +/** Good 'ol NULL. + */ +#define NULL 0 + +/** A 'false' value. + */ +#define FALSE 0 +/** A 'true' value. + */ +#define TRUE 1 + +/** No longer used. + */ +typedef void * POINTER; + +#endif diff --git a/ext/libexec/sdcc/cc1 b/ext/libexec/sdcc/cc1 new file mode 100755 index 0000000..026ca3d Binary files /dev/null and b/ext/libexec/sdcc/cc1 differ diff --git a/ext/rust-deps/.cargo/config.toml b/ext/rust-deps/.cargo/config.toml index 1a1800d..f3e9743 100644 --- a/ext/rust-deps/.cargo/config.toml +++ b/ext/rust-deps/.cargo/config.toml @@ -1,5 +1,6 @@ [build] target = "avr-unknown-gnu-atmega328" +rustflags = ["--emit=llvm-ir"] [unstable] build-std = ["core", "alloc"] diff --git a/source/.cargo/config.toml b/source/.cargo/config.toml index 21dee5a..3c495f3 100644 --- a/source/.cargo/config.toml +++ b/source/.cargo/config.toml @@ -4,6 +4,8 @@ rustflags = ["--emit=llvm-ir"] # [target.avr-unknown-gnu-atmega328] +[unstable] +build-std = ["core", "alloc"] [profile.dev] panic = "abort" diff --git a/source/Cargo.lock b/source/Cargo.lock deleted file mode 100644 index e0f6612..0000000 --- a/source/Cargo.lock +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "rust-gb" -version = "0.1.0" - -[[package]] -name = "xtask" -version = "0.1.0" diff --git a/source/Cargo.toml b/source/Cargo.toml index 552a3fb..253eef4 100644 --- a/source/Cargo.toml +++ b/source/Cargo.toml @@ -3,6 +3,4 @@ name = "rust-gb" version = "0.1.0" edition = "2021" -[dependencies] -buddy_system_allocator = "0.10.0" diff --git a/source/src/gbdk/gb.rs b/source/src/gbdk/gb.rs index 0f09907..f720171 100644 --- a/source/src/gbdk/gb.rs +++ b/source/src/gbdk/gb.rs @@ -1,50 +1,63 @@ pub mod gb { extern "C" { + #[link_name="delay"] pub fn delay(delay: u16); #[link_name="waitpad __preserves_regs(b, c, h, l)"] pub fn waitpad(mask: u8) -> u8; - #[link_name="waitpad __preserves_regs(a, b, c, d, e, h, l)"] + #[link_name="waitpadup __preserves_regs(a, b, c, d, e, h, l)"] pub fn waitpadup(); } } pub mod drawing { use core::ffi::c_char; + pub const GRAPHICS_WIDTH: u8 = 160; pub const GRAPHICS_HEIGHT: u8 = 144; + pub const SOLID: u8 = 0x00; + pub const OR: u8 = 0x01; + pub const XOR: u8 = 0x02; + pub const AND: u8 = 0x03; + pub const WHITE: u8 = 0; pub const LTGREY: u8 = 1; pub const DKGREY: u8 = 2; pub const BLACK: u8 = 3; - pub const SIGNED: u8 = 1; - pub const UNSIGNED: u8 = 0; - pub const M_NOFILL: u8 = 0; pub const M_FILL: u8 = 1; - pub const SOLID: u8 = 0x00; - pub const OR: u8 = 0x01; - pub const XOR: u8 = 0x02; - pub const AND: u8 = 0x03; + pub const SIGNED: u8 = 1; + pub const UNSIGNED: u8 = 0; extern "C" { - #[link_name="circle __sdcccall(0) __preserve_regs(a, b, c)"] - pub fn circle(x: u8, y: u8, radius: u8, style: u8); - #[link_name="color __sdcccall(0)"] - pub fn color(forecolor: u8, backcolor: u8, mode: u8); - #[link_name="line __sdcccall(0)"] - pub fn line(x1: u8, y1: u8, x2: u8, y2: u8); - #[link_name="gotogxy __sdcccall(0)"] - pub fn gotogxy(x: u8, y: u8); #[link_name="gprint __nonbanked"] pub fn gprint(str: *const c_char); + //gprintln + //gprintn + //gprintf + #[link_name="plot __sdcccall(0)"] + pub fn plot(x: u8, y: u8, colour: u8, mode: u8); + #[link_name="plot_point __sdcccall(0)"] + pub fn plot_point(x: u8, y:u8); + #[link_name="switch_data __sdcccall(0)"] + pub fn switch_data(x: u8, y: u8, src: *const u8, dst: *const u8); + #[link_name="draw_image"] + pub fn draw_image(data: *const u8); + #[link_name="line __sdcccall(0)"] + pub fn line(x1: u8, y1: u8, x2: u8, y2: u8); #[link_name="box __sdcccall(0)"] pub fn r#box(x1: u8, y1: u8, x2: u8, y2: u8, style: u8); + #[link_name="circle __sdcccall(0)"] + pub fn circle(x: u8, y: u8, radius: u8, style: u8); #[link_name="getpix __sdcccall(0)"] pub fn getpix(x: u8, y: u8) -> u8; - #[link_name="plot_point __sdcccall(0)"] - pub fn plot_point(x: u8, y:u8); + #[link_name="wrtchr __sdcccall(0)"] + pub fn wrtchr(chr: i8); + #[link_name="gotogxy __sdcccall(0)"] + pub fn gotogxy(x: u8, y: u8); + #[link_name="color __sdcccall(0)"] + pub fn color(forecolor: u8, backcolor: u8, mode: u8); } } diff --git a/source/src/gbdk/mod.rs b/source/src/gbdk/mod.rs index b3679eb..a7e0d96 100644 --- a/source/src/gbdk/mod.rs +++ b/source/src/gbdk/mod.rs @@ -1 +1,2 @@ pub mod gb; +pub mod rand; diff --git a/source/src/gbdk/rand.rs b/source/src/gbdk/rand.rs new file mode 100644 index 0000000..6c8a1c8 --- /dev/null +++ b/source/src/gbdk/rand.rs @@ -0,0 +1,8 @@ +extern "C" { + #[link_name="rand __sdcccall(0)"] + pub fn rand() -> u8; + #[link_name="arand __sdcccall(0)"] + pub fn arand() -> u8; + #[link_name="initarand __sdcccall(0)"] + pub fn initarand(seed: u16); +} diff --git a/source/src/main.rs b/source/src/main.rs index 49beae7..5e73d72 100644 --- a/source/src/main.rs +++ b/source/src/main.rs @@ -3,70 +3,32 @@ #![allow(dead_code)] #![feature(asm_experimental_arch)] -use core::ffi::c_char; - mod gbdk; -use gbdk::gb::drawing::{r#box, circle, color, getpix, gotogxy, gprint, line, plot_point, BLACK, DKGREY, LTGREY, M_FILL, M_NOFILL, SOLID, WHITE, XOR}; -fn linetest(x: u8, y: u8, w: u8) { - let w = w as i8; - unsafe { - color(DKGREY, WHITE, SOLID); - for i in -w..w+1 { - line(x, y, x+i as u8, y-w as u8); - } - for i in -w..w+1 { - line(x, y, x+w as u8, y+i as u8); - } - for i in -w..w+1 { - line(x, y, x+i as u8, y+w as u8); - } - for i in -w..w+1 { - line(x, y, x-w as u8, y+i as u8); - } - } -} +use core::ffi::c_char; + +use gbdk::{gb::{drawing::{gotogxy, gprint, plot, plot_point, LTGREY, SOLID}, gb::{delay, waitpad, waitpadup}}, rand::{initarand, rand}}; #[no_mangle] pub extern fn main() { - let mut c: c_char = 0; unsafe { - for a in 0..16 { - for b in 0..16 { - gotogxy(b, a); - let mut d = a/4; - let e = b/4; - if d == e { - d = 3 - e; - } - color(d, e, SOLID); - gprint(&[c, 0] as *const c_char); - c += 1; - } - } - - color(LTGREY,WHITE,SOLID); - circle(140,20,15,M_FILL); - color(BLACK,WHITE,SOLID); - circle(140,20,10,M_NOFILL); - color(DKGREY,WHITE,XOR); - circle(120,40,30,M_FILL); - line(0,0,159,143); - color(BLACK,LTGREY,SOLID); - r#box(0,130,40,143,M_NOFILL); - r#box(50,130,90,143,M_FILL); - - linetest(130, 100, 20); - - for _c in 0..144 { - for b in 0..143 { - for a in 0..160 { - color(getpix(a, b+1), WHITE, SOLID); - plot_point(a, b); - } - color(WHITE, WHITE, SOLID); - } - line(0, 143, 159, 143); + gprint("Getting seed\0".as_ptr() as *const c_char); + gotogxy(0, 1); + gprint("Push any key (1)\0".as_ptr() as *const c_char); + let a: u8 = waitpad(0xFF); + waitpadup(); + let mut seed = a as u16; + gotogxy(0, 2); + gprint("Push any key (2)\0".as_ptr() as *const c_char); + let b: u8 = waitpad(0xFF); + waitpadup(); + seed |= (b as u16) << 8; + + initarand(seed); + + loop { + let r = rand(); + gprint([r, 0].as_ptr() as *const c_char); } } } diff --git a/xtask/build-rom/Cargo.toml b/xtask/build-rom/Cargo.toml index 4b0cb0b..d8724e5 100644 --- a/xtask/build-rom/Cargo.toml +++ b/xtask/build-rom/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] clap = { version = "4.5.17", features = ["derive"] } colored = "2.1.0" +project-root = "0.2.2" tree-sitter = "0.23.0" tree-sitter-c = "0.23.0" diff --git a/xtask/build-rom/src/main.rs b/xtask/build-rom/src/main.rs index 491b26a..e6210a7 100644 --- a/xtask/build-rom/src/main.rs +++ b/xtask/build-rom/src/main.rs @@ -1,8 +1,9 @@ use core::str; -use std::{fs::{self, File, OpenOptions}, io::{ErrorKind, Write}, process::{self, Command}, str::FromStr}; +use std::{fs::{self, File}, io::{ErrorKind, Write}, process::{self, Command}, str::FromStr}; use clap::Parser; use colored::Colorize; +use project_root::get_project_root; use tree_sitter::{self, Query, QueryCursor}; ///Build GB ROM from Rust @@ -41,12 +42,15 @@ fn main() { let args = Args::parse(); let build_from = BuildChain::from_str(&args.from).unwrap(); + let root = get_project_root().unwrap(); + let root = root.to_str().unwrap(); + fs::create_dir_all("./out").unwrap(); if build_from <= BuildChain::Rust { let bundle_result = Command::new("rust_bundler_cp") .args([ - "--input", "./source", + "--input", ".", ]) .output() .unwrap(); @@ -68,9 +72,9 @@ fn main() { let libcompiler = Command::new("find") .args([ - "./ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", - "-name", - "libcompiler*.rlib" + format!("{}/ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", root), + "-name".to_string(), + "libcompiler*.rlib".to_string() ]) .output() .unwrap() @@ -79,9 +83,9 @@ fn main() { let libcore = Command::new("find") .args([ - "./ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", - "-name", - "libcore*.rlib" + format!("{}/ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", root), + "-name".to_string(), + "libcore*.rlib".to_string() ]) .output() .unwrap() @@ -90,9 +94,9 @@ fn main() { let liballoc = Command::new("find") .args([ - "./ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", - "-name", - "liballoc*.rlib" + format!("{}/ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", root), + "-name".to_string(), + "liballoc*.rlib".to_string() ]) .output() .unwrap() @@ -108,7 +112,7 @@ fn main() { "-C", "panic=abort", "-Z", "unstable-options", - "-L", "dependency=./ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", + "-L", format!("dependency={}/ext/rust-deps/target/avr-unknown-gnu-atmega328/release/deps", root).as_str(), "--extern", format!("noprelude:compiler_builtins={}", libcompiler).as_str(), "--extern", format!("noprelude:core={}", libcore).as_str(), "--extern", format!("noprelude:alloc={}", liballoc).as_str(), @@ -129,7 +133,7 @@ fn main() { } if build_from <= BuildChain::LLVM { - let llvm_status = Command::new("./ext/llvm-project/llvm/build/bin/llvm-cbe") + let llvm_status = Command::new(format!("{}/ext/llvm-project/llvm/build/bin/llvm-cbe", root)) .args([ "--cbe-declare-locals-late", "./out/out.ll", @@ -147,19 +151,29 @@ fn main() { } //C postprocessing for SDCC - //Command::new("sed 's/static __forceinline/inline/g' -i ./out/main.c").status().unwrap(); - //Command::new("sed 's/uint8_t\\* memset(uint8_t\\*, uint32_t, uint16_t);/inline uint8_t\\* memset(uint8_t\\* dst, uint8_t c, uint16_t sz) {uint8_t \\*p = dst; while (sz--) *p++ = c; return dst; }/g' -i ./out/main.c").status().unwrap(); - //Command::new("sed '/__noreturn void rust_begin_unwind(struct l_struct_core_KD__KD_panic_KD__KD_PanicInfo\\* llvm_cbe_info)/{:a;N;/__builtin_unreachable/{N;N;d};/ }/b;ba}' -i ./out/main.c").status().unwrap(); fs::copy("./out/out.c", "./out/pre.c").unwrap(); let postprocess_status = treesitter_process(); if postprocess_status.is_err() { - println!("{}", "[sed] C postprocess for SDCC failed".red()); + println!("{}", "[treesitter] C postprocess for SDCC failed".red()); process::exit(1); } else { - println!("{}", "[sed] C postprocess for SDCC succeeded".green()); + println!("{}", "[treesitter] C postprocess for SDCC succeeded".green()); } + + Command::new("sed") + .args(["s/static __forceinline/inline/g' -i ./out/out.c"]) + .status() + .unwrap(); + Command::new("sed") + .args(["s/uint8_t\\* memset(uint8_t\\*, uint32_t, uint16_t);/inline uint8_t\\* memset(uint8_t\\* dst, uint8_t c, uint16_t sz) {uint8_t \\*p = dst; while (sz--) *p++ = c; return dst; }/g' -i ./out/out.c"]) + .status() + .unwrap(); + Command::new("sed") + .args(["/__noreturn void rust_begin_unwind(struct l_struct_core_KD__KD_panic_KD__KD_PanicInfo\\* llvm_cbe_info)/{:a;N;/__builtin_unreachable/{N;N;d};/ }/b;ba}' -i ./out/out.c"]) + .status() + .unwrap(); } if build_from <= BuildChain::C { @@ -171,6 +185,8 @@ fn main() { "-D", "__builtin_unreachable()=while(1);", "--out-fmt-ihx", "--max-allocs-per-node", "2000", + "--disable-warning", "110", + "--disable-warning", "126", "--allow-unsafe-read", "--opt-code-speed", "--no-std-crt0", @@ -198,8 +214,9 @@ fn main() { } if build_from <= BuildChain::ASM { - let lcc_status = Command::new("./ext/bin/lcc") + let lcc_status = Command::new(format!("{}/ext/bin/lcc", root)) .args([ + "-msm83:gb", "-o", "./out/out.gb", "./out/out.asm" ]) @@ -218,22 +235,21 @@ fn main() { } } -fn treesitter_process() -> Result<(), std::io::Error> { - let mut code = fs::read_to_string("./out/out.c")?; - let code_bytes = code.clone(); - let code_bytes = code_bytes.as_bytes(); +fn parse_declarator_attributes(code: &mut String, code_bytes: &[u8]) { let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap(); let tree = parser.parse(code_bytes, None).unwrap(); - let query = Query::new(&tree_sitter_c::LANGUAGE.into(), "(function_declarator(identifier)@iden)@decl").unwrap(); + let query = Query::new(&tree_sitter_c::LANGUAGE.into(), "(function_declarator(identifier)@a)@b").unwrap(); let mut cursor = QueryCursor::new(); let mut diff: i32 = 0; for qm in cursor.matches(&query, tree.root_node(), code_bytes) { - let node = qm.captures[1].node; - let identifier = node.utf8_text(&code_bytes).unwrap(); + let declarator_node = qm.captures[0].node; + let identifier_node = qm.captures[1].node; + let declarator = declarator_node.utf8_text(&code_bytes).unwrap(); + let identifier = identifier_node.utf8_text(&code_bytes).unwrap(); let attributes: Vec<_> = identifier.split("_AC___").collect(); //` __` if attributes.len() < 2 { @@ -242,19 +258,69 @@ fn treesitter_process() -> Result<(), std::io::Error> { match &attributes[..] { [] | [_] => {}, - [name, attrib @ ..] => { - code.replace_range(((node.start_byte() as i32) + diff) as usize..((node.end_byte() as i32) + diff) as usize, name); - diff += name.len() as i32 - node.byte_range().len() as i32; + [_, attrib @ ..] => { let attrib = format!("__{}", attrib.join(" __")); let attrib = attrib .replace("_AC_", " ") .replace("_IC_", "(") .replace("_JC_", ")") .replace("_MC_", ","); - println!("{:?}", attrib); + + let start = declarator.find("_AC_").unwrap(); + let end = declarator.find("(").unwrap(); + let mut declarator = String::from(declarator); + declarator.replace_range(start..end, ""); + + code.replace_range( + ((declarator_node.start_byte() as i32) + diff) as usize.. + ((declarator_node.end_byte() as i32) + diff) as usize, + &format!("{} {}", declarator, attrib)); + diff += (declarator.len() + attrib.len() + 1) as i32 - declarator_node.byte_range().len() as i32; } } } +} + +fn parse_call_expression_attributes(code: &mut String, code_bytes: &[u8]) { + let mut parser = tree_sitter::Parser::new(); + parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap(); + + let tree = parser.parse(code_bytes, None).unwrap(); + let query = Query::new(&tree_sitter_c::LANGUAGE.into(), "(call_expression(identifier)@a)").unwrap(); + let mut cursor = QueryCursor::new(); + + let mut diff: i32 = 0; + + for qm in cursor.matches(&query, tree.root_node(), code_bytes) { + let identifier_node = qm.captures[0].node; + let identifier = identifier_node.utf8_text(&code_bytes).unwrap(); + + let start = identifier.find("_AC_"); + let start = match start { + None => continue, + Some(start) => start + }; + + let mut identifier = String::from(identifier); + identifier.replace_range(start.., ""); + + code.replace_range( + ((identifier_node.start_byte() as i32) + diff) as usize.. + ((identifier_node.end_byte() as i32) + diff) as usize, + &identifier); + diff += identifier.len() as i32 - identifier_node.byte_range().len() as i32; + } +} + +fn treesitter_process() -> Result<(), std::io::Error> { + let mut code = fs::read_to_string("./out/out.c")?; + let code_bytes = code.clone(); + let code_bytes = code_bytes.as_bytes(); + parse_declarator_attributes(&mut code, code_bytes); + + let code_bytes = code.clone(); + let code_bytes = code_bytes.as_bytes(); + parse_call_expression_attributes(&mut code, code_bytes); let mut file = File::create("./out/out.c")?; file.write_all(&code.as_bytes())?;