; Like the NES and Super NES, DMA on the Game Boy takes access to RAM ; and ROM away from the CPU. But unlike those two, the CPU continues ; to run. So store a tiny subroutine in HRAM (tightly coupled ; memory) to keep the CPU busy until OAM DMA is done. SECTION "hram_tools", HRAM RunDMA: ds 11 SECTION "Tools", ROM0 InitTools: ; Copy the sprite DMA routine ld de, dma_routine_start ld hl, RunDMA ld bc, dma_routine_end - dma_routine_start call Memcpy ret ; Memory copier ; @param de - Address source to start of data to be copied ; @param hl - Address destomatopm where to copy the data to ; @param bc - The total amount of bytes to copy ; @return a = Zero ; @return bc = Zero ; @return de = Address Source to the byte after the last byte from source (garbage) ; @return hl = Address Target to the byte after the last byte on the target (garbage) Memcpy: ld a, [de] ; Load the value at [de] to accumilator ld [hli], a ; Load the value from accumilator to the destination address and increment it by one inc de ; Increment de to point to next byte to copy dec bc ; Decrement bc the total amount of bytes to copy ld a, b ; Load the first half of total amount of bytes to write to accumilator or c ; OR together the second half of total amount with the first half jr nz, Memcpy ; Loop back to Memcpy if not zero ret Memfill: ; Fill an area in memory at position hl with value a for b amount of times ; ; @param hl - Starting address in memory to fill ; @param a - The value to fill said address space with ; @param b - How many bytes we should fill starting from said address space ; @return a - garbage ; @return b - PosX on where to draw text ; @return c - PosY on where to draw text ; @return hl - Workram position for text pointer ; @return de - Memory address to source string .repeatFill ld [hli], a dec b jr nz, .repeatFill ret Memfill16: ; Fill an area in memory at position hl with value a for bc amount of times ; ; @param hl - Starting address in memory to fill ; @param a - The value to fill said address space with ; @param b - How many bytes we should fill starting from said address space ; @return a - garbage ; @return b - PosX on where to draw text ; @return c - PosY on where to draw text ; @return hl - Workram position for text pointer ; @return de - Memory address to source string .repeatFill ld [hli], a dec bc jr nz, .repeatFill ret ;; ; Waits for the vblank ISR to increment the count of vertical blanks. ; Will lock up if DI, vblank IRQ off, or LCD off. ; Clobbers A, HL WaitVBlank: .wait halt ret ;; ; The routine gets copied to high RAM dma_routine_start: ld a,shadow_oam >> 8 ld [rDMA],a ld a,40 .loop: dec a jr nz,.loop ret dma_routine_end: