gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit 4f254b7fb54fb2f81ff0621ab62a3f935b5a4836 parent 6740391bda5cfb4bdf0516c030be495581583897 Author: Toxa <untoxa@mail.ru> Date: Wed, 21 Jul 2021 14:50:34 +0300 more use of definitions in crt0, gb.h, global.s Diffstat:
| M | gbdk-lib/include/gb/gb.h | 18 | +++++++++--------- |
| M | gbdk-lib/libc/gb/crash_handler.s | 6 | +++--- |
| M | gbdk-lib/libc/gb/crt0.s | 827 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
| M | gbdk-lib/libc/gb/global.s | 648 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
4 files changed, 885 insertions(+), 614 deletions(-)
diff --git a/gbdk-lib/include/gb/gb.h b/gbdk-lib/include/gb/gb.h @@ -619,7 +619,7 @@ void hiramcpy(uint8_t dst, @see display_off, DISPLAY_OFF */ #define DISPLAY_ON \ - LCDC_REG|=0x80U + LCDC_REG|=LCDCF_ON /** Turns the display off immediately. @see display_off, DISPLAY_ON @@ -631,49 +631,49 @@ void hiramcpy(uint8_t dst, Sets bit 0 of the LCDC register to 1. */ #define SHOW_BKG \ - LCDC_REG|=0x01U + LCDC_REG|=LCDCF_BGON /** Turns off the background layer. Sets bit 0 of the LCDC register to 0. */ #define HIDE_BKG \ - LCDC_REG&=0xFEU + LCDC_REG&=~LCDCF_BGON /** Turns on the window layer Sets bit 5 of the LCDC register to 1. */ #define SHOW_WIN \ - LCDC_REG|=0x20U + LCDC_REG|=LCDCF_WINON /** Turns off the window layer. Clears bit 5 of the LCDC register to 0. */ #define HIDE_WIN \ - LCDC_REG&=0xDFU + LCDC_REG&=~LCDCF_WINON /** Turns on the sprites layer. Sets bit 1 of the LCDC register to 1. */ #define SHOW_SPRITES \ - LCDC_REG|=0x02U + LCDC_REG|=LCDCF_OBJON /** Turns off the sprites layer. Clears bit 1 of the LCDC register to 0. */ #define HIDE_SPRITES \ - LCDC_REG&=0xFDU + LCDC_REG&=~LCDCF_OBJON /** Sets sprite size to 8x16 pixels, two tiles one above the other. Sets bit 2 of the LCDC register to 1. */ #define SPRITES_8x16 \ - LCDC_REG|=0x04U + LCDC_REG|=LCDCF_OBJ16 /** Sets sprite size to 8x8 pixels, one tile. Clears bit 2 of the LCDC register to 0. */ #define SPRITES_8x8 \ - LCDC_REG&=0xFBU + LCDC_REG&=~LCDCF_OBJ16 diff --git a/gbdk-lib/libc/gb/crash_handler.s b/gbdk-lib/libc/gb/crash_handler.s @@ -45,9 +45,9 @@ ___HandleCrash:: ld (wCrashIE), a ldh a, (.LCDC) ld (wCrashLCDC), a - ld a, #0b10000000 ; LCDCF_ON Make sure the LCD is turned on to avoid waiting infinitely + ld a, #LCDCF_ON ; LCDCF_ON Make sure the LCD is turned on to avoid waiting infinitely ldh (.LCDC), a - ld a, #0b00000001 ; IEF_VBLANK + ld a, #IEF_VBLANK ; IEF_VBLANK ld (.IE), a ld a, #0 ; `xor a` would overwrite flags ld (.IF), a ; No point in backing up that register, it's always changing @@ -250,7 +250,7 @@ ___HandleCrash:: .banksDone: ; Start displaying - ld a, #0b10001001 ; LCDCF_ON | LCDCF_BG9C00 | LCDCF_BGON + ld a, #(LCDCF_ON | LCDCF_BG9C00 | LCDCF_BGON) ldh (.LCDC), a .loop: diff --git a/gbdk-lib/libc/gb/crt0.s b/gbdk-lib/libc/gb/crt0.s @@ -1,508 +1,497 @@ - .include "global.s" + .include "global.s" - ;; **************************************** - ;; Beginning of module - ;; BANKED: checked - .title "Runtime" - .module Runtime - .area _HEADER (ABS) + ;; **************************************** + ;; Beginning of module + ;; BANKED: checked + .title "Runtime" + .module Runtime + .area _HEADER (ABS) - ;; RST vectors -; .org 0x00 ; Trap, utilized by crash_handler.h + ;; RST vectors +; .org 0x00 ; Trap, utilized by crash_handler.h -; .org 0x08 ; --profile handler utilized by bgb_emu.h +; .org 0x08 ; --profile handler utilized by bgb_emu.h -; .org 0x10 ; empty +; .org 0x10 ; empty -; .org 0x18 ; empty +; .org 0x18 ; empty - .org 0x20 ; RST 0x20 == call HL + .org 0x20 ; RST 0x20 == call HL .call_hl:: - JP (HL) + JP (HL) - .org 0x28 ; zero up to 256 bytes in C pointed by HL + .org 0x28 ; zero up to 256 bytes in C pointed by HL .MemsetSmall:: - LD (HL+),A - DEC C - JR NZ,.MemsetSmall - ret + LD (HL+),A + DEC C + JR NZ,.MemsetSmall + ret - .org 0x30 ; copy up to 256 bytes in C from DE to HL + .org 0x30 ; copy up to 256 bytes in C from DE to HL .MemcpySmall:: - LD A, (DE) - LD (HL+), A - INC DE - DEC C - JR NZ,.MemcpySmall - RET + LD A, (DE) + LD (HL+), A + INC DE + DEC C + JR NZ,.MemcpySmall + RET -; .org 0x38 ; crash handler utilized by crash_handler.h +; .org 0x38 ; crash handler utilized by crash_handler.h - ;; Hardware interrupt vectors - .org 0x40 ; VBL + ;; Hardware interrupt vectors + .org 0x40 ; VBL .int_VBL: - PUSH AF - PUSH HL - LD HL,#.int_0x40 - JP .int + PUSH AF + PUSH HL + LD HL,#.int_0x40 + JP .int -; .org 0x48 ; LCD +; .org 0x48 ; LCD -; .org 0x50 ; TIM +; .org 0x50 ; TIM -; .org 0x58 ; SIO +; .org 0x58 ; SIO -; .org 0x60 ; JOY +; .org 0x60 ; JOY -; .org 0x70 - ;; space for drawing.s bit table +; .org 0x70 + ;; space for drawing.s bit table - .org 0x80 + .org 0x80 .int:: - PUSH BC - PUSH DE + PUSH BC + PUSH DE 1$: - LD A,(HL+) - OR (HL) - JR Z,.int_tail - PUSH HL - LD A,(HL-) - LD L,(HL) - LD H,A - RST 0x20 ; .call_hl - POP HL - INC HL - JR 1$ + LD A,(HL+) + OR (HL) + JR Z,.int_tail + PUSH HL + LD A,(HL-) + LD L,(HL) + LD H,A + RST 0x20 ; .call_hl + POP HL + INC HL + JR 1$ _wait_int_handler:: - ADD SP,#4 + ADD SP,#4 .int_tail: - POP DE - POP BC - POP HL + POP DE + POP BC + POP HL - ;; we return at least at the beginning of mode 2 - WAIT_STAT + ;; we return at least at the beginning of mode 2 + WAIT_STAT - POP AF - RETI + POP AF + RETI - ;; VBlank default interrupt routine + ;; VBlank default interrupt routine __standard_VBL_handler:: .std_vbl: - LD HL,#.sys_time - INC (HL) - JR NZ,2$ - INC HL - INC (HL) + LD HL,#.sys_time + INC (HL) + JR NZ,2$ + INC HL + INC (HL) 2$: - CALL .refresh_OAM - - LD A, #1 - LDH (.vbl_done),A - RET + CALL .refresh_OAM + + LD A, #1 + LDH (.vbl_done),A + RET - ;; GameBoy Header + ;; GameBoy Header - ;; DO NOT CHANGE... - .org 0x100 + ;; DO NOT CHANGE... + .org 0x100 .header: - JR .code_start - - ;; Nintendo logo - .org 0x104 - .byte 0xCE,0xED,0x66,0x66 - .byte 0xCC,0x0D,0x00,0x0B - .byte 0x03,0x73,0x00,0x83 - .byte 0x00,0x0C,0x00,0x0D - .byte 0x00,0x08,0x11,0x1F - .byte 0x88,0x89,0x00,0x0E - .byte 0xDC,0xCC,0x6E,0xE6 - .byte 0xDD,0xDD,0xD9,0x99 - .byte 0xBB,0xBB,0x67,0x63 - .byte 0x6E,0x0E,0xEC,0xCC - .byte 0xDD,0xDC,0x99,0x9F - .byte 0xBB,0xB9,0x33,0x3E - - ;; Title of the game - .org 0x134 - .asciz "Title" - - .org 0x144 - .byte 0,0,0 - - ;; Cartridge type is ROM only - .org 0x147 - .byte 0 - - ;; ROM size is 32kB - .org 0x148 - .byte 0 - - ;; RAM size is 0kB - .org 0x149 - .byte 0 - - ;; Maker ID - .org 0x14A - .byte 0x00,0x00 - - ;; Version number - .org 0x14C - .byte 0x01 - - ;; Complement check - .org 0x14D - .byte 0x00 - - ;; Checksum - .org 0x14E - .byte 0x00,0x00 - - ;; **************************************** - .org 0x150 - - ;; soft reset: falldown to .code_start + JR .code_start + + ;; Nintendo logo + .org 0x104 + .byte 0xCE,0xED,0x66,0x66 + .byte 0xCC,0x0D,0x00,0x0B + .byte 0x03,0x73,0x00,0x83 + .byte 0x00,0x0C,0x00,0x0D + .byte 0x00,0x08,0x11,0x1F + .byte 0x88,0x89,0x00,0x0E + .byte 0xDC,0xCC,0x6E,0xE6 + .byte 0xDD,0xDD,0xD9,0x99 + .byte 0xBB,0xBB,0x67,0x63 + .byte 0x6E,0x0E,0xEC,0xCC + .byte 0xDD,0xDC,0x99,0x9F + .byte 0xBB,0xB9,0x33,0x3E + + ;; Title of the game + .org 0x134 + .asciz "Title" + + .org 0x144 + .byte 0,0,0 + + ;; Cartridge type is ROM only + .org 0x147 + .byte 0 + + ;; ROM size is 32kB + .org 0x148 + .byte 0 + + ;; RAM size is 0kB + .org 0x149 + .byte 0 + + ;; Maker ID + .org 0x14A + .byte 0x00,0x00 + + ;; Version number + .org 0x14C + .byte 0x01 + + ;; Complement check + .org 0x14D + .byte 0x00 + + ;; Checksum + .org 0x14E + .byte 0x00,0x00 + + ;; **************************************** + .org 0x150 + + ;; soft reset: falldown to .code_start .reset:: _reset:: - LD A,(__cpu) + LD A,(__cpu) - ;; Initialization code + ;; Initialization code .code_start:: - DI ; Disable interrupts - LD D,A ; Store CPU type in D - ;; Initialize the stack - LD SP,#.STACK - - LD A, #>_shadow_OAM - LDH (__shadow_OAM_base), A - LD H, A - XOR A - LD L, A - LD C, #(40 << 2) ; 40 entries 4 bytes each - RST 0x28 - - ;; Clear CRT0 global variables - LD HL,#.start_crt_globals - LD C,#(.end_crt_globals - .start_crt_globals) - RST 0x28 - -; LD (.mode),A ; Clearing (.mode) is performed when clearing RAM - - ;; Store CPU type - LD A,D - LD (__cpu),A - - ;; Turn the screen off - CALL .display_off - - XOR A - ;; Initialize the display - LDH (.SCY),A - LDH (.SCX),A - LDH (.STAT),A - LDH (.WY),A - LD A,#0x07 - LDH (.WX),A - - ;; Copy refresh_OAM routine to HRAM - LD DE,#.start_refresh_OAM ; source - LD HL,#.refresh_OAM ; dest - LD C,#(.end_refresh_OAM - .start_refresh_OAM) ; size - RST 0x30 ; call .MemcpySmall - - ;; Clear the OAM by calling refresh_OAM - CALL .refresh_OAM - - ;; Install interrupt routines - LD BC,#.std_vbl - CALL .add_VBL - - ;; Standard color palettes - LD A,#0b11100100 ; Grey 3 = 11 (Black) - ; Grey 2 = 10 (Dark grey) - ; Grey 1 = 01 (Light grey) - ; Grey 0 = 00 (Transparent) - LDH (.BGP),A - LDH (.OBP0),A - LD A,#0b00011011 - LDH (.OBP1),A - - ;; Turn the screen on - LD A,#0b11000000 ; LCD = On - ; WindowBank = 0x9C00 - ; Window = Off - ; BG Chr = 0x8800 - ; BG Bank = 0x9800 - ; OBJ = 8x8 - ; OBJ = Off - ; BG = Off - LDH (.LCDC),A - XOR A - LDH (.IF),A - LD A,#0b00000001 ; Pin P10-P13 = Off - ; Serial I/O = Off - ; Timer Ovfl = Off - ; LCDC = Off - ; V-Blank = On - LDH (.IE),A - - LDH (__current_bank),A ; current bank is 1 at startup - - XOR A - - LD HL,#.sys_time - LD (HL+),A - LD (HL),A - - LDH (.NR52),A ; Turn sound off - - CALL gsinit - - EI ; Enable interrupts - - ;; Call the main function - CALL _main -_exit:: + DI ; Disable interrupts + LD D,A ; Store CPU type in D + ;; Initialize the stack + LD SP,#.STACK + + LD A, #>_shadow_OAM + LDH (__shadow_OAM_base), A + LD H, A + XOR A + LD L, A + LD C, #(40 << 2) ; 40 entries 4 bytes each + RST 0x28 + + ;; Clear CRT0 global variables + LD HL,#.start_crt_globals + LD C,#(.end_crt_globals - .start_crt_globals) + RST 0x28 + +; LD (.mode),A ; Clearing (.mode) is performed when clearing RAM + + ;; Store CPU type + LD A,D + LD (__cpu),A + + ;; Turn the screen off + CALL .display_off + + XOR A + ;; Initialize the display + LDH (.SCY),A + LDH (.SCX),A + LDH (.STAT),A + LDH (.WY),A + LD A,#0x07 + LDH (.WX),A + + ;; Copy refresh_OAM routine to HRAM + LD DE,#.start_refresh_OAM ; source + LD HL,#.refresh_OAM ; dest + LD C,#(.end_refresh_OAM - .start_refresh_OAM) ; size + RST 0x30 ; call .MemcpySmall + + ;; Clear the OAM by calling refresh_OAM + CALL .refresh_OAM + + ;; Install interrupt routines + LD BC,#.std_vbl + CALL .add_VBL + + ;; Standard color palettes + LD A,#0b11100100 ; Grey 3 = 11 (Black) + ; Grey 2 = 10 (Dark grey) + ; Grey 1 = 01 (Light grey) + ; Grey 0 = 00 (Transparent) + LDH (.BGP),A + LDH (.OBP0),A + LD A,#0b00011011 + LDH (.OBP1),A + + ;; Turn the screen on + LD A,#(LCDCF_ON | LCDCF_WIN9C00 | LCDCF_WINOFF | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_BGOFF) + LDH (.LCDC),A + XOR A + LDH (.IF),A + LD A,#.VBL_IFLAG ; switch on VBlank interrupt only + LDH (.IE),A + + LDH (__current_bank),A ; current bank is 1 at startup + + XOR A + + LD HL,#.sys_time + LD (HL+),A + LD (HL),A + + LDH (.NR52),A ; Turn sound off + + CALL gsinit + + EI ; Enable interrupts + + ;; Call the main function + CALL _main +_exit:: 99$: - HALT - NOP - JR 99$ ; Wait forever + HALT + NOP + JR 99$ ; Wait forever _set_interrupts:: - DI - LDA HL,2(SP) ; Skip return address - XOR A - LDH (.IF),A ; Clear pending interrupts - LD A,(HL) - EI ; Enable interrupts - LDH (.IE),A ; interrupts are still disabled here - RET - - ;; Copy OAM data to OAM RAM + DI + LDA HL,2(SP) ; Skip return address + XOR A + LDH (.IF),A ; Clear pending interrupts + LD A,(HL) + EI ; Enable interrupts + LDH (.IE),A ; interrupts are still disabled here + RET + + ;; Copy OAM data to OAM RAM .start_refresh_OAM: - LDH A,(__shadow_OAM_base) - OR A - RET Z + LDH A,(__shadow_OAM_base) + OR A + RET Z - LDH (.DMA),A ; Put A into DMA registers - LD A,#0x28 ; We need to wait 160 ns + LDH (.DMA),A ; Put A into DMA registers + LD A,#0x28 ; We need to wait 160 ns 1$: - DEC A - JR NZ,1$ - RET + DEC A + JR NZ,1$ + RET .end_refresh_OAM: - .org .MODE_TABLE - ;; Jump table for modes - RET - - ;; **************************************** - - ;; Ordering of segments for the linker - ;; Code that really needs to be in bank 0 - .area _HOME - ;; Similar to _HOME - .area _BASE - ;; Code - .area _CODE - ;; #pragma bank 0 workaround - .area _CODE_0 - ;; Constant data - .area _LIT -; ;; since _CODE_1 area base address is pre-defined in the linker from 0x4000, -; ;; that moves initializer code and tables out of bank 0 -; .area _CODE_1 - ;; Constant data, used to init _DATA - .area _INITIALIZER - ;; Code, used to init _DATA - .area _GSINIT - .area _GSFINAL - ;; Uninitialised ram data - .area _DATA - .area _BSS - ;; Initialised in ram data - .area _INITIALIZED - ;; For malloc - .area _HEAP - - .area _BSS + .org .MODE_TABLE + ;; Jump table for modes + RET + + ;; **************************************** + + ;; Ordering of segments for the linker + ;; Code that really needs to be in bank 0 + .area _HOME + ;; Similar to _HOME + .area _BASE + ;; Code + .area _CODE + ;; #pragma bank 0 workaround + .area _CODE_0 + ;; Constant data + .area _LIT +; ;; since _CODE_1 area base address is pre-defined in the linker from 0x4000, +; ;; that moves initializer code and tables out of bank 0 +; .area _CODE_1 + ;; Constant data, used to init _DATA + .area _INITIALIZER + ;; Code, used to init _DATA + .area _GSINIT + .area _GSFINAL + ;; Uninitialised ram data + .area _DATA + .area _BSS + ;; Initialised in ram data + .area _INITIALIZED + ;; For malloc + .area _HEAP + + .area _BSS .start_crt_globals: __cpu:: - .ds 0x01 ; GB type (GB, PGB, CGB) + .ds 0x01 ; GB type (GB, PGB, CGB) .mode:: - .ds 0x01 ; Current mode + .ds 0x01 ; Current mode .sys_time:: _sys_time:: - .ds 0x02 ; System time in VBL units + .ds 0x02 ; System time in VBL units .int_0x40:: - .blkw 0x0A ; 4 interrupt handlers (built-in + user-defined) + .blkw 0x0A ; 4 interrupt handlers (built-in + user-defined) .end_crt_globals: - .area _HRAM (ABS) + .area _HRAM (ABS) - .org 0xFF90 -__current_bank:: ; Current bank - .ds 0x01 + .org 0xFF90 +__current_bank:: ; Current bank + .ds 0x01 .vbl_done: - .ds 0x01 ; Is VBL interrupt finished? + .ds 0x01 ; Is VBL interrupt finished? __shadow_OAM_base:: - .ds 0x01 + .ds 0x01 - ;; Runtime library - .area _GSINIT + ;; Runtime library + .area _GSINIT gsinit:: - LD DE, #l__INITIALIZER - LD A, D - OR E - JR Z, 4$ - LD HL, #s__INITIALIZED - LD BC, #s__INITIALIZER - - SRL D - RR E - JR NC,3$ - LD A,(BC) - LD (HL+),A - INC BC + LD DE, #l__INITIALIZER + LD A, D + OR E + JR Z, 4$ + LD HL, #s__INITIALIZED + LD BC, #s__INITIALIZER + + SRL D + RR E + JR NC,3$ + LD A,(BC) + LD (HL+),A + INC BC 3$: - INC D - INC E - JR 2$ + INC D + INC E + JR 2$ 1$: - LD A,(BC) - LD (HL+),A - INC BC - LD A,(BC) - LD (HL+),A - INC BC + LD A,(BC) + LD (HL+),A + INC BC + LD A,(BC) + LD (HL+),A + INC BC 2$: - DEC E - JR NZ,1$ - DEC D - JR NZ,1$ + DEC E + JR NZ,1$ + DEC D + JR NZ,1$ 4$: - .area _GSFINAL - ret + .area _GSFINAL + ret - .area _HOME + .area _HOME - ;; Remove interrupt routine in BC from the VBL interrupt list - ;; falldown to .remove_int + ;; Remove interrupt routine in BC from the VBL interrupt list + ;; falldown to .remove_int .remove_VBL:: - LD HL,#.int_0x40 + LD HL,#.int_0x40 - ;; Remove interrupt BC from interrupt list HL if it exists - ;; Abort if a 0000 is found (end of list) + ;; Remove interrupt BC from interrupt list HL if it exists + ;; Abort if a 0000 is found (end of list) .remove_int:: 1$: - LD A,(HL+) - LD E,A - LD D,(HL) - INC HL - OR D - RET Z ; No interrupt found - - LD A,E - CP C - JR NZ,1$ - LD A,D - CP B - JR NZ,1$ - - LD D,H - LD E,L - DEC DE - DEC DE - - ;; Now do a memcpy from here until the end of the list + LD A,(HL+) + LD E,A + LD D,(HL) + INC HL + OR D + RET Z ; No interrupt found + + LD A,E + CP C + JR NZ,1$ + LD A,D + CP B + JR NZ,1$ + + LD D,H + LD E,L + DEC DE + DEC DE + + ;; Now do a memcpy from here until the end of the list 2$: - LD A,(HL+) - LD (DE),A - LD B,A - INC DE - LD A,(HL+) - LD (DE),A - INC DE - OR B - RET Z - JR 2$ - - ;; Add interrupt routine in BC to the VBL interrupt list - ;; falldown to .add_int + LD A,(HL+) + LD (DE),A + LD B,A + INC DE + LD A,(HL+) + LD (DE),A + INC DE + OR B + RET Z + JR 2$ + + ;; Add interrupt routine in BC to the VBL interrupt list + ;; falldown to .add_int .add_VBL:: - LD HL,#.int_0x40 + LD HL,#.int_0x40 - ;; Add interrupt routine in BC to the interrupt list in HL + ;; Add interrupt routine in BC to the interrupt list in HL .add_int:: 1$: - LD A,(HL+) - OR (HL) - JR Z,2$ - INC HL - JR 1$ + LD A,(HL+) + OR (HL) + JR Z,2$ + INC HL + JR 1$ 2$: - LD A,B - LD (HL-),A - LD (HL),C - RET + LD A,B + LD (HL-),A + LD (HL),C + RET - ;; Wait for VBL interrupt to be finished + ;; Wait for VBL interrupt to be finished .wait_vbl_done:: _wait_vbl_done:: - ;; Check if the screen is on - LDH A,(.LCDC) - ADD A - RET NC ; Return if screen is off - XOR A - LDH (.vbl_done),A ; Clear any previous sets of vbl_done + ;; Check if the screen is on + LDH A,(.LCDC) + AND #LCDCF_ON + RET Z ; Return if screen is off + XOR A + LDH (.vbl_done),A ; Clear any previous sets of vbl_done 1$: - HALT ; Wait for any interrupt - NOP ; HALT sometimes skips the next instruction - LDH A,(.vbl_done) ; Was it a VBlank interrupt? - ;; Warning: we may lose a VBlank interrupt, if it occurs now - OR A - JR Z,1$ ; No: back to sleep! - RET + HALT ; Wait for any interrupt + NOP ; HALT sometimes skips the next instruction + LDH A,(.vbl_done) ; Was it a VBlank interrupt? + ;; Warning: we may lose a VBlank interrupt, if it occurs now + OR A + JR Z,1$ ; No: back to sleep! + RET .display_off:: _display_off:: - ;; Check if the screen is on - LDH A,(.LCDC) - ADD A - RET NC ; Return if screen is off -1$: ; We wait for the *NEXT* VBL - LDH A,(.LY) - CP #0x92 ; Smaller than or equal to 0x91? - JR NC,1$ ; Loop until smaller than or equal to 0x91 + ;; Check if the screen is on + LDH A,(.LCDC) + AND #LCDCF_ON + RET Z ; Return if screen is off +1$: ; We wait for the *NEXT* VBL + LDH A,(.LY) + CP #0x92 ; Smaller than or equal to 0x91? + JR NC,1$ ; Loop until smaller than or equal to 0x91 2$: - LDH A,(.LY) - CP #0x91 ; Bigger than 0x90? - JR C,2$ ; Loop until bigger than 0x90 + LDH A,(.LY) + CP #0x91 ; Bigger than 0x90? + JR C,2$ ; Loop until bigger than 0x90 - LDH A,(.LCDC) - AND #0b01111111 - LDH (.LCDC),A ; Turn off screen - RET + LDH A,(.LCDC) + AND #~LCDCF_ON + LDH (.LCDC),A ; Turn off screen + RET _remove_VBL:: - PUSH BC - LDA HL,4(SP) ; Skip return address and registers - LD A,(HL+) - LD C,A - LD B,(HL) - CALL .remove_VBL - POP BC - RET - + PUSH BC + LDA HL,4(SP) ; Skip return address and registers + LD A,(HL+) + LD C,A + LD B,(HL) + CALL .remove_VBL + POP BC + RET + _add_VBL:: - PUSH BC - LDA HL, 4(SP) ; Skip return address and registers - LD A,(HL+) - LD C,A - LD B,(HL) - CALL .add_VBL - POP BC - RET + PUSH BC + LDA HL, 4(SP) ; Skip return address and registers + LD A,(HL+) + LD C,A + LD B,(HL) + CALL .add_VBL + POP BC + RET diff --git a/gbdk-lib/libc/gb/global.s b/gbdk-lib/libc/gb/global.s @@ -1,204 +1,486 @@ - .NEAR_CALLS = 1 ; <near_calls> - tag so that sed can change this - - ;; Changed by astorgb.pl to 1 - __RGBDS__ = 0 - - - ;; Screen dimensions - .MAXCURSPOSX = 0x13 ; In tiles - .MAXCURSPOSY = 0x11 - - .START = 0x80 - .SELECT = 0x40 - .B = 0x20 - .A = 0x10 - .DOWN = 0x08 - .UP = 0x04 - .LEFT = 0x02 - .RIGHT = 0x01 - - .P14 = 0x10 - .P15 = 0x20 - - .SCREENWIDTH = 0xA0 - .SCREENHEIGHT = 0x90 - .MINWNDPOSX = 0x07 - .MINWNDPOSY = 0x00 - .MAXWNDPOSX = 0xA6 - .MAXWNDPOSY = 0x8F - - .VBL_IFLAG = 0x01 - .LCD_IFLAG = 0x02 - .TIM_IFLAG = 0x04 - .SIO_IFLAG = 0x08 - .JOY_IFLAG = 0x10 + .NEAR_CALLS = 1 ; <near_calls> - tag so that sed can change this + + ;; Changed by astorgb.pl to 1 + __RGBDS__ = 0 + + _VRAM = 0x8000 ; $8000->$9FFF + _VRAM8000 = _VRAM + _VRAM8800 = _VRAM+0x800 + _VRAM9000 = _VRAM+0x1000 + _SCRN0 = 0x9800 ; $9800->$9BFF + _SCRN1 = 0x9C00 ; $9C00->$9FFF + _SRAM = 0xA000 ; $A000->$BFFF + _RAM = 0xC000 ; $C000->$CFFF / $C000->$DFFF + _RAMBANK = 0xD000 ; $D000->$DFFF + _OAMRAM = 0xFE00 ; $FE00->$FE9F + _IO = 0xFF00 ; $FF00->$FF7F,$FFFF + _AUD3WAVERAM = 0xFF30 ; $FF30->$FF3F + _HRAM = 0xFF80 ; $FF80->$FFFE + + ;; MBC Equates + + .MBC1_ROM_PAGE = 0x2000 ; Address to write to for MBC1 switching + + rRAMG = 0x0000 ; $0000->$1fff + rROMB0 = 0x2000 ; $2000->$2fff + rROMB1 = 0x3000 ; $3000->$3fff - If more than 256 ROM banks are present. + rRAMB = 0x4000 ; $4000->$5fff - Bit 3 enables rumble (if present) + + ;; Keypad + .START = 0x80 + .SELECT = 0x40 + .B = 0x20 + .A = 0x10 + .DOWN = 0x08 + .UP = 0x04 + .LEFT = 0x02 + .RIGHT = 0x01 + + .P14 = 0x10 + .P15 = 0x20 + + ;; Screen dimensions + .MAXCURSPOSX = 0x13 ; In tiles + .MAXCURSPOSY = 0x11 + + .SCREENWIDTH = 0xA0 + .SCREENHEIGHT = 0x90 + .MINWNDPOSX = 0x07 + .MINWNDPOSY = 0x00 + .MAXWNDPOSX = 0xA6 + .MAXWNDPOSY = 0x8F + + ;; Hardware registers - .P1 = 0x00 ; Joystick: 1.1.P15.P14.P13.P12.P11.P10 - .SB = 0x01 ; Serial IO data buffer - .SC = 0x02 ; Serial IO control register - .DIV = 0x04 ; Divider register - .TIMA = 0x05 ; Timer counter - .TMA = 0x06 ; Timer modulo - .TAC = 0x07 ; Timer control - .IF = 0x0F ; Interrupt flags: 0.0.0.JST.SIO.TIM.LCD.VBL - .NR10 = 0x10 ; Sound register - .NR11 = 0x11 ; Sound register - .NR12 = 0x12 ; Sound register - .NR13 = 0x13 ; Sound register - .NR14 = 0x14 ; Sound register - .NR21 = 0x16 ; Sound register - .NR22 = 0x17 ; Sound register - .NR23 = 0x18 ; Sound register - .NR24 = 0x19 ; Sound register - .NR30 = 0x1A ; Sound register - .NR31 = 0x1B ; Sound register - .NR32 = 0x1C ; Sound register - .NR33 = 0x1D ; Sound register - .NR34 = 0x1E ; Sound register - .NR41 = 0x20 ; Sound register - .NR42 = 0x21 ; Sound register - .NR43 = 0x22 ; Sound register - .NR44 = 0x23 ; Sound register - .NR50 = 0x24 ; Sound register - .NR51 = 0x25 ; Sound register - .NR52 = 0x26 ; Sound register - .LCDC = 0x40 ; LCD control - .STAT = 0x41 ; LCD status - .SCY = 0x42 ; Scroll Y - .SCX = 0x43 ; Scroll X - .LY = 0x44 ; LCDC Y-coordinate - .LYC = 0x45 ; LY compare - .DMA = 0x46 ; DMA transfer - .BGP = 0x47 ; BG palette data - .OBP0 = 0x48 ; OBJ palette 0 data - .OBP1 = 0x49 ; OBJ palette 1 data - .WY = 0x4A ; Window Y coordinate - .WX = 0x4B ; Window X coordinate - .KEY1 = 0x4D ; CPU speed - .VBK = 0x4F ; VRAM bank - .HDMA1 = 0x51 ; DMA control 1 - .HDMA2 = 0x52 ; DMA control 2 - .HDMA3 = 0x53 ; DMA control 3 - .HDMA4 = 0x54 ; DMA control 4 - .HDMA5 = 0x55 ; DMA control 5 - .RP = 0x56 ; IR port - .BCPS = 0x68 ; BG color palette specification - .BCPD = 0x69 ; BG color palette data - .OCPS = 0x6A ; OBJ color palette specification - .OCPD = 0x6B ; OBJ color palette data - .SVBK = 0x70 ; WRAM bank - .IE = 0xFF ; Interrupt enable - - .G_MODE = 0x01 ; Graphic mode - .T_MODE = 0x02 ; Text mode (bit 2) - .T_MODE_OUT = 0x02 ; Text mode output only - .T_MODE_INOUT = 0x03 ; Text mode with input - .M_NO_SCROLL = 0x04 ; Disables scrolling of the screen in text mode - .M_NO_INTERP = 0x08 ; Disables special character interpretation - - .MBC1_ROM_PAGE = 0x2000 ; Address to write to for MBC1 switching - - ;; Status codes for IO - .IO_IDLE = 0x00 - .IO_SENDING = 0x01 - .IO_RECEIVING = 0x02 - .IO_ERROR = 0x04 - - ;; Type of IO data - .DT_IDLE = 0x66 - .DT_RECEIVING = 0x55 - - ;; Table of routines for modes - .MODE_TABLE = 0x01E0 - - ;; C related - ;; Overheap of a banked call. Used for parameters - ;; = ret + real ret + bank - - .if .NEAR_CALLS - .BANKOV = 2 - - .else - .BANKOV = 6 - - .endif - - .globl __current_bank - .globl __shadow_OAM_base - - ;; Global variables - .globl .mode - - .globl __cpu - - ;; Global routines -; .globl .set_mode ;; don't link mode.o by default - - .globl .reset - - .globl .display_off - - .globl .wait_vbl_done - - ;; Interrupt routines - .globl .add_VBL -; .globl .add_LCD ;; don't link LCD.o by default -; .globl .add_TIM ;; don't link TIM.o by default -; .globl .add_SIO ;; don't link serial.o by default -; .globl .add_JOY ;; don't link JOY.o by default - - ;; Symbols defined at link time - .globl .STACK - .globl _shadow_OAM - .globl .refresh_OAM - - ;; Main user routine - .globl _main - - ;; Macro definitions + .P1 = 0x00 ; Joystick: 1.1.P15.P14.P13.P12.P11.P10 + rP1 = 0xFF00 + + P1F_5 = 0b00100000 ; P15 out port, set to 0 to get buttons + P1F_4 = 0b00010000 ; P14 out port, set to 0 to get dpad + P1F_3 = 0b00001000 ; P13 in port + P1F_2 = 0b00000100 ; P12 in port + P1F_1 = 0b00000010 ; P11 in port + P1F_0 = 0b00000001 ; P10 in port + + P1F_GET_DPAD = P1F_5 + P1F_GET_BTN = P1F_4 + P1F_GET_NONE = P1F_4 | P1F_5 + + .SB = 0x01 ; Serial IO data buffer + rSB = 0xFF01 + + .SC = 0x02 ; Serial IO control register + rSC = 0xFF02 + + .DIV = 0x04 ; Divider register + rDIV = 0xFF04 + + .TIMA = 0x05 ; Timer counter + rTIMA = 0xFF05 + + .TMA = 0x06 ; Timer modulo + rTMA = 0xFF06 + + .TAC = 0x07 ; Timer control + rTAC = 0xFF07 + + TACF_START = 0b00000100 + TACF_STOP = 0b00000000 + TACF_4KHZ = 0b00000000 + TACF_16KHZ = 0b00000011 + TACF_65KHZ = 0b00000010 + TACF_262KHZ = 0b00000001 + + .IF = 0x0F ; Interrupt flags: 0.0.0.JST.SIO.TIM.LCD.VBL + rIF = 0xFF0F + + .NR10 = 0x10 ; Sound register + rNR10 = 0xFF10 + rAUD1SWEEP = rNR10 + + AUD1SWEEP_UP = 0b00000000 + AUD1SWEEP_DOWN = 0b00001000 + + .NR11 = 0x11 ; Sound register + rNR11 = 0xFF11 + rAUD1LEN = rNR11 + + .NR12 = 0x12 ; Sound register + rNR12 = 0xFF12 + rAUD1ENV = rNR12 + + .NR13 = 0x13 ; Sound register + rNR13 = 0xFF13 + rAUD1LOW = rNR13 + + .NR14 = 0x14 ; Sound register + rNR14 = 0xFF14 + rAUD1HIGH = rNR14 + + .NR21 = 0x16 ; Sound register + rNR21 = 0xFF16 + rAUD2LEN = rNR21 + + .NR22 = 0x17 ; Sound register + rNR22 = 0xFF17 + rAUD2ENV = rNR22 + + .NR23 = 0x18 ; Sound register + rNR23 = 0xFF18 + rAUD2LOW = rNR23 + + .NR24 = 0x19 ; Sound register + rNR24 = 0xFF19 + rAUD2HIGH = rNR24 + + .NR30 = 0x1A ; Sound register + rNR30 = 0xFF1A + rAUD3ENA = rNR30 + + .NR31 = 0x1B ; Sound register + rNR31 = 0xFF1B + rAUD3LEN = rNR31 + + .NR32 = 0x1C ; Sound register + rNR32 = 0xFF1C + rAUD3LEVEL = rNR32 + + .NR33 = 0x1D ; Sound register + rNR33 = 0xFF1D + rAUD3LOW = rNR33 + + .NR34 = 0x1E ; Sound register + rNR34 = 0xFF1E + rAUD3HIGH = rNR34 + + .NR41 = 0x20 ; Sound register + rNR41 = 0xFF20 + rAUD4LEN = rNR41 + + .NR42 = 0x21 ; Sound register + rNR42 = 0xFF21 + rAUD4ENV = rNR42 + + .NR43 = 0x22 ; Sound register + rNR43 = 0xFF22 + rAUD4POLY = rNR43 + + .NR44 = 0x23 ; Sound register + rNR44 = 0xFF23 + rAUD4GO = rNR44 + + .NR50 = 0x24 ; Sound register + rNR50 = 0xFF24 + rAUDVOL = rNR50 + + AUDVOL_VIN_LEFT = 0b10000000 ; SO2 + AUDVOL_VIN_RIGHT = 0b00001000 ; SO1 + + .NR51 = 0x25 ; Sound register + rNR51 = 0xFF25 + rAUDTERM = rNR51 + + AUDTERM_4_LEFT = 0b10000000 + AUDTERM_3_LEFT = 0b01000000 + AUDTERM_2_LEFT = 0b00100000 + AUDTERM_1_LEFT = 0b00010000 + AUDTERM_4_RIGHT = 0b00001000 + AUDTERM_3_RIGHT = 0b00000100 + AUDTERM_2_RIGHT = 0b00000010 + AUDTERM_1_RIGHT = 0b00000001 + + .NR52 = 0x26 ; Sound register + rNR52 = 0xFF26 + rAUDENA = rNR52 + + AUDENA_ON = 0b10000000 + AUDENA_OFF = 0b00000000 ; sets all audio regs to 0! + + .LCDC = 0x40 ; LCD control + rLCDC = 0xFF40 + + LCDCF_OFF = 0b00000000 ; LCD Control Operation + LCDCF_ON = 0b10000000 ; LCD Control Operation + LCDCF_WIN9800 = 0b00000000 ; Window Tile Map Display Select + LCDCF_WIN9C00 = 0b01000000 ; Window Tile Map Display Select + LCDCF_WINOFF = 0b00000000 ; Window Display + LCDCF_WINON = 0b00100000 ; Window Display + LCDCF_BG8800 = 0b00000000 ; BG & Window Tile Data Select + LCDCF_BG8000 = 0b00010000 ; BG & Window Tile Data Select + LCDCF_BG9800 = 0b00000000 ; BG Tile Map Display Select + LCDCF_BG9C00 = 0b00001000 ; BG Tile Map Display Select + LCDCF_OBJ8 = 0b00000000 ; OBJ Construction + LCDCF_OBJ16 = 0b00000100 ; OBJ Construction + LCDCF_OBJOFF = 0b00000000 ; OBJ Display + LCDCF_OBJON = 0b00000010 ; OBJ Display + LCDCF_BGOFF = 0b00000000 ; BG Display + LCDCF_BGON = 0b00000001 ; BG Display + + .STAT = 0x41 ; LCD status + rSTAT = 0xFF41 + + STATF_LYC = 0b01000000 ; LYC=LY Coincidence (Selectable) + STATF_MODE10 = 0b00100000 ; Mode 10 + STATF_MODE01 = 0b00010000 ; Mode 01 (V-Blank) + STATF_MODE00 = 0b00001000 ; Mode 00 (H-Blank) + STATF_LYCF = 0b00000100 ; Coincidence Flag + STATF_HBL = 0b00000000 ; H-Blank + STATF_VBL = 0b00000001 ; V-Blank + STATF_OAM = 0b00000010 ; OAM-RAM is used by system + STATF_LCD = 0b00000011 ; Both OAM and VRAM used by system + STATF_BUSY = 0b00000010 ; When set, VRAM access is unsafe + + .SCY = 0x42 ; Scroll Y + rSCY = 0xFF42 + + .SCX = 0x43 ; Scroll X + rSCX = 0xFF43 + + .LY = 0x44 ; LCDC Y-coordinate + rLY = 0xFF44 + + .LYC = 0x45 ; LY compare + rLYC = 0xFF45 + + .DMA = 0x46 ; DMA transfer + rDMA = 0xFF46 + + .BGP = 0x47 ; BG palette data + rBGP = 0xFF47 + + .OBP0 = 0x48 ; OBJ palette 0 data + rOBP0 = 0xFF48 + + .OBP1 = 0x49 ; OBJ palette 1 data + rOBP1 = 0xFF49 + + .WY = 0x4A ; Window Y coordinate + rWY = 0xFF4A + + .WX = 0x4B ; Window X coordinate + rWX = 0xFF4B + + .KEY1 = 0x4D ; CPU speed + rKEY1 = 0xFF4D + rSPD = rKEY1 + + KEY1F_DBLSPEED = 0b10000000 ; 0=Normal Speed, 1=Double Speed (R) + KEY1F_PREPARE = 0b00000001 ; 0=No, 1=Prepare (R/W) + + .VBK = 0x4F ; VRAM bank + rVBK = 0xFF4F + + .HDMA1 = 0x51 ; DMA control 1 + rHDMA1 = 0xFF51 + + .HDMA2 = 0x52 ; DMA control 2 + rHDMA2 = 0xFF52 + + .HDMA3 = 0x53 ; DMA control 3 + rHDMA3 = 0xFF53 + + .HDMA4 = 0x54 ; DMA control 4 + rHDMA4 = 0xFF54 + + .HDMA5 = 0x55 ; DMA control 5 + rHDMA5 = 0xFF55 + + HDMA5F_MODE_GP = 0b00000000 ; General Purpose DMA (W) + HDMA5F_MODE_HBL = 0b10000000 ; HBlank DMA (W) + + HDMA5F_BUSY = 0b10000000 ; 0=Busy (DMA still in progress), 1=Transfer complete (R) + + .RP = 0x56 ; IR port + rRP = 0xFF56 + + RPF_ENREAD = 0b11000000 + RPF_DATAIN = 0b00000010 ; 0=Receiving IR Signal, 1=Normal + RPF_WRITE_HI = 0b00000001 + RPF_WRITE_LO = 0b00000000 + + .BCPS = 0x68 ; BG color palette specification + rBCPS = 0xFF68 + + BCPSF_AUTOINC = 0b10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) + + .BCPD = 0x69 ; BG color palette data + rBCPD = 0xFF69 + + .OCPS = 0x6A ; OBJ color palette specification + rOCPS = 0xFF6A + + OCPSF_AUTOINC = 0b10000000 ; Auto Increment (0=Disabled, 1=Increment after Writing) + + .OCPD = 0x6B ; OBJ color palette data + rOCPD = 0xFF6B + + .SVBK = 0x70 ; WRAM bank + rSVBK = 0xFF70 + rSMBK = rSVBK + + rPCM12 = 0xFF76 + + rPCM34 = 0xFF77 + + .IE = 0xFF ; Interrupt enable + rIE = 0xFFFF + + .VBL_IFLAG = 0x01 + .LCD_IFLAG = 0x02 + .TIM_IFLAG = 0x04 + .SIO_IFLAG = 0x08 + .JOY_IFLAG = 0x10 + + IEF_HILO = 0b00010000 ; Transition from High to Low of Pin number P10-P13 + IEF_SERIAL = 0b00001000 ; Serial I/O transfer end + IEF_TIMER = 0b00000100 ; Timer Overflow + IEF_STAT = 0b00000010 ; STAT + IEF_VBLANK = 0b00000001 ; V-Blank + + ;; Flags common to multiple sound channels + + AUDLEN_DUTY_12_5 = 0b00000000 ; 12.5% + AUDLEN_DUTY_25 = 0b01000000 ; 25% + AUDLEN_DUTY_50 = 0b10000000 ; 50% + AUDLEN_DUTY_75 = 0b11000000 ; 75% + + AUDENV_UP = 0b00001000 + AUDENV_DOWN = 0b00000000 + + AUDHIGH_RESTART = 0b10000000 + AUDHIGH_LENGTH_ON = 0b01000000 + AUDHIGH_LENGTH_OFF = 0b00000000 + + ;; OAM related constants + + OAM_COUNT = 40 ; number of OAM entries in OAM RAM + + OAMF_PRI = 0b10000000 ; Priority + OAMF_YFLIP = 0b01000000 ; Y flip + OAMF_XFLIP = 0b00100000 ; X flip + OAMF_PAL0 = 0b00000000 ; Palette number; 0,1 (DMG) + OAMF_PAL1 = 0b00010000 ; Palette number; 0,1 (DMG) + OAMF_BANK0 = 0b00000000 ; Bank number; 0,1 (GBC) + OAMF_BANK1 = 0b00001000 ; Bank number; 0,1 (GBC) + + OAMF_PALMASK = 0b00000111 ; 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) + + ;; GBDK library screen modes + + .G_MODE = 0x01 ; Graphic mode + .T_MODE = 0x02 ; Text mode (bit 2) + .T_MODE_OUT = 0x02 ; Text mode output only + .T_MODE_INOUT = 0x03 ; Text mode with input + .M_NO_SCROLL = 0x04 ; Disables scrolling of the screen in text mode + .M_NO_INTERP = 0x08 ; Disables special character interpretation + + ;; Status codes for IO + .IO_IDLE = 0x00 + .IO_SENDING = 0x01 + .IO_RECEIVING = 0x02 + .IO_ERROR = 0x04 + + ;; Type of IO data + .DT_IDLE = 0x66 + .DT_RECEIVING = 0x55 + + ;; Table of routines for modes + .MODE_TABLE = 0x01E0 + + ;; C related + ;; Overheap of a banked call. Used for parameters + ;; = ret + real ret + bank + + .if .NEAR_CALLS + .BANKOV = 2 + + .else + .BANKOV = 6 + + .endif + + .globl __current_bank + .globl __shadow_OAM_base + + ;; Global variables + .globl .mode + + .globl __cpu + + ;; Global routines +; .globl .set_mode ;; don't link mode.o by default + + .globl .reset + + .globl .display_off + + .globl .wait_vbl_done + + ;; Interrupt routines + .globl .add_VBL +; .globl .add_LCD ;; don't link LCD.o by default +; .globl .add_TIM ;; don't link TIM.o by default +; .globl .add_SIO ;; don't link serial.o by default +; .globl .add_JOY ;; don't link JOY.o by default + + ;; Symbols defined at link time + .globl .STACK + .globl _shadow_OAM + .globl .refresh_OAM + + ;; Main user routine + .globl _main + + ;; Macro definitions .macro WAIT_STAT ?lbl -lbl: LDH A, (.STAT) - AND #0x02 ; Check if in LCD modes 0 or 1 - JR NZ, lbl +lbl: LDH A, (.STAT) + AND #STATF_BUSY ; Check if in LCD modes 0 or 1 + JR NZ, lbl .endm .macro ADD_A_REG16 regH regL - ADD regL - LD regL, A - ADC regH - SUB regL - LD regH, A + ADD regL + LD regL, A + ADC regH + SUB regL + LD regH, A .endm .macro SIGNED_ADD_A_REG16 regH regL ?lbl - ; If A is negative, we need to subtract 1 from upper byte of 16-bit value - BIT 7, A ; set z if a signed bit is 0 - JR Z, lbl ; if z is set jump to positive - dec regH ; if negative decrement upper byte + ; If A is negative, we need to subtract 1 from upper byte of 16-bit value + BIT 7, A ; set z if a signed bit is 0 + JR Z, lbl ; if z is set jump to positive + dec regH ; if negative decrement upper byte lbl: - ADD_A_REG16 regH, regL + ADD_A_REG16 regH, regL .endm .macro SIGNED_SUB_A_REG16 regH regL ?lbl - ; negate A then add to 16-bit value - CPL - INC A - SIGNED_ADD_A_REG16 regH, regL + ; negate A then add to 16-bit value + CPL + INC A + SIGNED_ADD_A_REG16 regH, regL .endm .macro MUL_DE_BY_A_RET_HL ?lbl1 ?lbl2 ?lbl3 - ; Multiply DE by A, return result in HL; preserves: BC - LD HL, #0 + ; Multiply DE by A, return result in HL; preserves: BC + LD HL, #0 lbl1: - SRL A - JR NC, lbl2 - ADD HL, DE + SRL A + JR NC, lbl2 + ADD HL, DE lbl2: - JR Z, lbl3 - SLA E - RL D - JR lbl1 + JR Z, lbl3 + SLA E + RL D + JR lbl1 lbl3: .endm
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.