        .GG_STATE       = 0x00

        .GGSTATE_STT    = 0b10000000
        .GGSTATE_NJAP   = 0b01000000
        .GGSTATE_NNTS   = 0b00100000

        .GG_EXT_7BIT    = 0x01

        .GG_EXT_CTL     = 0x02

        .GGEXT_NINIT    = 0b10000000

        .GG_SIO_SEND    = 0x03
        .GG_SIO_RECV    = 0x04
        .GG_SIO_CTL     = 0x05

        .SIOCTL_TXFL    = 0b00000001
        .SIOCTL_RXRD    = 0b00000010
        .SIOCTL_FRER    = 0b00000100
        .SIOCTL_INT     = 0b00001000
        .SIOCTL_TON     = 0b00010000
        .SIOCTL_RON     = 0b00100000
        .SIOCTL_BS0     = 0b01000000
        .SIOCTL_BS1     = 0b10000000

        .GG_SOUND_PAN   = 0x06

        .SOUNDPAN_TN1R  = 0b00000001
        .SOUNDPAN_TN2R  = 0b00000010
        .SOUNDPAN_TN3R  = 0b00000100
        .SOUNDPAN_NOSR  = 0b00001000
        .SOUNDPAN_TN1L  = 0b00010000
        .SOUNDPAN_TN2L  = 0b00100000
        .SOUNDPAN_TN3L  = 0b01000000
        .SOUNDPAN_NOSL  = 0b10000000

        .MEMORY_CTL     = 0x3E

        .MEMCTL_JOYON   = 0b00000000
        .MEMCTL_JOYOFF  = 0b00000100
        .MEMCTL_BASEON  = 0b00000000
        .MEMCTL_BASEOFF = 0b00001000
        .MEMCTL_RAMON   = 0b00000000
        .MEMCTL_RAMOFF  = 0b00010000
        .MEMCTL_CROMON  = 0b00000000
        .MEMCTL_CROMOFF = 0b00100000
        .MEMCTL_ROMON   = 0b00000000
        .MEMCTL_ROMOFF  = 0b01000000
        .MEMCTL_EXTON   = 0b00000000
        .MEMCTL_EXTOFF  = 0b10000000

        .JOY_CTL        = 0x3F

        .JOY_P1_TR_DIR_IN  = 0b00000001
        .JOY_P1_TR_DIR_OUT = 0b00000000
        .JOY_P1_TH_DIR_IN  = 0b00000010
        .GUN_P1_LATCH      = 0b00000010
        .JOY_P1_TH_DIR_OUT = 0b00000000
        .JOY_P2_TR_DIR_IN  = 0b00000100
        .JOY_P2_TR_DIR_OUT = 0b00000000
        .JOY_P2_TH_DIR_IN  = 0b00001000
        .GUN_P2_LATCH      = 0b00001000
        .JOY_P2_TH_DIR_OUT = 0b00000000
        .JOY_P1_TR_OUT_HI  = 0b00010000
        .JOY_P1_TR_OUT_LO  = 0b00000000
        .JOY_P1_TH_OUT_HI  = 0b00100000
        .JOY_P1_TH_OUT_LO  = 0b00000000
        .JOY_P2_TR_OUT_HI  = 0b01000000
        .JOY_P2_TR_OUT_LO  = 0b00000000
        .JOY_P2_TH_OUT_HI  = 0b10000000
        .JOY_P2_TH_OUT_LO  = 0b00000000

        .JOY_TH_HI      = 0b11110101
        .JOY_TH_LO      = 0b01010101

        .VDP_VRAM       = 0x4000
        .VDP_CRAM       = 0xC000

        .VDP_SAT_TERM   = 0xD0

        .VDP_VCOUNTER   = 0x7E
        .VDP_PSG        = 0x7F
        .VDP_HCOUNTER   = 0x7F

        .VDP_DATA       = 0xBE
        .VDP_CMD        = 0xBF
        .VDP_STAT       = 0xBF

        .STATF_INT_VBL  = 0b10000000
        .STATF_9_SPR    = 0b01000000
        .STATF_SPR_COLL = 0b00100000

        .VDP_REG_MASK   = 0b10000000
        .VDP_R0         = 0b10000000

        .R0_VSCRL       = 0b00000000
        .R0_VSCRL_INH   = 0b10000000
        .R0_HSCRL       = 0b00000000
        .R0_HSCRL_INH   = 0b01000000
        .R0_NO_LCB      = 0b00000000
        .R0_LCB         = 0b00100000
        .R0_IE1_OFF     = 0b00000000
        .R0_IE1         = 0b00010000
        .R0_SS_OFF      = 0b00000000
        .R0_SS          = 0b00001000
        .R0_DEFAULT     = 0b00000110
        .R0_ES_OFF      = 0b00000000
        .R0_ES          = 0b00000001

        .VDP_R1         = 0b10000001

        .R1_DEFAULT     = 0b10000000
        .R1_DISP_OFF    = 0b00000000
        .R1_DISP_ON     = 0b01000000
        .R1_IE_OFF      = 0b00000000
        .R1_IE          = 0b00100000
        .R1_SPR_8X8     = 0b00000000
        .R1_SPR_8X16    = 0b00000010

        .VDP_R2         = 0b10000010

        .R2_MAP_0x3800  = 0xFF
        .R2_MAP_0x3000  = 0xFD
        .R2_MAP_0x2800  = 0xFB
        .R2_MAP_0x2000  = 0xF9
        .R2_MAP_0x1800  = 0xF7
        .R2_MAP_0x1000  = 0xF5
        .R2_MAP_0x0800  = 0xF3
        .R2_MAP_0x0000  = 0xF1

        .VDP_R3         = 0b10000011
        .VDP_R4         = 0b10000100
        .VDP_R5         = 0b10000101

        .R5_SAT_0x3F00  = 0xFF
        .R5_SAT_0x1F00  = 0xBF
        .R5_SAT_MASK    = 0b10000001

        .VDP_R6         = 0b10000110

        .R6_BANK0       = 0xFB
        .R6_DATA_0x0000 = 0xFB
        .R6_BANK1       = 0xFF
        .R6_DATA_0x2000 = 0xFF

        .VDP_R7         = 0b10000111
        .VDP_RBORDER    = 0b10000111

        .R7_COLOR_MASK  = 0b11110000

        .VDP_R8         = 0b10001000
        .VDP_RSCX       = 0b10001000

        .VDP_R9         = 0b10001001
        .VDP_RSCY       = 0b10001001

        .VDP_R10        = 0b10001010

        .R10_INT_OFF    = 0xFF
        .R10_INT_EVERY  = 0x00

        .JOYPAD_COUNT   = 1

        .UP              = 0b00000001
        .DOWN            = 0b00000010
        .LEFT            = 0b00000100
        .RIGHT           = 0b00001000
        .A               = 0b00010000
        .B               = 0b00100000
        .START           = 0b01000000
        .SELECT          = 0b10000000

        .JOY_PORT1      = 0xDC

        .JOY_P1_UP       = 0b00000001
        .JOY_P1_MD_Z     = 0b00000001
        .JOY_P1_DOWN     = 0b00000010
        .JOY_P1_MD_Y     = 0b00000010
        .JOY_P1_LEFT     = 0b00000100
        .JOY_P1_MD_X     = 0b00000100
        .JOY_P1_RIGHT    = 0b00001000
        .JOY_P1_MD_MODE  = 0b00001000
        .JOY_P1_SW1      = 0b00010000
        .JOY_P1_TRIGGER  = 0b00010000
        .JOY_P1_MD_A     = 0b00010000
        .JOY_P1_SW2      = 0b00100000
        .JOY_P1_MD_START = 0b00100000
        .JOY_P2_UP       = 0b01000000
        .JOY_P2_MD_Z     = 0b01000000
        .JOY_P2_DOWN     = 0b10000000
        .JOY_P2_MD_Y     = 0b10000000

        .JOY_PORT2      = 0xDD

        .JOY_P2_LEFT     = 0b00000001
        .JOY_P2_MD_X     = 0b00000001
        .JOY_P2_RIGHT    = 0b00000010
        .JOY_P2_MD_MODE  = 0b00000010
        .JOY_P2_SW1      = 0b00000100
        .JOY_P2_TRIGGER  = 0b00000100
        .JOY_P2_MD_A     = 0b00000100
        .JOY_P2_SW2      = 0b00001000
        .JOY_P2_MD_START = 0b00001000
        .JOY_RESET       = 0b00010000
        .JOY_P1_LIGHT    = 0b01000000
        .JOY_P2_LIGHT    = 0b10000000

        .FMADDRESS      = 0xF0
        .FMDATA         = 0xF1
        .AUDIOCTRL      = 0xF2

        .RAM_CONTROL    = 0xfffc

        .RAMCTL_BANK    = 0b00000100
        .RAMCTL_ROM     = 0b00000000
        .RAMCTL_RAM     = 0b00001000
        .RAMCTL_RO      = 0b00010000
        .RAMCTL_PROT    = 0b10000000

        .GLASSES_3D     = 0xfff8

        .MAP_FRAME0     = 0xfffd
        .MAP_FRAME1     = 0xfffe
        .MAP_FRAME2     = 0xffff

        .BIOS           = 0xC000

        .SYSTEM_NTSC    = 0x00
        .SYSTEM_PAL     = 0x01

        .CPU_CLOCK      = 3579545

        ;; GBDK library screen modes

        .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

        ;; Screen dimentions in tiles

        .SCREEN_X_OFS   = 6
        .SCREEN_Y_OFS   = 3
        .SCREEN_WIDTH   = 20
        .SCREEN_HEIGHT  = 18
        .VDP_MAP_HEIGHT = 28
        .VDP_MAP_WIDTH  = 32

        ;; Interrupt flags

        .VBL_IFLAG      = 0x01
        .LCD_IFLAG      = 0x02

        ; characters
        .CR             = 0x0A
        .SPACE          = 0x00

        ;; C related
        ;; Overheap of a banked call.  Used for parameters
        ;;  = ret + real ret + bank

        .BANKOV         = 5

        ;; Global variables
        .globl  .mode

        ;; Interrupt routines
        .globl _INT_ISR
        .globl _NMI_ISR

        ;; Symbols defined at link time
        .globl  .STACK
        .globl  _shadow_OAM
        .globl  __shadow_OAM_OFF

        ;; Main user routine
        .globl  _main

        ;; Macro definitions

