diff --git a/src/assets/hello-world.asm b/src/assets/hello-world.asm index 725620eb..104a4637 100644 --- a/src/assets/hello-world.asm +++ b/src/assets/hello-world.asm @@ -56,7 +56,7 @@ CopyTilemap: jp nz, CopyTilemap ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON + ld a, LCDC_ON | LCDCF_BG_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers diff --git a/src/cheatsheet.md b/src/cheatsheet.md index b4770f82..40cc8432 100644 --- a/src/cheatsheet.md +++ b/src/cheatsheet.md @@ -64,12 +64,12 @@ WaitUntilVerticalBlankStart: ### Turn on/off the LCD -You can turn the LCD on and off by altering the most significant bit of the `rLCDC` register. hardware.inc a constant for this: `LCDCF_ON` . +You can turn the LCD on and off by altering the most significant bit of the `rLCDC` register. hardware.inc a constant for this: `LCDC_ON` . **To turn the LCD on:** ```rgbasm,linenos -ld a, LCDCF_ON +ld a, LCDC_ON ldh [rLCDC], a ``` @@ -83,20 +83,20 @@ Do not turn the LCD off outside of the Vertical Blank Phase. See "[Wait for the ```rgbasm,linenos ; Turn the LCD off -ld a, LCDCF_OFF +ld a, LCDC_OFF ldh [rLCDC], a ``` ### Turn on/off the background -To turn the background layer on and off, alter the least significant bit of the `rLCDC` register. You can use the `LCDCF_BGON` constant for this. +To turn the background layer on and off, alter the least significant bit of the `rLCDC` register. You can use the `LCDC_BG_ON` constant for this. **To turn the background on:** ```rgbasm,linenos ; Turn the background on ldh a, [rLCDC] -or a, LCDCF_BGON +or a, LCDC_BG_ON ldh [rLCDC], a ``` @@ -105,20 +105,20 @@ ldh [rLCDC], a ```rgbasm,linenos ; Turn the background off ldh a, [rLCDC] -and a, ~LCDCF_BGON +and a, ~LCDC_BG_ON ldh [rLCDC], a ``` ### Turn on/off the window -To turn the window layer on and off, alter the least significant bit of the `rLCDC` register. You can use the `LCDCF_WINON` and `LCDCF_WINOFF` constants for this. +To turn the window layer on and off, alter the least significant bit of the `rLCDC` register. You can use the `LCDC_WIN_ON` and `LCDC_WIN_OFF` constants for this. **To turn the window on:** ```rgbasm,linenos ; Turn the window on ldh a, [rLCDC] -or a, LCDCF_WINON +or a, LCDC_WIN_ON ldh [rLCDC], a ``` @@ -127,7 +127,7 @@ ldh [rLCDC], a ```rgbasm,linenos ; Turn the window off ldh a, [rLCDC] -and a, LCDCF_WINOFF +and a, LCDC_WIN_OFF ldh [rLCDC], a ``` @@ -141,10 +141,10 @@ Which region the background uses is controlled by the 4th bit of the `rLCDC` reg You can use one of the 4 constants to specify which layer uses which region: -- LCDCF_WIN9800 -- LCDCF_WIN9C00 -- LCDCF_BG9800 -- LCDCF_BG9C00 +- LCDC_WIN_9800 +- LCDC_WIN_9C00 +- LCDC_BG_9800 +- LCDC_BG_9C00 :::tip Note @@ -154,14 +154,14 @@ You still need to make sure the window and background are turned on when using t ### Turn on/off sprites -Sprites (or objects) can be toggled on and off using the 2nd bit of the `rLCDC` register. You can use the `LCDCF_OBJON` and `LCDCF_OBJOFF` constants for this. +Sprites (or objects) can be toggled on and off using the 2nd bit of the `rLCDC` register. You can use the `LCDC_OBJ_ON` and `LCDC_OBJ_OFF` constants for this. **To turn sprite objects on:** ```rgbasm,linenos ; Turn the sprites on ldh a, [rLCDC] -or a, LCDCF_OBJON +or a, LCDC_OBJ_ON ldh [rLCDC], a ``` @@ -170,7 +170,7 @@ ldh [rLCDC], a ```rgbasm,linenos ; Turn the sprites off ldh a, [rLCDC] -and a, LCDCF_OBJOFF +and a, LCDC_OBJ_OFF ldh [rLCDC], a ``` @@ -182,7 +182,7 @@ Sprites are in 8x8 mode by default. ### Turn on/off tall (8x16) sprites -Once sprites are enabled, you can enable tall sprites using the 3rd bit of the `rLCDC` register: `LCDCF_OBJ16` +Once sprites are enabled, you can enable tall sprites using the 3rd bit of the `rLCDC` register: `LCDC_OBJ_16` :::tip @@ -193,7 +193,7 @@ You can not have some 8x8 sprites and some 8x16 sprites. All sprites must be of ```rgbasm,linenos ; Turn tall sprites on ldh a, [rLCDC] -or a, LCDCF_OBJ16 +or a, LCDC_OBJ_16 ldh [rLCDC], a ``` @@ -201,7 +201,7 @@ ldh [rLCDC], a ### Put background/window tile data into VRAM -The region in VRAM dedicated for the background/window tilemaps is from $9000 to $97FF. hardware.inc defines a `_VRAM9000` constant you can use for that. +The region in VRAM dedicated for the background/window tilemaps is from $9000 to $97FF. The assembly language defines a `STARTOF` function you can use that will help to determine the value at link time. ```rgbasm, lineno MyBackground: @@ -211,7 +211,7 @@ MyBackground: CopyBackgroundWindowTileDataIntoVram: ; Copy the tile data ld de, myBackground - ld hl, \_VRAM + ld hl, STARTOF(VRAM) + $1000 ld bc, MyBackground.end - MyBackground .loop: ld a, [de] @@ -328,20 +328,20 @@ call UpdateKeys You can check if a button is down using any of the following constants from hardware.inc: -- PADF_DOWN -- PADF_UP -- PADF_LEFT -- PADF_RIGHT -- PADF_START -- PADF_SELECT -- PADF_B -- PADF_A +- PAD_DOWN +- PAD_UP +- PAD_LEFT +- PAD_RIGHT +- PAD_START +- PAD_SELECT +- PAD_B +- PAD_A You can check if the associataed button is down using the `wCurKeys` variable: ```rgbasm,linenos ld a, [wCurKeys] -and a, PADF_LEFT +and a, PAD_LEFT jp nz, LeftIsPressedDown ``` @@ -351,7 +351,7 @@ You can tell if a button was JUST pressed using the `wNewKeys` variable ```rgbasm,linenos ld a, [wNewKeys] -and a, PADF_A +and a, PAD_A jp nz, AWasJustPressed ``` @@ -374,7 +374,7 @@ This will halt all other logic (outside of interrupts), be careful if you need a ```rgbasm, linenos WaitForAButtonToBePressed: ld a, [wNewKeys] - and a, PADF_A + and a, PAD_A ret nz WaitUntilVerticalBlankStart: ld a, [rLY] @@ -515,7 +515,7 @@ Sprites will still show over the window. To fully prevent that, you can use STAT ### Put sprite tile data in VRAM -The region in VRAM dedicated for sprites is from `$8000` to `$87F0`. Hardware.inc defines a `_VRAM` constant you can use for that. To copy sprite tile data into VRAM, you can use a loop to copy the bytes. +The region in VRAM dedicated for sprites is from `$8000` to `$87F0`. The assembly language defines a `STARTOF` function you can use for that. To copy sprite tile data into VRAM, you can use a loop to copy the bytes. ```rgbasm,linenos mySprite: INCBIN "src/path/to/my/sprite.2bpp" @@ -524,7 +524,7 @@ mySpriteEnd: CopySpriteTileDataIntoVram: ; Copy the tile data ld de, Paddle - ld hl, _VRAM + ld hl, STARTOF(VRAM) ld bc, mySpriteEnd - mySprite CopySpriteTileDataIntoVram_Loop: ld a, [de] @@ -547,29 +547,29 @@ Each hardware sprite has 4 bytes: (in this order) Check out the Pan Docs page on [Object Attribute Memory (OAM)](https://gbdev.io/pandocs/OAM.html) for more info. -The bytes controlling hardware OAM sprites start at `$FE00`, for which hardware.inc has defined a constant as `_OAMRAM`. +The bytes controlling hardware OAM sprites start at `$FE00`, for which the assembly language has a section type `OAM`. **Moving (the first) OAM sprite, one pixel downwards:** ```rgbasm, linenos -ld a, [_OAMRAM] +ld a, [STARTOF(OAM)] inc a -ld [_OAMRAM], a +ld [STARTOF(OAM)], a ``` **Moving (the first) OAM sprite, one pixel to the right:** ```rgbasm, linenos -ld a, [_OAMRAM + 1] +ld a, [ + 1] inc a -ld [_OAMRAM + 1], a +ld [STARTOF(OAM) + 1], a ``` **Setting the tile for the first OAM sprite:** ```rgbasm, linenos ld a, 3 -ld [_OAMRAM+2], a +ld [STARTOF(OAM)+2], a ``` **Moving (the fifth) OAM sprite, one pixel downwards:** @@ -605,7 +605,7 @@ The library is relatively simple to get set up. First, put the following in your ; Reset hardware OAM xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) .resetOAM ld [hli], a dec b @@ -623,7 +623,7 @@ call hOAMDMA ### Manipulate Shadow OAM OAM sprites -Once you've set up @eievui5's Sprite Object Library, you can manipulate shadow OAM sprites the exact same way you would manipulate normal hardware OAM sprites. Except, this time you would use the library's `wShadowOAM` constant instead of the `_OAMRAM` register. +Once you've set up @eievui5's Sprite Object Library, you can manipulate shadow OAM sprites the exact same way you would manipulate normal hardware OAM sprites. Except, this time you would use the library's `wShadowOAM` constant instead of the `OAM` register. **Moving (the first) OAM sprite, one pixel downwards:** @@ -656,13 +656,13 @@ wCurrentLevel:: db ``` -To access SRAM, you need to write `CART_SRAM_ENABLE` to the `rRAMG` register. When done, you can disable SRAM using the `CART_SRAM_DISABLE` constant. +To access SRAM, you need to write `RAMG_SRAM_ENABLE` to the `rRAMG` register. When done, you can disable SRAM using the `RAMG_SRAM_DISABLE` constant. **To enable read/write access to SRAM:** ```rgbasm, linenos -ld a, CART_SRAM_ENABLE +ld a, RAMG_SRAM_ENABLE ld [rRAMG], a ``` @@ -671,7 +671,7 @@ ld [rRAMG], a ```rgbasm, linenos -ld a, CART_SRAM_DISABLE +ld a, RAMG_SRAM_DISABLE ld [rRAMG], a ``` @@ -703,7 +703,7 @@ When initializing your save data, you'll need to ;; Setup our save data InitSaveData:: - ld a, CART_SRAM_ENABLE + ld a, RAMG_SRAM_ENABLE ld [rRAMG], a ld a, 123 @@ -718,7 +718,7 @@ InitSaveData:: ld a, 0 ld [wCurrentLevel], a - ld a, CART_SRAM_DISABLE + ld a, RAMG_SRAM_DISABLE ld [rRAMG], a ret @@ -731,14 +731,14 @@ Once your save file has been initialized, you can access any variable normally o ;; Setup our save data StartNextLevel:: - ld a, CART_SRAM_ENABLE + ld a, RAMG_SRAM_ENABLE ld [rRAMG], a ld a, [wCurrentLevel] cp a, 3 call z, StartLevel3 - ld a, CART_SRAM_DISABLE + ld a, RAMG_SRAM_DISABLE ld [rRAMG], a ret diff --git a/src/part1/hello_world.md b/src/part1/hello_world.md index 8f26fae2..f0ee604c 100644 --- a/src/part1/hello_world.md +++ b/src/part1/hello_world.md @@ -8,7 +8,7 @@ It's a good idea to create a new directory (`mkdir gb_hello_world`, for example, Grab the following files (right-click each link, "Save Link As..."), and place them all in this new directory: - [`hello-world.asm`](../assets/hello-world.asm) -- [`hardware.inc`](https://raw.githubusercontent.com/gbdev/hardware.inc/v4.0/hardware.inc) +- [`hardware.inc v5.3.0`](https://raw.githubusercontent.com/gbdev/hardware.inc/v5.3.0/hardware.inc) Then, still from a terminal within that directory, run the following three commands. diff --git a/src/part2/bricks.md b/src/part2/bricks.md index e0e4b9a0..d9220494 100644 --- a/src/part2/bricks.md +++ b/src/part2/bricks.md @@ -32,10 +32,10 @@ It should go right **before** the momentum is modified. BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 + 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel ; Returns tile address in hl @@ -47,10 +47,10 @@ BounceOnTop: ld [wBallMomentumY], a BounceOnRight: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 - 1 ld b, a call GetTileByPixel @@ -62,10 +62,10 @@ BounceOnRight: ld [wBallMomentumX], a BounceOnLeft: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 + 1 ld b, a call GetTileByPixel @@ -77,10 +77,10 @@ BounceOnLeft: ld [wBallMomentumX], a BounceOnBottom: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 - 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel diff --git a/src/part2/collision.md b/src/part2/collision.md index e53c8465..d3419dcc 100644 --- a/src/part2/collision.md +++ b/src/part2/collision.md @@ -229,14 +229,14 @@ Hint: you can do this with just a single instruction!
Answer: ```diff linenos,start={{#line_no_of "" ../../unbricked/collision/main.asm:paddle-bounce}} - ld a, [_OAMRAM] + ld a, [STARTOF(OAM)] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] + add a, 6 cp a, b ``` -Alternatively, you can add `sub a, 6` just after `ld a, [_OAMRAM]`. +Alternatively, you can add `sub a, 6` just after `ld a, [STARTOF(OAM)]`. In both cases, try playing with that `6` value; see what feels right! diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index d0f7c1d1..24a75b88 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -6,7 +6,7 @@ We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%2 Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello_world.md). -Start by creating a file called `main.asm`, and include `hardware.inc` in your code. +Start by creating a file called `main.asm`, and include [`hardware.inc v5.3.0`](https://raw.githubusercontent.com/gbdev/hardware.inc/v5.3.0/hardware.inc) in your code. ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:includes}} {{#include ../../unbricked/getting-started/main.asm:includes}} @@ -23,9 +23,9 @@ But, having to remember all the numbers ([non-exhaustive list](https://gbdev.io/ :::tip -Don't worry if this flew over your head, we'll see an example below with `rLCDC` and `LCDCF_ON`. +Don't worry if this flew over your head, we'll see an example below with `rLCDC` and `LCDC_ON`. -By the way, the `r` stands for "register", and the `F` in `LCDCF` stands for "flag". +By the way, the `r` stands for "register". ::: @@ -78,7 +78,7 @@ But there is more to them than meets the eye, so we will start tackling them muc ::: Finally, let's turn the screen back on, and set a [background palette](../part1/palettes.md). -Rather than writing the non-descript number `%10000001` (or $81 or 129, to taste), we make use of two constants graciously provided by `hardware.inc`: `LCDCF_ON` and `LCDCF_BGON`. +Rather than writing the non-descript number `%10000001` (or $81 or 129, to taste), we make use of two constants graciously provided by `hardware.inc`: `LCDC_ON` and `LCDC_BG_ON`. When written to [`rLCDC`](https://gbdev.io/pandocs/LCDC), the former causes the PPU and screen to turn back on, and the latter enables the background to be drawn. (There are other elements that could be drawn, but we are not enabling them yet.) Combining these constants must be done using `|`, the *binary "or"* operator; we'll see why later. diff --git a/src/part2/input.md b/src/part2/input.md index f99074ce..f08759a2 100644 --- a/src/part2/input.md +++ b/src/part2/input.md @@ -37,7 +37,7 @@ We can do that below our initialization of `wFrameCounter`. ``` We're going to use the `and` opcode, which we can use to set the zero flag (`z`) to the value of the bit. -We can use this along with the `PADF` constants in hardware.inc to read a particular key. +We can use this along with the `PAD` constants in hardware.inc to read a particular key. ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/input/main.asm:main}} {{#include ../../unbricked/input/main.asm:main}} diff --git a/src/part2/objects.md b/src/part2/objects.md index ef79450c..d4f03e9e 100644 --- a/src/part2/objects.md +++ b/src/part2/objects.md @@ -110,9 +110,9 @@ WaitVBlank2: jp c, WaitVBlank2 ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ``` diff --git a/src/part3/project-structure.md b/src/part3/project-structure.md index 7c1482fe..9fda0d26 100644 --- a/src/part3/project-structure.md +++ b/src/part3/project-structure.md @@ -4,6 +4,12 @@ This page is going to give you an idea of how the Galactic Armada project is str The code can be found at [https://github.com/gbdev/gb-asm-tutorial/tree/master/galactic-armada](https://github.com/gbdev/gb-asm-tutorial/tree/master/galactic-armada). +:::tip + +Part III Galactic Aramada is using `hardware.inc v4.0` + +::: + ## Folder Layout For organizational purposes, many parts of the logic are separated into reusable functions. This is to reduce duplicate code, and make logic more clear. diff --git a/unbricked/audio/hardware.inc b/unbricked/audio/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/audio/hardware.inc +++ b/unbricked/audio/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/audio/main.asm b/unbricked/audio/main.asm index 784f5de3..f166188f 100644 --- a/unbricked/audio/main.asm +++ b/unbricked/audio/main.asm @@ -49,14 +49,14 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b jp nz, ClearOam ; Initialize the paddle sprite in OAM - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -81,7 +81,7 @@ ClearOam: ld [wBallMomentumY], a ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -105,24 +105,24 @@ WaitVBlank2: ; Add the ball's momentum to its position in OAM. ld a, [wBallMomentumX] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, b - ld [_OAMRAM + 5], a + ld [STARTOF(OAM) + 5], a ld a, [wBallMomentumY] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] add a, b - ld [_OAMRAM + 4], a + ld [STARTOF(OAM) + 4], a ; ANCHOR: updated-bounce BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 + 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel ; Returns tile address in hl @@ -135,10 +135,10 @@ BounceOnTop: call PlayBounceSound BounceOnRight: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 - 1 ld b, a call GetTileByPixel @@ -151,10 +151,10 @@ BounceOnRight: call PlayBounceSound BounceOnLeft: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 + 1 ld b, a call GetTileByPixel @@ -167,10 +167,10 @@ BounceOnLeft: call PlayBounceSound BounceOnBottom: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 - 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel @@ -184,15 +184,15 @@ BounceOnBottom: BounceDone: ; First, check if the ball is low enough to bounce off the paddle. - ld a, [_OAMRAM] + ld a, [STARTOF(OAM)] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] cp a, b jp nz, PaddleBounceDone ; Now let's compare the X positions of the objects to see if they're touching. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, 16 cp a, b jp c, PaddleBounceDone @@ -213,31 +213,31 @@ PaddleBounceDone: ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] - and a, PADF_LEFT + and a, PAD_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] - and a, PADF_RIGHT + and a, PAD_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Convert a pixel position to a tilemap address @@ -313,20 +313,20 @@ CheckForBrickRight: Input: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -338,11 +338,11 @@ Input: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/bcd/hardware.inc b/unbricked/bcd/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/bcd/hardware.inc +++ b/unbricked/bcd/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index 90d994c3..9420631e 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -53,14 +53,14 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b jp nz, ClearOam ; Initialize the paddle sprite in OAM - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -85,7 +85,7 @@ ClearOam: ld [wBallMomentumY], a ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -114,23 +114,23 @@ WaitVBlank2: ; Add the ball's momentum to its position in OAM. ld a, [wBallMomentumX] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, b - ld [_OAMRAM + 5], a + ld [STARTOF(OAM) + 5], a ld a, [wBallMomentumY] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] add a, b - ld [_OAMRAM + 4], a + ld [STARTOF(OAM) + 4], a BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 + 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel ; Returns tile address in hl @@ -142,10 +142,10 @@ BounceOnTop: ld [wBallMomentumY], a BounceOnRight: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 - 1 ld b, a call GetTileByPixel @@ -157,10 +157,10 @@ BounceOnRight: ld [wBallMomentumX], a BounceOnLeft: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 + 1 ld b, a call GetTileByPixel @@ -172,10 +172,10 @@ BounceOnLeft: ld [wBallMomentumX], a BounceOnBottom: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 - 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel @@ -188,15 +188,15 @@ BounceOnBottom: BounceDone: ; First, check if the ball is low enough to bounce off the paddle. - ld a, [_OAMRAM] + ld a, [STARTOF(OAM)] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] cp a, b jp nz, PaddleBounceDone ; Now let's compare the X positions of the objects to see if they're touching. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, 16 cp a, b jp c, PaddleBounceDone @@ -215,31 +215,31 @@ PaddleBounceDone: ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] - and a, PADF_LEFT + and a, PAD_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] - and a, PADF_RIGHT + and a, PAD_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Convert a pixel position to a tilemap address @@ -344,20 +344,20 @@ CheckAndHandleBrickRight: Input: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -369,11 +369,11 @@ Input: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/bricks/hardware.inc b/unbricked/bricks/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/bricks/hardware.inc +++ b/unbricked/bricks/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/bricks/main.asm b/unbricked/bricks/main.asm index 8dcc8c18..50af3330 100644 --- a/unbricked/bricks/main.asm +++ b/unbricked/bricks/main.asm @@ -49,14 +49,14 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b jp nz, ClearOam ; Initialize the paddle sprite in OAM - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -81,7 +81,7 @@ ClearOam: ld [wBallMomentumY], a ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -108,24 +108,24 @@ WaitVBlank2: ; Add the ball's momentum to its position in OAM. ld a, [wBallMomentumX] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, b - ld [_OAMRAM + 5], a + ld [STARTOF(OAM) + 5], a ld a, [wBallMomentumY] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] add a, b - ld [_OAMRAM + 4], a + ld [STARTOF(OAM) + 4], a ; ANCHOR: updated-bounce BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 + 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel ; Returns tile address in hl @@ -137,10 +137,10 @@ BounceOnTop: ld [wBallMomentumY], a BounceOnRight: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 - 1 ld b, a call GetTileByPixel @@ -152,10 +152,10 @@ BounceOnRight: ld [wBallMomentumX], a BounceOnLeft: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 + 1 ld b, a call GetTileByPixel @@ -167,10 +167,10 @@ BounceOnLeft: ld [wBallMomentumX], a BounceOnBottom: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 - 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel @@ -184,15 +184,15 @@ BounceDone: ; ANCHOR_END: updated-bounce ; First, check if the ball is low enough to bounce off the paddle. - ld a, [_OAMRAM] + ld a, [STARTOF(OAM)] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] cp a, b jp nz, PaddleBounceDone ; Now let's compare the X positions of the objects to see if they're touching. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, 16 cp a, b jp c, PaddleBounceDone @@ -211,31 +211,31 @@ PaddleBounceDone: ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] - and a, PADF_LEFT + and a, PAD_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] - and a, PADF_RIGHT + and a, PAD_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Convert a pixel position to a tilemap address @@ -309,20 +309,20 @@ CheckAndHandleBrickRight: Input: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -334,11 +334,11 @@ Input: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/collision/hardware.inc b/unbricked/collision/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/collision/hardware.inc +++ b/unbricked/collision/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/collision/main.asm b/unbricked/collision/main.asm index 51bca6b4..10831d12 100644 --- a/unbricked/collision/main.asm +++ b/unbricked/collision/main.asm @@ -45,7 +45,7 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b @@ -53,7 +53,7 @@ ClearOam: ; ANCHOR: oam ; Initialize the paddle sprite in OAM - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -81,7 +81,7 @@ ClearOam: ; ANCHOR_END: init ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -109,25 +109,25 @@ WaitVBlank2: ; Add the ball's momentum to its position in OAM. ld a, [wBallMomentumX] ld b, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] add a, b - ld [_OAMRAM + 5], a + ld [STARTOF(OAM) + 5], a ld a, [wBallMomentumY] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] add a, b - ld [_OAMRAM + 4], a + ld [STARTOF(OAM) + 4], a ; ANCHOR_END: momentum ; ANCHOR: first-tile-collision BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 + 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel ; Returns tile address in hl @@ -140,10 +140,10 @@ BounceOnTop: ; ANCHOR: tile-collision BounceOnRight: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 - 1 ld b, a call GetTileByPixel @@ -154,10 +154,10 @@ BounceOnRight: ld [wBallMomentumX], a BounceOnLeft: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 + 1 ld b, a call GetTileByPixel @@ -168,10 +168,10 @@ BounceOnLeft: ld [wBallMomentumX], a BounceOnBottom: - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] sub a, 16 - 1 ld c, a - ld a, [_OAMRAM + 5] + ld a, [STARTOF(OAM) + 5] sub a, 8 ld b, a call GetTileByPixel @@ -185,15 +185,15 @@ BounceDone: ; ANCHOR: paddle-bounce ; First, check if the ball is low enough to bounce off the paddle. - ld a, [_OAMRAM] + ld a, [STARTOF(OAM)] ld b, a - ld a, [_OAMRAM + 4] + ld a, [STARTOF(OAM) + 4] cp a, b jp nz, PaddleBounceDone ; If the ball isn't at the same Y position as the paddle, it can't bounce. ; Now let's compare the X positions of the objects to see if they're touching. - ld a, [_OAMRAM + 5] ; Ball's X position. + ld a, [STARTOF(OAM) + 5] ; Ball's X position. ld b, a - ld a, [_OAMRAM + 1] ; Paddle's X position. + ld a, [STARTOF(OAM) + 1] ; Paddle's X position. sub a, 8 cp a, b jp nc, PaddleBounceDone @@ -213,31 +213,31 @@ PaddleBounceDone: ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] - and a, PADF_LEFT + and a, PAD_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] - and a, PADF_RIGHT + and a, PAD_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; ANCHOR: get-tile @@ -296,20 +296,20 @@ IsWallTile: UpdateKeys: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -321,11 +321,11 @@ UpdateKeys: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/functions/hardware.inc b/unbricked/functions/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/functions/hardware.inc +++ b/unbricked/functions/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/functions/main.asm b/unbricked/functions/main.asm index 00818e3a..3988b9d9 100644 --- a/unbricked/functions/main.asm +++ b/unbricked/functions/main.asm @@ -43,13 +43,13 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b jp nz, ClearOam - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -59,7 +59,7 @@ ClearOam: ld [hl], a ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -93,9 +93,9 @@ WaitVBlank2: ld [wFrameCounter], a ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; ANCHOR_END: main diff --git a/unbricked/getting-started/hardware.inc b/unbricked/getting-started/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/getting-started/hardware.inc +++ b/unbricked/getting-started/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/getting-started/main.asm b/unbricked/getting-started/main.asm index 739879df..d0fe0533 100644 --- a/unbricked/getting-started/main.asm +++ b/unbricked/getting-started/main.asm @@ -57,7 +57,7 @@ CopyTilemap: ; ANCHOR: end ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON + ld a, LCDC_ON | LCDC_BG_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers diff --git a/unbricked/input/hardware.inc b/unbricked/input/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/input/hardware.inc +++ b/unbricked/input/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/input/input.asm b/unbricked/input/input.asm index 56c68c63..fc81de4b 100644 --- a/unbricked/input/input.asm +++ b/unbricked/input/input.asm @@ -10,20 +10,20 @@ SECTION "UpdateKeys", ROM0 UpdateKeys: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -35,11 +35,11 @@ UpdateKeys: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/input/main.asm b/unbricked/input/main.asm index 7acef36d..8cf2fec5 100644 --- a/unbricked/input/main.asm +++ b/unbricked/input/main.asm @@ -43,13 +43,13 @@ WaitVBlank: xor a, a ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b jp nz, ClearOam - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -59,7 +59,7 @@ ClearOam: ld [hl], a ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -92,51 +92,51 @@ WaitVBlank2: ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] - and a, PADF_LEFT + and a, PAD_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] - and a, PADF_RIGHT + and a, PAD_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; ANCHOR_END: main ; ANCHOR: input-routine UpdateKeys: ; Poll half the controller - ld a, P1F_GET_BTN + ld a, JOYP_GET_BUTTONS call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half - ld a, P1F_GET_DPAD + ld a, JOYP_GET_CTRL_PAD call .onenibble swap a ; A7-4 = unpressed directions; A3-0 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller - ld a, P1F_GET_NONE - ldh [rP1], a + ld a, JOYP_GET_NONE + ldh [rJOYP], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] @@ -148,11 +148,11 @@ UpdateKeys: ret .onenibble - ldh [rP1], a ; switch the key matrix + ldh [rJOYP], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret - ldh a, [rP1] ; ignore value while waiting for the key matrix to settle - ldh a, [rP1] - ldh a, [rP1] ; this read counts + ldh a, [rJOYP] ; ignore value while waiting for the key matrix to settle + ldh a, [rJOYP] + ldh a, [rJOYP] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret diff --git a/unbricked/objects/hardware.inc b/unbricked/objects/hardware.inc index 2e3be73b..7b180b4f 100644 --- a/unbricked/objects/hardware.inc +++ b/unbricked/objects/hardware.inc @@ -1,1069 +1,1158 @@ -;* -;* Gameboy Hardware definitions -;* -;* Based on Jones' hardware.inc -;* And based on Carsten Sorensen's ideas. -;* -;* Rev 1.1 - 15-Jul-97 : Added define check -;* Rev 1.2 - 18-Jul-97 : Added revision check macro -;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05 -;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes -;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines -;* : and Nintendo Logo -;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC -;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1 -;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC -;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format -;* Rev 2.0 - : Added GBC registers -;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines -;* Rev 2.2 - : Fixed NR42,NR43, & NR44 equates -;* Rev 2.3 - : Fixed incorrect _HRAM equate -;* Rev 2.4 - 27-Apr-13 : Added some cart defines (AntonioND) -;* Rev 2.5 - 03-May-15 : Fixed format (AntonioND) -;* Rev 2.6 - 09-Apr-16 : Added GBC OAM and cart defines (AntonioND) -;* Rev 2.7 - 19-Jan-19 : Added rPCMXX (ISSOtm) -;* Rev 2.8 - 03-Feb-19 : Added audio registers flags (Álvaro Cuesta) -;* Rev 2.9 - 28-Feb-20 : Added utility rP1 constants -;* Rev 3.0 - 27-Aug-20 : Register ordering, byte-based sizes, OAM additions, general cleanup (Blitter Object) -;* Rev 4.0 - 03-May-21 : Updated to use RGBDS 0.5.0 syntax, changed IEF_LCDC to IEF_STAT (Eievui) -;* Rev 4.1 - 16-Aug-21 : Added more flags, bit number defines, and offset constants for OAM and window positions (rondnelson99) -;* Rev 4.2 - 04-Sep-21 : Added CH3- and CH4-specific audio registers flags (ISSOtm) -;* Rev 4.3 - 07-Nov-21 : Deprecate VRAM address constants (Eievui) -;* Rev 4.4 - 11-Jan-22 : Deprecate VRAM CART_SRAM_2KB constant (avivace) -;* Rev 4.5 - 03-Mar-22 : Added bit number definitions for OCPS, BCPS and LCDC (sukus) -;* Rev 4.6 - 15-Jun-22 : Added MBC3 registers and special values -;* Rev 4.7.0 - 27-Jun-22 : Added alternate names for some constants -;* Rev 4.7.1 - 05-Jul-22 : Added RPB_LED_ON constant - -; NOTE: REVISION NUMBER CHANGES MUST BE REFLECTED -; IN `rev_Check_hardware_inc` BELOW! - -IF __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 - FAIL "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." -ENDC - -; If all of these are already defined, don't do it again. - - IF !DEF(HARDWARE_INC) -DEF HARDWARE_INC EQU 1 +;****************************************************************************** +; Game Boy hardware constant definitions +; https://github.com/gbdev/hardware.inc +;****************************************************************************** + +; To the extent possible under law, the authors of this work have +; waived all copyright and related or neighboring rights to the work. +; See https://creativecommons.org/publicdomain/zero/1.0/ for details. +; SPDX-License-Identifier: CC0-1.0 + +; If this file was already included, don't do it again +if !def(HARDWARE_INC) + +; Check for the minimum supported RGBDS version +if !def(__RGBDS_MAJOR__) || !def(__RGBDS_MINOR__) || !def(__RGBDS_PATCH__) + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later" +endc +if __RGBDS_MAJOR__ == 0 && __RGBDS_MINOR__ < 5 + fail "This version of 'hardware.inc' requires RGBDS version 0.5.0 or later." +endc + +; Define the include guard and the current hardware.inc version +; (do this after the RGBDS version check since the `def` syntax depends on it) +def HARDWARE_INC equ 1 +def HARDWARE_INC_VERSION equs "5.3.0" ; Usage: rev_Check_hardware_inc -; Examples: rev_Check_hardware_inc 4.1.2 -; rev_Check_hardware_inc 4.1 (equivalent to 4.1.0) -; rev_Check_hardware_inc 4 (equivalent to 4.0.0) +; Examples: +; rev_Check_hardware_inc 1.2.3 +; rev_Check_hardware_inc 1.2 (equivalent to 1.2.0) +; rev_Check_hardware_inc 1 (equivalent to 1.0.0) MACRO rev_Check_hardware_inc - DEF CUR_VER equs "4,7,1" ; ** UPDATE THIS LINE WHEN CHANGING THE REVISION NUMBER ** - DEF MIN_VER equs STRRPL("\1", ".", ",") - DEF INTERNAL_CHK equs """MACRO ___internal - IF \\1 != \\4 || \\2 < \\5 || (\\2 == \\5 && \\3 < \\6) - FAIL "Version \\1.\\2.\\3 of 'hardware.inc' is incompatible with requested version \\4.\\5.\\6" - ENDC -\nENDM""" - INTERNAL_CHK - ___internal {CUR_VER}, {MIN_VER},0,0 - PURGE CUR_VER, MIN_VER, INTERNAL_CHK, ___internal + if _NARG == 1 ; Actual invocation by the user + def hw_inc_cur_ver\@ equs strrpl("{HARDWARE_INC_VERSION}", ".", ",") + def hw_inc_min_ver\@ equs strrpl("\1", ".", ",") + rev_Check_hardware_inc {hw_inc_cur_ver\@}, {hw_inc_min_ver\@}, 0, 0 + purge hw_inc_cur_ver\@, hw_inc_min_ver\@ + else ; Recursive invocation + if \1 != \4 || (\2 < \5 || (\2 == \5 && \3 < \6)) + fail "Version \1.\2.\3 of 'hardware.inc' is incompatible with requested version \4.\5.\6" + endc + endc ENDM -;*************************************************************************** -;* -;* General memory region constants -;* -;*************************************************************************** - -DEF _VRAM EQU $8000 ; $8000->$9FFF -DEF _SCRN0 EQU $9800 ; $9800->$9BFF -DEF _SCRN1 EQU $9C00 ; $9C00->$9FFF -DEF _SRAM EQU $A000 ; $A000->$BFFF -DEF _RAM EQU $C000 ; $C000->$CFFF / $C000->$DFFF -DEF _RAMBANK EQU $D000 ; $D000->$DFFF -DEF _OAMRAM EQU $FE00 ; $FE00->$FE9F -DEF _IO EQU $FF00 ; $FF00->$FF7F,$FFFF -DEF _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F -DEF _HRAM EQU $FF80 ; $FF80->$FFFE - - -;*************************************************************************** -;* -;* MBC registers -;* -;*************************************************************************** - -; *** Common *** - -; -- -; -- RAMG ($0000-$1FFF) -; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) -; -- -DEF rRAMG EQU $0000 - -DEF CART_SRAM_ENABLE EQU $0A -DEF CART_SRAM_DISABLE EQU $00 - - -; -- -; -- ROMB0 ($2000-$3FFF) -; -- Selects which ROM bank is mapped to the ROMX space ($4000-$7FFF) (W) -; -- -; -- The range of accepted values, as well as the behavior of writing $00, -; -- varies depending on the MBC. -; -- -DEF rROMB0 EQU $2000 - -; -- -; -- RAMB ($4000-$5FFF) -; -- Selects which SRAM bank is mapped to the SRAM space ($A000-$BFFF) (W) -; -- -; -- The range of accepted values varies depending on the cartridge configuration. -; -- -DEF rRAMB EQU $4000 +;****************************************************************************** +; Memory-mapped registers ($FFxx range) +;****************************************************************************** + +; -- JOYP / P1 ($FF00) -------------------------------------------------------- +; Joypad face buttons +def rJOYP equ $FF00 + +def B_JOYP_GET_BUTTONS equ 5 ; 0 = reading buttons [r/w] +def B_JOYP_GET_CTRL_PAD equ 4 ; 0 = reading Control Pad [r/w] + def JOYP_GET equ %00_11_0000 ; select which inputs to read from the lower nybble + def JOYP_GET_BUTTONS equ %00_01_0000 ; reading A/B/Select/Start buttons + def JOYP_GET_CTRL_PAD equ %00_10_0000 ; reading Control Pad directions + def JOYP_GET_NONE equ %00_11_0000 ; reading nothing + +def B_JOYP_START equ 3 ; 0 = Start is pressed (if reading buttons) [ro] +def B_JOYP_SELECT equ 2 ; 0 = Select is pressed (if reading buttons) [ro] +def B_JOYP_B equ 1 ; 0 = B is pressed (if reading buttons) [ro] +def B_JOYP_A equ 0 ; 0 = A is pressed (if reading buttons) [ro] +def B_JOYP_DOWN equ 3 ; 0 = Down is pressed (if reading Control Pad) [ro] +def B_JOYP_UP equ 2 ; 0 = Up is pressed (if reading Control Pad) [ro] +def B_JOYP_LEFT equ 1 ; 0 = Left is pressed (if reading Control Pad) [ro] +def B_JOYP_RIGHT equ 0 ; 0 = Right is pressed (if reading Control Pad) [ro] + def JOYP_INPUTS equ %0000_1111 ; bits equal to 0 indicate pressed (when reading inputs) + def JOYP_START equ 1 << B_JOYP_START + def JOYP_SELECT equ 1 << B_JOYP_SELECT + def JOYP_B equ 1 << B_JOYP_B + def JOYP_A equ 1 << B_JOYP_A + def JOYP_DOWN equ 1 << B_JOYP_DOWN + def JOYP_UP equ 1 << B_JOYP_UP + def JOYP_LEFT equ 1 << B_JOYP_LEFT + def JOYP_RIGHT equ 1 << B_JOYP_RIGHT + +; SGB command packet transfer uses for JOYP bits +def B_JOYP_SGB_ONE equ 5 ; 0 = sending 1 bit +def B_JOYP_SGB_ZERO equ 4 ; 0 = sending 0 bit + def JOYP_SGB_START equ %00_00_0000 ; start SGB packet transfer + def JOYP_SGB_ONE equ %00_01_0000 ; send 1 bit + def JOYP_SGB_ZERO equ %00_10_0000 ; send 0 bit + def JOYP_SGB_FINISH equ %00_11_0000 ; finish SGB packet transfer + +; Combined input byte, with Control Pad in high nybble (conventional order) +def B_PAD_DOWN equ 7 +def B_PAD_UP equ 6 +def B_PAD_LEFT equ 5 +def B_PAD_RIGHT equ 4 +def B_PAD_START equ 3 +def B_PAD_SELECT equ 2 +def B_PAD_B equ 1 +def B_PAD_A equ 0 + def PAD_CTRL_PAD equ %1111_0000 + def PAD_BUTTONS equ %0000_1111 + def PAD_DOWN equ 1 << B_PAD_DOWN + def PAD_UP equ 1 << B_PAD_UP + def PAD_LEFT equ 1 << B_PAD_LEFT + def PAD_RIGHT equ 1 << B_PAD_RIGHT + def PAD_START equ 1 << B_PAD_START + def PAD_SELECT equ 1 << B_PAD_SELECT + def PAD_B equ 1 << B_PAD_B + def PAD_A equ 1 << B_PAD_A + +; Combined input byte, with Control Pad in low nybble (swapped order) +def B_PAD_SWAP_START equ 7 +def B_PAD_SWAP_SELECT equ 6 +def B_PAD_SWAP_B equ 5 +def B_PAD_SWAP_A equ 4 +def B_PAD_SWAP_DOWN equ 3 +def B_PAD_SWAP_UP equ 2 +def B_PAD_SWAP_LEFT equ 1 +def B_PAD_SWAP_RIGHT equ 0 + def PAD_SWAP_CTRL_PAD equ %0000_1111 + def PAD_SWAP_BUTTONS equ %1111_0000 + def PAD_SWAP_START equ 1 << B_PAD_SWAP_START + def PAD_SWAP_SELECT equ 1 << B_PAD_SWAP_SELECT + def PAD_SWAP_B equ 1 << B_PAD_SWAP_B + def PAD_SWAP_A equ 1 << B_PAD_SWAP_A + def PAD_SWAP_DOWN equ 1 << B_PAD_SWAP_DOWN + def PAD_SWAP_UP equ 1 << B_PAD_SWAP_UP + def PAD_SWAP_LEFT equ 1 << B_PAD_SWAP_LEFT + def PAD_SWAP_RIGHT equ 1 << B_PAD_SWAP_RIGHT + +; -- SB ($FF01) --------------------------------------------------------------- +; Serial transfer data [r/w] +def rSB equ $FF01 + +; -- SC ($FF02) --------------------------------------------------------------- +; Serial transfer control +def rSC equ $FF02 + +def B_SC_START equ 7 ; reading 1 = transfer in progress, writing 1 = start transfer [r/w] +def B_SC_SPEED equ 1 ; (CGB only) 1 = use faster internal clock [r/w] +def B_SC_SOURCE equ 0 ; 0 = use external clock ("slave"), 1 = use internal clock ("master") [r/w] + def SC_START equ 1 << B_SC_START + def SC_SPEED equ 1 << B_SC_SPEED + def SC_SLOW equ 0 << B_SC_SPEED + def SC_FAST equ 1 << B_SC_SPEED + def SC_SOURCE equ 1 << B_SC_SOURCE + def SC_EXTERNAL equ 0 << B_SC_SOURCE + def SC_INTERNAL equ 1 << B_SC_SOURCE + +; -- $FF03 is unused ---------------------------------------------------------- + +; -- DIV ($FF04) -------------------------------------------------------------- +; Divider register [r/w] +def rDIV equ $FF04 + +; -- TIMA ($FF05) ------------------------------------------------------------- +; Timer counter [r/w] +def rTIMA equ $FF05 + +; -- TMA ($FF06) -------------------------------------------------------------- +; Timer modulo [r/w] +def rTMA equ $FF06 + +; -- TAC ($FF07) -------------------------------------------------------------- +; Timer control +def rTAC equ $FF07 + +def B_TAC_START equ 2 ; enable incrementing TIMA [r/w] + def TAC_STOP equ 0 << B_TAC_START + def TAC_START equ 1 << B_TAC_START + +def TAC_CLOCK equ %000000_11 ; the frequency at which TIMA increments [r/w] + def TAC_4KHZ equ %000000_00 ; every 256 M-cycles = ~4 KHz on DMG + def TAC_262KHZ equ %000000_01 ; every 4 M-cycles = ~262 KHz on DMG + def TAC_65KHZ equ %000000_10 ; every 16 M-cycles = ~65 KHz on DMG + def TAC_16KHZ equ %000000_11 ; every 64 M-cycles = ~16 KHz on DMG + +; -- $FF08-$FF0E are unused --------------------------------------------------- + +; -- IF ($FF0F) --------------------------------------------------------------- +; Pending interrupts +def rIF equ $FF0F + +def B_IF_JOYPAD equ 4 ; 1 = joypad interrupt is pending [r/w] +def B_IF_SERIAL equ 3 ; 1 = serial interrupt is pending [r/w] +def B_IF_TIMER equ 2 ; 1 = timer interrupt is pending [r/w] +def B_IF_STAT equ 1 ; 1 = STAT interrupt is pending [r/w] +def B_IF_VBLANK equ 0 ; 1 = VBlank interrupt is pending [r/w] + def IF_JOYPAD equ 1 << B_IF_JOYPAD + def IF_SERIAL equ 1 << B_IF_SERIAL + def IF_TIMER equ 1 << B_IF_TIMER + def IF_STAT equ 1 << B_IF_STAT + def IF_VBLANK equ 1 << B_IF_VBLANK + +; -- AUD1SWEEP / NR10 ($FF10) ------------------------------------------------- +; Audio channel 1 sweep +def rAUD1SWEEP equ $FF10 + +def AUD1SWEEP_TIME equ %0_111_0000 ; how long between sweep iterations + ; (in 128 Hz ticks, ~7.8 ms apart) [r/w] + +def B_AUD1SWEEP_DIR equ 3 ; sweep direction [r/w] + def AUD1SWEEP_DIR equ 1 << B_AUD1SWEEP_DIR + def AUD1SWEEP_UP equ 0 << B_AUD1SWEEP_DIR + def AUD1SWEEP_DOWN equ 1 << B_AUD1SWEEP_DIR + +def AUD1SWEEP_SHIFT equ %00000_111 ; how much the period increases/decreases per iteration [r/w] + +; -- AUD1LEN / NR11 ($FF11) --------------------------------------------------- +; Audio channel 1 length timer and duty cycle +def rAUD1LEN equ $FF11 + +def AUD1LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD1LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD1LEN_DUTY_25 equ %01_000000 ; 25% + def AUD1LEN_DUTY_50 equ %10_000000 ; 50% + def AUD1LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD1LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD1ENV / NR12 ($FF12) --------------------------------------------------- +; Audio channel 1 volume and envelope +def rAUD1ENV equ $FF12 + +def AUD1ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD1ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD1ENV_DIR equ 1 << B_AUD1ENV_DIR + def AUD1ENV_DOWN equ 0 << B_AUD1ENV_DIR + def AUD1ENV_UP equ 1 << B_AUD1ENV_DIR + +def AUD1ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] +; -- AUD1LOW / NR13 ($FF13) --------------------------------------------------- +; Audio channel 1 period (low 8 bits) [wo] +def rAUD1LOW equ $FF13 -; *** MBC3-specific registers *** +; -- AUD1HIGH / NR14 ($FF14) -------------------------------------------------- +; Audio channel 1 period (high 3 bits) and control +def rAUD1HIGH equ $FF14 -; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space -DEF RTC_S EQU $08 ; Seconds (0-59) -DEF RTC_M EQU $09 ; Minutes (0-59) -DEF RTC_H EQU $0A ; Hours (0-23) -DEF RTC_DL EQU $0B ; Lower 8 bits of Day Counter ($00-$FF) -DEF RTC_DH EQU $0C ; Bit 7 - Day Counter Carry Bit (1=Counter Overflow) - ; Bit 6 - Halt (0=Active, 1=Stop Timer) - ; Bit 0 - Most significant bit of Day Counter (Bit 8) - - -; -- -; -- RTCLATCH ($6000-$7FFF) -; -- Write $00 then $01 to latch the current time into the RTC registers (W) -; -- -DEF rRTCLATCH EQU $6000 +def B_AUD1HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD1HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD1HIGH_RESTART equ 1 << B_AUD1HIGH_RESTART + def AUD1HIGH_LENGTH_OFF equ 0 << B_AUD1HIGH_LEN_ENABLE + def AUD1HIGH_LENGTH_ON equ 1 << B_AUD1HIGH_LEN_ENABLE +def AUD1HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] -; *** MBC5-specific register *** - -; -- -; -- ROMB1 ($3000-$3FFF) -; -- A 9th bit that "extends" ROMB0 if more than 256 banks are present (W) -; -- -; -- Also note that rROMB0 thus only spans $2000-$2FFF. -; -- -DEF rROMB1 EQU $3000 - - -; Bit 3 of RAMB enables the rumble motor (if any) -DEF CART_RUMBLE_ON EQU 1 << 3 - - -;*************************************************************************** -;* -;* Memory-mapped registers -;* -;*************************************************************************** - -; -- -; -- P1 ($FF00) -; -- Register for reading joy pad info. (R/W) -; -- -DEF rP1 EQU $FF00 - -DEF P1F_5 EQU %00100000 ; P15 out port, set to 0 to get buttons -DEF P1F_4 EQU %00010000 ; P14 out port, set to 0 to get dpad -DEF P1F_3 EQU %00001000 ; P13 in port -DEF P1F_2 EQU %00000100 ; P12 in port -DEF P1F_1 EQU %00000010 ; P11 in port -DEF P1F_0 EQU %00000001 ; P10 in port - -DEF P1F_GET_DPAD EQU P1F_5 -DEF P1F_GET_BTN EQU P1F_4 -DEF P1F_GET_NONE EQU P1F_4 | P1F_5 - - -; -- -; -- SB ($FF01) -; -- Serial Transfer Data (R/W) -; -- -DEF rSB EQU $FF01 - - -; -- -; -- SC ($FF02) -; -- Serial I/O Control (R/W) -; -- -DEF rSC EQU $FF02 - -DEF SCF_START EQU %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) -DEF SCF_SPEED EQU %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** -DEF SCF_SOURCE EQU %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) - -DEF SCB_START EQU 7 -DEF SCB_SPEED EQU 1 -DEF SCB_SOURCE EQU 0 - -; -- -; -- DIV ($FF04) -; -- Divider register (R/W) -; -- -DEF rDIV EQU $FF04 - - -; -- -; -- TIMA ($FF05) -; -- Timer counter (R/W) -; -- -DEF rTIMA EQU $FF05 - - -; -- -; -- TMA ($FF06) -; -- Timer modulo (R/W) -; -- -DEF rTMA EQU $FF06 - - -; -- -; -- TAC ($FF07) -; -- Timer control (R/W) -; -- -DEF rTAC EQU $FF07 - -DEF TACF_START EQU %00000100 -DEF TACF_STOP EQU %00000000 -DEF TACF_4KHZ EQU %00000000 -DEF TACF_16KHZ EQU %00000011 -DEF TACF_65KHZ EQU %00000010 -DEF TACF_262KHZ EQU %00000001 - -DEF TACB_START EQU 2 - - -; -- -; -- IF ($FF0F) -; -- Interrupt Flag (R/W) -; -- -DEF rIF EQU $FF0F - - -; -- -; -- AUD1SWEEP/NR10 ($FF10) -; -- Sweep register (R/W) -; -- -; -- Bit 6-4 - Sweep Time -; -- Bit 3 - Sweep Increase/Decrease -; -- 0: Addition (frequency increases???) -; -- 1: Subtraction (frequency increases???) -; -- Bit 2-0 - Number of sweep shift (# 0-7) -; -- Sweep Time: (n*7.8ms) -; -- -DEF rNR10 EQU $FF10 -DEF rAUD1SWEEP EQU rNR10 - -DEF AUD1SWEEP_UP EQU %00000000 -DEF AUD1SWEEP_DOWN EQU %00001000 - - -; -- -; -- AUD1LEN/NR11 ($FF11) -; -- Sound length/Wave pattern duty (R/W) -; -- -; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%) -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR11 EQU $FF11 -DEF rAUD1LEN EQU rNR11 - - -; -- -; -- AUD1ENV/NR12 ($FF12) -; -- Envelope (R/W) -; -- -; -- Bit 7-4 - Initial value of envelope -; -- Bit 3 - Envelope UP/DOWN -; -- 0: Decrease -; -- 1: Range of increase -; -- Bit 2-0 - Number of envelope sweep (# 0-7) -; -- -DEF rNR12 EQU $FF12 -DEF rAUD1ENV EQU rNR12 - - -; -- -; -- AUD1LOW/NR13 ($FF13) -; -- Frequency low byte (W) -; -- -DEF rNR13 EQU $FF13 -DEF rAUD1LOW EQU rNR13 - - -; -- -; -- AUD1HIGH/NR14 ($FF14) -; -- Frequency high byte (W) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- Bit 2-0 - Frequency's higher 3 bits -; -- -DEF rNR14 EQU $FF14 -DEF rAUD1HIGH EQU rNR14 - - -; -- -; -- AUD2LEN/NR21 ($FF16) -; -- Sound Length; Wave Pattern Duty (R/W) -; -- -; -- see AUD1LEN for info -; -- -DEF rNR21 EQU $FF16 -DEF rAUD2LEN EQU rNR21 - - -; -- -; -- AUD2ENV/NR22 ($FF17) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR22 EQU $FF17 -DEF rAUD2ENV EQU rNR22 - - -; -- -; -- AUD2LOW/NR23 ($FF18) -; -- Frequency low byte (W) -; -- -DEF rNR23 EQU $FF18 -DEF rAUD2LOW EQU rNR23 - - -; -- -; -- AUD2HIGH/NR24 ($FF19) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR24 EQU $FF19 -DEF rAUD2HIGH EQU rNR24 - - -; -- -; -- AUD3ENA/NR30 ($FF1A) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) -; -- -DEF rNR30 EQU $FF1A -DEF rAUD3ENA EQU rNR30 - -DEF AUD3ENA_OFF EQU %00000000 -DEF AUD3ENA_ON EQU %10000000 - - -; -- -; -- AUD3LEN/NR31 ($FF1B) -; -- Sound length (R/W) -; -- -; -- Bit 7-0 - Sound length -; -- -DEF rNR31 EQU $FF1B -DEF rAUD3LEN EQU rNR31 - - -; -- -; -- AUD3LEVEL/NR32 ($FF1C) -; -- Select output level -; -- -; -- Bit 6-5 - Select output level -; -- 00: 0/1 (mute) -; -- 01: 1/1 -; -- 10: 1/2 -; -- 11: 1/4 -; -- -DEF rNR32 EQU $FF1C -DEF rAUD3LEVEL EQU rNR32 - -DEF AUD3LEVEL_MUTE EQU %00000000 -DEF AUD3LEVEL_100 EQU %00100000 -DEF AUD3LEVEL_50 EQU %01000000 -DEF AUD3LEVEL_25 EQU %01100000 - - -; -- -; -- AUD3LOW/NR33 ($FF1D) -; -- Frequency low byte (W) -; -- -; -- see AUD1LOW for info -; -- -DEF rNR33 EQU $FF1D -DEF rAUD3LOW EQU rNR33 - - -; -- -; -- AUD3HIGH/NR34 ($FF1E) -; -- Frequency high byte (W) -; -- -; -- see AUD1HIGH for info -; -- -DEF rNR34 EQU $FF1E -DEF rAUD3HIGH EQU rNR34 - - -; -- -; -- AUD4LEN/NR41 ($FF20) -; -- Sound length (R/W) -; -- -; -- Bit 5-0 - Sound length data (# 0-63) -; -- -DEF rNR41 EQU $FF20 -DEF rAUD4LEN EQU rNR41 - - -; -- -; -- AUD4ENV/NR42 ($FF21) -; -- Envelope (R/W) -; -- -; -- see AUD1ENV for info -; -- -DEF rNR42 EQU $FF21 -DEF rAUD4ENV EQU rNR42 - - -; -- -; -- AUD4POLY/NR43 ($FF22) -; -- Polynomial counter (R/W) -; -- -; -- Bit 7-4 - Selection of the shift clock frequency of the (scf) -; -- polynomial counter (0000-1101) -; -- freq=drf*1/2^scf (not sure) -; -- Bit 3 - Selection of the polynomial counter's step -; -- 0: 15 steps -; -- 1: 7 steps -; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf) -; -- 000: f/4 001: f/8 010: f/16 011: f/24 -; -- 100: f/32 101: f/40 110: f/48 111: f/56 (f=4.194304 Mhz) -; -- -DEF rNR43 EQU $FF22 -DEF rAUD4POLY EQU rNR43 - -DEF AUD4POLY_15STEP EQU %00000000 -DEF AUD4POLY_7STEP EQU %00001000 - - -; -- -; -- AUD4GO/NR44 ($FF23) -; -- -; -- Bit 7 - Initial (when set, sound restarts) -; -- Bit 6 - Counter/consecutive selection -; -- -DEF rNR44 EQU $FF23 -DEF rAUD4GO EQU rNR44 - - -; -- -; -- AUDVOL/NR50 ($FF24) -; -- Channel control / ON-OFF / Volume (R/W) -; -- -; -- Bit 7 - Vin->SO2 ON/OFF (left) -; -- Bit 6-4 - SO2 output level (left speaker) (# 0-7) -; -- Bit 3 - Vin->SO1 ON/OFF (right) -; -- Bit 2-0 - SO1 output level (right speaker) (# 0-7) -; -- -DEF rNR50 EQU $FF24 -DEF rAUDVOL EQU rNR50 - -DEF AUDVOL_VIN_LEFT EQU %10000000 ; SO2 -DEF AUDVOL_VIN_RIGHT EQU %00001000 ; SO1 - - -; -- -; -- AUDTERM/NR51 ($FF25) -; -- Selection of Sound output terminal (R/W) -; -- -; -- Bit 7 - Output channel 4 to SO2 terminal (left) -; -- Bit 6 - Output channel 3 to SO2 terminal (left) -; -- Bit 5 - Output channel 2 to SO2 terminal (left) -; -- Bit 4 - Output channel 1 to SO2 terminal (left) -; -- Bit 3 - Output channel 4 to SO1 terminal (right) -; -- Bit 2 - Output channel 3 to SO1 terminal (right) -; -- Bit 1 - Output channel 2 to SO1 terminal (right) -; -- Bit 0 - Output channel 1 to SO1 terminal (right) -; -- -DEF rNR51 EQU $FF25 -DEF rAUDTERM EQU rNR51 - -; SO2 -DEF AUDTERM_4_LEFT EQU %10000000 -DEF AUDTERM_3_LEFT EQU %01000000 -DEF AUDTERM_2_LEFT EQU %00100000 -DEF AUDTERM_1_LEFT EQU %00010000 -; SO1 -DEF AUDTERM_4_RIGHT EQU %00001000 -DEF AUDTERM_3_RIGHT EQU %00000100 -DEF AUDTERM_2_RIGHT EQU %00000010 -DEF AUDTERM_1_RIGHT EQU %00000001 - - -; -- -; -- AUDENA/NR52 ($FF26) -; -- Sound on/off (R/W) -; -- -; -- Bit 7 - All sound on/off (sets all audio regs to 0!) -; -- Bit 3 - Sound 4 ON flag (read only) -; -- Bit 2 - Sound 3 ON flag (read only) -; -- Bit 1 - Sound 2 ON flag (read only) -; -- Bit 0 - Sound 1 ON flag (read only) -; -- -DEF rNR52 EQU $FF26 -DEF rAUDENA EQU rNR52 - -DEF AUDENA_ON EQU %10000000 -DEF AUDENA_OFF EQU %00000000 ; sets all audio regs to 0! - - -; -- -; -- LCDC ($FF40) -; -- LCD Control (R/W) -; -- -DEF rLCDC EQU $FF40 - -DEF LCDCF_OFF EQU %00000000 ; LCD Control Operation -DEF LCDCF_ON EQU %10000000 ; LCD Control Operation -DEF LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select -DEF LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select -DEF LCDCF_WINOFF EQU %00000000 ; Window Display -DEF LCDCF_WINON EQU %00100000 ; Window Display -DEF LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select -DEF LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select -DEF LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select -DEF LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select -DEF LCDCF_OBJ8 EQU %00000000 ; OBJ Construction -DEF LCDCF_OBJ16 EQU %00000100 ; OBJ Construction -DEF LCDCF_OBJOFF EQU %00000000 ; OBJ Display -DEF LCDCF_OBJON EQU %00000010 ; OBJ Display -DEF LCDCF_BGOFF EQU %00000000 ; BG Display -DEF LCDCF_BGON EQU %00000001 ; BG Display - -DEF LCDCB_ON EQU 7 ; LCD Control Operation -DEF LCDCB_WIN9C00 EQU 6 ; Window Tile Map Display Select -DEF LCDCB_WINON EQU 5 ; Window Display -DEF LCDCB_BG8000 EQU 4 ; BG & Window Tile Data Select -DEF LCDCB_BG9C00 EQU 3 ; BG Tile Map Display Select -DEF LCDCB_OBJ16 EQU 2 ; OBJ Construction -DEF LCDCB_OBJON EQU 1 ; OBJ Display -DEF LCDCB_BGON EQU 0 ; BG Display -; "Window Character Data Select" follows BG - - -; -- -; -- STAT ($FF41) -; -- LCDC Status (R/W) -; -- -DEF rSTAT EQU $FF41 - -DEF STATF_LYC EQU %01000000 ; LYC=LY Coincidence (Selectable) -DEF STATF_MODE10 EQU %00100000 ; Mode 10 -DEF STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank) -DEF STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank) -DEF STATF_LYCF EQU %00000100 ; Coincidence Flag -DEF STATF_HBL EQU %00000000 ; H-Blank -DEF STATF_VBL EQU %00000001 ; V-Blank -DEF STATF_OAM EQU %00000010 ; OAM-RAM is used by system -DEF STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system -DEF STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe - -DEF STATB_LYC EQU 6 -DEF STATB_MODE10 EQU 5 -DEF STATB_MODE01 EQU 4 -DEF STATB_MODE00 EQU 3 -DEF STATB_LYCF EQU 2 -DEF STATB_BUSY EQU 1 - -; -- -; -- SCY ($FF42) -; -- Scroll Y (R/W) -; -- -DEF rSCY EQU $FF42 - - -; -- -; -- SCX ($FF43) -; -- Scroll X (R/W) -; -- -DEF rSCX EQU $FF43 - - -; -- -; -- LY ($FF44) -; -- LCDC Y-Coordinate (R) -; -- -; -- Values range from 0->153. 144->153 is the VBlank period. -; -- -DEF rLY EQU $FF44 - - -; -- -; -- LYC ($FF45) -; -- LY Compare (R/W) -; -- -; -- When LY==LYC, STATF_LYCF will be set in STAT -; -- -DEF rLYC EQU $FF45 - - -; -- -; -- DMA ($FF46) -; -- DMA Transfer and Start Address (W) -; -- -DEF rDMA EQU $FF46 - - -; -- -; -- BGP ($FF47) -; -- BG Palette Data (W) -; -- -; -- Bit 7-6 - Intensity for %11 -; -- Bit 5-4 - Intensity for %10 -; -- Bit 3-2 - Intensity for %01 -; -- Bit 1-0 - Intensity for %00 -; -- -DEF rBGP EQU $FF47 - - -; -- -; -- OBP0 ($FF48) -; -- Object Palette 0 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP0 EQU $FF48 - - -; -- -; -- OBP1 ($FF49) -; -- Object Palette 1 Data (W) -; -- -; -- See BGP for info -; -- -DEF rOBP1 EQU $FF49 - - -; -- -; -- WY ($FF4A) -; -- Window Y Position (R/W) -; -- -; -- 0 <= WY <= 143 -; -- When WY = 0, the window is displayed from the top edge of the LCD screen. -; -- -DEF rWY EQU $FF4A - - -; -- -; -- WX ($FF4B) -; -- Window X Position (R/W) -; -- -; -- 7 <= WX <= 166 -; -- When WX = 7, the window is displayed from the left edge of the LCD screen. -; -- Values of 0-6 and 166 are unreliable due to hardware bugs. -; -- -DEF rWX EQU $FF4B - -DEF WX_OFS EQU 7 ; add this to a screen position to get a WX position - - -; -- -; -- SPEED ($FF4D) -; -- Select CPU Speed (R/W) -; -- -DEF rKEY1 EQU $FF4D -DEF rSPD EQU rKEY1 - -DEF KEY1F_DBLSPEED EQU %10000000 ; 0=Normal Speed, 1=Double Speed (R) -DEF KEY1F_PREPARE EQU %00000001 ; 0=No, 1=Prepare (R/W) - - -; -- -; -- VBK ($FF4F) -; -- Select Video RAM Bank (R/W) -; -- -; -- Bit 0 - Bank Specification (0: Specify Bank 0; 1: Specify Bank 1) -; -- -DEF rVBK EQU $FF4F - - -; -- -; -- HDMA1 ($FF51) -; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA1 EQU $FF51 - - -; -- -; -- HDMA2 ($FF52) -; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) -; -- CGB Mode Only -; -- -DEF rHDMA2 EQU $FF52 - - -; -- -; -- HDMA3 ($FF53) -; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA3 EQU $FF53 - - -; -- -; -- HDMA4 ($FF54) -; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) -; -- CGB Mode Only -; -- -DEF rHDMA4 EQU $FF54 - - -; -- -; -- HDMA5 ($FF55) -; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) -; -- CGB Mode Only -; -- -DEF rHDMA5 EQU $FF55 - -DEF HDMA5F_MODE_GP EQU %00000000 ; General Purpose DMA (W) -DEF HDMA5F_MODE_HBL EQU %10000000 ; HBlank DMA (W) -DEF HDMA5B_MODE EQU 7 ; DMA mode select (W) - -; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete -DEF HDMA5F_BUSY EQU %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) - - -; -- -; -- RP ($FF56) -; -- Infrared Communications Port (R/W) -; -- CGB Mode Only -; -- -DEF rRP EQU $FF56 - -DEF RPF_ENREAD EQU %11000000 -DEF RPF_DATAIN EQU %00000010 ; 0=Receiving IR Signal, 1=Normal -DEF RPF_WRITE_HI EQU %00000001 -DEF RPF_WRITE_LO EQU %00000000 - -DEF RPB_LED_ON EQU 0 -DEF RPB_DATAIN EQU 1 - - -; -- -; -- BCPS/BGPI ($FF68) -; -- Background Color Palette Specification (aka Background Palette Index) (R/W) -; -- -DEF rBCPS EQU $FF68 -DEF rBGPI EQU rBCPS - -DEF BCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF BCPSB_AUTOINC EQU 7 -DEF BGPIF_AUTOINC EQU BCPSF_AUTOINC -DEF BGPIB_AUTOINC EQU BCPSB_AUTOINC - - -; -- -; -- BCPD/BGPD ($FF69) -; -- Background Color Palette Data (aka Background Palette Data) (R/W) -; -- -DEF rBCPD EQU $FF69 -DEF rBGPD EQU rBCPD - - -; -- -; -- OCPS/OBPI ($FF6A) -; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) -; -- -DEF rOCPS EQU $FF6A -DEF rOBPI EQU rOCPS - -DEF OCPSF_AUTOINC EQU %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) -DEF OCPSB_AUTOINC EQU 7 -DEF OBPIF_AUTOINC EQU OCPSF_AUTOINC -DEF OBPIB_AUTOINC EQU OCPSB_AUTOINC - - -; -- -; -- OCPD/OBPD ($FF6B) -; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) -; -- -DEF rOCPD EQU $FF6B -DEF rOBPD EQU rOCPD - - -; -- -; -- SMBK/SVBK ($FF70) -; -- Select Main RAM Bank (R/W) -; -- -; -- Bit 2-0 - Bank Specification (0,1: Specify Bank 1; 2-7: Specify Banks 2-7) -; -- -DEF rSVBK EQU $FF70 -DEF rSMBK EQU rSVBK - - -; -- -; -- PCM12 ($FF76) -; -- Sound channel 1&2 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 2's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 1's PCM amplitude -; -- -DEF rPCM12 EQU $FF76 - - -; -- -; -- PCM34 ($FF77) -; -- Sound channel 3&4 PCM amplitude (R) -; -- -; -- Bit 7-4 - Copy of sound channel 4's PCM amplitude -; -- Bit 3-0 - Copy of sound channel 3's PCM amplitude -; -- -DEF rPCM34 EQU $FF77 - - -; -- -; -- IE ($FFFF) -; -- Interrupt Enable (R/W) -; -- -DEF rIE EQU $FFFF - -DEF IEF_HILO EQU %00010000 ; Transition from High to Low of Pin number P10-P13 -DEF IEF_SERIAL EQU %00001000 ; Serial I/O transfer end -DEF IEF_TIMER EQU %00000100 ; Timer Overflow -DEF IEF_STAT EQU %00000010 ; STAT -DEF IEF_VBLANK EQU %00000001 ; V-Blank - -DEF IEB_HILO EQU 4 -DEF IEB_SERIAL EQU 3 -DEF IEB_TIMER EQU 2 -DEF IEB_STAT EQU 1 -DEF IEB_VBLANK EQU 0 - - -;*************************************************************************** -;* -;* Flags common to multiple sound channels -;* -;*************************************************************************** - -; -- -; -- Square wave duty cycle -; -- -; -- Can be used with AUD1LEN and AUD2LEN -; -- See AUD1LEN for more info -; -- -DEF AUDLEN_DUTY_12_5 EQU %00000000 ; 12.5% -DEF AUDLEN_DUTY_25 EQU %01000000 ; 25% -DEF AUDLEN_DUTY_50 EQU %10000000 ; 50% -DEF AUDLEN_DUTY_75 EQU %11000000 ; 75% - - -; -- -; -- Audio envelope flags -; -- -; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV -; -- See AUD1ENV for more info -; -- -DEF AUDENV_UP EQU %00001000 -DEF AUDENV_DOWN EQU %00000000 - - -; -- -; -- Audio trigger flags -; -- -; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH -; -- See AUD1HIGH for more info -; -- -DEF AUDHIGH_RESTART EQU %10000000 -DEF AUDHIGH_LENGTH_ON EQU %01000000 -DEF AUDHIGH_LENGTH_OFF EQU %00000000 - - -;*************************************************************************** -;* -;* CPU values on bootup (a=type, b=qualifier) -;* -;*************************************************************************** - -DEF BOOTUP_A_DMG EQU $01 ; Dot Matrix Game -DEF BOOTUP_A_CGB EQU $11 ; Color GameBoy -DEF BOOTUP_A_MGB EQU $FF ; Mini GameBoy (Pocket GameBoy) - -; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or -; other system running in GBC mode -DEF BOOTUP_B_CGB EQU %00000000 -DEF BOOTUP_B_AGB EQU %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP - - -;*************************************************************************** -;* -;* Header -;* -;*************************************************************************** - -;* -;* Nintendo scrolling logo -;* (Code won't work on a real GameBoy) -;* (if next lines are altered.) -MACRO NINTENDO_LOGO - DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D - DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99 - DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E -ENDM +; -- $FF15 is unused ---------------------------------------------------------- + +; -- AUD2LEN / NR21 ($FF16) --------------------------------------------------- +; Audio channel 2 length timer and duty cycle +def rAUD2LEN equ $FF16 + +def AUD2LEN_DUTY equ %11_000000 ; ratio of time spent high vs. time spent low [r/w] + def AUD2LEN_DUTY_12_5 equ %00_000000 ; 12.5% + def AUD2LEN_DUTY_25 equ %01_000000 ; 25% + def AUD2LEN_DUTY_50 equ %10_000000 ; 50% + def AUD2LEN_DUTY_75 equ %11_000000 ; 75% + +def AUD2LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD2ENV / NR22 ($FF17) --------------------------------------------------- +; Audio channel 2 volume and envelope +def rAUD2ENV equ $FF17 + +def AUD2ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD2ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD2ENV_DIR equ 1 << B_AUD2ENV_DIR + def AUD2ENV_DOWN equ 0 << B_AUD2ENV_DIR + def AUD2ENV_UP equ 1 << B_AUD2ENV_DIR + +def AUD2ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD2LOW / NR23 ($FF18) --------------------------------------------------- +; Audio channel 2 period (low 8 bits) [wo] +def rAUD2LOW equ $FF18 + +; -- AUD2HIGH / NR24 ($FF19) -------------------------------------------------- +; Audio channel 2 period (high 3 bits) and control +def rAUD2HIGH equ $FF19 + +def B_AUD2HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD2HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD2HIGH_RESTART equ 1 << B_AUD2HIGH_RESTART + def AUD2HIGH_LENGTH_OFF equ 0 << B_AUD2HIGH_LEN_ENABLE + def AUD2HIGH_LENGTH_ON equ 1 << B_AUD2HIGH_LEN_ENABLE + +def AUD2HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- AUD3ENA / NR30 ($FF1A) --------------------------------------------------- +; Audio channel 3 enable +def rAUD3ENA equ $FF1A + +def B_AUD3ENA_ENABLE equ 7 ; 1 = channel is active [r/w] + def AUD3ENA_OFF equ 0 << B_AUD3ENA_ENABLE + def AUD3ENA_ON equ 1 << B_AUD3ENA_ENABLE + +; -- AUD3LEN / NR31 ($FF1B) --------------------------------------------------- +; Audio channel 3 length timer [wo] +def rAUD3LEN equ $FF1B + +; -- AUD3LEVEL / NR32 ($FF1C) ------------------------------------------------- +; Audio channel 3 volume +def rAUD3LEVEL equ $FF1C + +def AUD3LEVEL_VOLUME equ %0_11_00000 ; volume level [r/w] + def AUD3LEVEL_MUTE equ %0_00_00000 ; 0% (muted) + def AUD3LEVEL_100 equ %0_01_00000 ; 100% + def AUD3LEVEL_50 equ %0_10_00000 ; 50% + def AUD3LEVEL_25 equ %0_11_00000 ; 25% + +; -- AUD3LOW / NR33 ($FF1D) --------------------------------------------------- +; Audio channel 3 period (low 8 bits) [wo] +def rAUD3LOW equ $FF1D + +; -- AUD3HIGH / NR34 ($FF1E) -------------------------------------------------- +; Audio channel 3 period (high 3 bits) and control +def rAUD3HIGH equ $FF1E + +def B_AUD3HIGH_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD3HIGH_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD3HIGH_RESTART equ 1 << B_AUD3HIGH_RESTART + def AUD3HIGH_LENGTH_OFF equ 0 << B_AUD3HIGH_LEN_ENABLE + def AUD3HIGH_LENGTH_ON equ 1 << B_AUD3HIGH_LEN_ENABLE + +def AUD3HIGH_PERIOD_HIGH equ %00000_111 ; upper 3 bits of the channel's period [wo] + +; -- $FF1F is unused ---------------------------------------------------------- + +; -- AUD4LEN / NR41 ($FF20) --------------------------------------------------- +; Audio channel 4 length timer +def rAUD4LEN equ $FF20 + +def AUD4LEN_TIMER equ %00_111111 ; initial length timer (0-63) [wo] + +; -- AUD4ENV / NR42 ($FF21) --------------------------------------------------- +; Audio channel 4 volume and envelope +def rAUD4ENV equ $FF21 + +def AUD4ENV_INIT_VOLUME equ %1111_0000 ; initial volume [r/w] + +def B_AUD4ENV_DIR equ 3 ; direction of volume envelope [r/w] + def AUD4ENV_DIR equ 1 << B_AUD4ENV_DIR + def AUD4ENV_DOWN equ 0 << B_AUD4ENV_DIR + def AUD4ENV_UP equ 1 << B_AUD4ENV_DIR + +def AUD4ENV_PACE equ %00000_111 ; how long between envelope iterations + ; (in 64 Hz ticks, ~15.6 ms apart) [r/w] + +; -- AUD4POLY / NR43 ($FF22) -------------------------------------------------- +; Audio channel 4 period and randomness +def rAUD4POLY equ $FF22 + +def AUD4POLY_SHIFT equ %1111_0000 ; coarse control of the channel's period [r/w] + +def B_AUD4POLY_WIDTH equ 3 ; controls the noise generator (LFSR)'s step width [r/w] + def AUD4POLY_15STEP equ 0 << B_AUD4POLY_WIDTH + def AUD4POLY_7STEP equ 1 << B_AUD4POLY_WIDTH + +def AUD4POLY_DIV equ %00000_111 ; fine control of the channel's period [r/w] + +; -- AUD4GO / NR44 ($FF23) ---------------------------------------------------- +; Audio channel 4 control +def rAUD4GO equ $FF23 + +def B_AUD4GO_RESTART equ 7 ; 1 = restart the channel [wo] +def B_AUD4GO_LEN_ENABLE equ 6 ; 1 = reset the channel after the length timer expires [r/w] + def AUD4GO_RESTART equ 1 << B_AUD4GO_RESTART + def AUD4GO_LENGTH_OFF equ 0 << B_AUD4GO_LEN_ENABLE + def AUD4GO_LENGTH_ON equ 1 << B_AUD4GO_LEN_ENABLE + +; -- AUDVOL / NR50 ($FF24) ---------------------------------------------------- +; Audio master volume and VIN mixer +def rAUDVOL equ $FF24 + +def B_AUDVOL_VIN_LEFT equ 7 ; 1 = output VIN to left ear (SO2, speaker 2) [r/w] + def AUDVOL_VIN_LEFT equ 1 << B_AUDVOL_VIN_LEFT + +def AUDVOL_LEFT equ %0_111_0000 ; 0 = barely audible, 7 = full volume [r/w] + +def B_AUDVOL_VIN_RIGHT equ 3 ; 1 = output VIN to right ear (SO1, speaker 1) [r/w] + def AUDVOL_VIN_RIGHT equ 1 << B_AUDVOL_VIN_RIGHT + +def AUDVOL_RIGHT equ %00000_111 ; 0 = barely audible, 7 = full volume [r/w] + +; -- AUDTERM / NR51 ($FF25) --------------------------------------------------- +; Audio channel mixer +def rAUDTERM equ $FF25 + +def B_AUDTERM_4_LEFT equ 7 ; 1 = output channel 4 to left ear [r/w] +def B_AUDTERM_3_LEFT equ 6 ; 1 = output channel 3 to left ear [r/w] +def B_AUDTERM_2_LEFT equ 5 ; 1 = output channel 2 to left ear [r/w] +def B_AUDTERM_1_LEFT equ 4 ; 1 = output channel 1 to left ear [r/w] +def B_AUDTERM_4_RIGHT equ 3 ; 1 = output channel 4 to right ear [r/w] +def B_AUDTERM_3_RIGHT equ 2 ; 1 = output channel 3 to right ear [r/w] +def B_AUDTERM_2_RIGHT equ 1 ; 1 = output channel 2 to right ear [r/w] +def B_AUDTERM_1_RIGHT equ 0 ; 1 = output channel 1 to right ear [r/w] + def AUDTERM_4_LEFT equ 1 << B_AUDTERM_4_LEFT + def AUDTERM_3_LEFT equ 1 << B_AUDTERM_3_LEFT + def AUDTERM_2_LEFT equ 1 << B_AUDTERM_2_LEFT + def AUDTERM_1_LEFT equ 1 << B_AUDTERM_1_LEFT + def AUDTERM_4_RIGHT equ 1 << B_AUDTERM_4_RIGHT + def AUDTERM_3_RIGHT equ 1 << B_AUDTERM_3_RIGHT + def AUDTERM_2_RIGHT equ 1 << B_AUDTERM_2_RIGHT + def AUDTERM_1_RIGHT equ 1 << B_AUDTERM_1_RIGHT + +; -- AUDENA / NR52 ($FF26) ---------------------------------------------------- +; Audio master enable +def rAUDENA equ $FF26 + +def B_AUDENA_ENABLE equ 7 ; 0 = disable the APU (resets all audio registers to 0!) [r/w] +def B_AUDENA_ENABLE_CH4 equ 3 ; 1 = channel 4 is running [ro] +def B_AUDENA_ENABLE_CH3 equ 2 ; 1 = channel 3 is running [ro] +def B_AUDENA_ENABLE_CH2 equ 1 ; 1 = channel 2 is running [ro] +def B_AUDENA_ENABLE_CH1 equ 0 ; 1 = channel 1 is running [ro] + def AUDENA_OFF equ 0 << B_AUDENA_ENABLE + def AUDENA_ON equ 1 << B_AUDENA_ENABLE + def AUDENA_CH4_OFF equ 0 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH4_ON equ 1 << B_AUDENA_ENABLE_CH4 + def AUDENA_CH3_OFF equ 0 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH3_ON equ 1 << B_AUDENA_ENABLE_CH3 + def AUDENA_CH2_OFF equ 0 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH2_ON equ 1 << B_AUDENA_ENABLE_CH2 + def AUDENA_CH1_OFF equ 0 << B_AUDENA_ENABLE_CH1 + def AUDENA_CH1_ON equ 1 << B_AUDENA_ENABLE_CH1 + +; -- $FF27-$FF2F are unused --------------------------------------------------- + +; -- AUD3WAVE ($FF30-$FF3F) --------------------------------------------------- +; Audio channel 3 wave pattern RAM [r/w] +def rAUD3WAVE_0 equ $FF30 +def rAUD3WAVE_1 equ $FF31 +def rAUD3WAVE_2 equ $FF32 +def rAUD3WAVE_3 equ $FF33 +def rAUD3WAVE_4 equ $FF34 +def rAUD3WAVE_5 equ $FF35 +def rAUD3WAVE_6 equ $FF36 +def rAUD3WAVE_7 equ $FF37 +def rAUD3WAVE_8 equ $FF38 +def rAUD3WAVE_9 equ $FF39 +def rAUD3WAVE_A equ $FF3A +def rAUD3WAVE_B equ $FF3B +def rAUD3WAVE_C equ $FF3C +def rAUD3WAVE_D equ $FF3D +def rAUD3WAVE_E equ $FF3E +def rAUD3WAVE_F equ $FF3F + +; -- LCDC ($FF40) ------------------------------------------------------------- +; PPU graphics control +def rLCDC equ $FF40 + +def B_LCDC_ENABLE equ 7 ; whether the PPU (and LCD) are turned on [r/w] +def B_LCDC_WIN_MAP equ 6 ; which tilemap the Window reads from [r/w] +def B_LCDC_WINDOW equ 5 ; whether the Window is enabled [r/w] +def B_LCDC_BLOCKS equ 4 ; which "tile blocks" the BG and Window use [r/w] +def B_LCDC_BG_MAP equ 3 ; which tilemap the BG reads from [r/w] +def B_LCDC_OBJ_SIZE equ 2 ; how many pixels tall each OBJ is [r/w] +def B_LCDC_OBJS equ 1 ; whether OBJs are enabled [r/w] +def B_LCDC_BG equ 0 ; (DMG only) whether the BG is enabled [r/w] +def B_LCDC_PRIO equ 0 ; (CGB only) whether OBJ priority bits are enabled [r/w] + def LCDC_ENABLE equ 1 << B_LCDC_ENABLE + def LCDC_OFF equ 0 << B_LCDC_ENABLE + def LCDC_ON equ 1 << B_LCDC_ENABLE + def LCDC_WIN_MAP equ 1 << B_LCDC_WIN_MAP + def LCDC_WIN_9800 equ 0 << B_LCDC_WIN_MAP + def LCDC_WIN_9C00 equ 1 << B_LCDC_WIN_MAP + def LCDC_WINDOW equ 1 << B_LCDC_WINDOW + def LCDC_WIN_OFF equ 0 << B_LCDC_WINDOW + def LCDC_WIN_ON equ 1 << B_LCDC_WINDOW + def LCDC_BLOCKS equ 1 << B_LCDC_BLOCKS + def LCDC_BLOCK21 equ 0 << B_LCDC_BLOCKS + def LCDC_BLOCK01 equ 1 << B_LCDC_BLOCKS + def LCDC_BG_MAP equ 1 << B_LCDC_BG_MAP + def LCDC_BG_9800 equ 0 << B_LCDC_BG_MAP + def LCDC_BG_9C00 equ 1 << B_LCDC_BG_MAP + def LCDC_OBJ_SIZE equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_8 equ 0 << B_LCDC_OBJ_SIZE + def LCDC_OBJ_16 equ 1 << B_LCDC_OBJ_SIZE + def LCDC_OBJS equ 1 << B_LCDC_OBJS + def LCDC_OBJ_OFF equ 0 << B_LCDC_OBJS + def LCDC_OBJ_ON equ 1 << B_LCDC_OBJS + def LCDC_BG equ 1 << B_LCDC_BG + def LCDC_BG_OFF equ 0 << B_LCDC_BG + def LCDC_BG_ON equ 1 << B_LCDC_BG + def LCDC_PRIO equ 1 << B_LCDC_PRIO + def LCDC_PRIO_OFF equ 0 << B_LCDC_PRIO + def LCDC_PRIO_ON equ 1 << B_LCDC_PRIO + +; -- STAT ($FF41) ------------------------------------------------------------- +; Graphics status and interrupt control +def rSTAT equ $FF41 + +def B_STAT_LYC equ 6 ; 1 = LY match triggers the STAT interrupt [r/w] +def B_STAT_MODE_2 equ 5 ; 1 = OAM Scan triggers the PPU interrupt [r/w] +def B_STAT_MODE_1 equ 4 ; 1 = VBlank triggers the PPU interrupt [r/w] +def B_STAT_MODE_0 equ 3 ; 1 = HBlank triggers the PPU interrupt [r/w] +def B_STAT_LYCF equ 2 ; 1 = LY is currently equal to LYC [ro] +def B_STAT_BUSY equ 1 ; 1 = the PPU is currently accessing VRAM [ro] + def STAT_LYC equ 1 << B_STAT_LYC + def STAT_MODE_2 equ 1 << B_STAT_MODE_2 + def STAT_MODE_1 equ 1 << B_STAT_MODE_1 + def STAT_MODE_0 equ 1 << B_STAT_MODE_0 + def STAT_LYCF equ 1 << B_STAT_LYCF + def STAT_BUSY equ 1 << B_STAT_BUSY + +def STAT_MODE equ %000000_11 ; PPU's current status [ro] + def STAT_HBLANK equ %000000_00 ; waiting after a line's rendering (HBlank) + def STAT_VBLANK equ %000000_01 ; waiting between frames (VBlank) + def STAT_OAM equ %000000_10 ; checking which OBJs will be rendered on this line (OAM scan) + def STAT_LCD equ %000000_11 ; pushing pixels to the LCD + +; -- SCY ($FF42) -------------------------------------------------------------- +; Background Y scroll offset (in pixels) [r/w] +def rSCY equ $FF42 + +; -- SCX ($FF43) -------------------------------------------------------------- +; Background X scroll offset (in pixels) [r/w] +def rSCX equ $FF43 + +; -- LY ($FF44) --------------------------------------------------------------- +; Y coordinate of the line currently processed by the PPU (0-153) [ro] +def rLY equ $FF44 + +def LY_VBLANK equ 144 ; 144-153 is the VBlank period + +; -- LYC ($FF45) -------------------------------------------------------------- +; Value that LY is constantly compared to [r/w] +def rLYC equ $FF45 + +; -- DMA ($FF46) -------------------------------------------------------------- +; OAM DMA start address (high 8 bits) and start [wo] +def rDMA equ $FF46 + +; -- BGP ($FF47) -------------------------------------------------------------- +; (DMG only) Background color mapping [r/w] +def rBGP equ $FF47 + +def BGP_SGB_TRANSFER equ %11_10_01_00 ; set BGP to this value before SGB VRAM transfer + +; -- OBP0 ($FF48) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #0 [r/w] +def rOBP0 equ $FF48 + +; -- OBP1 ($FF49) ------------------------------------------------------------- +; (DMG only) OBJ color mapping #1 [r/w] +def rOBP1 equ $FF49 + +; -- WY ($FF4A) --------------------------------------------------------------- +; Y coordinate of the Window's top-left pixel (0-143) [r/w] +def rWY equ $FF4A + +; -- WX ($FF4B) --------------------------------------------------------------- +; X coordinate of the Window's top-left pixel, plus 7 (7-166) [r/w] +def rWX equ $FF4B + +def WX_OFS equ 7 ; subtract this to get the actual Window X coordinate + +; -- SYS / KEY0 ($FF4C) ------------------------------------------------------- +; (CGB boot ROM only) CPU mode select +def rSYS equ $FF4C + +; This is known as the "CPU mode register" in Fig. 11 of this patent: +; https://patents.google.com/patent/US6322447B1/en?oq=US6322447bi +; "OBJ priority mode designating register" in the same patent +; Credit to @mattcurrie for this finding! + +def SYS_MODE equ %0000_11_00 ; current system mode [r/w] + def SYS_CGB equ %0000_00_00 ; CGB mode + def SYS_DMG equ %0000_01_00 ; DMG compatibility mode + def SYS_PGB1 equ %0000_10_00 ; LCD is driven externally, CPU is stopped + def SYS_PGB2 equ %0000_11_00 ; LCD is driven externally, CPU is running + +; -- SPD / KEY1 ($FF4D) ------------------------------------------------------- +; (CGB only) Double-speed mode control +def rSPD equ $FF4D + +def B_SPD_DOUBLE equ 7 ; current clock speed [ro] +def B_SPD_PREPARE equ 0 ; 1 = next `stop` instruction will switch clock speeds [r/w] + def SPD_SINGLE equ 0 << B_SPD_DOUBLE + def SPD_DOUBLE equ 1 << B_SPD_DOUBLE + def SPD_PREPARE equ 1 << B_SPD_PREPARE + +; -- $FF4E is unused ---------------------------------------------------------- + +; -- VBK ($FF4F) -------------------------------------------------------------- +; (CGB only) VRAM bank number (0 or 1) +def rVBK equ $FF4F + +def VBK_BANK equ %0000000_1 ; mapped VRAM bank [r/w] + +; -- BANK ($FF50) ------------------------------------------------------------- +; (boot ROM only) Boot ROM mapping control +def rBANK equ $FF50 + +def B_BANK_ON equ 0 ; whether the boot ROM is mapped [wo] + def BANK_ON equ 0 << B_BANK_ON + def BANK_OFF equ 1 << B_BANK_ON + +; -- VDMA_SRC_HIGH / HDMA1 ($FF51) -------------------------------------------- +; (CGB only) VRAM DMA source address (high 8 bits) [wo] +def rVDMA_SRC_HIGH equ $FF51 + +; -- VDMA_SRC_LOW / HDMA2 ($FF52) --------------------------------------------- +; (CGB only) VRAM DMA source address (low 8 bits) [wo] +def rVDMA_SRC_LOW equ $FF52 + +; -- VDMA_DEST_HIGH / HDMA3 ($FF53) ------------------------------------------- +; (CGB only) VRAM DMA destination address (high 8 bits) [wo] +def rVDMA_DEST_HIGH equ $FF53 + +; -- VDMA_DEST_LOW / HDMA4 ($FF54) -------------------------------------------- +; (CGB only) VRAM DMA destination address (low 8 bits) [wo] +def rVDMA_DEST_LOW equ $FF54 + +; -- VDMA_LEN / HDMA5 ($FF55) ------------------------------------------------- +; (CGB only) VRAM DMA length, mode, and start +def rVDMA_LEN equ $FF55 + +def B_VDMA_LEN_MODE equ 7 ; on write: VRAM DMA mode [wo] + def VDMA_LEN_MODE equ 1 << B_VDMA_LEN_MODE + def VDMA_LEN_MODE_GENERAL equ 0 << B_VDMA_LEN_MODE ; GDMA (general-purpose) + def VDMA_LEN_MODE_HBLANK equ 1 << B_VDMA_LEN_MODE ; HDMA (HBlank) + +def B_VDMA_LEN_BUSY equ 7 ; on read: is a VRAM DMA active? + def VDMA_LEN_BUSY equ 1 << B_VDMA_LEN_BUSY + def VDMA_LEN_NO equ 0 << B_VDMA_LEN_BUSY + def VDMA_LEN_YES equ 1 << B_VDMA_LEN_BUSY + +def VDMA_LEN_SIZE equ %0_1111111 ; how many 16-byte blocks (minus 1) to transfer [r/w] + +; -- RP ($FF56) --------------------------------------------------------------- +; (CGB only) Infrared communications port +def rRP equ $FF56 + +def RP_READ equ %11_000000 ; whether the IR read is enabled [r/w] + def RP_DISABLE equ %00_000000 + def RP_ENABLE equ %11_000000 + +def B_RP_DATA_IN equ 1 ; 0 = IR light is being received [ro] +def B_RP_LED_ON equ 0 ; 1 = IR light is being sent [r/w] + def RP_DATA_IN equ 1 << B_RP_DATA_IN + def RP_LED_ON equ 1 << B_RP_LED_ON + def RP_WRITE_LOW equ 0 << B_RP_LED_ON + def RP_WRITE_HIGH equ 1 << B_RP_LED_ON + +; -- $FF57-$FF67 are unused --------------------------------------------------- + +; -- BGPI / BCPS ($FF68) ------------------------------------------------------ +; (CGB only) Background palette I/O index +def rBGPI equ $FF68 + +def B_BGPI_AUTOINC equ 7 ; whether the index field is incremented after each write to BCPD [r/w] + def BGPI_AUTOINC equ 1 << B_BGPI_AUTOINC + +def BGPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via BCPD [r/w] + +; -- BGPD / BCPD ($FF69) ------------------------------------------------------ +; (CGB only) Background palette I/O access [r/w] +def rBGPD equ $FF69 + +; -- OBPI / OCPS ($FF6A) ------------------------------------------------------ +; (CGB only) OBJ palette I/O index +def rOBPI equ $FF6A + +def B_OBPI_AUTOINC equ 7 ; whether the index field is incremented after each write to OBPD [r/w] + def OBPI_AUTOINC equ 1 << B_OBPI_AUTOINC + +def OBPI_INDEX equ %00_111111 ; the index within Palette RAM accessed via OBPD [r/w] + +; -- OBPD / OCPD ($FF6B) ------------------------------------------------------ +; (CGB only) OBJ palette I/O access [r/w] +def rOBPD equ $FF6B + +; -- OPRI ($FF6C) ------------------------------------------------------------- +; (CGB boot ROM only) OBJ draw priority mode +def rOPRI equ $FF6C + +def B_OPRI_PRIORITY equ 0 ; which drawing priority is used for OBJs [r/w] + def OPRI_PRIORITY equ 1 << B_OPRI_PRIORITY + def OPRI_OAM equ 0 << B_OPRI_PRIORITY ; CGB mode default: earliest OBJ in OAM wins + def OPRI_COORD equ 1 << B_OPRI_PRIORITY ; DMG mode default: leftmost OBJ wins + +; -- $FF6D-$FF6F are unused --------------------------------------------------- + +; -- WBK / SVBK ($FF70) ------------------------------------------------------- +; (CGB only) WRAM bank number +def rWBK equ $FF70 + +def WBK_BANK equ %00000_111 ; mapped WRAM bank (0-7) [r/w] + +; -- PSW ($FF71) -------------------------------------------------------------- +; (CGB boot ROM's DMG mode only) Palette Selection Window and NMI control. [r/w] +; Bits 1-6 are always 1. +; In CGB mode, reads return $FF and writes are ignored. +def rPSW equ $FF71 + +def B_PSW_WINDOW equ 7 ; whether the Palette Selection Window is enabled [r/w] +def B_PSW_NMI equ 0 ; whether the NMI is enabled [r/w] + def PSW_WINDOW equ 1 << B_PSW_WINDOW + def PSW_WIN_OFF equ 0 << B_PSW_WINDOW + def PSW_WIN_ON equ 1 << B_PSW_WINDOW + def PSW_NMI equ 1 << B_PSW_NMI + def PSW_NMI_DISABLE equ 0 << B_PSW_NMI + def PSW_NMI_ENABLE equ 1 << B_PSW_NMI + +; -- PSWX ($FF72) ------------------------------------------------------------- +; (CGB boot ROM only) X coordinate of the Palette Selection Window's top-left pixel, plus 7 (7-166) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWX equ $FF72 + +; -- PSWY ($FF73) ------------------------------------------------------------- +; (CGB boot ROM only) Y coordinate of the Palette Selection Window's top-left pixel (0-143) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSWY equ $FF73 + +; -- PSM ($FF74) -------------------------------------------------------------- +; (CGB boot ROM only) Set the Palette Selection Window button mask (triggers NMI when pressed) [r/w] +; Readable and writable in both CGB and DMG mode. +def rPSM equ $FF74 + +def B_PSM_START equ 7 +def B_PSM_SELECT equ 6 +def B_PSM_B equ 5 +def B_PSM_A equ 4 +def B_PSM_DOWN equ 3 +def B_PSM_UP equ 2 +def B_PSM_LEFT equ 1 +def B_PSM_RIGHT equ 0 + def PSM_START equ 1 << B_PSM_START + def PSM_SELECT equ 1 << B_PSM_SELECT + def PSM_B equ 1 << B_PSM_B + def PSM_A equ 1 << B_PSM_A + def PSM_DOWN equ 1 << B_PSM_DOWN + def PSM_UP equ 1 << B_PSM_UP + def PSM_LEFT equ 1 << B_PSM_LEFT + def PSM_RIGHT equ 1 << B_PSM_RIGHT + +; -- $FF75 is unused ---------------------------------------------------------- + +; -- PCM12 ($FF76) ------------------------------------------------------------ +; Audio channels 1 and 2 output +def rPCM12 equ $FF76 + +def PCM12_CH2 equ %1111_0000 ; audio channel 2 output [ro] +def PCM12_CH1 equ %0000_1111 ; audio channel 1 output [ro] + +; -- PCM34 ($FF77) ------------------------------------------------------------ +; Audio channels 3 and 4 output +def rPCM34 equ $FF77 + +def PCM34_CH4 equ %1111_0000 ; audio channel 4 output [ro] +def PCM34_CH3 equ %0000_1111 ; audio channel 3 output [ro] + +; -- $FF78-$FF7F are unused --------------------------------------------------- + +; -- IE ($FFFF) --------------------------------------------------------------- +; Interrupt enable +def rIE equ $FFFF + +def B_IE_JOYPAD equ 4 ; 1 = joypad interrupt is enabled [r/w] +def B_IE_SERIAL equ 3 ; 1 = serial interrupt is enabled [r/w] +def B_IE_TIMER equ 2 ; 1 = timer interrupt is enabled [r/w] +def B_IE_STAT equ 1 ; 1 = STAT interrupt is enabled [r/w] +def B_IE_VBLANK equ 0 ; 1 = VBlank interrupt is enabled [r/w] + def IE_JOYPAD equ 1 << B_IE_JOYPAD + def IE_SERIAL equ 1 << B_IE_SERIAL + def IE_TIMER equ 1 << B_IE_TIMER + def IE_STAT equ 1 << B_IE_STAT + def IE_VBLANK equ 1 << B_IE_VBLANK + + +;****************************************************************************** +; Cartridge registers (MBC) +;****************************************************************************** + +; Note that these "registers" are each actually accessible at an entire address range; +; however, one address for each of these ranges is considered the "canonical" one, and +; these addresses are what's provided here. + + +; ** Common to most MBCs ****************************************************** + +; -- RAMG ($0000-$1FFF) ------------------------------------------------------- +; Whether SRAM can be accessed [wo] +def rRAMG equ $0000 + +; Common values (not for HuC1 or HuC-3) +def RAMG_SRAM_DISABLE equ $00 +def RAMG_SRAM_ENABLE equ $0A ; some MBCs accept any value whose low nybble is $A + +; (HuC-3 only) switch SRAM to map cartridge RAM, RTC, or IR +def RAMG_CART_RAM_RO equ $00 ; select cartridge RAM [ro] +def RAMG_CART_RAM equ $0A ; select cartridge RAM [r/w] +def RAMG_RTC_IN equ $0B ; select RTC command/argument [wo] + def RAMG_RTC_IN_CMD equ %0_111_0000 ; command + def RAMG_RTC_IN_ARG equ %0_000_1111 ; argument +def RAMG_RTC_OUT equ $0C ; select RTC command/response [ro] + def RAMG_RTC_OUT_CMD equ %0_111_0000 ; command + def RAMG_RTC_OUT_RESULT equ %0_000_1111 ; result +def RAMG_RTC_SEMAPHORE equ $0D ; select RTC semaphore [r/w] +def RAMG_IR equ $0E ; (HuC1 and HuC-3 only) select IR [r/w] + +; -- ROMB ($2000-$3FFF) ------------------------------------------------------- +; ROM bank number (not for MBC5 or MBC6) [wo] +def rROMB equ $2000 + +; -- RAMB ($4000-$5FFF) ------------------------------------------------------- +; SRAM bank number (not for MBC2, MBC6, or MBC7) [wo] +def rRAMB equ $4000 + +; (MBC3 only) Special RAM bank numbers that actually map values into RTCREG +def RAMB_RTC_S equ $08 ; seconds counter (0-59) +def RAMB_RTC_M equ $09 ; minutes counter (0-59) +def RAMB_RTC_H equ $0A ; hours counter (0-23) +def RAMB_RTC_DL equ $0B ; days counter, low byte (0-255) +def RAMB_RTC_DH equ $0C ; days counter, high bit and other flags + def B_RAMB_RTC_DH_CARRY equ 7 ; 1 = days counter overflowed [wo] + def B_RAMB_RTC_DH_HALT equ 6 ; 0 = run timer, 1 = stop timer [wo] + def B_RAMB_RTC_DH_HIGH equ 0 ; days counter, high bit (bit 8) [wo] + def RAMB_RTC_DH_CARRY equ 1 << B_RAMB_RTC_DH_CARRY + def RAMB_RTC_DH_HALT equ 1 << B_RAMB_RTC_DH_HALT + def RAMB_RTC_DH_HIGH equ 1 << B_RAMB_RTC_DH_HIGH + +def B_RAMB_RUMBLE equ 3 ; (MBC5 and MBC7 only) enable the rumble motor (if any) + def RAMB_RUMBLE equ 1 << B_RAMB_RUMBLE + def RAMB_RUMBLE_OFF equ 0 << B_RAMB_RUMBLE + def RAMB_RUMBLE_ON equ 1 << B_RAMB_RUMBLE + + +; ** MBC1 and MMM01 only ****************************************************** + +; -- BMODE ($6000-$7FFF) ------------------------------------------------------ +; Banking mode select [wo] +def rBMODE equ $6000 + +def BMODE_SIMPLE equ $00 ; locks ROMB and RAMB to bank 0 +def BMODE_ADVANCED equ $01 ; allows bank-switching with RAMB + + +; ** MBC2 only **************************************************************** + +; -- ROM2B ($0000-$3FFF with bit 8 set) --------------------------------------- +; ROM bank number [wo] +def rROM2B equ $2100 + + +; ** MBC3 only **************************************************************** + +; -- RTCLATCH ($6000-$7FFF) --------------------------------------------------- +; RTC latch clock data [wo] +def rRTCLATCH equ $6000 + +; Write $00 then $01 to latch the current time into RTCREG +def RTCLATCH_START equ $00 +def RTCLATCH_FINISH equ $01 + +; -- RTCREG ($A000-$BFFF) ----------------------------------------------------- +; RTC register [r/w] +def rRTCREG equ $A000 + + +; ** MBC5 only **************************************************************** + +; -- ROMB0 ($2000-$2FFF) ------------------------------------------------------ +; ROM bank number low byte (bits 0-7) [wo] +def rROMB0 equ $2000 + +; -- ROMB1 ($3000-$3FFF) ------------------------------------------------------ +; ROM bank number high bit (bit 8) [wo] +def rROMB1 equ $3000 + + +; ** MBC6 only **************************************************************** + +; -- RAMBA ($0400-$07FF) ------------------------------------------------------ +; RAM bank A number [wo] +def rRAMBA equ $0400 + +; -- RAMBB ($0800-$0BFF) ------------------------------------------------------ +; RAM bank B number [wo] +def rRAMBB equ $0800 + +; -- FLASH ($0C00-$0FFF) ------------------------------------------------------ +; Whether the flash chip can be accessed [wo] +def rFLASH equ $0C00 + +; -- FMODE ($1000) ------------------------------------------------------------ +; Write mode select for the flash chip +def rFMODE equ $1000 + +; -- ROMBA ($2000-$27FF) ------------------------------------------------------ +; ROM/Flash bank A number [wo] +def rROMBA equ $2000 + +; -- FLASHA ($2800-$2FFF) ----------------------------------------------------- +; ROM/Flash bank A select [wo] +def rFLASHA equ $2800 + +; -- ROMBB ($3000-$37FF) ------------------------------------------------------ +; ROM/Flash bank B number [wo] +def rROMBB equ $3000 + +; -- FLASHB ($3800-$3FFF) ----------------------------------------------------- +; ROM/Flash bank B select [wo] +def rFLASHB equ $3800 + + +; ** MBC7 only **************************************************************** + +; -- RAMREG ($4000-$5FFF) ----------------------------------------------------- +; Enable RAM register access [wo] +def rRAMREG equ $4000 + +def RAMREG_ENABLE equ $40 + +; -- ACCLATCH0 ($Ax0x) -------------------------------------------------------- +; Latch accelerometer start [wo] +def rACCLATCH0 equ $A000 + +; Write $55 to ACCLATCH0 to erase the latched data +def ACCLATCH0_START equ $55 + +; -- ACCLATCH1 ($Ax1x) -------------------------------------------------------- +; Latch accelerometer finish [wo] +def rACCLATCH1 equ $A010 + +; Write $AA to ACCLATCH1 to latch the accelerometer and update ACCEL* +def ACCLATCH1_FINISH equ $AA + +; -- ACCELX0 ($Ax2x) ---------------------------------------------------------- +; Accelerometer X value low byte [ro] +def rACCELX0 equ $A020 + +; -- ACCELX1 ($Ax3x) ---------------------------------------------------------- +; Accelerometer X value high byte [ro] +def rACCELX1 equ $A030 + +; -- ACCELY0 ($Ax4x) ---------------------------------------------------------- +; Accelerometer Y value low byte [ro] +def rACCELY0 equ $A040 + +; -- ACCELY1 ($Ax5x) ---------------------------------------------------------- +; Accelerometer Y value high byte [ro] +def rACCELY1 equ $A050 + +; -- EEPROM ($Ax8x) ----------------------------------------------------------- +; EEPROM access [r/w] +def rEEPROM equ $A080 + + +; ** HuC1 only **************************************************************** + +; -- IRREG ($A000-$BFFF) ------------------------------------------------------ +; IR register [r/w] +def rIRREG equ $A000 + +; whether the IR transmitter sees light +def IR_LED_OFF equ $C0 +def IR_LED_ON equ $C1 + + +;****************************************************************************** +; Screen-related constants +;****************************************************************************** + +def SCREEN_WIDTH_PX equ 160 ; width of screen in pixels +def SCREEN_HEIGHT_PX equ 144 ; height of screen in pixels +def SCREEN_WIDTH equ 20 ; width of screen in bytes +def SCREEN_HEIGHT equ 18 ; height of screen in bytes +def SCREEN_AREA equ SCREEN_WIDTH * SCREEN_HEIGHT ; size of screen in bytes + +def TILEMAP_WIDTH_PX equ 256 ; width of tilemap in pixels +def TILEMAP_HEIGHT_PX equ 256 ; height of tilemap in pixels +def TILEMAP_WIDTH equ 32 ; width of tilemap in bytes +def TILEMAP_HEIGHT equ 32 ; height of tilemap in bytes +def TILEMAP_AREA equ TILEMAP_WIDTH * TILEMAP_HEIGHT ; size of tilemap in bytes + +def TILE_WIDTH equ 8 ; width of tile in pixels +def TILE_HEIGHT equ 8 ; height of tile in pixels +def TILE_SIZE equ 16 ; size of tile in bytes (2 bits/pixel) + +def COLOR_SIZE equ 2 ; size of color in bytes (little-endian BGR555) +def PAL_COLORS equ 4 ; colors per palette +def PAL_SIZE equ COLOR_SIZE * PAL_COLORS ; size of palette in bytes + +def COLOR_CH_WIDTH equ 5 ; bits per RGB color channel +def COLOR_CH_MAX equ (1 << COLOR_CH_WIDTH) - 1 + def B_COLOR_RED equ COLOR_CH_WIDTH * 0 ; bits 4-0 + def B_COLOR_GREEN equ COLOR_CH_WIDTH * 1 ; bits 9-5 + def B_COLOR_BLUE equ COLOR_CH_WIDTH * 2 ; bits 14-10 + def COLOR_RED equ %000_11111 ; for the low byte + def COLOR_GREEN_LOW equ %111_00000 ; for the low byte + def COLOR_GREEN_HIGH equ %0_00000_11 ; for the high byte + def COLOR_BLUE equ %0_11111_00 ; for the high byte + +; (DMG only) grayscale shade indexes for BGP, OBP0, and OBP1 +def SHADE_WHITE equ %00 +def SHADE_LIGHT equ %01 +def SHADE_DARK equ %10 +def SHADE_BLACK equ %11 + +; Tilemaps the BG or Window can read from (controlled by LCDC) +def TILEMAP0 equ $9800 ; $9800-$9BFF +def TILEMAP1 equ $9C00 ; $9C00-$9FFF + +; (CGB only) BG tile attribute fields +def B_BG_PRIO equ 7 ; whether the BG tile colors 1-3 are drawn above OBJs +def B_BG_YFLIP equ 6 ; whether the whole BG tile is flipped vertically +def B_BG_XFLIP equ 5 ; whether the whole BG tile is flipped horizontally +def B_BG_BANK1 equ 3 ; which VRAM bank the BG tile is taken from +def BG_PALETTE equ %00000_111 ; which palette the BG tile uses + def BG_PRIO equ 1 << B_BG_PRIO + def BG_YFLIP equ 1 << B_BG_YFLIP + def BG_XFLIP equ 1 << B_BG_XFLIP + def BG_BANK0 equ 0 << B_BG_BANK1 + def BG_BANK1 equ 1 << B_BG_BANK1 + + +;****************************************************************************** +; OBJ-related constants +;****************************************************************************** + +; OAM attribute field offsets +rsreset +def OAMA_Y rb ; 0 + def OAM_Y_OFS equ 16 ; subtract 16 from what's written to OAM to get the real Y position +def OAMA_X rb ; 1 + def OAM_X_OFS equ 8 ; subtract 8 from what's written to OAM to get the real X position +def OAMA_TILEID rb ; 2 +def OAMA_FLAGS rb ; 3 + def B_OAM_PRIO equ 7 ; whether the OBJ is drawn below BG colors 1-3 + def B_OAM_YFLIP equ 6 ; whether the whole OBJ is flipped vertically + def B_OAM_XFLIP equ 5 ; whether the whole OBJ is flipped horizontally + def B_OAM_PAL1 equ 4 ; (DMG only) which of the two palettes the OBJ uses + def B_OAM_BANK1 equ 3 ; (CGB only) which VRAM bank the OBJ takes its tile(s) from + def OAM_PALETTE equ %00000_111 ; (CGB only) which palette the OBJ uses + def OAM_PRIO equ 1 << B_OAM_PRIO + def OAM_YFLIP equ 1 << B_OAM_YFLIP + def OAM_XFLIP equ 1 << B_OAM_XFLIP + def OAM_PAL0 equ 0 << B_OAM_PAL1 + def OAM_PAL1 equ 1 << B_OAM_PAL1 + def OAM_BANK0 equ 0 << B_OAM_BANK1 + def OAM_BANK1 equ 1 << B_OAM_BANK1 +def OBJ_SIZE rb 0 ; size of OBJ in bytes = 4 + +def OAM_COUNT equ 40 ; how many OBJs there are room for in OAM +def OAM_SIZE equ OBJ_SIZE * OAM_COUNT + + +;****************************************************************************** +; Audio channel RAM addresses +;****************************************************************************** + +def AUD1RAM equ $FF10 ; $FF10-$FF14 +def AUD2RAM equ $FF15 ; $FF15-$FF19 +def AUD3RAM equ $FF1A ; $FF1A-$FF1E +def AUD4RAM equ $FF1F ; $FF1F-$FF23 +def AUDRAM_SIZE equ 5 ; size of each audio channel RAM in bytes + +def _AUD3WAVERAM equ $FF30 ; $FF30-$FF3F +def AUD3WAVE_SIZE equ 16 ; size of wave pattern RAM in bytes + + +;****************************************************************************** +; Interrupt vector addresses +;****************************************************************************** + +def INT_HANDLER_VBLANK equ $0040 ; VBlank interrupt handler address +def INT_HANDLER_STAT equ $0048 ; STAT interrupt handler address +def INT_HANDLER_TIMER equ $0050 ; timer interrupt handler address +def INT_HANDLER_SERIAL equ $0058 ; serial interrupt handler address +def INT_HANDLER_JOYPAD equ $0060 ; joypad interrupt handler address + + +;****************************************************************************** +; Boot-up register values +;****************************************************************************** + +; Register A = CPU type +def BOOTUP_A_DMG equ $01 +def BOOTUP_A_CGB equ $11 ; CGB or AGB +def BOOTUP_A_MGB equ $FF + def BOOTUP_A_SGB equ BOOTUP_A_DMG + def BOOTUP_A_SGB2 equ BOOTUP_A_MGB + +; Register B = CPU qualifier (if A is BOOTUP_A_CGB) +def B_BOOTUP_B_AGB equ 0 + def BOOTUP_B_CGB equ 0 << B_BOOTUP_B_AGB + def BOOTUP_B_AGB equ 1 << B_BOOTUP_B_AGB + +; Register C = CPU qualifier +def BOOTUP_C_DMG equ $13 +def BOOTUP_C_SGB equ $14 +def BOOTUP_C_CGB equ $00 ; CGB or AGB + +; Register D = color qualifier +def BOOTUP_D_MONO equ $00 ; DMG, MGB, SGB, or CGB or AGB in DMG mode +def BOOTUP_D_COLOR equ $FF ; CGB or AGB + +; Register E = CPU qualifier (distinguishes DMG variants) +def BOOTUP_E_DMG0 equ $C1 +def BOOTUP_E_DMG equ $C8 +def BOOTUP_E_SGB equ $00 +def BOOTUP_E_CGB_DMGMODE equ $08 ; CGB or AGB in DMG mode +def BOOTUP_E_CGB equ $56 ; CGB or AGB + + +;****************************************************************************** +; Aliases +;****************************************************************************** + +; Prefer the standard names to these aliases, which may be official but are +; less directly meaningful or human-readable. + +def rP1 equ rJOYP + +def rNR10 equ rAUD1SWEEP +def rNR11 equ rAUD1LEN +def rNR12 equ rAUD1ENV +def rNR13 equ rAUD1LOW +def rNR14 equ rAUD1HIGH +def rNR21 equ rAUD2LEN +def rNR22 equ rAUD2ENV +def rNR23 equ rAUD2LOW +def rNR24 equ rAUD2HIGH +def rNR30 equ rAUD3ENA +def rNR31 equ rAUD3LEN +def rNR32 equ rAUD3LEVEL +def rNR33 equ rAUD3LOW +def rNR34 equ rAUD3HIGH +def rNR41 equ rAUD4LEN +def rNR42 equ rAUD4ENV +def rNR43 equ rAUD4POLY +def rNR44 equ rAUD4GO +def rNR50 equ rAUDVOL +def rNR51 equ rAUDTERM +def rNR52 equ rAUDENA + +def rKEY0 equ rSYS +def rKEY1 equ rSPD + +def rHDMA1 equ rVDMA_SRC_HIGH +def rHDMA2 equ rVDMA_SRC_LOW +def rHDMA3 equ rVDMA_DEST_HIGH +def rHDMA4 equ rVDMA_DEST_LOW +def rHDMA5 equ rVDMA_LEN + +def rBCPS equ rBGPI +def rBCPD equ rBGPD + +def rOCPS equ rOBPI +def rOCPD equ rOBPD + +def rSVBK equ rWBK + +endc ; HARDWARE_INC -; $0143 Color GameBoy compatibility code -DEF CART_COMPATIBLE_DMG EQU $00 -DEF CART_COMPATIBLE_DMG_GBC EQU $80 -DEF CART_COMPATIBLE_GBC EQU $C0 - -; $0146 GameBoy/Super GameBoy indicator -DEF CART_INDICATOR_GB EQU $00 -DEF CART_INDICATOR_SGB EQU $03 - -; $0147 Cartridge type -DEF CART_ROM EQU $00 -DEF CART_ROM_MBC1 EQU $01 -DEF CART_ROM_MBC1_RAM EQU $02 -DEF CART_ROM_MBC1_RAM_BAT EQU $03 -DEF CART_ROM_MBC2 EQU $05 -DEF CART_ROM_MBC2_BAT EQU $06 -DEF CART_ROM_RAM EQU $08 -DEF CART_ROM_RAM_BAT EQU $09 -DEF CART_ROM_MMM01 EQU $0B -DEF CART_ROM_MMM01_RAM EQU $0C -DEF CART_ROM_MMM01_RAM_BAT EQU $0D -DEF CART_ROM_MBC3_BAT_RTC EQU $0F -DEF CART_ROM_MBC3_RAM_BAT_RTC EQU $10 -DEF CART_ROM_MBC3 EQU $11 -DEF CART_ROM_MBC3_RAM EQU $12 -DEF CART_ROM_MBC3_RAM_BAT EQU $13 -DEF CART_ROM_MBC5 EQU $19 -DEF CART_ROM_MBC5_BAT EQU $1A -DEF CART_ROM_MBC5_RAM_BAT EQU $1B -DEF CART_ROM_MBC5_RUMBLE EQU $1C -DEF CART_ROM_MBC5_RAM_RUMBLE EQU $1D -DEF CART_ROM_MBC5_RAM_BAT_RUMBLE EQU $1E -DEF CART_ROM_MBC7_RAM_BAT_GYRO EQU $22 -DEF CART_ROM_POCKET_CAMERA EQU $FC -DEF CART_ROM_BANDAI_TAMA5 EQU $FD -DEF CART_ROM_HUDSON_HUC3 EQU $FE -DEF CART_ROM_HUDSON_HUC1 EQU $FF - -; $0148 ROM size -; these are kilobytes -DEF CART_ROM_32KB EQU $00 ; 2 banks -DEF CART_ROM_64KB EQU $01 ; 4 banks -DEF CART_ROM_128KB EQU $02 ; 8 banks -DEF CART_ROM_256KB EQU $03 ; 16 banks -DEF CART_ROM_512KB EQU $04 ; 32 banks -DEF CART_ROM_1024KB EQU $05 ; 64 banks -DEF CART_ROM_2048KB EQU $06 ; 128 banks -DEF CART_ROM_4096KB EQU $07 ; 256 banks -DEF CART_ROM_8192KB EQU $08 ; 512 banks -DEF CART_ROM_1152KB EQU $52 ; 72 banks -DEF CART_ROM_1280KB EQU $53 ; 80 banks -DEF CART_ROM_1536KB EQU $54 ; 96 banks - -; $0149 SRAM size -; these are kilobytes -DEF CART_SRAM_NONE EQU 0 -DEF CART_SRAM_8KB EQU 2 ; 1 bank -DEF CART_SRAM_32KB EQU 3 ; 4 banks -DEF CART_SRAM_128KB EQU 4 ; 16 banks - -; $014A Destination code -DEF CART_DEST_JAPANESE EQU $00 -DEF CART_DEST_NON_JAPANESE EQU $01 - - -;*************************************************************************** -;* -;* Keypad related -;* -;*************************************************************************** - -DEF PADF_DOWN EQU $80 -DEF PADF_UP EQU $40 -DEF PADF_LEFT EQU $20 -DEF PADF_RIGHT EQU $10 -DEF PADF_START EQU $08 -DEF PADF_SELECT EQU $04 -DEF PADF_B EQU $02 -DEF PADF_A EQU $01 - -DEF PADB_DOWN EQU $7 -DEF PADB_UP EQU $6 -DEF PADB_LEFT EQU $5 -DEF PADB_RIGHT EQU $4 -DEF PADB_START EQU $3 -DEF PADB_SELECT EQU $2 -DEF PADB_B EQU $1 -DEF PADB_A EQU $0 - - -;*************************************************************************** -;* -;* Screen related -;* -;*************************************************************************** - -DEF SCRN_X EQU 160 ; Width of screen in pixels -DEF SCRN_Y EQU 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. -DEF SCRN_X_B EQU 20 ; Width of screen in bytes -DEF SCRN_Y_B EQU 18 ; Height of screen in bytes - -DEF SCRN_VX EQU 256 ; Virtual width of screen in pixels -DEF SCRN_VY EQU 256 ; Virtual height of screen in pixels -DEF SCRN_VX_B EQU 32 ; Virtual width of screen in bytes -DEF SCRN_VY_B EQU 32 ; Virtual height of screen in bytes - - -;*************************************************************************** -;* -;* OAM related -;* -;*************************************************************************** - -; OAM attributes -; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) -RSRESET -DEF OAMA_Y RB 1 ; y pos plus 16 -DEF OAMA_X RB 1 ; x pos plus 8 -DEF OAMA_TILEID RB 1 ; tile id -DEF OAMA_FLAGS RB 1 ; flags (see below) -DEF sizeof_OAM_ATTRS RB 0 - -DEF OAM_Y_OFS EQU 16 ; add this to a screen-relative Y position to get an OAM Y position -DEF OAM_X_OFS EQU 8 ; add this to a screen-relative X position to get an OAM X position - -DEF OAM_COUNT EQU 40 ; number of OAM entries in OAM RAM - -; flags -DEF OAMF_PRI EQU %10000000 ; Priority -DEF OAMF_YFLIP EQU %01000000 ; Y flip -DEF OAMF_XFLIP EQU %00100000 ; X flip -DEF OAMF_PAL0 EQU %00000000 ; Palette number; 0,1 (DMG) -DEF OAMF_PAL1 EQU %00010000 ; Palette number; 0,1 (DMG) -DEF OAMF_BANK0 EQU %00000000 ; Bank number; 0,1 (GBC) -DEF OAMF_BANK1 EQU %00001000 ; Bank number; 0,1 (GBC) - -DEF OAMF_PALMASK EQU %00000111 ; Palette (GBC) - -DEF OAMB_PRI EQU 7 ; Priority -DEF OAMB_YFLIP EQU 6 ; Y flip -DEF OAMB_XFLIP EQU 5 ; X flip -DEF OAMB_PAL1 EQU 4 ; Palette number; 0,1 (DMG) -DEF OAMB_BANK1 EQU 3 ; Bank number; 0,1 (GBC) - - -; Deprecated constants. Please avoid using. - -DEF IEF_LCDC EQU %00000010 ; LCDC (see STAT) -DEF _VRAM8000 EQU _VRAM -DEF _VRAM8800 EQU _VRAM+$800 -DEF _VRAM9000 EQU _VRAM+$1000 -DEF CART_SRAM_2KB EQU 1 ; 1 incomplete bank - - - ENDC ;HARDWARE_INC \ No newline at end of file diff --git a/unbricked/objects/main.asm b/unbricked/objects/main.asm index b0126daa..eeeec818 100644 --- a/unbricked/objects/main.asm +++ b/unbricked/objects/main.asm @@ -63,7 +63,7 @@ CopyPaddle: ; ANCHOR: clear-oam ld a, 0 ld b, 160 - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ClearOam: ld [hli], a dec b @@ -71,7 +71,7 @@ ClearOam: ; ANCHOR_END: clear-oam ; ANCHOR: init-object - ld hl, _OAMRAM + ld hl, STARTOF(OAM) ld a, 128 + 16 ld [hli], a ld a, 16 + 8 @@ -83,7 +83,7 @@ ClearOam: ; ANCHOR: enable-oam ; Turn the LCD on - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld a, LCDC_ON | LCDC_BG_ON | LCDC_OBJ_ON ld [rLCDC], a ; During the first (blank) frame, initialize display registers @@ -118,9 +118,9 @@ WaitVBlank2: ld [wFrameCounter], a ; Move the paddle one pixel to the right. - ld a, [_OAMRAM + 1] + ld a, [STARTOF(OAM) + 1] inc a - ld [_OAMRAM + 1], a + ld [STARTOF(OAM) + 1], a jp Main ; ANCHOR_END: main-loop