From 64f7106143b28183f9bfe33abdb79cd36acd5df9 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Fri, 19 May 2023 20:40:52 -0500 Subject: [PATCH] Fix absolute address issue in rom --- demos/smb/App.Msg.s | 105 +++++++ demos/smb/Main.s | 516 ++++++++++++++++++++++++------- demos/smb/chr.s | 59 +++- demos/smb/font.s | 668 +++++++++++++++++++++++++++++++++++++++++ demos/smb/ppu.s | 36 ++- demos/smb/rom.s | 625 ++++++++++++++++++++++++++++++-------- macros/GTE.Macs.s | 1 + src/Defs.s | 2 + src/Render.s | 16 +- src/Tool.s | 26 +- src/static/TileStore.s | 2 + 11 files changed, 1812 insertions(+), 244 deletions(-) create mode 100644 demos/smb/App.Msg.s create mode 100644 demos/smb/font.s diff --git a/demos/smb/App.Msg.s b/demos/smb/App.Msg.s new file mode 100644 index 0000000..4afc4dd --- /dev/null +++ b/demos/smb/App.Msg.s @@ -0,0 +1,105 @@ +HexToChar dfb '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' + +; Convert a byte (Acc) into a string and store at (Y) +ByteToString and #$00FF + sep #$20 + pha + lsr + lsr + lsr + lsr + and #$0F + tax + ldal HexToChar,x + sta: $0000,y + + pla + and #$0F + tax + ldal HexToChar,x + sta: $0001,y + + rep #$20 + rts + +; Convert a word (Acc) into a hexadecimal string and store at (Y) +WordToString pha + bra Addr2ToString + +; Pass in Acc = High, X = low +Addr3ToString phx + jsr ByteToString + iny + iny + lda 1,s +Addr2ToString xba + jsr ByteToString + iny + iny + pla + jsr ByteToString + rts + +; A=Value +; X=Screen offset +DrawWord phx ; Save register value + phy + ldy #WordBuff+1 + jsr WordToString + ply + plx + lda #WordBuff + jsr DrawString + rts + +WordBuff str '0000' +Addr3Buff str '000000' ; str adds leading length byte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/smb/Main.s b/demos/smb/Main.s index ff5efc8..e1abedb 100644 --- a/demos/smb/Main.s +++ b/demos/smb/Main.s @@ -22,11 +22,20 @@ MyUserId equ 0 ROMStk equ 2 ROMZeroPg equ 4 LastScroll equ 6 -RenderCtr equ 8 +TileX equ 10 ; GTE tile store coordinates that correspond to the PPUSCROLL edge +TileY equ 12 +ROMScreenEdge equ 14 +ROMScrollEdge equ 16 +ROMScrollDelta equ 18 +OldROMScrollEdge equ 20 +CurrScrollEdge equ 22 + Tmp0 equ 240 Tmp1 equ 242 Tmp2 equ 244 Tmp3 equ 246 +Tmp4 equ 248 +Tmp5 equ 250 phk plb @@ -34,7 +43,12 @@ Tmp3 equ 246 _MTStartUp ; GTE requires the miscellaneous toolset to be running stz LastScroll - stz RenderCtr + stz TileX + stz TileY + stz ROMScreenEdge + stz ROMScrollEdge + stz ROMScrollDelta + stz OldROMScrollEdge ; The next two direct pages will be used by GTE, so get another 2 pages beyond that for the ROM. We get ; 4K of DP/Stack space by default, so there is plenty to share @@ -79,6 +93,12 @@ Tmp3 equ 246 pea #drawOAMSprites _GTESetAddress +; Install a custom callback to update the tile store as the screen scrolls + pea extBG0TileUpdate + pea #^UpdateFromPPU + pea #UpdateFromPPU + _GTESetAddress + ; Get the address of a low-level routine that can be used to draw a tile directly to the graphics screen pea rawDrawTile _GTEGetAddress @@ -133,42 +153,6 @@ Tmp3 equ 246 cpx #512*16 bcc :tloop -; Put the tile set on the screen - -* lda #0 -* stz Tmp1 -* :yloop stz Tmp0 -* :xloop -* pha -* pei Tmp0 -* pei Tmp1 -* pha -* _GTESetTile -* pla -* inc - -* inc Tmp0 -* ldx Tmp0 -* cpx #32 -* bcc :xloop - -* inc Tmp1 -* ldx Tmp1 -* cpx #20 -* bcc :yloop - -* ; Render and wait for the user to continue -* pea $0000 -* _GTERender - -* :wait1 -* pha -* _GTEReadControl -* pla -* and #$007F -* cmp #' ' -* bne :wait1 - ; Set an internal flag to tell the VBL interrupt handler that it is ; ok to start invoking the game logic. The ROM code has to be run ; at 60 Hz because it controls the audio. Bad audio is way worse @@ -184,38 +168,60 @@ EvtLoop beq :spin stz nmiCount -; lda ppustatus ; Set the bit that the VBL has started -; bit #$80 -; beq :spin -; and #$FF7F -; sta ppustatus +; The GTE playfield is 41 tiles wide, but the NES is 32 tiles wide. Fortunately, the game +; keeps track of the global coordinates of each level at +; +; ScreenEdge_PageLoc = $071a +; ScreenEdge_X_Pos = $071c +; +; So we can keep our scrolling in sync with the game. In order to efficiently update the +; GTE tile store, we handle this in two stages +; +; 1. When new column(s) are exposed, set the tiles directly from the PPU nametable memory +; 2. When the PPU nametable memory is updated in an area that is already on-screen, set the tile -; jsr triggerNMI +; Get the current global coordinates -; lda RenderCtr -; bne :no_render + sei + lda ROMScrollEdge ; This is set in the VBL IRQ + sta CurrScrollEdge ; Freeze it, then we can let the IRQs continue + cli -; lda #5 -; sta RenderCtr + lsr + lsr + lsr + sta ROMScreenEdge - jsr CopyNametable +; Calculate how many blocks have been scrolled into view - lda ppuscroll+1 - and #$00FF + lda CurrScrollEdge + sec + sbc OldROMScrollEdge + sta Tmp1 ; This is the raw number of pixels moved + + lda OldROMScrollEdge ; This is the number of partial pixels the old scroll position occupied + and #7 + sta Tmp0 + lda #7 + sec + sbc Tmp0 ; This account for situations where going from 8 -> 9 reveals a new column + clc + adc Tmp1 + lsr + lsr + lsr + sta ROMScrollDelta ; This many columns have been revealed + + lda CurrScrollEdge + sta OldROMScrollEdge ; Stash a copy for the next round through lsr pha - sta LastScroll - lda ppuscroll - and #$00FF - pha + pea $0000 _GTESetBG0Origin pea $FFFF ; NES mode _GTERender -:no_render - dec RenderCtr - pha _GTEReadControl pla @@ -226,7 +232,8 @@ EvtLoop and #PAD_BUTTON_A+PAD_BUTTON_B ; bits 0x200 and 0x100 lsr lsr - sta native_joy + sta native_joy ; Put inputs on both controllers + sta native_joy+1 lda 1,s and #$00FF cmp #'n' @@ -254,6 +261,7 @@ EvtLoop lda #$0001 :nes_merge ora native_joy sta native_joy + sta native_joy+1 :nes_done pla ; bit #PAD_KEY_DOWN @@ -262,23 +270,51 @@ EvtLoop and #$007F - cmp #'1' ; Copy nametable 1 + cmp #'r' ; Refresh bne :not_1 - lda #$2000 + jsr CopyStatus + + lda ROMScreenEdge ; global tile index + and #$003F ; mod the mirrored nametable size + ldx #33 + ldy #0 jsr CopyNametable brl EvtLoop :not_1 - - cmp #'2' - bne :not_2 - lda #$2400 + cmp #'1' + bne :not_v + lda ROMScreenEdge + clc + adc #33 + and #$003F + ldx #1 + ldy #33 jsr CopyNametable -:not_2 + brl EvtLoop - cmp #'s' ; next step - bne :not_n - jsr triggerNMI -:not_n +:not_v + + cmp #'t' ; test by placing markers on screen + bne :not_t + pea 0 + pea #3 + pea $0150 + _GTESetTile + pea #31 + pea #3 + pea $0150 + _GTESetTile + pea #32 + pea #3 + pea $0150 + _GTESetTile + pea #39 + pea #3 + pea $0150 + _GTESetTile + + brl EvtLoop +:not_t cmp #'q' beq Exit @@ -298,46 +334,234 @@ Greyscale dw $0000,$5555,$AAAA,$FFFF nmiCount dw 0 DPSave dw 0 -; Copy the tile and attribute bytes into the GTE buffer +; Take a PPU address and convert it to a tile store coordinate ; -; A = Nametable address ($2000, $2400, $2800, or $2C00) -CopyNametable - lda ppuctrl - and #$0003 ; nametable select bits - xba - asl - asl +; Inputs +; A = PPU address +; X = Global Address in GTE bytes + +; Outputs +; X = relative tile store column +; Y = relative tile store row +PPUAddrToTileStore +:PPUAddr equ Tmp0 +:PPUTopLeft equ Tmp1 + + sta :PPUAddr + +; Based on the global coordiate, figure out whhat the left column in the PPU RAM is + txa + lsr ; Convert from bytes to tiles + lsr + and #$003F ; Logically there are 64 tiles in the mirrored PPU RAM + sta :PPUTopLeft + +; Now we have the PPU address of the column that corresponds to the left edge of the GTE +; playfield. Now, calculate the relative coordinates of the passed PPU address + +; The y-coordinate is easy. Since the top-left address is always on the top row (row = 0), +; we just have to extract the row that the PPU address occupies. + + lda :PPUAddr + and #$03E0 ; Take the middle 5 bits (ignore nametable) + lsr + lsr + lsr + lsr + lsr + tay ; Save the y-index here + +; The GTE playfield is positioned with the third PPU row as it's origin and is 25 tiles high. +; If the PPU tile is in rows 0, 1, 27, 28 or 29 then we can ignore it + + cpy #2 + bcc :outOfRange + cpy #27 + bcs :outOfRange + +; Adjust the relative position down by 2 + + dey + dey + +; The horizontal coordinate is a bit trickier. We need to add 32 to the horizontal +; coordinate in it's in the second nametable + + lda :PPUAddr + and #$041F ; Project it to the top row + bit #$0400 + beq *+5 + ora #$0020 ; Add 32 + and #$003F ; Clamp to range of 0 - 63 + +; If we're in the top two row, they don't scroll, so skip the displacement + cpy #2 + bcc :noshift + +; Now calculate the difference between the PPUTopLeft index and this value + + cmp :PPUTopLeft + bcs :ahead ; If the provided address is > than the origin, just calc the difference + adc #64 ; Else distance is (a - 0) + (64 - b) = a + 64 - b + sec +:ahead sbc :PPUTopLeft +:noshift + +; If this value is larger than the payfield + 1, then we have the carry set or clear + + tax + cmp #33 + rts + +:outOfRange + sec + rts + +; If there is some other reason to draw the full screen, this will empty the queue +ClearNTQueue + stz nt_queue_front + stz nt_queue_end + rts + +; Scan through the queue of tiles that need to be updated before applying the scroll change +DrainNTQueue +:GTELeftEdge equ Tmp3 +:PPUAddr equ Tmp4 + +; Prep item -- get the logical block of the left edge of the scroll window + + lda CurrScrollEdge ; Global position that the GTE playfield was set to + lsr + sta :GTELeftEdge + + lda nt_queue_front + cmp nt_queue_end + beq :out + +:loop + tax + phx ; Save the x register + + lda nt_queue,x ; get the PPU address that was stored + sta :PPUAddr ; save for later if we draw this tile + + ldx :GTELeftEdge ; get the global coordinate + jsr PPUAddrToTileStore ; convert the PPU address to realtive tile store coordinates + bcs :skip ; if it's offscreen, no reason to draw it + +; Now we have the relative position from the left edge of the tile. Add the origin +; tile to it (uless we're in rows 0 or 1) + + txa + cpy #2 + bcc :toprow clc - adc #2*32 - sta Tmp0 ; base address offset into nametable memory + adc TileX + cmp #41 + bcc *+5 + sbc #41 +:toprow + pha ; Tile Store horizontal tile coordinate -; ora #$2000 -; clc -; adc #PPU_MEM -; clc -; adc #2*32 -; sta Tmp0 ; base address + phy ; No translation needed for y -; NES RAM $6D = page, $86 = player_x_in_page can be used to get a global position in the level, then subtracting the -; player's x coordinate will give us the global coordinate of the left edge of the screen and allow us to map between -; the GTE tile buffer and the PPU nametables + ldx :PPUAddr + lda PPU_MEM,x + and #$00FF + ora #$0100 + pha + _GTESetTile - lda ppuscroll+1 +:skip + pla ; Pop the saved x-register into the accumulator + inc + inc + and #{2*1024}-1 + cmp nt_queue_end + bne :loop + +:out + sta nt_queue_front + rts + +; Copy the necessary columns into the TileStore when setting a new scroll position +UpdateFromPPU +:StartXMod164 equ 36 + + phb + phd + +; Snag the StartXmod164 value from the GTE direct page so we can calulate the tile origin +; ourselves + + ldx :StartXMod164 + + phk + plb + lda DPSave + tcd + + txa lsr lsr - lsr - and #$001F - sta Tmp1 ; starting offset + sta TileX ; Tile column of playfield origin +; Check the scroll delta, if it's negative or just large enough, do a whole copy of the current PPU +; memory into the TileStore + + lda ROMScrollDelta + beq :queue + + cmp #32 + bcc :partial + + jsr ClearNTQueue ; kill any pending updates + lda ROMScreenEdge ; global tile index + and #$003F ; mod the mirrored nametable size + ldx #33 ; do the full width + ldy #0 + jsr CopyNametable + bra :done + +; Calculate the difference between the old and new +:partial + jsr DrainNTQueue + + lda #33 + sec + sbc ROMScrollDelta + tay + + ldx ROMScrollDelta + inx + inx + + lda ROMScreenEdge + clc + adc #33 + sec + sbc ROMScrollDelta + and #$003F + + jsr CopyNametable +:done + pld + plb + rtl + +; Just drain the queue of any on-screen changes and then exit +:queue + jsr DrainNTQueue + pld + plb + rtl + +CopyStatus ; Copy the first two rows from $2400 because they don't scroll ldy #0 :yloop ldx #0 - - cpy #2 - bcs :offset - tya clc adc #2 @@ -346,19 +570,84 @@ CopyNametable asl asl asl - sta Tmp2 - lda #0 - sta Tmp3 - bra :xloop + stz Tmp3 +:xloop + phx ; Save X and Y + phy -:offset - lda Tmp0 ; Get the base address for this line - ora Tmp1 ; Move over to the first horizontal tile + phx ; x = GTE tile index = PPU tile index + phy ; No vertical scroll, so screen_y = tile_y + + ldx Tmp2 ; Nametable address + lda PPU_MEM+$2000,x + and #$00FF + ora #$0100 + pha + +; Advance to the next tile (no wrapping needed) + + inx + stx Tmp2 + + _GTESetTile + + ply + plx + + inx + cpx #33 + bcc :xloop + + iny + cpy #2 + bcc :yloop + rts + +; Copy the tile and attribute bytes into the GTE buffer +; +; A = logical column in mirrored PPU memory (0 - 63) +; X = number of columns to copy +; Y = number of GTE tiles to offset +CopyNametable +; cmp #5 +; bcc *+4 +; brk $88 + sta Tmp2 + bit #$0020 ; Is it >32? + beq *+5 + ora #$0400 ; Move to the next nametable + and #$041F ; Mask to the top of a valid column + + clc ; Add in the offset since we only copy rows 2 - 27 + adc #4*32 + sta Tmp0 ; base address offset into nametable memory + + stx Tmp4 + + tya + clc + adc TileX + cmp #41 + bcc *+5 + sbc #41 + sta Tmp5 + +; NES RAM $6D = page, $86 = player_x_in_page can be used to get a global position in the level, then subtracting the +; player's x coordinate will give us the global coordinate of the left edge of the screen and allow us to map between +; the GTE tile buffer and the PPU nametables + +; Skip the first two rows -- call CopyStatus to get those + + ldy #2 +:yloop + ldx #0 + + lda Tmp0 ; Get the base address for this row sta Tmp2 ; coarse x-scroll - lda Tmp1 - sta Tmp3 ; Keep a separate count for the GTE tile position + lda Tmp5 + sta Tmp3 ; Keep a separate variable for the GTE tile position :xloop phx ; Save X and Y phy @@ -401,7 +690,7 @@ CopyNametable sta Tmp3 inx - cpx #33 + cpx Tmp4 bcc :xloop lda Tmp0 @@ -766,12 +1055,25 @@ nmiTask jsr triggerNMI +; Immediately after the NMI returns, freeze some of the global state variables so we can sync up with this frame when +; we render the next frame. Since we're in an interrupt handler here, sno change of the variables changing under +; our nose + + sep #$20 + ldal ROMBase+$071a + xba + ldal ROMBase+$071c + rep #$20 + sta ROMScrollEdge + pld plb plp :skip rtl mx %00 + put App.Msg.s + put font.s put palette.s put ppu.s diff --git a/demos/smb/chr.s b/demos/smb/chr.s index 3226de7..829b58e 100644 --- a/demos/smb/chr.s +++ b/demos/smb/chr.s @@ -1,3 +1,25 @@ +; 8 * 8 * 2 (2 bits to codify color) = 128 bits = 16 bytes to codify a single tile +; +; Surprisingly, 2 bits of a pixel are not codified in the same byte. A tile is +; described using 16 bytes. And each row is encoded using 2 bytes that stand 8 +; bytes apart from each other. To figure out the color index of the top-left pixel, +; we need to read the 7th bit of byte 0x0000 and the 7th bit of byte 0x0008, to get +; the next pixel in the same row we would need to read 6th bits in the same bytes, etc. +; +; Decode the first row which is the back of mario's head +; +; ADDR VAL BITS ADDR VAL BITS +; +; 0x00 $03 00000011 0x08 $00 00000000 00 00 00 00 00 00 01 01 0 0 0 0 0 0 1 1 +; 0x01 $0F 00001111 0x09 $00 00000000 00 00 00 00 01 01 01 01 0 0 0 0 1 1 1 1 +; 0x02 $1F 00011111 0x0A $00 00000000 00 00 00 01 01 01 01 01 0 0 0 1 1 1 1 1 +; 0x03 $1F 00011111 0x0B $00 00000000 = 00 00 00 01 01 01 01 01 = 0 0 0 1 1 1 1 1 +; 0x04 $1C 00011100 0x0C $1F 00011111 00 00 00 11 11 11 10 10 0 0 0 3 3 3 2 2 +; 0x05 $24 00100100 0x0D $3F 00111111 00 00 11 10 10 11 10 10 0 0 3 2 2 3 2 2 +; 0x06 $26 00100110 0x0E $3F 00111111 00 00 11 10 10 11 11 10 0 0 3 2 2 3 3 2 +; 0x07 $66 01100110 0x0F $7F 11111111 10 11 11 10 10 11 11 10 2 3 3 2 2 3 3 2 + + ; Begin Bank 0 db $03,$0f,$1f,$1f,$1c,$24,$26,$66,$00,$00,$00,$00,$1f,$3f,$3f,$7f db $e0,$c0,$80,$fc,$80,$c0,$00,$20,$00,$20,$60,$00,$f0,$fc,$fe,$fe db $60,$70,$18,$07,$0f,$1f,$3f,$7f,$7f,$7f,$1f,$07,$00,$1e,$3f,$7f @@ -254,6 +276,9 @@ db $00,$00,$00,$00,$00,$00,$00,$00,$66,$e6,$66,$66,$66,$67,$f3,$00 db $00,$00,$00,$00,$00,$00,$00,$00,$5e,$59,$59,$59,$5e,$d8,$98,$00 db $00,$00,$00,$00,$00,$7c,$38,$00,$00,$00,$00,$00,$00,$04,$08,$00 + + ; Begin Bank 1 + ; Tiles 0 - 15 db $38,$4c,$c6,$c6,$c6,$64,$38,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $18,$38,$18,$18,$18,$18,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $7c,$c6,$0e,$3c,$78,$e0,$fe,$00,$00,$00,$00,$00,$00,$00,$00,$00 @@ -270,6 +295,8 @@ db $f8,$cc,$c6,$c6,$c6,$cc,$f8,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $fe,$c0,$c0,$fc,$c0,$c0,$fe,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $fe,$c0,$c0,$fc,$c0,$c0,$c0,$00,$00,$00,$00,$00,$00,$00,$00,$00 + + ; Tiles 16 - 31 db $3e,$60,$c0,$ce,$c6,$66,$3e,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $c6,$c6,$c6,$fe,$c6,$c6,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $7e,$18,$18,$18,$18,$18,$7e,$00,$00,$00,$00,$00,$00,$00,$00,$00 @@ -286,6 +313,8 @@ db $7e,$18,$18,$18,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $c6,$c6,$c6,$c6,$c6,$c6,$7c,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $c6,$c6,$c6,$ee,$7c,$38,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00 + + ; Tiles 32 - 47 db $c6,$c6,$d6,$fe,$fe,$ee,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $c6,$ee,$7c,$38,$7c,$ee,$c6,$00,$00,$00,$00,$00,$00,$00,$00,$00 db $66,$66,$66,$3c,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00,$00 @@ -302,6 +331,8 @@ db $80,$80,$80,$c1,$e3,$ff,$ff,$ff,$7f,$7f,$7f,$3e,$1c,$00,$00,$ff db $38,$7c,$7c,$7c,$7c,$7c,$38,$00,$08,$04,$04,$04,$04,$04,$08,$00 db $03,$06,$0c,$0c,$08,$08,$04,$03,$03,$05,$0b,$0b,$0f,$0f,$07,$03 + + ; Tiles 48 - 63 db $01,$02,$04,$08,$10,$20,$40,$80,$01,$03,$07,$0f,$1f,$3f,$7f,$ff db $00,$00,$00,$00,$00,$07,$38,$c0,$00,$00,$00,$00,$00,$07,$3f,$ff db $00,$00,$00,$00,$00,$e0,$1c,$03,$00,$00,$00,$00,$00,$e0,$fc,$ff @@ -318,6 +349,8 @@ db $c0,$20,$10,$10,$10,$10,$20,$c0,$c0,$e0,$f0,$f0,$f0,$f0,$e0,$c0 db $00,$00,$00,$00,$3f,$7f,$e0,$c0,$00,$00,$00,$00,$00,$00,$1c,$3e db $88,$9c,$88,$80,$80,$80,$80,$80,$7f,$7f,$7f,$3e,$1c,$00,$00,$00 + +; Tiles 64 - 79 db $fe,$fe,$fe,$fe,$fe,$fe,$fe,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff db $08,$14,$24,$c4,$03,$40,$a1,$26,$00,$08,$18,$38,$fc,$bf,$5e,$d9 db $ff,$ff,$ff,$ff,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81 @@ -334,6 +367,8 @@ db $ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$80,$80,$80,$80,$80,$81,$42,$3c db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$00,$00,$00,$00,$00,$00,$00 db $ff,$ff,$ff,$ff,$ff,$ff,$fe,$7c,$00,$00,$00,$00,$00,$01,$82,$7c + + ; Tiles 80 - 95 db $ff,$ff,$ff,$ff,$ff,$ff,$fe,$7c,$00,$00,$00,$00,$00,$01,$83,$ff db $f8,$fc,$fe,$fe,$ff,$ff,$ff,$ff,$f8,$04,$02,$02,$01,$01,$01,$01 db $ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$01,$01,$01,$01,$01,$81,$42,$3c @@ -350,6 +385,8 @@ db $11,$39,$11,$01,$01,$01,$01,$01,$fe,$fe,$fe,$7c,$38,$00,$00,$00 db $ef,$28,$28,$28,$28,$28,$ef,$00,$20,$e7,$e7,$e7,$e7,$e7,$ef,$00 db $fe,$82,$82,$82,$82,$82,$fe,$00,$02,$7e,$7e,$7e,$7e,$7e,$fe,$00 + + ; Tiles 96 - 111 db $80,$80,$80,$98,$9c,$8c,$80,$7f,$7f,$7f,$7f,$67,$67,$7f,$7f,$7f db $ff,$ff,$83,$f3,$f3,$f3,$f3,$f3,$ff,$80,$fc,$8c,$8c,$8c,$8c,$8c db $ff,$ff,$f0,$f6,$f6,$f6,$f6,$f6,$ff,$00,$0f,$09,$09,$09,$09,$09 @@ -366,6 +403,8 @@ db $ff,$80,$80,$c0,$ff,$ff,$fe,$fe,$ff,$7f,$7f,$3f,$00,$00,$01,$01 db $ff,$7f,$7f,$ff,$ff,$07,$03,$03,$ff,$80,$80,$00,$00,$f8,$fc,$fc db $ff,$00,$00,$00,$00,$81,$c3,$ff,$ff,$ff,$ff,$ff,$ff,$7e,$3c,$00 + + ; Tiles 112 - 127 db $f8,$fc,$fe,$fe,$e3,$c1,$81,$81,$f8,$04,$02,$02,$1d,$3f,$7f,$7f db $83,$ff,$ff,$ff,$ff,$ff,$7f,$1f,$fc,$80,$80,$80,$80,$80,$60,$1f db $fc,$fc,$fc,$fc,$fe,$fe,$ff,$ff,$03,$03,$03,$03,$01,$01,$00,$ff @@ -382,6 +421,8 @@ db $04,$9a,$fa,$fd,$fd,$fd,$fd,$fd,$00,$80,$80,$80,$80,$80,$80,$80 db $7e,$38,$21,$00,$01,$00,$01,$00,$21,$21,$01,$01,$01,$01,$01,$01 db $fa,$8a,$84,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80 + + ; Tiles 128 - 143 db $02,$04,$00,$10,$00,$40,$80,$00,$01,$01,$06,$08,$18,$20,$20,$c0 db $0b,$0b,$3b,$0b,$fb,$0b,$0b,$0a,$04,$04,$c4,$f4,$f4,$04,$04,$05 db $90,$10,$1f,$10,$1f,$10,$10,$90,$70,$f0,$f0,$ff,$ff,$f0,$f0,$70 @@ -398,6 +439,8 @@ db $ff,$ff,$ff,$ff,$ff,$00,$ff,$ff,$00,$00,$00,$00,$00,$ff,$00,$00 db $fc,$fc,$fe,$fe,$fe,$02,$fe,$fe,$07,$07,$03,$03,$03,$ff,$03,$03 db $ff,$80,$80,$80,$80,$80,$80,$80,$80,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Tiles 144 - 159 db $ff,$03,$03,$03,$03,$03,$03,$03,$03,$ff,$ff,$ff,$ff,$ff,$ff,$ff db $02,$02,$02,$02,$02,$02,$04,$04,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff db $80,$80,$aa,$d5,$aa,$ff,$ff,$ff,$ff,$ff,$d5,$aa,$d5,$80,$80,$ff @@ -414,6 +457,8 @@ db $e1,$f9,$fd,$ff,$fe,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff db $f0,$10,$10,$10,$10,$10,$10,$ff,$00,$e0,$e0,$e0,$e0,$e0,$e0,$e0 db $1f,$10,$10,$10,$10,$10,$10,$ff,$00,$0f,$0f,$0f,$0f,$0f,$0f,$0f + + ; Tiles 160 - 175 db $92,$92,$92,$fe,$fe,$00,$00,$00,$48,$48,$6c,$00,$00,$00,$fe,$00 db $0a,$0a,$3a,$0a,$fb,$0b,$0b,$0b,$05,$05,$c5,$f5,$f4,$04,$04,$04 db $90,$90,$9f,$90,$9f,$90,$90,$90,$70,$70,$70,$7f,$7f,$70,$70,$70 @@ -426,10 +471,12 @@ db $f8,$f8,$f8,$f8,$f8,$f0,$f0,$e0,$98,$98,$98,$98,$98,$30,$30,$60 db $f1,$11,$11,$1f,$10,$10,$10,$ff,$0f,$ef,$ef,$ef,$ef,$ef,$ef,$e0 db $1f,$10,$10,$f0,$10,$10,$10,$ff,$e0,$ef,$ef,$ef,$ef,$ef,$ef,$0f - db $7f,$bf,$df,$ef,$f0,$f0,$f0,$f0,$80,$40,$20,$10,$0f,$0f,$0f,$0f +; db $7f,$bf,$df,$ef,$f0,$f0,$f0,$f0,$80,$40,$20,$10,$0f,$0f,$0f,$0f db $f0,$f0,$f0,$f0,$ff,$ff,$ff,$ff,$0f,$0f,$0f,$0f,$1f,$3f,$7f,$ff db $ff,$ff,$ff,$ff,$0f,$0f,$0f,$0f,$01,$03,$07,$0f,$ff,$ff,$ff,$ff db $0f,$0f,$0f,$0f,$f7,$fb,$fd,$fe,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff + + ; Tiles 176 - 191 db $00,$00,$00,$00,$00,$00,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00 db $1f,$3f,$7f,$7f,$7f,$ff,$ff,$ff,$1f,$20,$40,$40,$40,$80,$82,$82 db $ff,$ff,$ff,$7f,$7f,$7f,$3f,$1e,$82,$80,$a0,$44,$43,$40,$21,$1e @@ -446,6 +493,8 @@ db $7f,$7f,$7f,$3f,$3f,$1f,$0f,$07,$40,$40,$40,$20,$30,$1c,$0f,$07 db $fe,$fe,$fe,$fc,$fc,$f8,$f0,$f0,$02,$02,$02,$04,$0c,$38,$f0,$f0 db $0f,$0f,$0f,$0f,$0f,$0f,$07,$0f,$08,$08,$08,$08,$08,$0c,$05,$0a + + ; Tiles 192 - 207 db $f0,$f0,$f0,$f0,$f0,$f0,$e0,$f0,$10,$50,$50,$50,$50,$30,$a0,$50 db $81,$c1,$a3,$a3,$9d,$81,$81,$81,$00,$41,$22,$22,$1c,$00,$00,$00 db $e3,$f7,$c1,$c1,$c1,$c1,$f7,$e3,$e3,$14,$3e,$3e,$3e,$3e,$14,$e3 @@ -462,6 +511,8 @@ db $e9,$e9,$e9,$ef,$e2,$e3,$f0,$ff,$76,$76,$76,$70,$7d,$7c,$7f,$7f db $96,$96,$96,$f6,$46,$c6,$0e,$fe,$6f,$6f,$6f,$0f,$bf,$3f,$ff,$ff db $00,$00,$00,$00,$00,$00,$7e,$3c,$3c,$7e,$7e,$ff,$ff,$ff,$42,$00 + + ; Tiles 208 - 223 db $3c,$42,$99,$a1,$a1,$99,$42,$3c,$00,$00,$00,$00,$00,$00,$00,$00 db $0f,$1f,$1f,$3f,$3f,$7f,$7f,$7f,$f0,$e0,$e0,$c0,$c0,$80,$80,$80 db $f0,$f8,$f8,$fc,$fc,$fe,$fe,$fe,$0f,$07,$07,$03,$03,$01,$01,$01 @@ -478,6 +529,8 @@ db $ff,$ff,$ff,$ff,$fc,$fe,$fe,$7e,$ff,$03,$03,$03,$03,$03,$03,$ff db $ff,$ff,$ff,$ff,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff db $7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$80,$80,$80,$80,$80,$80,$80,$80 + + ; Tiles 224 - 239 db $ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$01,$01,$01,$03,$07,$03,$01,$01 db $7e,$7e,$7f,$7f,$7f,$7f,$7f,$7f,$81,$81,$81,$81,$81,$81,$81,$81 db $3f,$3f,$3f,$3f,$00,$00,$00,$00,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff @@ -494,6 +547,8 @@ db $20,$a6,$54,$26,$20,$c6,$54,$26,$20,$e6,$54,$26,$21,$06,$54,$26 db $20,$85,$01,$44,$20,$86,$54,$48,$20,$9a,$01,$49,$20,$a5,$c9,$46 db $20,$ba,$c9,$4a,$20,$a6,$0a,$d0,$d1,$d8,$d8,$de,$d1,$d0,$da,$de + + ; Tiles 240 - 255 db $d1,$20,$c6,$0a,$d2,$d3,$db,$db,$db,$d9,$db,$dc,$db,$df,$20,$e6 db $0a,$d4,$d5,$d4,$d9,$db,$e2,$d4,$da,$db,$e0,$21,$06,$0a,$d6,$d7 db $d6,$d7,$e1,$26,$d6,$dd,$e1,$e1,$21,$26,$14,$d0,$e8,$d1,$d0,$d1 @@ -510,3 +565,5 @@ db $0a,$16,$0e,$22,$8b,$0d,$02,$24,$19,$15,$0a,$22,$0e,$1b,$24,$10 db $0a,$16,$0e,$22,$ec,$04,$1d,$18,$19,$28,$22,$f6,$01,$00,$23,$c9 db $56,$55,$23,$e2,$04,$99,$aa,$aa,$aa,$23,$ea,$04,$99,$aa,$aa,$aa + + db $7f,$bf,$df,$ef,$f0,$f0,$f0,$f0,$80,$40,$20,$10,$0f,$0f,$0f,$0f diff --git a/demos/smb/font.s b/demos/smb/font.s new file mode 100644 index 0000000..8c71e10 --- /dev/null +++ b/demos/smb/font.s @@ -0,0 +1,668 @@ +**************************************** +* FONT ENGINE (v3?) * +* * +* Dagen Brock * +* 2013-07-20 * +**************************************** +* A= ptr to string preceded by length * +* X= screen location * +**************************************** +; each char: +; draw char at loc +; update loc +; see if length hit - no? back to draw char + rel + mx %00 +]F_Length ds 2 ;length of string (only one byte currently used) +]F_CharIdx ds 2 ;index of current character +]F_CurrentPos ds 2 ;current top left char position +]F_StrPtr equ $01 ;pointer to string (including length byte) / DP +]F_StrClr equ $03 + +DrawString + pha ; local variable space + pha + tsc + phd + tcd + +; sta ]F_StrPtr ; (done in pha init above) store at dp 0 ($00) for indirect loads + stx ]F_CurrentPos + sty ]F_StrClr + stz ]F_CharIdx + lda (]F_StrPtr) + and #$00ff ;strip off first char (len is only one byte) + sta ]F_Length ;get our length byte + +NextChar lda ]F_CharIdx + cmp ]F_Length + bne :notDone + ldy ]F_StrClr ;restore the color pattern + pld + pla + pla + rts ;DONE! Return to caller + +:notDone inc ]F_CharIdx + ldy ]F_CharIdx + lda (]F_StrPtr),y ;get next char! + and #$00FF ;mask high byte + sec + sbc #' ' ;our table starts with space ' ' + asl ;*2 + tay + ldx ]F_CurrentPos + jsr :drawChar + inc ]F_CurrentPos ;compare to addition time (?) + inc ]F_CurrentPos + inc ]F_CurrentPos + inc ]F_CurrentPos ;update screen pos (2 words=8 pixels) + bra NextChar + +;x = TopLeft screen pos +;y = char table offset +:drawChar lda FontTable,y ;get real address of char data + sec + sbc #FontData ;pivot offset - now a is offset of fontdata + tay ;so we'll index with that + + lda FontData,y + and ]F_StrClr + stal $E12000,x + + lda FontData+2,y + and ]F_StrClr + stal $E12000+2,x + + lda FontData+4,y + and ]F_StrClr + stal $E12000+160,x + + lda FontData+6,y + and ]F_StrClr + stal $E12000+160+2,x + + lda FontData+8,y + and ]F_StrClr + stal {$E12000+160*2},x + + lda FontData+10,y + and ]F_StrClr + stal {$E12000+160*2+2},x + + lda FontData+12,y + and ]F_StrClr + stal {$E12000+160*3},x + + lda FontData+14,y + and ]F_StrClr + stal {$E12000+160*3+2},x + + lda FontData+16,y + and ]F_StrClr + stal {$E12000+160*4},x + + lda FontData+18,y + and ]F_StrClr + stal {$E12000+160*4+2},x + + lda FontData+20,y + and ]F_StrClr + stal {$E12000+160*5},x + + lda FontData+22,y + and ]F_StrClr + stal {$E12000+160*5+2},x + rts + +FontTable dw s_Space + dw s_Exclaim + dw s_Quote + dw s_Number + dw s_Dollar + dw s_Percent + dw s_Amper + dw s_Single + dw s_OpenParen + dw s_CloseParen + dw s_Asterix + dw s_Plus + dw s_Comma + dw s_Minus + dw s_Period + dw s_Slash + dw s_N0 + dw s_N1 + dw s_N2 + dw s_N3 + dw s_N4 + dw s_N5 + dw s_N6 + dw s_N7 + dw s_N8 + dw s_N9 + dw s_Colon + dw s_Semi + dw s_LAngle + dw s_Equal + dw s_RAngle + dw s_Question + dw s_At + dw s_A + dw s_B + dw s_C + dw s_D + dw s_E + dw s_F + dw s_G + dw s_H + dw s_I + dw s_J + dw s_K + dw s_L + dw s_M + dw s_N + dw s_O + dw s_P + dw s_Q + dw s_R + dw s_S + dw s_T + dw s_U + dw s_V + dw s_W + dw s_X + dw s_Y + dw s_Z + dw s_LBracket + dw s_BackSlash + dw s_RBracket + dw s_Carot + dw s_UnderLine + +FontData = * +s_Space hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + +s_Exclaim hex 000FF000 + hex 000FF000 + hex 000FF000 + hex 000FF000 + hex 00000000 + hex 000FF000 + +s_Quote hex 0FF00FF0 + hex 00F000F0 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + +s_Number hex 00000000 + hex 00F00F00 + hex 0FFFFFF0 + hex 00F00F00 + hex 0FFFFFF0 + hex 00F00F00 + +s_Dollar hex 000F0F00 + hex 00FFFFF0 + hex 0F0F0F00 + hex 00FFFF00 + hex 000F0FF0 + hex 0FFFFF00 + +s_Percent hex 0FF000F0 + hex 00000F00 + hex 0000F000 + hex 000F0000 + hex 00F00000 + hex 0F000FF0 + +s_Amper hex 000FF000 + hex 00F00F00 + hex 0F00F000 + hex 00F000F0 + hex 0F0FFF00 + hex 00F0F000 + +s_Single hex 000FF000 + hex 0000F000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + +s_OpenParen hex 000FF000 + hex 00FF0000 + hex 0FF00000 + hex 0FF00000 + hex 00FF0000 + hex 000FF000 + +s_CloseParen hex 000FF000 + hex 0000FF00 + hex 00000FF0 + hex 00000FF0 + hex 0000FF00 + hex 000FF000 + + +s_Asterix hex 00000000 + hex 00F0F0F0 + hex 000FFF00 + hex 00FFFFF0 + hex 000FFF00 + hex 00F0F0F0 + +s_Plus hex 000F0000 + hex 000F0000 + hex 0FFFFF00 + hex 000F0000 + hex 000F0000 + hex 00000000 + +s_Comma hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 0000FF00 + hex 0000F000 + +s_Minus hex 00000000 + hex 00000000 + hex 0FFFFF00 + hex 00000000 + hex 00000000 + hex 00000000 + + +s_Period hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 0000FF00 + hex 0000FF00 + +s_Slash hex 000000F0 + hex 00000F00 + hex 0000F000 + hex 000F0000 + hex 00F00000 + hex 0F000000 + +s_N0 hex 00FFFF00 + hex 0F000FF0 + hex 0F00F0F0 + hex 0F0F00F0 + hex 0FF000F0 + hex 00FFFF00 + +s_N1 hex 000F0000 + hex 00FF0000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 00FFF000 + +s_N2 hex 00FFFF00 + hex 0F0000F0 + hex 00000F00 + hex 000FF000 + hex 00F00000 + hex 0FFFFFF0 + +s_N3 hex 00FFFF00 + hex 000000F0 + hex 000FFF00 + hex 000000F0 + hex 000000F0 + hex 00FFFF00 + +s_N4 hex 0000FF00 + hex 000F0F00 + hex 00F00F00 + hex 0FFFFFF0 + hex 00000F00 + hex 00000F00 + +s_N5 hex 0FFFFFF0 + hex 0F000000 + hex 0FFFFF00 + hex 000000F0 + hex 0F0000F0 + hex 00FFFF00 + +s_N6 hex 000FFF00 + hex 00F00000 + hex 0F000000 + hex 0FFFFF00 + hex 0F0000F0 + hex 00FFFFF0 + +s_N7 hex 0FFFFFF0 + hex 000000F0 + hex 00000F00 + hex 0000F000 + hex 000F0000 + hex 000F0000 + +s_N8 hex 00FFFF00 + hex 0F0000F0 + hex 00FFFF00 + hex 0F0000F0 + hex 0F0000F0 + hex 00FFFF00 + +s_N9 hex 00FFFF00 + hex 0F0000F0 + hex 00FFFF00 + hex 0000F000 + hex 000F0000 + hex 00F00000 + +s_Colon hex 000FF000 + hex 000FF000 + hex 00000000 + hex 000FF000 + hex 000FF000 + hex 00000000 + +s_Semi hex 00000000 + hex 000FF000 + hex 000FF000 + hex 00000000 + hex 000FF000 + hex 000F0000 + +s_LAngle hex 0000F000 + hex 000F0000 + hex 00F00000 + hex 000F0000 + hex 0000F000 + hex 00000000 + +s_Equal hex 00000000 + hex 00000000 + hex 0FFFFF00 + hex 00000000 + hex 0FFFFF00 + hex 00000000 + +s_RAngle hex 0000F000 + hex 00000F00 + hex 000000F0 + hex 00000F00 + hex 0000F000 + hex 00000000 + +s_Question hex 00FFF000 + hex 0F000F00 + hex 00000F00 + hex 000FF000 + hex 00000000 + hex 000FF000 + +s_At hex 00FFFF00 + hex 0F0000F0 + hex 0F00F0F0 + hex 0FFFF0F0 + hex 000000F0 + hex 0FFFFF00 + +s_A hex 000FF000 + hex 00F00F00 + hex 0F0000F0 + hex 0FFFFFF0 + hex 0F0000F0 + hex 0F0000F0 + +s_B hex 0FFFFF00 + hex 0F0000F0 + hex 0FFFFF00 + hex 0F0000F0 + hex 0F0000F0 + hex 0FFFFF00 + +s_C hex 00FFFFF0 + hex 0F000000 + hex 0F000000 + hex 0F000000 + hex 0F000000 + hex 00FFFFF0 + +s_D hex 0FFFFF00 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0FFFFF00 + +s_E hex 0FFFFFF0 + hex 0F000000 + hex 0FFFF000 + hex 0F000000 + hex 0F000000 + hex 0FFFFFF0 + +s_F hex 0FFFFFF0 + hex 0F000000 + hex 0FFFF000 + hex 0F000000 + hex 0F000000 + hex 0F000000 + +s_G hex 00FFFFF0 + hex 0F000000 + hex 0F000000 + hex 0F00FFF0 + hex 0F0000F0 + hex 00FFFF00 + +s_H hex 0F0000F0 + hex 0F0000F0 + hex 0FFFFFF0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + +s_I hex 0FFFFF00 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 0FFFFF00 + +s_J hex 000000F0 + hex 000000F0 + hex 000000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 00FFFF00 + +s_K hex 0F000F00 + hex 0F00F000 + hex 0FFF0000 + hex 0F00F000 + hex 0F000F00 + hex 0F000F00 + +s_L hex 0F000000 + hex 0F000000 + hex 0F000000 + hex 0F000000 + hex 0F000000 + hex 0FFFFFF0 + +s_M hex 0F0000F0 + hex 0FF00FF0 + hex 0F0FF0F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + +s_N hex 0F0000F0 + hex 0FF000F0 + hex 0F0F00F0 + hex 0F00F0F0 + hex 0F000FF0 + hex 0F0000F0 + +s_O hex 00FFFF00 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 00FFFF00 + +s_P hex 0FFFFF00 + hex 0F0000F0 + hex 0FFFFF00 + hex 0F000000 + hex 0F000000 + hex 0F000000 + +s_Q hex 00FFFF00 + hex 0F0000F0 + hex 0F0000F0 + hex 0F00F0F0 + hex 0F000FF0 + hex 00FFFFF0 + +s_R hex 0FFFFF00 + hex 0F0000F0 + hex 0FFFFF00 + hex 0F000F00 + hex 0F0000F0 + hex 0F0000F0 + +s_S hex 00FFFFF0 + hex 0F000000 + hex 00FFFF00 + hex 000000F0 + hex 000000F0 + hex 0FFFFF00 + +s_T hex 0FFFFF00 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + +s_U hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 00FFFF00 + +s_V hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 00F00F00 + hex 000FF000 + +s_W hex 0F0000F0 + hex 0F0000F0 + hex 0F0000F0 + hex 0F0FF0F0 + hex 0FF00FF0 + hex 0F0000F0 + +s_X hex 0F0000F0 + hex 00F00F00 + hex 000FF000 + hex 000FF000 + hex 00F00F00 + hex 0F0000F0 + +s_Y hex F00000F0 + hex 0F000F00 + hex 00F0F000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + +s_Z hex 0FFFFFF0 + hex 00000F00 + hex 0000F000 + hex 000F0000 + hex 00F00000 + hex 0FFFFFF0 + +s_LBracket hex 000FFF00 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 000F0000 + hex 000FFF00 + +s_BackSlash hex 0F000000 + hex 00F00000 + hex 000F0000 + hex 0000F000 + hex 00000F00 + hex 000000F0 + +s_RBracket hex 00FFF000 + hex 0000F000 + hex 0000F000 + hex 0000F000 + hex 0000F000 + hex 00FFF000 + +s_Carot hex 0000F000 + hex 000F0F00 + hex 00F000F0 + hex 00000000 + hex 00000000 + hex 00000000 + +s_UnderLine hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex FFFFFFF0 + +s_Template hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + hex 00000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/smb/ppu.s b/demos/smb/ppu.s index 5380a7d..6e1df35 100644 --- a/demos/smb/ppu.s +++ b/demos/smb/ppu.s @@ -168,6 +168,7 @@ PPUADDR_WRITE ENT plp rtl + ; 2007 - PPUDATA (Read/Write) ; ; If reading from the $0000 - $3EFF range, the value from vram_buff is returned and the actual data is loaded @@ -212,6 +213,10 @@ PPUDATA_READ ENT pla rtl +nt_queue_front dw 0 +nt_queue_end dw 0 +nt_queue ds 2*{1024} + PPUDATA_WRITE ENT php phb @@ -230,16 +235,43 @@ PPUDATA_WRITE ENT adc ppuincr sta ppuaddr +; Anything between $2000 and $3000, we need to add to the queue. We can't reject updates here because we may not +; actually update the GTE tile store for several game frames and the position of the tile within the tile store +; may change if the screen is scrolling + + cpx #$3000 + bcs :nocache + cpx #$2000 + bcc :nocache + + phy + lda nt_queue_end + tay + inc + inc + and #{2*1024}-1 + cmp nt_queue_front + beq :full + + sta nt_queue_end + txa + sta nt_queue,y + +:full + ply + +:nocache cpx #$3F00 bcs :extra +:done sep #$30 plx pla plb plp rtl - + ; Do some extra work to keep palette data in sync ; ; Based on the palette data that SMB uses, we map the NES palette entries as @@ -526,7 +558,7 @@ drawOAMSprites bra :noflip :hflip - lda PPU_OAM,x ; Loda the tile index into the high byte (x256) + lda PPU_OAM,x ; Load the tile index into the high byte (x256) and #$FF00 lsr ; multiple by 128 adc #64 ; horizontal flip diff --git a/demos/smb/rom.s b/demos/smb/rom.s index 680bb36..145b13e 100644 --- a/demos/smb/rom.s +++ b/demos/smb/rom.s @@ -30,19 +30,20 @@ PPU_SCROLL_REG = $2005 PPU_ADDRESS = $2006 PPU_DATA = $2007 -SND_REGISTER = $4000 -SND_SQUARE1_REG = $4000 -SND_SQUARE2_REG = $4004 -SND_TRIANGLE_REG = $4008 -SND_NOISE_REG = $400c -SND_DELTA_REG = $4010 -SND_MASTERCTRL_REG = $4015 +SND_REGISTER = $4000 ; Only accessed via abs,x addressing +SND_SQUARE1_REG = $4000 ; Only accessed via abs addressing; sta, sty and stx +SND_SQUARE2_REG = $4004 ; Only accessed via abs addressing; sta, sty and stx +SND_TRIANGLE_REG = $4008 ; Only accessed via abs addressing; sta +SND_NOISE_REG = $400c ; Only accessed via abs addressing; sta, sty and stx +SND_DELTA_REG = $4010 ; Only accessed via abs addressing; sta, sty +SND_MASTERCTRL_REG = $4015 ; Only accessed via abs addressing; sta, stx SPR_DMA = $4014 JOYPAD_PORT = $4016 JOYPAD_PORT1 = $4016 JOYPAD_PORT2 = $4017 +GTE_TMP = $10 ; No zero page references in the assembly to this location ; GAME SPECIFIC DEFINES ObjectOffset = $08 @@ -271,13 +272,13 @@ Misc_SprDataOffset = $06f3 SprDataOffset_Ctrl = $03ee Player_State = $1d -Enemy_State = $1e +Enemy_State = $1e ; (11) Lots of ,y indexing on this variable Fireball_State = $24 Block_State = $26 -Misc_State = $2a +Misc_State = $2a ; (4) Lots of ,y indexing on this variable Player_MovingDir = $45 -Enemy_MovingDir = $46 +Enemy_MovingDir = $46 ; (1) SprObject_X_Speed = $57 Player_X_Speed = $57 @@ -292,41 +293,41 @@ JumpspringForce = $06db SprObject_PageLoc = $6d Player_PageLoc = $6d -Enemy_PageLoc = $6e +Enemy_PageLoc = $6e ; (6) Fireball_PageLoc = $74 -Block_PageLoc = $76 -Misc_PageLoc = $7a +Block_PageLoc = $76 ; (1) +Misc_PageLoc = $7a ; (2) Bubble_PageLoc = $83 SprObject_X_Position = $86 Player_X_Position = $86 -Enemy_X_Position = $87 +Enemy_X_Position = $87 ; Fix ,y indexing (7) Fireball_X_Position = $8d -Block_X_Position = $8f -Misc_X_Position = $93 +Block_X_Position = $8f ; (1) +Misc_X_Position = $93 ; (2) Bubble_X_Position = $9c SprObject_Y_Speed = $9f Player_Y_Speed = $9f -Enemy_Y_Speed = $a0 +Enemy_Y_Speed = $a0 ; (4) Fireball_Y_Speed = $a6 Block_Y_Speed = $a8 -Misc_Y_Speed = $ac +Misc_Y_Speed = $ac ; (1) SprObject_Y_HighPos = $b5 Player_Y_HighPos = $b5 -Enemy_Y_HighPos = $b6 +Enemy_Y_HighPos = $b6 ; (1) Fireball_Y_HighPos = $bc Block_Y_HighPos = $be -Misc_Y_HighPos = $c2 +Misc_Y_HighPos = $c2 ; (1) Bubble_Y_HighPos = $cb SprObject_Y_Position = $ce Player_Y_Position = $ce -Enemy_Y_Position = $cf +Enemy_Y_Position = $cf ; (11) Fireball_Y_Position = $d5 -Block_Y_Position = $d7 -Misc_Y_Position = $db +Block_Y_Position = $d7 ; (1) +Misc_Y_Position = $db ; (2) Bubble_Y_Position = $e4 SprObject_Rel_XPos = $03ad @@ -374,8 +375,8 @@ Misc_BoundBoxCtrl = $04a2 EnemyFrenzyBuffer = $06cb EnemyFrenzyQueue = $06cd -Enemy_Flag = $0f -Enemy_ID = $16 +Enemy_Flag = $0f ; (4) +Enemy_ID = $16 ; (7) PlayerGfxOffset = $06d5 Player_XSpeedAbsolute = $0700 @@ -682,7 +683,11 @@ PPUDATA_WRITE EXT PPUDMA_WRITE EXT ROMBase ENT - ds $8000-14-50-14 + ds $7800-14-50-14 + +; Macro to replace sta abs,y instructions that access zero page space with direct page +; instruction to actually get the correct data on the direct page _and_ bank memory. +; That way any lda 00,x or lda 0000,y will ; Hooks to call back to the GTE harness for PPU memory-mapped accesses mx %11 @@ -3708,12 +3713,23 @@ NoKillE dex ;do this until all FrenzyIDData db FlyCheepCheepFrenzy, BBill_CCheep_Frenzy, -AreaFrenzy ldx $00 ;use area object identifier bit as offset - lda FrenzyIDData-8,x ;note that it starts at 8, thus weird address here - ldy #$05 -FreCompLoop dey ;check regular slots of enemy object buffer +;AreaFrenzy ldx $00 ;use area object identifier bit as offset +; lda FrenzyIDData-8,x ;note that it starts at 8, thus weird address here +; ldy #$05 +;FreCompLoop dey ;check regular slots of enemy object buffer +; bmi ExitAFrenzy ;if all slots checked and enemy object not found, branch to store +; cmp Enemy_ID,y ;check for enemy object in buffer versus frenzy object +; bne FreCompLoop +; lda #$00 ;if enemy object already present, nullify queue and leave +;ExitAFrenzy sta EnemyFrenzyQueue ;store enemy into frenzy queue +; rts + +AreaFrenzy ldy $00 ;use area object identifier bit as offset + lda FrenzyIDData-8,y ;note that it starts at 8, thus weird address here + ldx #$05 +FreCompLoop dex ;check regular slots of enemy object buffer bmi ExitAFrenzy ;if all slots checked and enemy object not found, branch to store - cmp Enemy_ID,y ;check for enemy object in buffer versus frenzy object + cmp Enemy_ID,x ;check for enemy object in buffer versus frenzy object bne FreCompLoop lda #$00 ;if enemy object already present, nullify queue and leave ExitAFrenzy sta EnemyFrenzyQueue ;store enemy into frenzy queue @@ -6783,12 +6799,30 @@ Setup_Vine sta Enemy_ID,x ;store in buffer lda #$01 sta Enemy_Flag,x ;set flag for enemy object buffer - lda Block_PageLoc,y - sta Enemy_PageLoc,x ;copy page location from previous object - lda Block_X_Position,y - sta Enemy_X_Position,x ;copy horizontal coordinate from previous object - lda Block_Y_Position,y + +; lda Block_PageLoc,y ; FIXME +; sta Enemy_PageLoc,x ;copy page location from previous object +; lda Block_X_Position,y ; FIXME +; sta Enemy_X_Position,x ;copy horizontal coordinate from previous object +; lda Block_Y_Position,y ; FIXME +; sta Enemy_Y_Position,x ;copy vertical coordinate from previous object + stx GTE_TMP + tyx + + lda Block_PageLoc,x ; FIXME + pha + lda Block_X_Position,x ; FIXME + pha + lda Block_Y_Position,x ; FIXME + + ldx GTE_TMP sta Enemy_Y_Position,x ;copy vertical coordinate from previous object + pla + sta Enemy_X_Position,x ;copy horizontal coordinate from previous object + pla + sta Enemy_PageLoc,x ;copy page location from previous object + + ldy VineFlagOffset ;load vine flag/offset to next available vine slot bne NextVO ;if set at all, don't bother to store vertical sta VineStart_Y_Position ;otherwise store vertical coordinate here @@ -6981,7 +7015,12 @@ SpawnHammerObj lda PseudoRandomBitReg+1 and #%00001000 ;get d3 from same part of LSFR SetMOfs tay ;use either d3 or d2-d0 for offset here - lda Misc_State,y ;if any values loaded in + +; lda Misc_State,y ;if any values loaded in + tyx + lda Misc_State,x +; x is set immediately on both paths + bne NoHammer ;$2a-$32 where offset is then leave with carry clear ldx HammerEnemyOfsData,y ;get offset of enemy slot to check using Y as offset lda Enemy_Flag,x ;check enemy buffer flag at offset @@ -6990,7 +7029,13 @@ SetMOfs tay ;use either d3 or d txa sta HammerEnemyOffset,y ;save here lda #$90 - sta Misc_State,y ;save hammer's state here + +; sta Misc_State,y ;save hammer's state here + phx + tyx + sta Misc_State,x + plx + lda #$07 sta Misc_BoundBoxCtrl,y ;set something else entirely, here sec ;return with carry set @@ -7030,23 +7075,47 @@ ProcHammerObj jmp RunAllH ;branch to essential subroutines SetHSpd lda #$fe sta Misc_Y_Speed,x ;set hammer's vertical speed - lda Enemy_State,y ;get enemy object state + +; No need to preserve x here because it's loaded afterward + tyx +; lda Enemy_State,y ;get enemy object state + lda Enemy_State,x and #%11110111 ;mask out d3 - sta Enemy_State,y ;store new state +; sta Enemy_State,y ;store new state + sta Enemy_State,x + ldx Enemy_MovingDir,y ;get enemy's moving direction dex ;decrement to use as offset lda HammerXSpdData,x ;get proper speed to use based on moving direction ldx ObjectOffset ;reobtain hammer's buffer offset sta Misc_X_Speed,x ;set hammer's horizontal speed + SetHPos dec Misc_State,x ;decrement hammer's state - lda Enemy_X_Position,y ;get enemy's horizontal position + + stx GTE_TMP + +; lda Enemy_X_Position,y ;get enemy's horizontal position + tyx + lda Enemy_X_Position,x + ldx GTE_TMP + clc adc #$02 ;set position 2 pixels to the right sta Misc_X_Position,x ;store as hammer's horizontal position - lda Enemy_PageLoc,y ;get enemy's page location + +; lda Enemy_PageLoc,y ;get enemy's page location + tyx + lda Enemy_PageLoc,x + ldx GTE_TMP + adc #$00 ;add carry sta Misc_PageLoc,x ;store as hammer's page location - lda Enemy_Y_Position,y ;get enemy's vertical position + +; lda Enemy_Y_Position,y ;get enemy's vertical position + tyx + lda Enemy_Y_Position,x + ldx GTE_TMP + sec sbc #$0a ;move position 10 pixels upward sta Misc_Y_Position,x ;store as hammer's vertical position @@ -7066,50 +7135,98 @@ RunHSubs jsr GetMiscOffscreenBits ;get offscreen info CoinBlock jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot +; lda Block_PageLoc,x ;get page location of block object +; sta Misc_PageLoc,y ;store as page location of misc object +; lda Block_X_Position,x ;get horizontal coordinate of block object +; ora #$05 ;add 5 pixels +; sta Misc_X_Position,y ;store as horizontal coordinate of misc object +; lda Block_Y_Position,x ;get vertical coordinate of block object +; sbc #$10 ;subtract 16 pixels +; sta Misc_Y_Position,y ;store as vertical coordinate of misc object + + stx GTE_TMP lda Block_PageLoc,x ;get page location of block object - sta Misc_PageLoc,y ;store as page location of misc object + tyx + sta Misc_PageLoc,x ;store as page location of misc object + ldx GTE_TMP lda Block_X_Position,x ;get horizontal coordinate of block object ora #$05 ;add 5 pixels - sta Misc_X_Position,y ;store as horizontal coordinate of misc object + tyx + sta Misc_X_Position,x ;store as horizontal coordinate of misc object + ldx GTE_TMP lda Block_Y_Position,x ;get vertical coordinate of block object sbc #$10 ;subtract 16 pixels - sta Misc_Y_Position,y ;store as vertical coordinate of misc object + tyx + sta Misc_Y_Position,x ;store as vertical coordinate of misc object + ldx GTE_TMP + jmp JCoinC ;jump to rest of code as applies to this misc object SetupJumpCoin jsr FindEmptyMiscSlot ;set offset for empty or last misc object buffer slot lda Block_PageLoc2,x ;get page location saved earlier - sta Misc_PageLoc,y ;and save as page location for misc object +; sta Misc_PageLoc,y ;and save as page location for misc object + phx + tyx + sta Misc_PageLoc,x + lda $06 ;get low byte of block buffer offset asl asl ;multiply by 16 to use lower nybble asl asl ora #$05 ;add five pixels - sta Misc_X_Position,y ;save as horizontal coordinate for misc object +; sta Misc_X_Position,y ;save as horizontal coordinate for misc object + sta Misc_X_Position,X + lda $02 ;get vertical high nybble offset from earlier adc #$20 ;add 32 pixels for the status bar - sta Misc_Y_Position,y ;store as vertical coordinate +; sta Misc_Y_Position,y ;store as vertical coordinate + sta Misc_Y_Position,x + plx + JCoinC lda #$fb - sta Misc_Y_Speed,y ;set vertical speed + +; sta Misc_Y_Speed,y ;set vertical speed + phx + tyx + sta Misc_Y_Speed,x + lda #$01 - sta Misc_Y_HighPos,y ;set vertical high byte - sta Misc_State,y ;set state for misc object +; sta Misc_Y_HighPos,y ;set vertical high byte +; sta Misc_State,y ;set state for misc object + sta Misc_Y_HighPos,x + sta Misc_State,x + plx + + sta Square2SoundQueue ;load coin grab sound stx ObjectOffset ;store current control bit as misc object offset jsr GiveOneCoin ;update coin tally on the screen and coin amount variable inc CoinTallyFor1Ups ;increment coin tally used to activate 1-up block flag + rts FindEmptyMiscSlot - ldy #$08 ;start at end of misc objects buffer -FMiscLoop lda Misc_State,y ;get misc object state +; ldy #$08 ;start at end of misc objects buffer +;FMiscLoop lda Misc_State,y ;get misc object state +; beq UseMiscS ;branch if none found to use current offset +; dey ;decrement offset +; cpy #$05 ;do this for three slots +; bne FMiscLoop ;do this until all slots are checked +; ldy #$08 ;if no empty slots found, use last slot +;UseMiscS sty JumpCoinMiscOffset ;store offset of misc object buffer here (residual) + phx + ldx #$08 ;start at end of misc objects buffer +FMiscLoop lda Misc_State,x ;get misc object state beq UseMiscS ;branch if none found to use current offset - dey ;decrement offset - cpy #$05 ;do this for three slots + dex ;decrement offset + cpx #$05 ;do this for three slots bne FMiscLoop ;do this until all slots are checked - ldy #$08 ;if no empty slots found, use last slot -UseMiscS sty JumpCoinMiscOffset ;store offset of misc object buffer here (residual) + ldx #$08 ;if no empty slots found, use last slot +UseMiscS stx JumpCoinMiscOffset ;store offset of misc object buffer here (residual) + txy + plx rts ;------------------------------------------------------------------------------------- @@ -7130,7 +7247,7 @@ MiscLoop stx ObjectOffset ;store misc object ;$02 - used to set maximum speed ProcJumpCoin - ldy Misc_State,x ;check misc object state + ldy Misc_State,x dey ;decrement to see if it's set to 1 beq JCoinRun ;if so, branch to handle jumping coin inc Misc_State,x ;otherwise increment state to either start off or as timer @@ -7880,9 +7997,17 @@ ChkAreaTsk lda AreaParserTaskNum ;check number of ta ChkBowserF pla ;get data from stack and #%00001111 ;mask out high nybble tay - lda Enemy_Flag,y ;use as pointer and load same place with different offset - bne ExitELCore +; lda Enemy_Flag,y ;use as pointer and load same place with different offset +; bne ExitELCore + stx GTE_TMP + tyx + lda Enemy_Flag,x + bne ExitELCore2 + + ldx GTE_TMP sta Enemy_Flag,x ;if second enemy flag not set, also clear first one +ExitELCore2 ldx GTE_TMP + ExitELCore rts ;-------------------------------- @@ -8384,7 +8509,13 @@ LakituAndSpinyHandler lda #$80 ;set timer sta FrenzyEnemyTimer ldy #$04 ;start with the last enemy slot -ChkLak lda Enemy_ID,y ;check all enemy slots to see +ChkLak +; lda Enemy_ID,y ;check all enemy slots to see + phx + tyx + lda Enemy_ID,x + plx + cmp #Lakitu ;if lakitu is on one of them beq CreateSpiny ;if so, branch out of this loop dey ;otherwise check another slot @@ -8415,15 +8546,31 @@ CreateSpiny lda Player_Y_Position ;if player above a certain point, branch to leave cmp #$2c bcc ExLSHand - lda Enemy_State,y ;if lakitu is not in normal state, branch to leave +; lda Enemy_State,y ;if lakitu is not in normal state, branch to leave + stx GTE_TMP + tyx + lda Enemy_State,x + ldx GTE_TMP + bne ExLSHand - lda Enemy_PageLoc,y ;store horizontal coordinates (high and low) of lakitu +; lda Enemy_PageLoc,y ;store horizontal coordinates (high and low) of lakitu + tyx + lda Enemy_PageLoc,x + ldx GTE_TMP sta Enemy_PageLoc,x ;into the coordinates of the spiny we're going to create - lda Enemy_X_Position,y + +; lda Enemy_X_Position,y + tyx + lda Enemy_X_Position,x + ldx GTE_TMP sta Enemy_X_Position,x lda #$01 ;put spiny within vertical screen unit sta Enemy_Y_HighPos,x - lda Enemy_Y_Position,y ;put spiny eight pixels above where lakitu is + +; lda Enemy_Y_Position,y ;put spiny eight pixels above where lakitu is + tyx + lda Enemy_Y_Position,x + ldx GTE_TMP sec sbc #$08 sta Enemy_Y_Position,x @@ -8628,23 +8775,64 @@ InitBowser ;-------------------------------- DuplicateEnemyObj - ldy #$ff ;start at beginning of enemy slots -FSLoop iny ;increment one slot - lda Enemy_Flag,y ;check enemy buffer flag for empty slot - bne FSLoop ;if set, branch and keep checking - sty DuplicateObj_Offset ;otherwise set offset here +; ldy #$ff ;start at beginning of enemy slots +;:FSLoop iny ;increment one slot +; lda Enemy_Flag,y ;check enemy buffer flag for empty slot +; bne :FSLoop ;if set, branch and keep checking +; sty DuplicateObj_Offset ;otherwise set offset here +; txa ;transfer original enemy buffer offset +; ora #%10000000 ;store with d7 set as flag in new enemy +; sta Enemy_Flag,y ;slot as well as enemy offset +; lda Enemy_PageLoc,x +; sta Enemy_PageLoc,y ;copy page location and horizontal coordinates +; lda Enemy_X_Position,x ;from original enemy to new enemy +; sta Enemy_X_Position,y +; lda #$01 +; sta Enemy_Flag,x ;set flag as normal for original enemy +; sta Enemy_Y_HighPos,y ;set high vertical byte for new enemy +; lda Enemy_Y_Position,x +; sta Enemy_Y_Position,y ;copy vertical coordinate from original to new + + stx GTE_TMP + ldx #$ff ;start at beginning of enemy slots +:FSLoop inx ;increment one slot + lda Enemy_Flag,x ;check enemy buffer flag for empty slot + bne :FSLoop ;if set, branch and keep checking + stx DuplicateObj_Offset ;otherwise set offset here + + ldx GTE_TMP txa ;transfer original enemy buffer offset ora #%10000000 ;store with d7 set as flag in new enemy - sta Enemy_Flag,y ;slot as well as enemy offset +; sta Enemy_Flag,y ;slot as well as enemy offset + pha + lda Enemy_PageLoc,x - sta Enemy_PageLoc,y ;copy page location and horizontal coordinates +; sta Enemy_PageLoc,y ;copy page location and horizontal coordinates + pha + lda Enemy_X_Position,x ;from original enemy to new enemy - sta Enemy_X_Position,y +; sta Enemy_X_Position,y + pha + lda #$01 sta Enemy_Flag,x ;set flag as normal for original enemy - sta Enemy_Y_HighPos,y ;set high vertical byte for new enemy +; sta Enemy_Y_HighPos,y ;set high vertical byte for new enemy + lda Enemy_Y_Position,x - sta Enemy_Y_Position,y ;copy vertical coordinate from original to new +; sta Enemy_Y_Position,y ;copy vertical coordinate from original to new + + tyx + sta Enemy_Y_Position,x + lda #$01 + sta Enemy_Y_HighPos,x + pla + sta Enemy_X_Position,x + pla + sta Enemy_PageLoc,x + pla + sta Enemy_Flag,x + + ldx GTE_TMP FlmEx rts ;and then leave ;-------------------------------- @@ -8663,7 +8851,13 @@ InitBowserFlame ora #Sfx_BowserFlame ;load bowser's flame sound into queue sta NoiseSoundQueue ldy BowserFront_Offset ;get bowser's buffer offset - lda Enemy_ID,y ;check for bowser + +; lda Enemy_ID,y ;check for bowser + phx + tyx + lda Enemy_ID,x + plx + cmp #Bowser beq SpawnFromMouth ;branch if found jsr SetFlameTimer ;get timer data based on flame counter @@ -8692,13 +8886,27 @@ PutAtRightExtent jmp FinishFlame ;skip this part to finish setting values SpawnFromMouth - lda Enemy_X_Position,y ;get bowser's horizontal position +; lda Enemy_X_Position,y ;get bowser's horizontal position + stx GTE_TMP + tyx + lda Enemy_X_Position,x + ldx GTE_TMP + sec sbc #$0e ;subtract 14 pixels sta Enemy_X_Position,x ;save as flame's horizontal position - lda Enemy_PageLoc,y +; lda Enemy_PageLoc,y + tyx + lda Enemy_PageLoc,x + ldx GTE_TMP + sta Enemy_PageLoc,x ;copy page location from bowser to flame - lda Enemy_Y_Position,y + +; lda Enemy_Y_Position,y + tyx + lda Enemy_Y_Position,x + ldx GTE_TMP + clc ;add 8 pixels to bowser's vertical position adc #$08 sta Enemy_Y_Position,x ;save as flame's vertical position @@ -8741,25 +8949,40 @@ InitFireworks lda #$20 ;otherwise reset timer sta FrenzyEnemyTimer dec FireworksCounter ;decrement for each explosion - ldy #$06 ;start at last slot -StarFChk dey - lda Enemy_ID,y ;check for presence of star flag object +; ldy #$06 ;start at last slot +;:StarFChk dey +; lda Enemy_ID,y ;check for presence of star flag object + + stx GTE_TMP + ldx #$06 ;start at last slot +:StarFChk dex + lda Enemy_ID,x ;check for presence of star flag object + cmp #StarFlagObject ;if there isn't a star flag object, - bne StarFChk ;routine goes into infinite loop = crash - lda Enemy_X_Position,y + bne :StarFChk ;routine goes into infinite loop = crash + +; lda Enemy_X_Position,y + lda Enemy_X_Position,x sec ;get horizontal coordinate of star flag object, then sbc #$30 ;subtract 48 pixels from it and save to pha ;the stack - lda Enemy_PageLoc,y + +; lda Enemy_PageLoc,y + lda Enemy_PageLoc,x sbc #$00 ;subtract the carry from the page location sta $00 ;of the star flag object lda FireworksCounter ;get fireworks counter clc - adc Enemy_State,y ;add state of star flag object (possibly not necessary) + +; adc Enemy_State,y ;add state of star flag object (possibly not necessary) + adc Enemy_State,x + ldx GTE_TMP + tay ;use as offset pla ;get saved horizontal coordinate of star flag - 48 pixels clc adc FireworksXPosData,y ;add number based on offset of fireworks counter + sta Enemy_X_Position,x ;store as the fireworks object horizontal coordinate lda $00 adc #$00 ;add carry and store as page location for @@ -8832,18 +9055,35 @@ AddFBit ora BitMFilter ;add bit to already jmp CheckpointEnemyID ;process our new enemy object DoBulletBills - ldy #$ff ;start at beginning of enemy slots -BB_SLoop iny ;move onto the next slot - cpy #$05 ;branch to play sound if we've done all slots +; ldy #$ff ;start at beginning of enemy slots +;BB_SLoop iny ;move onto the next slot +; cpy #$05 ;branch to play sound if we've done all slots +; bcs FireBulletBill +; lda Enemy_Flag,y ;if enemy buffer flag not set, +; beq BB_SLoop ;loop back and check another slot +; lda Enemy_ID,y +; cmp #BulletBill_FrenzyVar ;check enemy identifier for +; bne BB_SLoop ;bullet bill object (frenzy variant) + + stx GTE_TMP + ldx #$ff ;start at beginning of enemy slots +:BB_SLoop inx ;move onto the next slot + cpx #$05 ;branch to play sound if we've done all slots bcs FireBulletBill - lda Enemy_Flag,y ;if enemy buffer flag not set, - beq BB_SLoop ;loop back and check another slot - lda Enemy_ID,y + lda Enemy_Flag,x ;if enemy buffer flag not set, + beq :BB_SLoop ;loop back and check another slot + lda Enemy_ID,x cmp #BulletBill_FrenzyVar ;check enemy identifier for - bne BB_SLoop ;bullet bill object (frenzy variant) + bne :BB_SLoop ;bullet bill object (frenzy variant) + txy + stx GTE_TMP + ExF17 rts ;if found, leave FireBulletBill + txy + stx GTE_TMP + lda Square2SoundQueue ora #Sfx_Blast ;play fireworks/gunfire sound sta Square2SoundQueue @@ -8954,14 +9194,23 @@ NoFrenzyCode ;-------------------------------- EndFrenzy - ldy #$05 ;start at last slot -LakituChk lda Enemy_ID,y ;check enemy identifiers + phx +; ldy #$05 ;start at last slot +;:LakituChk lda Enemy_ID,y ;check enemy identifiers + ldx #$05 +:LakituChk lda Enemy_ID,x ;check enemy identifiers cmp #Lakitu ;for lakitu - bne NextFSlot + bne :NextFSlot lda #$01 ;if found, set state - sta Enemy_State,y -NextFSlot dey ;move onto the next slot - bpl LakituChk ;do this until all slots are checked +; sta Enemy_State,y +;:NextFSlot dey ;move onto the next slot + sta Enemy_State,x +:NextFSlot dex ;move onto the next slot + bpl :LakituChk ;do this until all slots are checked + + txy + plx + lda #$00 sta EnemyFrenzyBuffer ;empty enemy frenzy buffer sta Enemy_Flag,x ;disable enemy buffer flag for this object @@ -10083,11 +10332,20 @@ ChkLS lda Enemy_State,x ;if lakitu's enemy bne SetLSpd ;load horizontal speed and do unconditional branch Fr12S lda #Spiny sta EnemyFrenzyBuffer ;set spiny identifier in frenzy buffer - ldy #$02 -LdLDa lda LakituDiffAdj,y ;load values - sta $0001,y ;store in zero page - dey - bpl LdLDa ;do this until all values are stired + +; ldy #$02 +;:LdLDa lda LakituDiffAdj,y ;load values +; sta $0001,y ;store in zero page +; dey +; bpl :LdLDa ;do this until all values are stired + phx + ldx #$02 +:LdLDa lda LakituDiffAdj,x ;load values + sta $01,x ;store in zero page + dex + bpl :LdLDa ;do this until all values are stired + plx + jsr PlayerLakituDiff ;execute sub to set speed and create spinys SetLSpd sta LakituMoveSpeed,x ;set movement speed returned from sub ldy #$01 ;set moving direction to right by default @@ -10157,7 +10415,13 @@ ChkSpinyO lda Enemy_ID,x ;check for spiny ob ChkEmySpd lda Enemy_Y_Speed,x ;check vertical speed bne SubDifAdj ;branch if nonzero ldy #$00 ;otherwise reinit offset -SubDifAdj lda $0001,y ;get one of three saved values from earlier +SubDifAdj +; lda $0001,y ;get one of three saved values from earlier + phx + tyx + lda $01,x + plx + ldy $00 ;get saved horizontal difference SPixelLak sec ;subtract one for each pixel of horizontal difference sbc #$01 ;from one of three saved values @@ -10376,15 +10640,36 @@ CopyFToR tya ;move bowser's rear clc adc Enemy_X_Position,x ;add to bowser's front object horizontal coordinate ldy DuplicateObj_Offset ;get bowser's rear object offset - sta Enemy_X_Position,y ;store A as bowser's rear horizontal coordinate + + stx GTE_TMP +; sta Enemy_X_Position,y ;store A as bowser's rear horizontal coordinate + tyx + sta Enemy_X_Position,x ;store A as bowser's rear horizontal coordinate + ldx GTE_TMP + lda Enemy_Y_Position,x clc ;add eight pixels to bowser's front object adc #$08 ;vertical coordinate and store as vertical coordinate - sta Enemy_Y_Position,y ;for bowser's rear + +; sta Enemy_Y_Position,y ;for bowser's rear + tyx + sta Enemy_Y_Position,x + ldx GTE_TMP + lda Enemy_State,x - sta Enemy_State,y ;copy enemy state directly from front to rear +; sta Enemy_State,y ;copy enemy state directly from front to rear + tyx + sta Enemy_State,x + ldx GTE_TMP + + lda Enemy_MovingDir,x - sta Enemy_MovingDir,y ;copy moving direction also +; sta Enemy_MovingDir,y ;copy moving direction also + tyx + sta Enemy_MovingDir,x + ldx GTE_TMP + + lda ObjectOffset ;save enemy object offset of front to stack pha ldx DuplicateObj_Offset ;put enemy object offset of rear as current @@ -10800,13 +11085,23 @@ MakePlatformFall jmp InitPlatformFall ;make platforms fall ChkOtherForFall - cmp Enemy_Y_Position,y ;check if other platform is above a certain point +; cmp Enemy_Y_Position,y ;check if other platform is above a certain point + phx + tyx + cmp Enemy_Y_Position,x + plx + bcc ChkToMoveBalPlat ;if not, branch elsewhere cpx $00 ;if collision flag is set to same value as beq MakePlatformFall ;enemy state, branch to make platforms fall clc adc #$02 ;otherwise add 2 pixels to vertical position - sta Enemy_Y_Position,y ;of other platform and branch elsewhere +; sta Enemy_Y_Position,y ;of other platform and branch elsewhere + phx + tyx + sta Enemy_Y_Position,x + plx + jmp StopPlatforms ;jump to stop movement and do not return ChkToMoveBalPlat @@ -10840,8 +11135,15 @@ DoOtherPlatform sec sbc Enemy_Y_Position,x ;get difference of old vs. new coordinate clc - adc Enemy_Y_Position,y ;add difference to vertical coordinate of other - sta Enemy_Y_Position,y ;platform to move it in the opposite direction + +; adc Enemy_Y_Position,y ;add difference to vertical coordinate of other +; sta Enemy_Y_Position,y ;platform to move it in the opposite direction + phx + tyx + adc Enemy_Y_Position,x + sta Enemy_Y_Position,x + plx + lda PlatformCollisionFlag,x ;if no collision, skip this part here bmi DrawEraseRope tax ;put offset which collision occurred here @@ -10849,13 +11151,23 @@ DoOtherPlatform DrawEraseRope ldy ObjectOffset ;get enemy object offset - lda Enemy_Y_Speed,y ;check to see if current platform is +; lda Enemy_Y_Speed,y ;check to see if current platform is + phx + tyx + lda Enemy_Y_Speed,x + plx + ora Enemy_Y_MoveForce,y ;moving at all beq ExitRp ;if not, skip all of this and branch to leave ldx VRAM_Buffer1_Offset ;get vram buffer offset cpx #$20 ;if offset beyond a certain point, go ahead bcs ExitRp ;and skip this, branch to leave - lda Enemy_Y_Speed,y +; lda Enemy_Y_Speed,y + phx + tyx + lda Enemy_Y_Speed,x + plx + pha ;save two copies of vertical speed to stack pha jsr SetupPlatformRope ;do a sub to figure out where to put new bg tiles @@ -10865,8 +11177,12 @@ DrawEraseRope sta VRAM_Buffer1+1,x lda #$02 ;set length for 2 bytes sta VRAM_Buffer1+2,x - lda Enemy_Y_Speed,y ;if platform moving upwards, branch - bmi EraseR1 ;to do something else + ; lda Enemy_Y_Speed,y + phx + tyx + lda Enemy_Y_Speed,x + plx + bmi EraseR1 ;to do something else lda #$a2 sta VRAM_Buffer1+3,x ;otherwise put tile numbers for left lda #$a3 ;and right sides of rope in vram buffer @@ -10877,7 +11193,12 @@ EraseR1 lda #$24 ;put blank tiles in sta VRAM_Buffer1+4,x OtherRope - lda Enemy_State,y ;get offset of other platform from state + phx +; lda Enemy_State,y ;get offset of other platform from state + tyx + lda Enemy_State,x + plx + tay ;use as Y here pla ;pull second copy of vertical speed from stack eor #$ff ;invert bits to reverse speed @@ -10909,7 +11230,12 @@ ExitRp ldx ObjectOffset ;get enemy object b SetupPlatformRope pha ;save second/third copy to stack - lda Enemy_X_Position,y ;get horizontal coordinate +; lda Enemy_X_Position,y ;get horizontal coordinate + phx + tyx + lda Enemy_X_Position,x + plx + clc adc #$08 ;add eight pixels ldx SecondaryHardMode ;if secondary hard mode flag set, @@ -10917,7 +11243,12 @@ SetupPlatformRope clc adc #$10 ;otherwise add sixteen more pixels GetLRp pha ;save modified horizontal coordinate to stack - lda Enemy_PageLoc,y +; lda Enemy_PageLoc,y + phx + tyx + lda Enemy_PageLoc,x + plx + adc #$00 ;add carry to page location sta $02 ;and save here pla ;pull modified horizontal coordinate @@ -10953,7 +11284,12 @@ GetHRp txa ;move vertical coor clc adc $00 ;add to horizontal part saved here sta $00 ;save as name table low byte - lda Enemy_Y_Position,y +; lda Enemy_Y_Position,y + phx + tyx + lda Enemy_Y_Position,x + plx + cmp #$e8 ;if vertical position not below the bcc ExPRp ;bottom of the screen, we're done, branch to leave lda $00 @@ -10976,7 +11312,12 @@ InitPlatformFall StopPlatforms jsr InitVStf ;initialize vertical speed and low byte - sta Enemy_Y_Speed,y ;for both platforms and leave +; sta Enemy_Y_Speed,y ;for both platforms and leave + phx + tyx + sta Enemy_Y_Speed,x + plx + sta Enemy_Y_MoveForce,y rts @@ -11696,7 +12037,13 @@ ECLoop stx $01 ;save enemy object ldy $01 ;use second enemy offset for Y bcc NoEnemyCollision ;if carry clear, no collision, branch ahead of this lda Enemy_State,x - ora Enemy_State,y ;check both enemy states for d7 set + +; ora Enemy_State,y ;check both enemy states for d7 set + phx + tyx + ora Enemy_State,x + plx + and #%10000000 bne YesEC ;branch if at least one of them is set lda Enemy_CollisionBits,y ;load first enemy's collision-related bits @@ -11725,7 +12072,12 @@ ExitECRoutine rts ;leave ProcEnemyCollisions - lda Enemy_State,y ;check both enemy states for d5 set +; lda Enemy_State,y ;check both enemy states for d5 set + stx GTE_TMP + tyx + lda Enemy_State,x + ldx GTE_TMP + ora Enemy_State,x and #%00100000 ;if d5 is set in either state, or both, branch bne ExitProcessEColl ;to leave and do nothing else at this point @@ -11735,7 +12087,12 @@ ProcEnemyCollisions lda Enemy_ID,x ;check second enemy identifier for hammer bro cmp #HammerBro ;if hammer bro found in alt state, branch to leave beq ExitProcessEColl - lda Enemy_State,y ;check first enemy state for d7 set + +; lda Enemy_State,y ;check first enemy state for d7 set + tyx + lda Enemy_State,x + ldx GTE_TMP + asl bcc ShellCollisions ;branch if d7 is clear lda #$06 @@ -11760,10 +12117,20 @@ ExitProcessEColl rts ;leave!!! ProcSecondEnemyColl - lda Enemy_State,y ;if first enemy state < $06, branch elsewhere + stx GTE_TMP + +; lda Enemy_State,y ;if first enemy state < $06, branch elsewhere + tyx + lda Enemy_State,x + ldx GTE_TMP + cmp #$06 bcc MoveEOfs - lda Enemy_ID,y ;check first enemy identifier for hammer bro +; lda Enemy_ID,y ;check first enemy identifier for hammer bro + tyx + lda Enemy_ID,x + ldx GTE_TMP + cmp #HammerBro ;if hammer bro found in alt state, branch to leave beq ExitProcessEColl jsr ShellOrBlockDefeat ;otherwise, kill first enemy @@ -16450,7 +16817,7 @@ BrickShatterEnvData ;------------------------------------------------------------------------------------- ;INTERRUPT VECTORS - +; ds 34 dw NonMaskableInterrupt dw Start dw $fff0 ;unused diff --git a/macros/GTE.Macs.s b/macros/GTE.Macs.s index e46fd98..6670ae4 100644 --- a/macros/GTE.Macs.s +++ b/macros/GTE.Macs.s @@ -182,6 +182,7 @@ tileStore equ $0003 vblCallback equ $0004 extSpriteRenderer equ $0005 rawDrawTile equ $0006 +extBG0TileUpdate equ $0007 ; CopyPicToBG1 flags COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" diff --git a/src/Defs.s b/src/Defs.s index c540bd4..4b95a06 100644 --- a/src/Defs.s +++ b/src/Defs.s @@ -195,6 +195,7 @@ tileStore equ $0003 vblCallback equ $0004 ; User routine to be called by VBL interrupt. Set to $000000 to disconnect extSpriteRenderer equ $0005 rawDrawTile equ $0006 +extBG0TileUpdate equ $0007 ; CopyPicToBG1 flags COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" treating the buffer as a 164x208 pixmap with stride of 256 @@ -310,6 +311,7 @@ StartXMod164Tbl EXT LastOffsetTbl EXT BG1StartXMod164Tbl EXT ExtSpriteRenderer EXT +ExtUpdateBG0Tiles EXT ; Tool error codes NO_TIMERS_AVAILABLE equ 10 diff --git a/src/Render.s b/src/Render.s index 2a8be22..5c870e6 100644 --- a/src/Render.s +++ b/src/Render.s @@ -153,10 +153,24 @@ _DoOverlay :disp jsl $000000 rts -; Special NES renderer that externalizes the sprite rendreing in order to exceed the internal limit of 16 sprites +; Special NES renderer that externalizes the sprite rendering in order to exceed the internal limit of 16 sprites _RenderNES jsr _ApplyBG0YPos jsr _ApplyBG0XPosPre + +; Callback to update the tilestore with any new tiles + + lda ExtUpdateBG0Tiles + ora ExtUpdateBG0Tiles+2 + beq :no_tile + + lda ExtUpdateBG0Tiles + stal :patch0+1 + lda ExtUpdateBG0Tiles+1 + stal :patch0+2 +:patch0 jsl $000000 +:no_tile + jsr _ApplyTiles ; This function actually draws the new tiles into the code field ; jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode diff --git a/src/Tool.s b/src/Tool.s index 28b1554..e0f64ba 100644 --- a/src/Tool.s +++ b/src/Tool.s @@ -597,7 +597,9 @@ _TSSetBG1Origin _TSGetTileAt :y equ FirstParam :x equ FirstParam+2 -:output equ FirstParam+4 +:output_id equ FirstParam+4 +:output_x equ FirstParam+6 +:output_y equ FirstParam+8 _TSEntry @@ -609,16 +611,23 @@ _TSGetTileAt jsr _GetTileAt bcc :ok lda #0 + sta :output_x,s + sta :output_y,s bra :out +:ok + txa + sta :output_x,s + tya + sta :output_y,s + ; Load the tile at that tile store location -:ok jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position tax lda TileStore+TS_TILE_ID,x :out - sta :output,s + sta :output_id,s _TSExit #0;#4 @@ -990,7 +999,16 @@ _TSSetAddress sta ExtSpriteRenderer+2 bra :out -:next_4 +:next_4 cmp #extBG0TileUpdate + bne :next_5 + + lda :ptr,s + sta ExtUpdateBG0Tiles + lda :ptr+2,s + sta ExtUpdateBG0Tiles+2 + bra :out +:next_5 + :out _TSExit #0;#6 diff --git a/src/static/TileStore.s b/src/static/TileStore.s index da65cab..7196cd0 100644 --- a/src/static/TileStore.s +++ b/src/static/TileStore.s @@ -562,6 +562,8 @@ BG1YCache ENT ExtSpriteRenderer ENT dw 0,0 +ExtUpdateBG0Tiles ENT + dw 0,0 ; Scaling tables for the BG1 rotation tables. ScalingTables ENT