From 028a7ccf90103b51a51b751be4a4a2e0732fe9c4 Mon Sep 17 00:00:00 2001 From: MineRobber9000 Date: Mon, 19 May 2025 06:10:30 -0400 Subject: [PATCH] Add gameboy (SM83) ruledefs, platform, and example What it says on the tin. The GameBoy's SM83 CPU is kinda like a Z80... if you vaguely described a Z80 to someone over a bad phone line. A lot of things that work on a Z80 do not work on a SM83, but there are some shared features; however, I just took the SM83 opcode table, found the patterns in instruction encoding, and translated them into ruledefs. The constants in platform/gameboy/constants.asm come from hardware.inc, a well-worn definitions file that pretty much every GameBoy homebrew project uses (though it has been known under other names too) for register locations, bit flags, and other magic values that you need in order to write a GameBoy game. The cart_rom.asm file doesn't actually output a header; this is because unlike the NES' iNES header, the GameBoy header actually includes data that someone making a ROM might want to control (things like GBC or SGB compatibility, game title (which some emulators display), revision number, etc.). Instead, it defines the ROM bank, puts you in it, and gets out of your way. The common_banks.asm file sets up banks for things that don't change no matter what MBC you use; this is VRAM, SRAM, WRAM, HRAM, and OAM. Finally, the example ROM is a simple Hello World. Unfortunately, customasm isn't powerful enough to generate the right header checksum, but fortunately, most emulators don't care (and tooling does exist to fix that if you feel like fixing that is necessary). It uses ibmpc1.bin, a binary representation of the classic IBM PC font, as its font of choice. --- examples/gameboy_hello_world.asm | 153 ++++ examples/ibmpc1.bin | Bin 0 -> 2048 bytes std/cpu/sm83.asm | 205 +++++ std/platform/gameboy/cart_rom.asm | 12 + std/platform/gameboy/common_banks.asm | 24 + std/platform/gameboy/constants.asm | 1069 +++++++++++++++++++++++++ std/platform/gameboy/cpu.asm | 1 + 7 files changed, 1464 insertions(+) create mode 100644 examples/gameboy_hello_world.asm create mode 100644 examples/ibmpc1.bin create mode 100644 std/cpu/sm83.asm create mode 100644 std/platform/gameboy/cart_rom.asm create mode 100644 std/platform/gameboy/common_banks.asm create mode 100644 std/platform/gameboy/constants.asm create mode 100644 std/platform/gameboy/cpu.asm diff --git a/examples/gameboy_hello_world.asm b/examples/gameboy_hello_world.asm new file mode 100644 index 00000000..92bf1ada --- /dev/null +++ b/examples/gameboy_hello_world.asm @@ -0,0 +1,153 @@ +#include "/platform/gameboy/cpu.asm" +#include "/platform/gameboy/constants.asm" +#include "/platform/gameboy/cart_rom.asm" + +; number of bits to align RST/interrupt vectors to +VECTOR_ALIGNMENT = 8*8 + +#addr INT_HANDLER_VBLANK +VBlank: +reti +#align VECTOR_ALIGNMENT +LCD: +reti +#align VECTOR_ALIGNMENT +Timer: +reti +#align VECTOR_ALIGNMENT +Serial: +reti +#align VECTOR_ALIGNMENT +Joypad: +reti +#align VECTOR_ALIGNMENT +#addr $0100 ; gameboy header starts at 0x100 +; entrypoint (we get 4 bytes here, which run when the gameboy's boot ROM exits) +; this is a standard entrypoint in lots of gameboy games +nop +jp Start +; nintendo logo (must match what the boot ROM expects or we won't be able to +; boot on real hardware) +#d NINTENDO_LOGO ; constants.asm provides the correct value +; title of our ROM +Title: +#d "HELLOWORLD" +.len = $-Title +#d 0`((15-Title.len)*8) +; a byte to determine if we support GBC +; (GBC is backwards compatible with original DMG but this byte is for whether +; the game supports additional features when run on GBC) +#d CART_COMPATIBLE_DMG ; we don't +; 2-character licensee code (if $014B==0x33) +#d "CA" ; for *c*ustom*a*sm +; a byte to determine if we support SGB +; (again, this is for if we have additional features when played in a SGB) +#d CART_INDICATOR_GB ; we don't +; cartridge type +#d CART_TYPE ; cart_rom.asm set this for us +; ROM size +#d CART_ROM_32KB +; SRAM size +#d CART_SRAM_NONE +; destination code (not actually checked AFAICT) +#d CART_DEST_NON_JAPANESE +; old licensee code +#d 0x33 ; we used the new licensee code above so this must be 0x33 +; version number +#d 0x00 +; header checksum (must be correct to run on real hardware) +; ...we can't actually do this. customasm just isn't powerful enough to compute +; this checksum and include it +; for now you can use rgbfix from RGBDS(.github.io) to "fix" the header (pass +; -v option to just fix the header) +#d8 0 +; global checksum +; same issue (though at least this one isn't checked by anything, except for +; GB Tower on Pokemon Stadium) +; rgbfix -v will fix this one too +#d16 0 + +#addr $0150 +Start: +di ; disable interrupts +ld sp, $dfff ; initialize stack pointer +ld a, %11100100 ; initialize palette +ld [rBGP], a +xor a ; zero out scroll x and y +ld [rSCX], a +ld [rSCY], a +; turn off LCD +ld a, [rLCDC] +rlca ; LCD on/off flag in carry +jr nc, .skip ; LCD already off? skip turning it off then +.waitForLY: +ld a, [rLY] +cp 145 ; line 145 is start of vblank +jr nz, .waitForLY ; if we aren't there yet, loop +ld a, [rLCDC] +res 7, a ; reset on/off flag +ld [rLCDC], a +.skip: +ld hl, Tiles ; load font into character RAM +ld de, _VRAM +ld bc, Tiles.size +inc b +.tileLoop: +ld a,[hli] +ld [de],a +inc de +ld [de],a +inc de +dec c +jr nz, .tileLoop +dec b +jr nz, .tileLoop +; clear screen +ld hl, _SCRN0 +ld bc, SCRN_VX_B * SCRN_VY_B +ld a, " " +inc b +.clearScreenLoop: +ld [hli], a +dec c +jr nz, .clearScreenLoop +dec b +jr nz, .clearScreenLoop +; now write hello world in the center +ld hl, HelloWorldFrom +ld de, _SCRN0+(8*SCRN_VX_B)+2 +ld c, HelloWorldFrom.size +.helloWorldLoop: +ld a,[hli] +ld [de],a +inc de +dec c +jr nz, .helloWorldLoop +ld hl, Customasm +ld de, _SCRN0+(9*SCRN_VX_B)+2 +ld c, Customasm.size +.helloWorldLoop2: +ld a,[hli] +ld [de],a +inc de +dec c +jr nz, .helloWorldLoop2 +; turn the LCD back on and wait +ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BG9800 | LCDCF_BGON | LCDCF_OBJOFF +ld [rLCDC], a +ei +.spin: +halt +nop +jr .spin + +HelloWorldFrom: +#d "Hello world from" +.size = $ - HelloWorldFrom +Customasm: +#d " customasm!" +.size = $ - Customasm + +Tiles: +#d incbin("ibmpc1.bin") +.size = $ - Tiles \ No newline at end of file diff --git a/examples/ibmpc1.bin b/examples/ibmpc1.bin new file mode 100644 index 0000000000000000000000000000000000000000..708eba39d8da9d0f57b9824a725edaec8ab77792 GIT binary patch literal 2048 zcmYjSziZ@16n8^dQTstLpr=%Hpyt(@=>DQ^&(Jq#{+dA{FtY$QP-q+jH1g64~LfelLn5iLAAepZQx~Y-zo_nCv6yAKW+gv z^ZhLHvCUesvUhd$+xq&t^moEI4vR!US(Z6Fm{rc+_r(W6Mp$0yfr&Py(X^gUrzKd= zR<;L@4TzS3J9Eq&X_9D(E zT*O9IWU-|63V=0fF375pxF!!hSWovQ%`a}=%~R343}7Wm;f1ECxrcN+QCyVXhODMb zk8)_HOO#bs1pt7PK%k5v_559jP5kCD^uqX@dqjXaJ=2fReAE2q=4P6R2EeK)WMyq? z?Fz?u zbIIrLZZ5#XIM4GqbpDK4F#h5?={TADl46#0n5V>9bQhYA|ru6ck)W1s13BTisgmw%&m8ZL>~2VF(liZ=Ig*YB_NDZoTp6wgrKM zWf+?dzxGQ<&3Z-7u$sV{w8X_-HN>r)E*e^Eh&l%=^7G51U(k=^bU5V8Q4R-#8Tn{5 zx`)(N-64M<(yvdvfd1Ek2!4gCgTkaICn?L69{zop(k?wbjDvgdZqp<2$%*@^Y&VwC zKo24qM*Q`{k-Jdg61T`eJy2*^!Kfa9d+_rC8Mwp-c>LiNZ$_@^7R3H?)W-Nx>!04o TK4;(c*l>ERx`|u;Ab0r}!?c-X literal 0 HcmV?d00001 diff --git a/std/cpu/sm83.asm b/std/cpu/sm83.asm new file mode 100644 index 00000000..2cb89860 --- /dev/null +++ b/std/cpu/sm83.asm @@ -0,0 +1,205 @@ +#subruledef sm83_reladdr { + {addr: u16} => { + reladdr = addr - $ - 2 + assert(reladdr <= 0x7f) + assert(reladdr >= !0x7f) + reladdr`8 + } +} + +; instruction decoding on the SM83 chip uses a weird blend of octal masks and +; binary ones; this is incorporated here using concatenation and slicing to +; "construct" the correct encoding from these fields, with notes regarding +; usage below + +; 8-bit registers (plus [hl], which is not a register but instead an indirect +; access to the address stored in the 16-bit register HL described below) are +; B/C/D/E/H/L/[HL]/A, stored as an octal digit/3 bit binary number +#subruledef sm83_r8 { + B => 0`3 + C => 1`3 + D => 2`3 + E => 3`3 + H => 4`3 + L => 5`3 + [HL] => 6`3 + A => 7`3 +} + +; 16-bit registers are BC (glue B and C together), DE (ditto D and E), HL +; (ditto H and L), and SP (the stack pointer). There's also AF (A and processor +; flags), which can be used in push/pop instructions but not general ones +#subruledef sm83_r16 { + BC => 0`2 + DE => 1`2 + HL => 2`2 + SP => 3`2 + AF => assert(0!=0, "invalid operand AF for this instruction") +} + +#subruledef sm83_r16_pushpop { + BC => 0`2 + DE => 1`2 + HL => 2`2 + AF => 3`2 + SP => assert(0!=0, "invalid operand SP for this instruction") +} + +; indirect registers are only used in LD [BC/DE/HLI/HLD], A and the inverse +; but we'll put them out here for good measure +#subruledef sm83_r16_indirect { + [BC] => 0`2 + [DE] => 1`2 + [HLI] => 2`2 + [HL+] => 2`2 ; alternate way to say HLI + [HLD] => 3`2 + [HL-] => 3`2 ; ditto HLD +} + +; conditions are always ordered NZ, Z, NC, C +#subruledef sm83_cond { + NZ => 0`2 + Z => 1`2 + NC => 2`2 + C => 3`2 +} + +; ALU operations are an octal field +#subruledef sm83_aluop { + ADD => 0`3 + ADC => 1`3 + SUB => 2`3 + SBC => 3`3 + AND => 4`3 + XOR => 5`3 + OR => 6`3 + CP => 7`3 +} + +; RST vectors are every 8 bytes before $0040 (which is itself vblank) +#subruledef sm83_rst { + {n: u8} => { + assert((n%8==0)&&(n<0x40),"invalid RST vector!") + n[5:3] + } +} + +; LDH takes an unsigned 8 bit address relative to 0xff00 +; allow providing either the byte or 0xff(the byte) +#subruledef sm83_a8 { + {byte: u8} => byte + {addr: u16} => { + assert(addr>=0xff00, "invalid operand address for LDH") + addr`8 + } +} + +; the first 64 prefixed operations are in the pattern 0b00xxxyyy, where xxx is +; an operation in the list RLC/RRC/RL/RR/SLA/SRA/SWAP/SRL, and yyy is an 8-bit +; register; the xxx comes from here +#subruledef sm83_cbprefixop { + RLC => 0`3 + RRC => 1`3 + RL => 2`3 + RR => 3`3 + SLA => 4`3 + SRA => 5`3 + SWAP => 6`3 + SRL => 7`3 +} + +; the remaining 192 operations are in the form 0bxxyyyzzz, where xx is one of +; BIT/RES/SET (01/10/11 resp.), yyy is an immediate octal digit, and zzz is an +; 8-bit register; the yyy comes from here +#subruledef sm83_u3 { + {n} => { + assert(n<8, "invalid operand (must be in 0-7 range)") + n`3 + } +} + +#subruledef sm83_cbprefix { + {op: sm83_cbprefixop} {r8: sm83_r8} => 0b00 @ op @ r8 + BIT {n: sm83_u3},{r8: sm83_r8} => 0b01 @ n @ r8 + RES {n: sm83_u3},{r8: sm83_r8} => 0b10 @ n @ r8 + SET {n: sm83_u3},{r8: sm83_r8} => 0b11 @ n @ r8 +} + +#ruledef sm83 { + NOP => 0x00 + ; the 16-bit registers in these instructions use the upper 2 bits of the + ; octal digit as the register index, with the lower bit of the octal digit + ; being 0 for one set of instructions and 1 for the other + LD {r16: sm83_r16},{n16: u16} => (r16 @ 0b0 @ 0o1)`8 @ le(n16) + ADD HL,{r16: sm83_r16} => (r16 @ 0b1 @ 0o1)`8 @ le(n16) + LD {r16: sm83_r16_indirect},A => (r16 @ 0b0 @ 0o2)`8 + LD A,{r16: sm83_r16_indirect} => (r16 @ 0b1 @ 0o2)`8 + INC {r16: sm83_r16} => (r16 @ 0b0 @ 0o3)`8 + DEC {r16: sm83_r16} => (r16 @ 0b1 @ 0o3)`8 + ; 8-bit register instructions often line up nicely when looked at octally + ; for example: + INC {r8: sm83_r8} => (r8 @ 0o4)`8 + DEC {r8: sm83_r8} => (r8 @ 0o5)`8 + LD {r8: sm83_r8},{n8: u8} => (r8 @ 0o6)`8 @ n8 + ; now for the rest of the instructions <0x40 + RLCA => 0o07`8 + RRCA => 0o17`8 + RLA => 0o27`8 + RRA => 0o37`8 + LD [{a16: u16}],SP => 0o10`8 @ le(a16) + STOP {n8: u8} => 0o20`8 @ n8 + ; alias to let you STOP without defining the following byte + ; (it's not used, but canonically 0x10 0x00 is the "correct" use of STOP) + STOP => asm { STOP 0 } + JR {e8: sm83_reladdr} => 0o30`8 @ e8 + DAA => 0o47 + CPL => 0o57 + SCF => 0o67 + CCF => 0o77 + ; conditional JR uses the lower 2 bits of the octal digit as the condition + ; code, with the upper bit of the octal digit fixed at 1 + JR {cond: sm83_cond},{e8: sm83_reladdr} => (0b1 @ cond @ 0o0)`8 @ e8 + ; now for load instructions + ; load instructions are 0b01xxxyyy, where xxx is the destination register + ; and yyy is the source register + ; if they are the same, this is functionally a no-op, except in the case + ; where source and destination are [hl], which would read a byte from memory + ; and then write it directly back but instead is the encoding for `halt` + LD {dst: sm83_r8},{src: sm83_r8} => { + assert(!(dst==6 && src==6),"`ld [hl],[hl]` encodes as `halt`") + 0b01 @ dst @ src + } + HALT => 0x76 + ; ALU operations are 0b10xxxyyy, where xxx is the operation and yyy is the + ; source register (all ALU operations are on the A register), or 0b11zzz110 + ; where zzz is the operation and the source is an immediate 8-bit value + {op: sm83_aluop} A,{r8: sm83_r8} => 0b10 @ op @ r8 + {op: sm83_aluop} A,{n8: u8} => 0b10 @ op @ 0o6 @ n8 + ; since all ALU operations are on A, let users omit A + {op: sm83_aluop} {r8: sm83_r8} => 0b10 @ op @ r8 + {op: sm83_aluop} {n8: u8} => 0b10 @ op @ 0o6 @ n8 + ; now for the rest of 0b11xxxxxx + RET {cond: sm83_cond} => 0b11 @ 0b0 @ cond @ 0o0 + POP {r16: sm83_r16_pushpop} => 0b11 @ r16 @ 0b0 @ 0o1 + JP {cond: sm83_cond},{a16: u16} => 0b11 @ 0b0 @ cond @ 0o2 @ le(a16) + JP {a16: u16} => 0xc3 @ le(a16) + CALL {cond: sm83_cond},{a16: u16} => 0b11 @ 0b0 @ cond @ 0o4 @ le(a16) + PUSH {r16: sm83_r16_pushpop} => 0b11 @ r16 @ 0b0 @ 0o5 + RST {vector: sm83_rst} => 0b11 @ vector @ 0o7 + RET => 0xc9 + {instr: sm83_cbprefix} => 0xcb @ instr + CALL {a16: u16} => 0xcd @ le(a16) + RETI => 0xd9 + LDH [{a8: sm83_a8}],A => 0xe0 @ a8 + LDH [C],A => 0xe2 + ADD SP, {e8: s8} => 0xe8 @ e8 + JP HL => 0xe9 + LD [{a16: u16}],A => 0xea @ le(a16) + LDH A,[{a8: sm83_a8}] => 0xf0 @ a8 + LDH A,[C] => 0xf2 + DI => 0xf3 + LD HL,SP+{e8: s8} => 0xf8 @ e8 + LD SP, HL => 0xf9 + LD A,[{a16: u16}] => 0xfa @ le(a16) + EI => 0xfb +} \ No newline at end of file diff --git a/std/platform/gameboy/cart_rom.asm b/std/platform/gameboy/cart_rom.asm new file mode 100644 index 00000000..1b75f10d --- /dev/null +++ b/std/platform/gameboy/cart_rom.asm @@ -0,0 +1,12 @@ +#include "/platform/gameboy/constants.asm" +CART_TYPE = CART_ROM + +#include "/platform/gameboy/common_banks.asm" + +#bankdef rom { + #addr 0x0000 + #size 0x8000 + #outp 0x0000 +} + +#bank rom \ No newline at end of file diff --git a/std/platform/gameboy/common_banks.asm b/std/platform/gameboy/common_banks.asm new file mode 100644 index 00000000..817b6f3b --- /dev/null +++ b/std/platform/gameboy/common_banks.asm @@ -0,0 +1,24 @@ +#bankdef vram { + #addr 0x8000 + #size 0x2000 +} + +#bankdef sram { + #addr 0xa000 + #size 0x2000 +} + +#bankdef wram { + #addr 0xc000 + #size 0x2000 +} + +#bankdef oam { + #addr 0xfe00 + #size 0x00a0 +} + +#bankdef hram { + #addr 0xff80 + #size 0x007f +} \ No newline at end of file diff --git a/std/platform/gameboy/constants.asm b/std/platform/gameboy/constants.asm new file mode 100644 index 00000000..974e71b5 --- /dev/null +++ b/std/platform/gameboy/constants.asm @@ -0,0 +1,1069 @@ +#once +; * +; * Game Boy Hardware definitions +; * https://github.com/gbdev/hardware.inc +; * +; * Based on Jones' hardware.inc +; * And based on Carsten Sorensen's ideas. +; * +; * 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 +; * +; * 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 +; * Rev 4.8.0 - 25-Oct-22 : Changed background addressing constants (zlago) +; * Rev 4.8.1 - 29-Apr-23 : Added rOPRI (rbong) +; * Rev 4.9.0 - 24-Jun-23 : Added definitions for interrupt vectors (sukus) +; * Rev 4.9.1 - 11-Sep-23 : Added repository link and CC0 waiver notice +; * Rev 4.9.2 - 18-Aug-24 : Corrected CART_ROM_MBC5_BAT to CART_ROM_MBC5_RAM (DevEd) +; * +; * Initial conversion to customasm format by MineRobber9000 19-May-25 +; * Check back with upstream every now and again and port changes (not that I expect there to be many changes) +; * I also removed the deprecated constants, since I don't need to maintain backcompatibility with over 25 years of people using +; * hardware.inc in their RGBDS projects. + + +; *************************************************************************** +; * +; * General memory region constants +; * +; *************************************************************************** + +_VRAM = $8000 ; $8000->$9FFF +_SCRN0 = $9800 ; $9800->$9BFF +_SCRN1 = $9C00 ; $9C00->$9FFF +_SRAM = $A000 ; $A000->$BFFF +_RAM = $C000 ; $C000->$CFFF / $C000->$DFFF +_RAMBANK = $D000 ; $D000->$DFFF +_OAMRAM = $FE00 ; $FE00->$FE9F +_IO = $FF00 ; $FF00->$FF7F,$FFFF +_AUD3WAVERAM = $FF30 ; $FF30->$FF3F +_HRAM = $FF80 ; $FF80->$FFFE + + +; *************************************************************************** +; * +; * MBC registers +; * +; *************************************************************************** + +; *** Common *** + +; -- +; -- RAMG ($0000-$1FFF) +; -- Controls whether access to SRAM (and the MBC3 RTC registers) is allowed (W) +; -- +rRAMG = $0000 + +CART_SRAM_ENABLE = $0A +CART_SRAM_DISABLE = $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. +; -- +rROMB0 = $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. +; -- +rRAMB = $4000 + + +; *** MBC3-specific registers *** + +; Write one of these to rRAMG to map the corresponding RTC register to all SRAM space +RTC_S = $08 ; Seconds (0-59) +RTC_M = $09 ; Minutes (0-59) +RTC_H = $0A ; Hours (0-23) +RTC_DL = $0B ; Lower 8 bits of Day Counter ($00-$FF) +RTC_DH = $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) +; -- +rRTCLATCH = $6000 + + +; *** 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. +; -- +rROMB1 = $3000 + + +; Bit 3 of RAMB enables the rumble motor (if any) +CART_RUMBLE_ON = 1 << 3 + + +; *************************************************************************** +; * +; * Memory-mapped registers +; * +; *************************************************************************** + +; -- +; -- P1 ($FF00) +; -- Register for reading joy pad info. (R/W) +; -- +rP1 = $FF00 + +P1F_5 = %00100000 ; P15 out port, set to 0 to get buttons +P1F_4 = %00010000 ; P14 out port, set to 0 to get dpad +P1F_3 = %00001000 ; P13 in port +P1F_2 = %00000100 ; P12 in port +P1F_1 = %00000010 ; P11 in port +P1F_0 = %00000001 ; P10 in port + +P1F_GET_DPAD = P1F_5 +P1F_GET_BTN = P1F_4 +P1F_GET_NONE = P1F_4 | P1F_5 + + +; -- +; -- SB ($FF01) +; -- Serial Transfer Data (R/W) +; -- +rSB = $FF01 + + +; -- +; -- SC ($FF02) +; -- Serial I/O Control (R/W) +; -- +rSC = $FF02 + +SCF_START = %10000000 ; Transfer Start Flag (1=Transfer in progress, or requested) +SCF_SPEED = %00000010 ; Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only ** +SCF_SOURCE = %00000001 ; Shift Clock (0=External Clock, 1=Internal Clock) + +SCB_START = 7 +SCB_SPEED = 1 +SCB_SOURCE = 0 + +; -- +; -- DIV ($FF04) +; -- Divider register (R/W) +; -- +rDIV = $FF04 + + +; -- +; -- TIMA ($FF05) +; -- Timer counter (R/W) +; -- +rTIMA = $FF05 + + +; -- +; -- TMA ($FF06) +; -- Timer modulo (R/W) +; -- +rTMA = $FF06 + + +; -- +; -- TAC ($FF07) +; -- Timer control (R/W) +; -- +rTAC = $FF07 + +TACF_START = %00000100 +TACF_STOP = %00000000 +TACF_4KHZ = %00000000 +TACF_16KHZ = %00000011 +TACF_65KHZ = %00000010 +TACF_262KHZ = %00000001 + +TACB_START = 2 + + +; -- +; -- IF ($FF0F) +; -- Interrupt Flag (R/W) +; -- +rIF = $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) +; -- +rNR10 = $FF10 +rAUD1SWEEP = rNR10 + +AUD1SWEEP_UP = %00000000 +AUD1SWEEP_DOWN = %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) +; -- +rNR11 = $FF11 +rAUD1LEN = 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) +; -- +rNR12 = $FF12 +rAUD1ENV = rNR12 + + +; -- +; -- AUD1LOW/NR13 ($FF13) +; -- Frequency low byte (W) +; -- +rNR13 = $FF13 +rAUD1LOW = 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 +; -- +rNR14 = $FF14 +rAUD1HIGH = rNR14 + + +; -- +; -- AUD2LEN/NR21 ($FF16) +; -- Sound Length; Wave Pattern Duty (R/W) +; -- +; -- see AUD1LEN for info +; -- +rNR21 = $FF16 +rAUD2LEN = rNR21 + + +; -- +; -- AUD2ENV/NR22 ($FF17) +; -- Envelope (R/W) +; -- +; -- see AUD1ENV for info +; -- +rNR22 = $FF17 +rAUD2ENV = rNR22 + + +; -- +; -- AUD2LOW/NR23 ($FF18) +; -- Frequency low byte (W) +; -- +rNR23 = $FF18 +rAUD2LOW = rNR23 + + +; -- +; -- AUD2HIGH/NR24 ($FF19) +; -- Frequency high byte (W) +; -- +; -- see AUD1HIGH for info +; -- +rNR24 = $FF19 +rAUD2HIGH = rNR24 + + +; -- +; -- AUD3ENA/NR30 ($FF1A) +; -- Sound on/off (R/W) +; -- +; -- Bit 7 - Sound ON/OFF (1=ON,0=OFF) +; -- +rNR30 = $FF1A +rAUD3ENA = rNR30 + +AUD3ENA_OFF = %00000000 +AUD3ENA_ON = %10000000 + + +; -- +; -- AUD3LEN/NR31 ($FF1B) +; -- Sound length (R/W) +; -- +; -- Bit 7-0 - Sound length +; -- +rNR31 = $FF1B +rAUD3LEN = 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 +; -- +rNR32 = $FF1C +rAUD3LEVEL = rNR32 + +AUD3LEVEL_MUTE = %00000000 +AUD3LEVEL_100 = %00100000 +AUD3LEVEL_50 = %01000000 +AUD3LEVEL_25 = %01100000 + + +; -- +; -- AUD3LOW/NR33 ($FF1D) +; -- Frequency low byte (W) +; -- +; -- see AUD1LOW for info +; -- +rNR33 = $FF1D +rAUD3LOW = rNR33 + + +; -- +; -- AUD3HIGH/NR34 ($FF1E) +; -- Frequency high byte (W) +; -- +; -- see AUD1HIGH for info +; -- +rNR34 = $FF1E +rAUD3HIGH = rNR34 + + +; -- +; -- AUD4LEN/NR41 ($FF20) +; -- Sound length (R/W) +; -- +; -- Bit 5-0 - Sound length data (# 0-63) +; -- +rNR41 = $FF20 +rAUD4LEN = rNR41 + + +; -- +; -- AUD4ENV/NR42 ($FF21) +; -- Envelope (R/W) +; -- +; -- see AUD1ENV for info +; -- +rNR42 = $FF21 +rAUD4ENV = 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) +; -- +rNR43 = $FF22 +rAUD4POLY = rNR43 + +AUD4POLY_15STEP = %00000000 +AUD4POLY_7STEP = %00001000 + + +; -- +; -- AUD4GO/NR44 ($FF23) +; -- +; -- Bit 7 - Initial (when set, sound restarts) +; -- Bit 6 - Counter/consecutive selection +; -- +rNR44 = $FF23 +rAUD4GO = 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) +; -- +rNR50 = $FF24 +rAUDVOL = rNR50 + +AUDVOL_VIN_LEFT = %10000000 ; SO2 +AUDVOL_VIN_RIGHT = %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) +; -- +rNR51 = $FF25 +rAUDTERM = rNR51 + +; SO2 +AUDTERM_4_LEFT = %10000000 +AUDTERM_3_LEFT = %01000000 +AUDTERM_2_LEFT = %00100000 +AUDTERM_1_LEFT = %00010000 +; SO1 +AUDTERM_4_RIGHT = %00001000 +AUDTERM_3_RIGHT = %00000100 +AUDTERM_2_RIGHT = %00000010 +AUDTERM_1_RIGHT = %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) +; -- +rNR52 = $FF26 +rAUDENA = rNR52 + +AUDENA_ON = %10000000 +AUDENA_OFF = %00000000 ; sets all audio regs to 0! + + +; -- +; -- LCDC ($FF40) +; -- LCD Control (R/W) +; -- +rLCDC = $FF40 + +LCDCF_OFF = %00000000 ; LCD Control Operation +LCDCF_ON = %10000000 ; LCD Control Operation +LCDCF_WIN9800 = %00000000 ; Window Tile Map Display Select +LCDCF_WIN9C00 = %01000000 ; Window Tile Map Display Select +LCDCF_WINOFF = %00000000 ; Window Display +LCDCF_WINON = %00100000 ; Window Display +LCDCF_BLK21 = %00000000 ; BG & Window Tile Data Select +LCDCF_BLK01 = %00010000 ; BG & Window Tile Data Select +LCDCF_BG9800 = %00000000 ; BG Tile Map Display Select +LCDCF_BG9C00 = %00001000 ; BG Tile Map Display Select +LCDCF_OBJ8 = %00000000 ; OBJ Construction +LCDCF_OBJ16 = %00000100 ; OBJ Construction +LCDCF_OBJOFF = %00000000 ; OBJ Display +LCDCF_OBJON = %00000010 ; OBJ Display +LCDCF_BGOFF = %00000000 ; BG Display +LCDCF_BGON = %00000001 ; BG Display + +LCDCB_ON = 7 ; LCD Control Operation +LCDCB_WIN9C00 = 6 ; Window Tile Map Display Select +LCDCB_WINON = 5 ; Window Display +LCDCB_BLKS = 4 ; BG & Window Tile Data Select +LCDCB_BG9C00 = 3 ; BG Tile Map Display Select +LCDCB_OBJ16 = 2 ; OBJ Construction +LCDCB_OBJON = 1 ; OBJ Display +LCDCB_BGON = 0 ; BG Display +; "Window Character Data Select" follows BG + + +; -- +; -- STAT ($FF41) +; -- LCDC Status (R/W) +; -- +rSTAT = $FF41 + +STATF_LYC = %01000000 ; LYC=LY Coincidence (Selectable) +STATF_MODE10 = %00100000 ; Mode 10 +STATF_MODE01 = %00010000 ; Mode 01 (V-Blank) +STATF_MODE00 = %00001000 ; Mode 00 (H-Blank) +STATF_LYCF = %00000100 ; Coincidence Flag +STATF_HBL = %00000000 ; H-Blank +STATF_VBL = %00000001 ; V-Blank +STATF_OAM = %00000010 ; OAM-RAM is used by system +STATF_LCD = %00000011 ; Both OAM and VRAM used by system +STATF_BUSY = %00000010 ; When set, VRAM access is unsafe + +STATB_LYC = 6 +STATB_MODE10 = 5 +STATB_MODE01 = 4 +STATB_MODE00 = 3 +STATB_LYCF = 2 +STATB_BUSY = 1 + +; -- +; -- SCY ($FF42) +; -- Scroll Y (R/W) +; -- +rSCY = $FF42 + + +; -- +; -- SCX ($FF43) +; -- Scroll X (R/W) +; -- +rSCX = $FF43 + + +; -- +; -- LY ($FF44) +; -- LCDC Y-Coordinate (R) +; -- +; -- Values range from 0->153. 144->153 is the VBlank period. +; -- +rLY = $FF44 + + +; -- +; -- LYC ($FF45) +; -- LY Compare (R/W) +; -- +; -- When LY==LYC, STATF_LYCF will be set in STAT +; -- +rLYC = $FF45 + + +; -- +; -- DMA ($FF46) +; -- DMA Transfer and Start Address (W) +; -- +rDMA = $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 +; -- +rBGP = $FF47 + + +; -- +; -- OBP0 ($FF48) +; -- Object Palette 0 Data (W) +; -- +; -- See BGP for info +; -- +rOBP0 = $FF48 + + +; -- +; -- OBP1 ($FF49) +; -- Object Palette 1 Data (W) +; -- +; -- See BGP for info +; -- +rOBP1 = $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. +; -- +rWY = $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. +; -- +rWX = $FF4B + +WX_OFS = 7 ; add this to a screen position to get a WX position + + +; -- +; -- SPEED ($FF4D) +; -- Select CPU Speed (R/W) +; -- +rKEY1 = $FF4D +rSPD = rKEY1 + +KEY1F_DBLSPEED = %10000000 ; 0=Normal Speed, 1=Double Speed (R) +KEY1F_PREPARE = %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) +; -- +rVBK = $FF4F + + +; -- +; -- HDMA1 ($FF51) +; -- High byte for Horizontal Blanking/General Purpose DMA source address (W) +; -- CGB Mode Only +; -- +rHDMA1 = $FF51 + + +; -- +; -- HDMA2 ($FF52) +; -- Low byte for Horizontal Blanking/General Purpose DMA source address (W) +; -- CGB Mode Only +; -- +rHDMA2 = $FF52 + + +; -- +; -- HDMA3 ($FF53) +; -- High byte for Horizontal Blanking/General Purpose DMA destination address (W) +; -- CGB Mode Only +; -- +rHDMA3 = $FF53 + + +; -- +; -- HDMA4 ($FF54) +; -- Low byte for Horizontal Blanking/General Purpose DMA destination address (W) +; -- CGB Mode Only +; -- +rHDMA4 = $FF54 + + +; -- +; -- HDMA5 ($FF55) +; -- Transfer length (in tiles minus 1)/mode/start for Horizontal Blanking, General Purpose DMA (R/W) +; -- CGB Mode Only +; -- +rHDMA5 = $FF55 + +HDMA5F_MODE_GP = %00000000 ; General Purpose DMA (W) +HDMA5F_MODE_HBL = %10000000 ; HBlank DMA (W) +HDMA5B_MODE = 7 ; DMA mode select (W) + +; -- Once DMA has started, use HDMA5F_BUSY to check when the transfer is complete +HDMA5F_BUSY = %10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) + + +; -- +; -- RP ($FF56) +; -- Infrared Communications Port (R/W) +; -- CGB Mode Only +; -- +rRP = $FF56 + +RPF_ENREAD = %11000000 +RPF_DATAIN = %00000010 ; 0=Receiving IR Signal, 1=Normal +RPF_WRITE_HI = %00000001 +RPF_WRITE_LO = %00000000 + +RPB_LED_ON = 0 +RPB_DATAIN = 1 + + +; -- +; -- BCPS/BGPI ($FF68) +; -- Background Color Palette Specification (aka Background Palette Index) (R/W) +; -- +rBCPS = $FF68 +rBGPI = rBCPS + +BCPSF_AUTOINC = %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) +BCPSB_AUTOINC = 7 +BGPIF_AUTOINC = BCPSF_AUTOINC +BGPIB_AUTOINC = BCPSB_AUTOINC + + +; -- +; -- BCPD/BGPD ($FF69) +; -- Background Color Palette Data (aka Background Palette Data) (R/W) +; -- +rBCPD = $FF69 +rBGPD = rBCPD + + +; -- +; -- OCPS/OBPI ($FF6A) +; -- Object Color Palette Specification (aka Object Background Palette Index) (R/W) +; -- +rOCPS = $FF6A +rOBPI = rOCPS + +OCPSF_AUTOINC = %10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) +OCPSB_AUTOINC = 7 +OBPIF_AUTOINC = OCPSF_AUTOINC +OBPIB_AUTOINC = OCPSB_AUTOINC + + +; -- +; -- OCPD/OBPD ($FF6B) +; -- Object Color Palette Data (aka Object Background Palette Data) (R/W) +; -- +rOCPD = $FF6B +rOBPD = rOCPD + + +; -- +; -- OPRI ($FF6C) +; -- Object Priority Mode (R/W) +; -- CGB Only + +; -- +; -- Priority can be changed only from the boot ROM +; -- +rOPRI = $FF6C + +OPRI_OAM = 0 ; Prioritize objects by location in OAM (CGB Mode default) +OPRI_COORD = 1 ; Prioritize objects by x-coordinate (Non-CGB Mode default) + + + +; -- +; -- 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) +; -- +rSVBK = $FF70 +rSMBK = 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 +; -- +rPCM12 = $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 +; -- +rPCM34 = $FF77 + + +; -- +; -- IE ($FFFF) +; -- Interrupt Enable (R/W) +; -- +rIE = $FFFF + +IEF_HILO = %00010000 ; Transition from High to Low of Pin number P10-P13 +IEF_SERIAL = %00001000 ; Serial I/O transfer end +IEF_TIMER = %00000100 ; Timer Overflow +IEF_STAT = %00000010 ; STAT +IEF_VBLANK = %00000001 ; V-Blank + +IEB_HILO = 4 +IEB_SERIAL = 3 +IEB_TIMER = 2 +IEB_STAT = 1 +IEB_VBLANK = 0 + + +; *************************************************************************** +; * +; * Flags common to multiple sound channels +; * +; *************************************************************************** + +; -- +; -- Square wave duty cycle +; -- +; -- Can be used with AUD1LEN and AUD2LEN +; -- See AUD1LEN for more info +; -- +AUDLEN_DUTY_12_5 = %00000000 ; 12.5% +AUDLEN_DUTY_25 = %01000000 ; 25% +AUDLEN_DUTY_50 = %10000000 ; 50% +AUDLEN_DUTY_75 = %11000000 ; 75% + + +; -- +; -- Audio envelope flags +; -- +; -- Can be used with AUD1ENV, AUD2ENV, AUD4ENV +; -- See AUD1ENV for more info +; -- +AUDENV_UP = %00001000 +AUDENV_DOWN = %00000000 + + +; -- +; -- Audio trigger flags +; -- +; -- Can be used with AUD1HIGH, AUD2HIGH, AUD3HIGH +; -- See AUD1HIGH for more info +; -- +AUDHIGH_RESTART = %10000000 +AUDHIGH_LENGTH_ON = %01000000 +AUDHIGH_LENGTH_OFF = %00000000 + + +; *************************************************************************** +; * +; * CPU values on bootup (a=type, b=qualifier) +; * +; *************************************************************************** + +BOOTUP_A_DMG = $01 ; Dot Matrix Game +BOOTUP_A_CGB = $11 ; Color Game Boy +BOOTUP_A_MGB = $FF ; Mini Game Boy (Pocket Game Boy) + +; if a=BOOTUP_A_CGB, bit 0 in b can be checked to determine if real CGB or +; other system running in GBC mode +BOOTUP_B_CGB = %00000000 +BOOTUP_B_AGB = %00000001 ; GBA, GBA SP, Game Boy Player, or New GBA SP + + +; *************************************************************************** +; * +; * Interrupt vector addresses +; * +; *************************************************************************** + +INT_HANDLER_VBLANK = $0040 +INT_HANDLER_STAT = $0048 +INT_HANDLER_TIMER = $0050 +INT_HANDLER_SERIAL = $0058 +INT_HANDLER_JOYPAD = $0060 + + +; *************************************************************************** +; * +; * Header +; * +; *************************************************************************** + +; * +; * Nintendo scrolling logo +; * (Code won't work on a real Game Boy) +; * (if next lines are altered.) +NINTENDO_LOGO = 0xCE_ED_66_66_CC_0D_00_0B_03_73_00_83_00_0C_00_0D_00_08_11_1F_88_89_00_0E_DC_CC_6E_E6_DD_DD_D9_99_BB_BB_67_63_6E_0E_EC_CC_DD_DC_99_9F_BB_B9_33_3E + +; $0143 Color Game Boy compatibility code +CART_COMPATIBLE_DMG = $00 +CART_COMPATIBLE_DMG_GBC = $80 +CART_COMPATIBLE_GBC = $C0 + +; $0146 Game Boy/Super Game Boy indicator +CART_INDICATOR_GB = $00 +CART_INDICATOR_SGB = $03 + +; $0147 Cartridge type +CART_ROM = $00 +CART_ROM_MBC1 = $01 +CART_ROM_MBC1_RAM = $02 +CART_ROM_MBC1_RAM_BAT = $03 +CART_ROM_MBC2 = $05 +CART_ROM_MBC2_BAT = $06 +CART_ROM_RAM = $08 +CART_ROM_RAM_BAT = $09 +CART_ROM_MMM01 = $0B +CART_ROM_MMM01_RAM = $0C +CART_ROM_MMM01_RAM_BAT = $0D +CART_ROM_MBC3_BAT_RTC = $0F +CART_ROM_MBC3_RAM_BAT_RTC = $10 +CART_ROM_MBC3 = $11 +CART_ROM_MBC3_RAM = $12 +CART_ROM_MBC3_RAM_BAT = $13 +CART_ROM_MBC5 = $19 +CART_ROM_MBC5_RAM = $1A +CART_ROM_MBC5_RAM_BAT = $1B +CART_ROM_MBC5_RUMBLE = $1C +CART_ROM_MBC5_RAM_RUMBLE = $1D +CART_ROM_MBC5_RAM_BAT_RUMBLE = $1E +CART_ROM_MBC7_RAM_BAT_GYRO = $22 +CART_ROM_POCKET_CAMERA = $FC +CART_ROM_BANDAI_TAMA5 = $FD +CART_ROM_HUDSON_HUC3 = $FE +CART_ROM_HUDSON_HUC1 = $FF + +; $0148 ROM size +; these are kilobytes +CART_ROM_32KB = $00 ; 2 banks +CART_ROM_64KB = $01 ; 4 banks +CART_ROM_128KB = $02 ; 8 banks +CART_ROM_256KB = $03 ; 16 banks +CART_ROM_512KB = $04 ; 32 banks +CART_ROM_1024KB = $05 ; 64 banks +CART_ROM_2048KB = $06 ; 128 banks +CART_ROM_4096KB = $07 ; 256 banks +CART_ROM_8192KB = $08 ; 512 banks +CART_ROM_1152KB = $52 ; 72 banks +CART_ROM_1280KB = $53 ; 80 banks +CART_ROM_1536KB = $54 ; 96 banks + +; $0149 SRAM size +; these are kilobytes +CART_SRAM_NONE = $00 +CART_SRAM_8KB = $02 ; 1 bank +CART_SRAM_32KB = $03 ; 4 banks +CART_SRAM_128KB = $04 ; 16 banks + +; $014A Destination code +CART_DEST_JAPANESE = $00 +CART_DEST_NON_JAPANESE = $01 + + +; *************************************************************************** +; * +; * Keypad related +; * +; *************************************************************************** + +PADF_DOWN = $80 +PADF_UP = $40 +PADF_LEFT = $20 +PADF_RIGHT = $10 +PADF_START = $08 +PADF_SELECT = $04 +PADF_B = $02 +PADF_A = $01 + +PADB_DOWN = $7 +PADB_UP = $6 +PADB_LEFT = $5 +PADB_RIGHT = $4 +PADB_START = $3 +PADB_SELECT = $2 +PADB_B = $1 +PADB_A = $0 + + +; *************************************************************************** +; * +; * Screen related +; * +; *************************************************************************** + +SCRN_X = 160 ; Width of screen in pixels +SCRN_Y = 144 ; Height of screen in pixels. Also corresponds to the value in LY at the beginning of VBlank. +SCRN_X_B = 20 ; Width of screen in bytes +SCRN_Y_B = 18 ; Height of screen in bytes + +SCRN_VX = 256 ; Virtual width of screen in pixels +SCRN_VY = 256 ; Virtual height of screen in pixels +SCRN_VX_B = 32 ; Virtual width of screen in bytes +SCRN_VY_B = 32 ; Virtual height of screen in bytes + + +; *************************************************************************** +; * +; * OAM related +; * +; *************************************************************************** + +; OAM attributes +; each entry in OAM RAM is 4 bytes (sizeof_OAM_ATTRS) +OAMA_Y = 0 ; y pos plus 16 +OAMA_X = 1 ; x pos plus 8 +OAMA_TILEID = 2 ; tile id +OAMA_FLAGS = 3 ; flags (see below) +sizeof_OAM_ATTRS = 4 + +OAM_Y_OFS = 16 ; add this to a screen-relative Y position to get an OAM Y position +OAM_X_OFS = 8 ; add this to a screen-relative X position to get an OAM X position + +OAM_COUNT = 40 ; number of OAM entries in OAM RAM + +; flags +OAMF_PRI = %10000000 ; Priority +OAMF_YFLIP = %01000000 ; Y flip +OAMF_XFLIP = %00100000 ; X flip +OAMF_PAL0 = %00000000 ; Palette number; 0,1 (DMG) +OAMF_PAL1 = %00010000 ; Palette number; 0,1 (DMG) +OAMF_BANK0 = %00000000 ; Bank number; 0,1 (GBC) +OAMF_BANK1 = %00001000 ; Bank number; 0,1 (GBC) + +OAMF_PALMASK = %00000111 ; Palette (GBC) + +OAMB_PRI = 7 ; Priority +OAMB_YFLIP = 6 ; Y flip +OAMB_XFLIP = 5 ; X flip +OAMB_PAL1 = 4 ; Palette number; 0,1 (DMG) +OAMB_BANK1 = 3 ; Bank number; 0,1 (GBC) \ No newline at end of file diff --git a/std/platform/gameboy/cpu.asm b/std/platform/gameboy/cpu.asm new file mode 100644 index 00000000..5df0d274 --- /dev/null +++ b/std/platform/gameboy/cpu.asm @@ -0,0 +1 @@ +#include "/cpu/sm83.asm" \ No newline at end of file