From 2ade6c993c036e1f65fe29e47589cf87eb227833 Mon Sep 17 00:00:00 2001 From: Daniel Borges Date: Thu, 3 Jan 2019 23:15:27 +0100 Subject: [PATCH] split into several files --- Code/automata.asm | 320 ++++++++++++++++++++++++++ Code/data.asm | 50 ++++ Code/main.asm | 563 +--------------------------------------------- Code/render.asm | 155 +++++++++++++ Code/utils.asm | 47 ++++ 5 files changed, 578 insertions(+), 557 deletions(-) create mode 100644 Code/automata.asm create mode 100644 Code/data.asm create mode 100644 Code/render.asm create mode 100644 Code/utils.asm diff --git a/Code/automata.asm b/Code/automata.asm new file mode 100644 index 0000000..9c011a3 --- /dev/null +++ b/Code/automata.asm @@ -0,0 +1,320 @@ +INCLUDE "hardware.inc" + +; automata buffers with 4 cells per byte +; 2x2 bytes per cell, bit ordering: +; ___ ___ +; |0 1| |0 1| +; |2 3| eg. |1 0| is %0110 = 6 +; ‾‾‾ ‾‾‾ +; bits 4, 5, 6 and 7 are not used +EXPORT Buffer0 +SECTION "Automata buffer 0", WRAM0, ALIGN[9] +Buffer0: ds 20 * 18 + +EXPORT Buffer1 +SECTION "Automata buffer 1", WRAM0, ALIGN[9] +Buffer1: ds 20 * 18 + +SECTION "Automata data", HRAM +New: ds 1 ; high byte of pointer to bufferX +Old: ds 1 ; high byte of pointer to bufferX +Progress: ds 1; low byte of pointer to bufferX, common to new and old +XLoop: ds 1 +YLoop: ds 1 + +AddConstantToHL: MACRO +IF \1 == 1 + inc hl +ELIF \1 == -1 + dec hl +ELIF \1 > 0 && \1 <= 255 + ld a, l + add a, \1 + ld l, a + jr nc, .nocarry1\@ + inc h +.nocarry1\@ +ELIF \1 > -255 && \1 < 0 + ld a, l + sub a, -(\1) + ld l, a + jr nc, .nocarry2\@ + ld l, a + dec h +.nocarry2\@ +ELIF \1 > 255 + ld a, l + add a, LOW(\1) + ld l, a + ld a, h + adc a, HIGH(\1) + ld h, a +ELIF \1 <= -255 + ld a, l + sub a, LOW(-(\1)) + ld l, a + ld a, h + sbc a, HIGH(-(\1)) + ld h, a +ELSE +ENDC +ENDM + +AddLiveNeighbors: MACRO + ; \1 offset + ; \2 is mask for 2x2 cell + ; D must be high byte of a BitsSet table (for 0..15) + ; C register will be incremented with number of alive neighbors + ; moves HL with given offset + ; destroys A, E + ; does not touch B + + ; load current 2x2 cell and mask out bits that are not neighbors + AddConstantToHL \1 + ld a, [hl] + and a, \2 + + ; count bits set + ld e, a + ld a, [de] + + ; add to alive + add a, c + ld c, a +ENDM + +Conway: MACRO + ; \1 = bit of target cell in 2x2 group + ; (\2, \3), (\4, \5), (\6, \7) = (offset to neighbor, neighbor mask) + ; + ; B will be updated with cell result + ; destroys all other registers + + ; reset alive counter + ld c, 0 + + ; Check all neighbors + AddLiveNeighbors 0, (~(1 << \1)) & $F + AddLiveNeighbors \2, \3 + AddLiveNeighbors \4 - \2, \5 + AddLiveNeighbors \6 - \4, \7 + AddConstantToHL -(\6) + + ; if there are 3 neighbors, it's always alive + ld a, c + cp a, 3 + jr z, .alive\@ + + ; if there are only 2 neighbors, it's alive only if it was dead + cp a, 2 + jr nz, .dead\@ + + ; load current old cell and test if alive + ld a, [hl] + bit \1, a + jr z, .dead\@ + +.alive\@ + set \1, b + +.dead\@ +ENDM + + ; \1..\8 offset to neighbors + ; destroys all registers +ConwayGroup: MACRO + + ld d, HIGH(BitsSet) + + ; load old pointer into hl + ldh a, [Old] + ld h, a + ldh a, [Progress] + ld l, a + + ; reset result + xor a + ld b, a + + ; compute all 4 cells in current 2x2 cell group + Conway 0, \5, 10, \6, 8, \7, 12 + Conway 1, \1, 5, \7, 12, \8, 4 + Conway 2, \5, 10, \4, 2, \3, 3 + Conway 3, \1, 5, \3, 3, \2, 1 + + ; load new pointer + ldh a, [New] + ld h, a + + ; save result to new buffer + ld [hl], b +ENDM + +EXPORT UpdateAutomata +SECTION "Update Automata", ROM0 +UpdateAutomata: +.topleft + ; handle top left corner + ConwayGroup 1, 21, 20, 39, 19, 359, 340, 341 + + ; advance to next cell in top row + ld hl, Progress + inc [hl] + + ; handle all cells in top row except corners + ld a, 18 +.top + ld [XLoop], a + + ; handle top row cell + ConwayGroup 1, 21, 20, 19, -1, 339, 340, 341 + + ; advance to next cell in top row + ld hl, Progress + inc [hl] + + ; loop horizontally + ld a, [XLoop] + dec a + jp nz, .top + + ; handle top right corner +.topright + ConwayGroup -19, 1, 20, 19, -1, 339, 340, 321 + + ; advance pointers to next row + ld hl, Progress + inc [hl] + + ld a, 16 +.leftcolumn + ld [YLoop], a + + ; handle first element in row + ConwayGroup 1, 21, 20, 39, 19, -1, -20, -19 + + ; advance to next cell + ld hl, Progress + inc [hl] + + ld a, 18 +.inner + ld [XLoop], a + + ; handle element inside row + ConwayGroup 1, 21, 20, 19, -1, -21, -20, -19 + + ; advance to next cell + ld hl, Progress + inc [hl] + jr nz, .noCarry + ld hl, Old + inc [hl] + ld hl, New + inc [hl] +.noCarry + + ; loop horizontally + ld a, [XLoop] + dec a + jp nz, .inner + + ; handle last element in row +.rightcolumn + ConwayGroup -19, 1, 20, 19, -1, -21, -20, -39 + + ; advance to next row + ld hl, Progress + inc [hl] + + ; loop vertically + ld a, [YLoop] + dec a + jp nz, .leftcolumn + + ; handle bottom left element +.bottomleft + ConwayGroup 1, -339, -340, -321, 19, -1, -20, -19 + + ; advance to next cell in bottom row + ld hl, Progress + inc [hl] + + ; handle all cells in bottom row except corners + ld a, 18 +.bottom + ld [XLoop], a + + ; handle top row cell + ConwayGroup 1, -339, -340, -341, -1, -21, -20, -19 + + ; advance to next cell in top row + ld hl, Progress + inc [hl] + + ; loop horizontally + ld a, [XLoop] + dec a + jp nz, .bottom + + ; handle last element +.bottomright + ConwayGroup -19, -359, -340, -341, -1, -21, -20, -39 + + ret + +EXPORT SwapBuffers, InitAutomata +SECTION "Swap Buffers", ROM0 +SwapBuffers: + ; check which buffer has just been rendered + ldh a, [Old] + cp a, HIGH(Buffer1) + jr nc, .newToBuffer1 + +.newToBuffer0 + ; set old and rendered pointers to buffer1 + ld a, HIGH(Buffer1) + ldh [Old], a + ldh [Rendered + 1], a + + ; set new pointer to buffer0 + ld a, HIGH(Buffer0) + ldh [New], a + + ; set video pointer to first tilemap + ld a, HIGH(_SCRN1) + ldh [Video + 1], a + + ; display bg 9800 that has just been filled + ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BG9800 + ld [rLCDC], a + + jr InitAutomata.resetLow + +.newToBuffer1 +InitAutomata: + ; set old and rendered pointers to buffer0 + ld a, HIGH(Buffer0) + ldh [Old], a + ldh [Rendered + 1], a + + ; set new pointer to buffer1 + ld a, HIGH(Buffer1) + ldh [New], a + + ; set video pointer to second tilemap + ld a, HIGH(_SCRN0) + ldh [Video + 1], a + + ; display bg 9C00 that has just been filled + ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BG9C00 + ld [rLCDC], a + +.resetLow + ; reset low bytes of pointers + xor a + ldh [Progress], a + ldh [Rendered], a + ldh [Video], a + + ret \ No newline at end of file diff --git a/Code/data.asm b/Code/data.asm new file mode 100644 index 0000000..56d3917 --- /dev/null +++ b/Code/data.asm @@ -0,0 +1,50 @@ +INCLUDE "hardware.inc" + +EXPORT BitsSet +SECTION "Bits Set", ROM0, ALIGN[8] +BitsSet: + db 0; 0 = 0000 + db 1; 1 = 0001 + db 1; 2 = 0010 + db 2; 3 = 0011 + db 1; 4 = 0100 + db 2; 5 = 0101 + db 2; 6 = 0110 + db 3; 7 = 0111 + db 1; 8 = 1000 + db 2; 9 = 1001 + db 2; 10 = 1010 + db 3; 11 = 1011 + db 2; 12 = 1100 + db 3; 13 = 1101 + db 3; 14 = 1110 + db 4; 15 = 1111 + +EXPORT DefaultMap +SECTION "Default Map", ROM0 +DefaultMap: + ; 20x18 map with a glider on the top left corner + db 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 3, 1, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 9,12, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 3, 1, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 5, 0,10,10, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 1,12, 6, 2,12, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0,12, 4, 0,12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 5, 0,10,10, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 1, 0, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 3, 1, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + +EXPORT Tiles, TilesEnd +SECTION "Graphics", ROM0 +Tiles: +INCBIN "Tiles.bin" +TilesEnd: ds 0 \ No newline at end of file diff --git a/Code/main.asm b/Code/main.asm index aa0e7b7..189efac 100644 --- a/Code/main.asm +++ b/Code/main.asm @@ -1,183 +1,8 @@ INCLUDE "hardware.inc" -RENDER_IN_HBL EQU 0 - EMPTY_BG_TILE EQU 17 - _VRAM_BG_TILES EQU $9000 -SECTION "Memory Copy", ROM0 -; hl = destination -; de = source -; bc = count -MemoryCopy: - ld a, [de] - ld [hl+], a - inc de - dec bc - ld a, b - or c - jr nz, MemoryCopy - ret - -SECTION "Memory Set", ROM0 -; hl = destination -; d = data -; bc = count -MemorySet: - ld a, d - ld [hl+], a - dec bc - ld a, b - or c - jr nz, MemorySet - ret - - ; \1: sprite ID - ; \2: X position - ; \3: Y position - ; \4: tile number - ; \5: flags -SetSprite: MACRO - ld hl, _OAMRAM + \1 * 4 - ld a, \3 - ld [hl+], a - ld a, \2 - ld [hl+], a - ld a, \4 - ld [hl+], a - ld a, \5 - ld [hl+], a -ENDM - -AddConstantToHL: MACRO -IF \1 == 1 - inc hl -ELIF \1 == -1 - dec hl -ELIF \1 > 0 && \1 <= 255 - ld a, l - add a, \1 - ld l, a - jr nc, .nocarry1\@ - inc h -.nocarry1\@ -ELIF \1 > -255 && \1 < 0 - ld a, l - sub a, -(\1) - ld l, a - jr nc, .nocarry2\@ - ld l, a - dec h -.nocarry2\@ -ELIF \1 > 255 - ld a, l - add a, LOW(\1) - ld l, a - ld a, h - adc a, HIGH(\1) - ld h, a -ELIF \1 <= -255 - ld a, l - sub a, LOW(-(\1)) - ld l, a - ld a, h - sbc a, HIGH(-(\1)) - ld h, a -ELSE -ENDC -ENDM - -AddLiveNeighbors: MACRO - ; \1 offset - ; \2 is mask for 2x2 cell - ; D must be high byte of a BitsSet table (for 0..15) - ; C register will be incremented with number of alive neighbors - ; moves HL with given offset - ; destroys A, E - ; does not touch B - - ; load current 2x2 cell and mask out bits that are not neighbors - AddConstantToHL \1 - ld a, [hl] - and a, \2 - - ; count bits set - ld e, a - ld a, [de] - - ; add to alive - add a, c - ld c, a -ENDM - -Conway: MACRO - ; \1 = bit of target cell in 2x2 group - ; (\2, \3), (\4, \5), (\6, \7) = (offset to neighbor, neighbor mask) - ; - ; B will be updated with cell result - ; destroys all other registers - - ; reset alive counter - ld c, 0 - - ; Check all neighbors - AddLiveNeighbors 0, (~(1 << \1)) & $F - AddLiveNeighbors \2, \3 - AddLiveNeighbors \4 - \2, \5 - AddLiveNeighbors \6 - \4, \7 - AddConstantToHL -(\6) - - ; if there are 3 neighbors, it's always alive - ld a, c - cp a, 3 - jr z, .alive\@ - - ; if there are only 2 neighbors, it's alive only if it was dead - cp a, 2 - jr nz, .dead\@ - - ; load current old cell and test if alive - ld a, [hl] - bit \1, a - jr z, .dead\@ - -.alive\@ - set \1, b - -.dead\@ -ENDM - - ; \1..\8 offset to neighbors - ; destroys all registers -ConwayGroup: MACRO - - ld d, HIGH(BitsSet) - - ; load old pointer into hl - ldh a, [Old] - ld h, a - ldh a, [Progress] - ld l, a - - ; reset result - xor a - ld b, a - - ; compute all 4 cells in current 2x2 cell group - Conway 0, \5, 10, \6, 8, \7, 12 - Conway 1, \1, 5, \7, 12, \8, 4 - Conway 2, \5, 10, \4, 2, \3, 3 - Conway 3, \1, 5, \3, 3, \2, 1 - - ; load new pointer - ldh a, [New] - ld h, a - - ; save result to new buffer - ld [hl], b -ENDM - SECTION "Header", ROM0[$100] EntryPoint: di @@ -192,19 +17,6 @@ Start: xor a ld [rNR52], a - ; set old and rendered pointers to buffer0 - ld a, HIGH(Buffer0) - ldh [Old], a - ldh [Rendered + 1], a - - ; set new pointer to buffer1 - ld a, HIGH(Buffer1) - ldh [New], a - - ; set video pointer to first tilemap - ld a, HIGH(_SCRN0) - ldh [Video + 1], a - ; enable v-blank interrupt ld a, IEF_VBLANK ld [rIE], a @@ -255,6 +67,8 @@ Start: ld bc, 20 * 18 call MemoryCopy + call InitAutomata + ; enable h-blank interrupt in lcd stat ld a, STATF_MODE00 ld [rSTAT], a @@ -264,373 +78,8 @@ Start: ld [rLCDC], a .mainloop - ; reset low bytes of pointers - xor a - ldh [Progress], a - ldh [Rendered], a - ldh [Video], a - - ; start rendering - ld a, 20 - ldh [TilesLeft], a - ld a, 18 - ldh [LinesLeft], a - - ; enable v-blank and lcd stat interrupt for h-blank - ; rendering routine is too slow for lcdc right now so disabled -IF RENDER_IN_HBL != 0 - ld a, IEF_VBLANK | IEF_LCDC -ELSE - ld a, IEF_VBLANK -ENDC - ld [rIE], a - xor a - ei - ldh [rIF], a - -.topleft - ; handle top left corner - ConwayGroup 1, 21, 20, 39, 19, 359, 340, 341 - - ; advance to next cell in top row - ld hl, Progress - inc [hl] - - ; handle all cells in top row except corners - ld a, 18 -.top - ld [XLoop], a - - ; handle top row cell - ConwayGroup 1, 21, 20, 19, -1, 339, 340, 341 - - ; advance to next cell in top row - ld hl, Progress - inc [hl] - - ; loop horizontally - ld a, [XLoop] - dec a - jp nz, .top - - ; handle top right corner -.topright - ConwayGroup -19, 1, 20, 19, -1, 339, 340, 321 - - ; advance pointers to next row - ld hl, Progress - inc [hl] - - ld a, 16 -.leftcolumn - ld [YLoop], a - - ; handle first element in row - ConwayGroup 1, 21, 20, 39, 19, -1, -20, -19 - - ; advance to next cell - ld hl, Progress - inc [hl] - - ld a, 18 -.inner - ld [XLoop], a - - ; handle element inside row - ConwayGroup 1, 21, 20, 19, -1, -21, -20, -19 - - ; advance to next cell - ld hl, Progress - inc [hl] - jr nz, .noCarry - ld hl, Old - inc [hl] - ld hl, New - inc [hl] -.noCarry - - ; loop horizontally - ld a, [XLoop] - dec a - jp nz, .inner - - ; handle last element in row -.rightcolumn - ConwayGroup -19, 1, 20, 19, -1, -21, -20, -39 - - ; advance to next row - ld hl, Progress - inc [hl] - - ; loop vertically - ld a, [YLoop] - dec a - jp nz, .leftcolumn - - ; handle bottom left element -.bottomleft - ConwayGroup 1, -339, -340, -321, 19, -1, -20, -19 - - ; advance to next cell in bottom row - ld hl, Progress - inc [hl] - - ; handle all cells in bottom row except corners - ld a, 18 -.bottom - ld [XLoop], a - - ; handle top row cell - ConwayGroup 1, -339, -340, -341, -1, -21, -20, -19 - - ; advance to next cell in top row - ld hl, Progress - inc [hl] - - ; loop horizontally - ld a, [XLoop] - dec a - jp nz, .bottom - - ; handle last element -.bottomright - ConwayGroup -19, -359, -340, -341, -1, -21, -20, -39 - - ; wait end of rendering -.waitRender - ldh a, [LinesLeft] - ld b, a - ldh a, [TilesLeft] - or a, b - jr z, .swap - halt - jr .waitRender - -.swap - -IF RENDER_IN_HBL != 0 - ; enable only v-blank interrupt and wait for vbl - ld a, IEF_VBLANK - ld [rIE], a - xor a - ldh [rIF], a - halt -ENDC - - ; check which buffer has just been rendered - ldh a, [Old] - cp a, HIGH(Buffer1) - jr nc, .newToBuffer1 - -.newToBuffer0 - ; set old and rendered pointers to buffer1 - ld a, HIGH(Buffer1) - ldh [Old], a - ldh [Rendered + 1], a - - ; set new pointer to buffer0 - ld a, HIGH(Buffer0) - ldh [New], a - - ; set video pointer to first tilemap - ld a, HIGH(_SCRN1) - ldh [Video + 1], a - - ; display bg 9800 that has just been filled - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BG9800 - ld [rLCDC], a - - jr .resetLowBytes - -.newToBuffer1 - ; set old and rendered pointers to buffer0 - ld a, HIGH(Buffer0) - ldh [Old], a - ldh [Rendered + 1], a - - ; set new pointer to buffer1 - ld a, HIGH(Buffer1) - ldh [New], a - - ; set video pointer to second tilemap - ld a, HIGH(_SCRN0) - ldh [Video + 1], a - - ; display bg 9C00 that has just been filled - ld a, LCDCF_ON | LCDCF_BGON | LCDCF_BG9C00 - ld [rLCDC], a - -.resetLowBytes - + call StartRender + call UpdateAutomata + call WaitRender + call SwapBuffers jp .mainloop - -SECTION "V-Blank Interrupt Handler", ROM0[$40] -VBlankInterruptHandler: - jr LCDStatInterruptHandler - -SECTION "LCD Stat Interrupt Handler", ROM0[$48] -LCDStatInterruptHandler: - ; save registers - push af - push bc - - ; check there are tiles to render - ldh a, [LinesLeft] - or a - jr z, .exit - - ; move lines left to B - ld b, a - - push de - push hl - -.render - ; load buffer pointer into DE - ld hl, Video - ld a, [hl+] - ld d, [hl] - ld e, a - - ; load video pointer into HL - ld hl, Rendered - ld a, [hl+] - ld h, [hl] - ld l, a - - ; load counters - ldh a, [TilesLeft] - ld c, a - -.loop - ; check we can still render - ldh a, [rSTAT] - and a, STATF_BUSY - jr nz, .finish - - ; copy one byte - ld a, [hl+] - ld [de], a - inc e ; it will never overflow since it only increments - ; up to 20 bytes starting on 32 byte boundaries - - ; loop while there are tiles to render - dec c - jr nz, .loop - - ; go to next line - ld a, e - add a, 32 - 20 - ld e, a - jr nc, .nocarry - inc d -.nocarry - - ; loop while there are lines to render - dec b - jr z, .finish - - ; reset tile counter - ld c, 20 - - jr .loop - -.finish - ; save counters - ld a, c - ldh [TilesLeft], a - ld a, b - ldh [LinesLeft], a - - ; save incremented video pointer and buffer pointer - ld a, e - ldh [Video], a - ld a, d - ldh [Video + 1], a - - ld a, l - ldh [Rendered], a - ld a, h - ldh [Rendered + 1], a - - ; restore registers saved in interrupt handler - pop hl - pop de - -.exit - pop bc - pop af - - ; return from v-blank or lcd interrupt - reti - -; automata buffers with 4 cells per byte -; 2x2 bytes per cell, bit ordering: -; ___ ___ -; |0 1| |0 1| -; |2 3| eg. |1 0| is %0110 = 6 -; ‾‾‾ ‾‾‾ -; bits 4, 5, 6 and 7 are not used -SECTION "Automata buffer 0", WRAM0, ALIGN[9] -Buffer0: ds 20 * 18 -SECTION "Automata buffer 1", WRAM0, ALIGN[9] -Buffer1: ds 20 * 18 - -SECTION "Compute Memory", HRAM -New: ds 1 ; high byte of pointer to bufferX -Old: ds 1 ; high byte of pointer to bufferX -Progress: ds 1; low byte of pointer to bufferX, common to new and old -XLoop: ds 1 -YLoop: ds 1 - -SECTION "Render Memory", HRAM -LinesLeft: ds 1 ; number of lines left to render -TilesLeft: ds 1 ; number of tiles left to render in current line -Video: ds 2 ; progressing pointer in tilemap (VRAM) -Rendered: ds 2 ; progressing pointer in old buffer - -SECTION "Bits Set", ROM0, ALIGN[8] -BitsSet: - db 0; 0 = 0000 - db 1; 1 = 0001 - db 1; 2 = 0010 - db 2; 3 = 0011 - db 1; 4 = 0100 - db 2; 5 = 0101 - db 2; 6 = 0110 - db 3; 7 = 0111 - db 1; 8 = 1000 - db 2; 9 = 1001 - db 2; 10 = 1010 - db 3; 11 = 1011 - db 2; 12 = 1100 - db 3; 13 = 1101 - db 3; 14 = 1110 - db 4; 15 = 1111 - -SECTION "Default Map", ROM0 -DefaultMap: - ; 20x18 map with a glider on the top left corner - db 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 3, 1, 0, 0, 0, 0, 0, 1, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 9,12, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 3, 1, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 5, 0,10,10, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 1,12, 6, 2,12, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0,12, 4, 0,12, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 5, 0,10,10, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 1, 0, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 3, 1, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - -SECTION "Graphics", ROM0 -Tiles: -INCBIN "Tiles.bin" -TilesEnd: ds 0 diff --git a/Code/render.asm b/Code/render.asm new file mode 100644 index 0000000..ed150a3 --- /dev/null +++ b/Code/render.asm @@ -0,0 +1,155 @@ +INCLUDE "hardware.inc" + +RENDER_IN_HBL EQU 0 + +EXPORT Video, Rendered +SECTION "Render Memory", HRAM +LinesLeft: ds 1 ; number of lines left to render +TilesLeft: ds 1 ; number of tiles left to render in current line +Video: ds 2 ; progressing pointer in tilemap (VRAM) +Rendered: ds 2 ; progressing pointer in old buffer + +SECTION "V-Blank Interrupt Handler", ROM0[$40] +VBlankInterruptHandler: + jr LCDStatInterruptHandler + +SECTION "LCD Stat Interrupt Handler", ROM0[$48] +LCDStatInterruptHandler: + ; save registers + push af + push bc + + ; check there are tiles to render + ldh a, [LinesLeft] + or a + jr z, .exit + + ; move lines left to B + ld b, a + + push de + push hl + +.render + ; load buffer pointer into DE + ld hl, Video + ld a, [hl+] + ld d, [hl] + ld e, a + + ; load video pointer into HL + ld hl, Rendered + ld a, [hl+] + ld h, [hl] + ld l, a + + ; load counters + ldh a, [TilesLeft] + ld c, a + +.loop + ; check we can still render + ldh a, [rSTAT] + and a, STATF_BUSY + jr nz, .finish + + ; copy one byte + ld a, [hl+] + ld [de], a + inc e ; it will never overflow since it only increments + ; up to 20 bytes starting on 32 byte boundaries + + ; loop while there are tiles to render + dec c + jr nz, .loop + + ; go to next line + ld a, e + add a, 32 - 20 + ld e, a + jr nc, .nocarry + inc d +.nocarry + + ; loop while there are lines to render + dec b + jr z, .finish + + ; reset tile counter + ld c, 20 + + jr .loop + +.finish + ; save counters + ld a, c + ldh [TilesLeft], a + ld a, b + ldh [LinesLeft], a + + ; save incremented video pointer and buffer pointer + ld a, e + ldh [Video], a + ld a, d + ldh [Video + 1], a + + ld a, l + ldh [Rendered], a + ld a, h + ldh [Rendered + 1], a + + ; restore registers saved in interrupt handler + pop hl + pop de + +.exit + pop bc + pop af + + ; return from v-blank or lcd interrupt + reti + +EXPORT StartRender +SECTION "StartRender", ROM0 +StartRender: + ; start rendering + ld a, 20 + ldh [TilesLeft], a + ld a, 18 + ldh [LinesLeft], a + + ; enable v-blank and lcd stat interrupt for h-blank + ; rendering routine is too slow for lcdc right now so disabled +IF RENDER_IN_HBL != 0 + ld a, IEF_VBLANK | IEF_LCDC +ELSE + ld a, IEF_VBLANK +ENDC + ld [rIE], a + xor a + ei + ldh [rIF], a + + ret + +EXPORT WaitRender +SECTION "WaitRender", ROM0 +WaitRender: + ldh a, [LinesLeft] + ld b, a + ldh a, [TilesLeft] + or a, b + ret z + halt + jr WaitRender + +IF RENDER_IN_HBL != 0 + ; enable only v-blank interrupt and wait for vbl + ld a, IEF_VBLANK + ld [rIE], a + xor a + ldh [rIF], a + halt +ENDC + + ret \ No newline at end of file diff --git a/Code/utils.asm b/Code/utils.asm new file mode 100644 index 0000000..85e16d0 --- /dev/null +++ b/Code/utils.asm @@ -0,0 +1,47 @@ +INCLUDE "hardware.inc" + +EXPORT MemoryCopy +SECTION "Memory Copy", ROM0 +; hl = destination +; de = source +; bc = count +MemoryCopy: + ld a, [de] + ld [hl+], a + inc de + dec bc + ld a, b + or c + jr nz, MemoryCopy + ret + +EXPORT MemorySet +SECTION "Memory Set", ROM0 +; hl = destination +; d = data +; bc = count +MemorySet: + ld a, d + ld [hl+], a + dec bc + ld a, b + or c + jr nz, MemorySet + ret + + ; \1: sprite ID + ; \2: X position + ; \3: Y position + ; \4: tile number + ; \5: flags +SetSprite: MACRO + ld hl, _OAMRAM + \1 * 4 + ld a, \3 + ld [hl+], a + ld a, \2 + ld [hl+], a + ld a, \4 + ld [hl+], a + ld a, \5 + ld [hl+], a +ENDM