.macro VDP_WRITE_DATA regH regL
        ld a, regL
        out (#.VDP_DATA), a
        ld a, regH
        inc hl
        dec hl
        out (#.VDP_DATA), a
.endm

.macro VDP_WRITE_CMD regH regL
        ld a, regL
        di
        out (#.VDP_CMD), a
        ld a, regH
        ei
        out (#.VDP_CMD), a
.endm

.macro VDP_DELAY ?lbl
        nop
        jr lbl
lbl:
.endm

.macro VDP_CANCEL_INT
        in a, (.VDP_STAT)       ; cancel pending VDP interrupts
.endm

.macro WRITE_VDP_CMD_HL
        rst 0x10
.endm

.macro WRITE_VDP_DATA_HL
        rst 0x20
.endm

.macro CALL_HL
        rst 0x30
.endm

.macro DISABLE_VBLANK_COPY
        ld hl, #__shadow_OAM_OFF
        inc (hl)
.endm

.macro ENABLE_VBLANK_COPY
        ld hl, #__shadow_OAM_OFF
        dec (hl)
.endm

.macro ADD_A_REG16 regH regL
        add regL
        ld regL, a
        adc regH
        sub regL
        ld regH, a
.endm

.macro MUL_DE_BY_A_RET_HL ?lbl1 ?lbl2
        ; Multiply DE by A, return result in HL; preserves: BC
        ld hl, #0
lbl1:
        srl a
        jp nc, lbl2
        add hl, de
lbl2:
        sla e
        rl d
        or a
        jp nz, lbl1
.endm

.macro DIV_PART divident divisor ?lbl
        rl divident
        rla
        sub divisor
        jr  nc, lbl
        add divisor
lbl:
.endm
.macro FAST_MOD8 divident divisor
        ; returns modulus in A
        .rept 8
                DIV_PART divident divisor
        .endm
.endm
