From cb13c2ae2dd735a0e894214cbc48418bebe6fce8 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Tue, 16 May 2023 12:34:18 -0500 Subject: [PATCH] Secret sauce --- demos/smb/Externals.s | 5 +- demos/smb/Main.s | 720 +++++++++++++++++++++++++++++++++++++- demos/smb/build-image.bat | 1 + demos/smb/chr2.s | 512 +++++++++++++++++++++++++++ demos/smb/package.json | 10 +- demos/smb/palette.s | 69 ++++ demos/smb/ppu.s | 521 +++++++++++++++++++++++++++ demos/smb/rom.s | 372 ++++++++++++-------- macros/GTE.Macs.s | 2 + src/Defs.s | 3 + src/Render.s | 83 ++++- src/SpriteRender.s | 27 ++ src/Tool.s | 36 +- src/blitter/Horz.s | 7 +- src/static/TileStore.s | 3 + 15 files changed, 2199 insertions(+), 172 deletions(-) create mode 100644 demos/smb/chr2.s create mode 100644 demos/smb/palette.s create mode 100644 demos/smb/ppu.s diff --git a/demos/smb/Externals.s b/demos/smb/Externals.s index 67e579a..5123518 100644 --- a/demos/smb/Externals.s +++ b/demos/smb/Externals.s @@ -1 +1,4 @@ -SMBStart EXT ; Base address of the ROM. Should be XX/8000 in the bank the ROM is loaded into \ No newline at end of file +SMBStart EXT ; Base address of the ROM. Should be XX/8000 in the bank the ROM is loaded into +NonMaskableInterrupt EXT ; Called every VBL +ExtIn EXT +ROMBase EXT \ No newline at end of file diff --git a/demos/smb/Main.s b/demos/smb/Main.s index 1c06145..a290818 100644 --- a/demos/smb/Main.s +++ b/demos/smb/Main.s @@ -9,43 +9,735 @@ use GTE.Macs use Externals.s +; Keycodes +LEFT_ARROW equ $08 +RIGHT_ARROW equ $15 +UP_ARROW equ $0B +DOWN_ARROW equ $0A + mx %00 ; Direct page space MyUserId equ 0 +ROMStk equ 2 +ROMZeroPg equ 4 +LastScroll equ 6 +Tmp0 equ 240 +Tmp1 equ 242 +Tmp2 equ 244 +Tmp3 equ 246 phk plb sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program - _MTStartUp ; GTE requires the miscellaneous toolset to be running - pea $00A0 ; Load from System:Tools - pea $0100 ; Tool160, version 1.0 - _LoadOneTool + stz LastScroll - clc ; Give GTE a page of direct page memory +; 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 tdc - adc #$0100 - pha - pea $0000 ; Default fast mode - lda MyUserId ; Pass the userId for memory allocation - pha - _GTEStartUp + clc + adc #$300 + sta ROMZeroPg + clc + adc #$1FF ; Stack starts at the top of the page + sta ROMStk + +* ldx #SMBStart +* jsr romxfer + +* ; Call the main loop 23 times +* lda #23 +* :pre pha +* jsr triggerNMI +* pla +* dec +* bne :pre + +* :gloop +* jsr triggerNMI +* bra :gloop + +* brl Quit + + lda #ENGINE_MODE_USER_TOOL ; Engine in Fast Mode as a User Tool + jsr GTEStartUp ; Load and install the GTE User Tool + +; Install a VBL callback task that we will use to invoke the NMI routine in the ROM + pea vblCallback + pea #^nmiTask + pea #nmiTask + _GTESetAddress + +; Install a custom sprite renderer that will read directly off of the OAM table + pea extSpriteRenderer + pea #^drawOAMSprites + pea #drawOAMSprites + _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 + lda 1,s + sta drawTilePatch+1 + lda 2,s + sta drawTilePatch+2 + pla + plx ; Initialize the graphics screen playfield (256x160). The NES is 240 lines high, so 160 ; is a reasonable compromise. - pea #160 + pea #128 pea #200 _GTESetScreenMode + pea $0000 + pea #^Greyscale + pea #Greyscale + _GTESetPalette + ; Convert the CHR ROM from the cart into GTE tiles -; jsr LoadTilesFromROM + ldx #0 + ldy #0 +:tloop + phx + phy + lda #TileBuff + jsr ConvertROMTile + lda 1,s + + pha + inc + pha + pea #^TileBuff + pea #TileBuff + _GTELoadTileSet + + ply + iny + + pla + clc + adc #16 ; NES tiles are 16 bytes + tax + 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 +; than a choppy refresh rate. +; +; Call the boot code in the ROM + + ldx #SMBStart + jsr romxfer + +EvtLoop +:spin lda ppustatus ; Set the bit that the VBL has started + bit #$80 + beq :spin + and #$FF7F + sta ppustatus + + jsr triggerNMI + + lda #$2000 + jsr CopyNametable + + lda ppuscroll+1 + and #$00FF + lsr + pha + sta LastScroll + lda ppuscroll + and #$00FF + pha + _GTESetBG0Origin + + pea $FFFF ; NES mode + _GTERender + + pha + _GTEReadControl + pla + +; Map the GTE field to the NES controller format: A-B-Select-Start-Up-Down-Left-Right + + pha + and #PAD_BUTTON_A+PAD_BUTTON_B ; bits 0x200 and 0x100 + lsr + lsr + sta native_joy + lda 1,s + and #$00FF + cmp #'n' + bne *+7 + lda #$0020 + bra :nes_merge + cmp #'m' + bne *+7 + lda #$0010 + bra :nes_merge + cmp #UP_ARROW + bne *+7 + lda #$0008 + bra :nes_merge + cmp #DOWN_ARROW + bne *+7 + lda #$0004 + bra :nes_merge + cmp #LEFT_ARROW + bne *+7 + lda #$0002 + bra :nes_merge + cmp #RIGHT_ARROW + bne :nes_done + lda #$0001 +:nes_merge ora native_joy + sta native_joy +:nes_done + pla +; bit #PAD_KEY_DOWN +; bne *+5 +; brl EvtLoop + + and #$007F + + cmp #'1' ; Copy nametable 1 + bne :not_1 + lda #$2000 + jsr CopyNametable + brl EvtLoop +:not_1 + + cmp #'2' + bne :not_2 + lda #$2400 + jsr CopyNametable +:not_2 + + cmp #'s' ; next step + bne :not_n + jsr triggerNMI +:not_n + + cmp #'q' + beq Exit + brl EvtLoop + +Exit _GTEShutDown +Quit _QuitGS qtRec qtRec adrl $0000 - da $00 \ No newline at end of file + da $00 +Greyscale dw $0000,$5555,$AAAA,$FFFF + dw $0000,$5555,$AAAA,$FFFF + dw $0000,$5555,$AAAA,$FFFF + dw $0000,$5555,$AAAA,$FFFF + +; Copy the tile and attribute bytes into the GTE buffer +; +; A = Nametable address ($2000, $2400, $2800, or $2C00) +CopyNametable + lda ppuctrl + and #$0003 ; nametable select bits + xba + asl + asl + clc + adc #2*32 + sta Tmp0 ; base address offset into nametable memory + +; ora #$2000 +; clc +; adc #PPU_MEM +; clc +; adc #2*32 +; sta Tmp0 ; base address + +; 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 + + lda ppuscroll+1 + lsr + lsr + lsr + and #$001F + sta Tmp1 ; starting offset + +; 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 + asl + asl + asl + asl + asl + +; lda #$0000+{2*32} + sta Tmp2 + lda #0 + sta Tmp3 + bra :xloop + +:offset + lda Tmp0 ; Get the base address for this line + ora Tmp1 ; Move over to the first horizontal tile + sta Tmp2 ; coarse x-scroll + + lda Tmp1 + sta Tmp3 ; Keep a separate count for the GTE tile position +:xloop + phx ; Save X and Y + phy + + pei Tmp3 ; Wrap-around tile column + 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 (handle nametable wrapping) + + lda #$001F + and Tmp2 + cmp #$001F + bne :inc_x + txa + and #$FFE0 + eor #$0400 + sta Tmp2 + bra :x_hop + +:inc_x inx + stx Tmp2 +:x_hop + + _GTESetTile + + ply + plx + + lda Tmp3 + inc + cmp #41 + bcc *+5 + lda #0 + sta Tmp3 + + inx + cpx #33 + bcc :xloop + + lda Tmp0 + clc + adc #32 + sta Tmp0 + + iny + cpy #25 + bcc :yloop + + rts + +; Trigger an NMI in the ROM +triggerNMI + ldal ppuctrl ; If the ROM has not enabled VBL NMI, also skip + bit #$80 + beq :skip + + lda ppustatus ; Set the bit that the VBL has started + ora #$80 + sta ppustatus + + ldx #NonMaskableInterrupt + jmp romxfer +:skip rts + +; Expose joypad bits from GTE to the ROM: A-B-Select-Start-Up-Down-Left-Right +native_joy ENT + db 0,0 + +; X = address in the rom file +; A = address to write + +ConvertROMTile +DPtr equ Tmp1 +MPtr equ Tmp2 + + sta DPtr + clc + adc #32 ; Move to the mask + sta MPtr + lda #0 ; Clear A and B + + sep #$20 ; 8-bit mode + ldy #0 + +:loop + lda CHR_ROM,x ; Load the high bits + rol + rol + rol + rol + and #$06 + sta Tmp0 + + lda CHR_ROM+8,x + and #$C0 + lsr + lsr + lsr + ora Tmp0 ; Combine the two and create a lookup value + + phx + tax + lda DLUT,x ; Look up the two, 4-bit pixel values for this quad of bits + sta (DPtr),y + lda MLUT,x + sta (MPtr),y + iny + plx + +; Repeat for bits 4 & 5 + + ldal CHR_ROM,x ; Load the high bits + and #$30 + lsr + lsr + lsr + sta Tmp0 + + ldal CHR_ROM+8,x + and #$30 + lsr + ora Tmp0 ; Combine the two and create a lookup value + + phx + tax + lda DLUT,x + sta (DPtr),y + lda MLUT,x + sta (MPtr),y + iny + plx + +; Repeat for bits 2 & 3 + + ldal CHR_ROM,x ; Load the high bits + and #$0C + lsr + sta Tmp0 + + ldal CHR_ROM+8,x + and #$0C + asl + ora Tmp0 ; Combine the two and create a lookup value + + phx + tax + lda DLUT,x + sta (DPtr),y + lda MLUT,x + sta (MPtr),y + iny + plx + +; Repeat for bits 0 & 1 + + ldal CHR_ROM,x ; Load the high bits + and #$03 + asl + sta Tmp0 + + ldal CHR_ROM+8,x + and #$03 + asl + asl + asl + ora Tmp0 ; Combine the two and create a lookup value + + phx + tax + lda DLUT,x + sta (DPtr),y + lda MLUT,x + sta (MPtr),y + iny + plx + + inx + cpy #32 + bcs :done + brl :loop +:done + rep #$20 + +; Flip the tile before returning + ldy #16 + ldx DPtr +:rloop + lda: 0,x + jsr reverse + sta: 66,x + lda: 2,x + jsr reverse + sta: 64,x + inx + inx + inx + inx + dey + bne :rloop + rts + +reverse + xba + sta Tmp0 + and #$0F0F + asl + asl + asl + asl + sta Tmp1 + lda Tmp0 + and #$F0F0 + lsr + lsr + lsr + lsr + ora Tmp1 + rts + + +DLUT dw $00,$01,$10,$11 ; CHR_ROM[0] = xx, CHR_ROM[8] = 00 + dw $02,$03,$12,$13 ; CHR_ROM[0] = xx, CHR_ROM[8] = 01 + dw $20,$21,$30,$31 ; CHR_ROM[0] = xx, CHR_ROM[8] = 10 + dw $22,$23,$32,$33 ; CHR_ROM[0] = xx, CHR_ROM[8] = 11 + +MLUT dw $FF,$F0,$0F,$00 + dw $F0,$F0,$00,$00 + dw $0F,$00,$0F,$00 + dw $00,$00,$00,$00 + +; Extracted tiles +TileBuff ds 128 + +GTEStartUp + pha ; Save engine mode + + pea $0000 + _LoaderStatus + pla + + pea $0000 + pea $0000 + pea $0000 + pea $0000 + pea $0000 ; result space + + lda MyUserId + pha + + pea #^ToolPath + pea #ToolPath + pea $0001 ; do not load into special memory + _InitialLoad + bcc *+4 + brk $01 + + ply + pla ; Address of the loaded tool + plx + ply + ply + + pea $8000 ; User toolset + pea $00A0 ; Set the tool set number + phx + pha ; Address of function pointer table + _SetTSPtr + bcc *+4 + brk $02 + + plx ; Pop the Engine Mode value + + clc ; Give GTE two pages of direct page memory + tdc + adc #$0100 + pha + phx + lda MyUserId ; Pass the userId for memory allocation + pha + _GTEStartUp + bcc *+4 + brk $03 + + rts + +ToolPath str '1/Tool160' + +* ; Store sprite and tile data as 0000000w wxxyyzz0 to facilitate swizzle loads + +* ; sprite high priority (8-bit acc, compiled) +* ldy #PPU_DATA +* lda screen +* andl tilemask,x +* ora (palptr),y ; 512 byte lookup table per palette +* sta screen + +* ; sprite low (this is just slow) .... +* lda screen +* beq empty +* ; do 4 bits to figure out a mask and then + + +* bit #$FF00 +* ... +* ... +* ldy #PPU_DATA +* lda (palptr),y +* eor screen +* andl tilemask,x +* and bgmask +* eor screen +* sta screen + +* ; tile +* ldy tiledata,x +* lda (palptr),y +* ldy tmp +* sta abs,y + + +* ; Custom tile renderer that swizzles the tile data based on the PPU attribute tables. This +* ; is more complicate than just combining the palette select bits with the tile index bits +* ; because the NES can have >16 colors on screen at once, we remap the possible colors +* ; onto a smaller set of indices. +* SwizzleTile +* tax +* ]line equ 0 +* lup 8 +* ldal tiledata+{]line*4},x ; Tile data is 00ww00xx 00yy00zz +* ora metatile ; Pre-calculated metatile mask +* and tilemask+{]line*4},x ; Set any zero indices to actual zero +* sta: $0004+{]line*$1000},y +* ldal tiledata+{]line*4}+2,x +* sta: $0001+{]line*$1000},y +* ]line equ ]line+1 +* --^ +* plb +* rts + + + +; Transfer control to the ROM. This function is trampoline that is responsible for +; setting up the direct page and stack for the ROM and then passing control into +; the ROM wrapped in a JSL/RTL vector stashed in the ROM space. +; +; X = ROM Address +romxfer phb ; Save the bank and direct page + phd + tsc + sta StkSave+1 ; Save the current stack in the main program + pea #^ExtIn ; Set the bank to the ROM + plb + + lda ROMStk ; Set the ROM stack address + tcs + lda ROMZeroPg ; Set the ROM zero page + tcd + + jml ExtIn +ExtRtn ENT + tsx ; Copy the stack address returned by the emulator +StkSave lda #$0000 + tcs + + pld + plb + stx ROMStk ; Keep an updated copy of the stack address + rts + +; VBL Interrupt task (called in native 8-bit mode) + mx %11 +nmiTask + ldal ppustatus ; Set the bit that the VBL has started + ora #$80 + stal ppustatus + + ldal ppuctrl + bit #$80 ; Should an NMI be generated with the VBL? + beq :skip + + php +; jsr triggerNMI + plp +:skip + rtl + mx %00 + put palette.s + put ppu.s + + ds \,$00 ; pad to the next page boundary +PPU_MEM +CHR_ROM put chr2.s ; 8K of CHR-ROM at PPU memory $0000 - $2000 +PPU_NT ds $2000 ; Nametable memory from $2000 - $3000, $3F00 - $3F14 is palette RAM +PPU_OAM ds 256 ; 256 bytes of separate OAM RAM + diff --git a/demos/smb/build-image.bat b/demos/smb/build-image.bat index f18078e..e71d339 100644 --- a/demos/smb/build-image.bat +++ b/demos/smb/build-image.bat @@ -14,3 +14,4 @@ REM Cadius does not overwrite files, so clear the root folder first REM Now copy files and folders as needed %CADIUS% ADDFILE %IMAGE% %FOLDER% .\SuperMarioGS +%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160 diff --git a/demos/smb/chr2.s b/demos/smb/chr2.s new file mode 100644 index 0000000..8ae085d --- /dev/null +++ b/demos/smb/chr2.s @@ -0,0 +1,512 @@ + 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 + db $FC,$7C,$00,$00,$E0,$F0,$F8,$F8,$FC,$FC,$F8,$C0,$C2,$67,$2F,$37 + db $7F,$7F,$FF,$FF,$07,$07,$0F,$0F,$7F,$7E,$FC,$F0,$F8,$F8,$F0,$70 + db $FD,$FE,$B4,$F8,$F8,$F9,$FB,$FF,$37,$36,$5C,$00,$00,$01,$03,$1F + db $1F,$3F,$FF,$FF,$FC,$70,$70,$38,$08,$24,$E3,$F0,$F8,$70,$70,$38 + db $FF,$FF,$FF,$1F,$00,$00,$00,$00,$1F,$1F,$1F,$1F,$00,$00,$00,$00 + db $00,$00,$01,$07,$0F,$0F,$0E,$12,$00,$00,$00,$00,$00,$00,$0F,$1F + db $00,$00,$F0,$E0,$C0,$FE,$40,$60,$00,$00,$00,$10,$30,$00,$F8,$FE + db $13,$33,$30,$18,$04,$0F,$1F,$1F,$1F,$3F,$3F,$1F,$07,$08,$17,$17 + db $00,$10,$7E,$3E,$00,$00,$C0,$E0,$FF,$FF,$FE,$FE,$FC,$E0,$40,$A0 + db $3F,$3F,$3F,$1F,$1F,$1F,$1F,$1F,$37,$27,$23,$03,$01,$00,$00,$00 + db $F0,$F0,$F0,$F8,$F8,$F8,$F8,$F8,$CC,$FF,$FF,$FF,$FF,$70,$00,$08 + db $FF,$FF,$FF,$FE,$F0,$C0,$80,$00,$F0,$F0,$F0,$F0,$F0,$C0,$80,$00 + db $FC,$FC,$F8,$78,$78,$78,$7E,$7E,$10,$60,$80,$00,$78,$78,$7E,$7E + db $00,$03,$0F,$1F,$1F,$1C,$24,$26,$00,$00,$00,$00,$00,$1F,$3F,$3F + db $00,$E0,$C0,$80,$FC,$80,$C0,$00,$00,$00,$20,$60,$00,$F0,$FC,$FE + db $66,$60,$30,$18,$0F,$1F,$3F,$3F,$7F,$7F,$3F,$1F,$00,$16,$2F,$2F + db $20,$FC,$7C,$00,$00,$E0,$E0,$F0,$FE,$FC,$FC,$F8,$C0,$60,$20,$30 + db $3F,$3F,$3F,$3F,$3F,$3F,$3F,$1F,$2F,$2F,$2F,$0F,$07,$03,$00,$00 + db $F0,$90,$00,$08,$0C,$1C,$FC,$F8,$10,$F0,$F0,$F0,$F0,$E0,$C0,$E0 + db $0F,$0F,$07,$07,$07,$0F,$0F,$03,$01,$03,$01,$04,$07,$0F,$0F,$03 + db $F8,$F0,$E0,$F0,$B0,$80,$E0,$E0,$F8,$F0,$E0,$70,$B0,$80,$E0,$E0 + db $03,$3F,$7F,$19,$09,$09,$28,$5C,$00,$30,$70,$7F,$FF,$FF,$F7,$F3 + db $F8,$E0,$E0,$FC,$26,$30,$80,$10,$00,$18,$10,$00,$F8,$F8,$FE,$FF + db $3E,$1E,$3F,$38,$30,$30,$00,$3A,$E7,$0F,$0F,$1F,$1F,$1F,$0F,$07 + db $78,$1E,$80,$FE,$7E,$7E,$7F,$7F,$FF,$FE,$FC,$C6,$8E,$EE,$FF,$FF + db $3C,$3F,$1F,$0F,$07,$3F,$21,$20,$03,$00,$00,$0E,$07,$3F,$3F,$3F + db $FF,$FF,$FF,$FE,$FE,$FE,$FC,$70,$FF,$7F,$3F,$0E,$C0,$C0,$E0,$E0 + db $0F,$9F,$CF,$FF,$7F,$3F,$1E,$0E,$00,$80,$C8,$FE,$7F,$3F,$1E,$0E + db $20,$C0,$80,$80,$00,$00,$00,$00,$E0,$00,$00,$00,$00,$00,$00,$00 + db $00,$00,$03,$0F,$1F,$1F,$1C,$24,$00,$00,$00,$00,$00,$00,$1F,$3F + db $00,$04,$E6,$E0,$FF,$FF,$8F,$83,$0E,$1F,$1F,$1F,$1F,$03,$FF,$FF + db $26,$26,$60,$78,$18,$0F,$7F,$FF,$3F,$3F,$7F,$7F,$1F,$00,$7E,$FF + db $01,$21,$FE,$7A,$06,$FE,$FC,$FC,$FF,$FF,$FE,$FE,$FE,$DE,$5C,$6C + db $FF,$CF,$87,$07,$07,$0F,$1F,$1F,$FF,$FF,$FE,$FC,$F8,$B0,$60,$00 + db $F8,$F8,$F0,$B8,$F8,$F9,$FB,$FF,$28,$30,$18,$40,$00,$01,$03,$0F + db $1F,$FF,$FF,$FF,$FF,$FE,$C0,$80,$10,$EC,$E3,$E0,$E0,$E0,$C0,$80 + db $FF,$FF,$FF,$3F,$00,$00,$00,$00,$0F,$0F,$0F,$0F,$00,$00,$00,$00 + db $13,$33,$30,$18,$04,$0F,$1F,$1F,$1F,$3F,$3F,$1F,$07,$09,$13,$17 + db $00,$10,$7E,$30,$E0,$F0,$F0,$E0,$FF,$FF,$FE,$FF,$FE,$FC,$F8,$E0 + db $1F,$1F,$0F,$0F,$0F,$1F,$1F,$1F,$17,$17,$03,$00,$00,$00,$00,$00 + db $F0,$F0,$F8,$F8,$B8,$F8,$F8,$F8,$D0,$90,$18,$08,$40,$00,$00,$00 + db $3F,$FF,$FF,$FF,$F6,$C6,$84,$00,$30,$F0,$F0,$F1,$F6,$C6,$84,$00 + db $F0,$E0,$80,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $1F,$1F,$3F,$3F,$1F,$0F,$0F,$1F,$1F,$1F,$3F,$3E,$7C,$78,$F0,$E0 + db $F0,$F0,$F8,$F8,$B8,$F8,$F8,$F0,$B0,$90,$18,$08,$40,$00,$00,$00 + db $E0,$F0,$F0,$F0,$F0,$F0,$F8,$F0,$C0,$E0,$FC,$FE,$FF,$7F,$03,$00 + db $1F,$1F,$1F,$3F,$3E,$3C,$38,$18,$00,$00,$10,$38,$3E,$3C,$38,$18 + db $00,$03,$07,$07,$0A,$0B,$0C,$00,$00,$00,$00,$07,$0F,$0F,$0F,$03 + db $00,$E0,$FC,$20,$20,$10,$3C,$00,$00,$00,$00,$F0,$FC,$FE,$FC,$F8 + db $07,$07,$07,$1F,$1F,$3E,$21,$01,$07,$0F,$1B,$18,$10,$30,$21,$01 + db $E0,$E0,$E0,$F0,$F0,$E0,$C0,$E0,$A8,$FC,$F8,$00,$00,$00,$C0,$E0 + db $07,$0F,$0E,$14,$16,$18,$00,$3F,$00,$00,$0F,$1F,$1F,$1F,$07,$3C + db $C0,$F8,$40,$40,$20,$78,$00,$C0,$00,$00,$E0,$F8,$FC,$F8,$F0,$C0 + db $3F,$0E,$0F,$1F,$3F,$7C,$70,$38,$FC,$ED,$C0,$00,$00,$60,$70,$38 + db $F0,$F8,$E4,$FC,$FC,$7C,$00,$00,$7E,$1E,$04,$0C,$0C,$0C,$00,$00 + db $07,$0F,$0E,$14,$16,$18,$00,$0F,$00,$00,$0F,$1F,$1F,$1F,$07,$0D + db $1F,$1F,$1F,$1C,$0C,$07,$07,$07,$1E,$1C,$1E,$0F,$07,$00,$07,$07 + db $E0,$60,$F0,$70,$E0,$E0,$F0,$80,$60,$90,$00,$80,$00,$E0,$F0,$80 + db $07,$1F,$3F,$12,$13,$08,$1F,$31,$00,$10,$3F,$7F,$7F,$3F,$03,$0F + db $C0,$F0,$40,$00,$30,$18,$C0,$F8,$00,$00,$E0,$F8,$FC,$F8,$B0,$38 + db $31,$39,$1F,$1F,$0F,$5F,$7E,$3C,$1F,$07,$00,$0E,$0F,$53,$7C,$3C + db $F8,$F8,$F0,$E0,$E0,$C0,$00,$00,$F8,$F8,$F0,$00,$00,$80,$00,$00 + db $00,$E0,$FC,$27,$27,$11,$3E,$04,$07,$07,$03,$F7,$FF,$FF,$FE,$FC + db $3F,$7F,$3F,$0F,$1F,$3F,$7F,$4F,$3E,$7F,$FF,$E2,$50,$38,$70,$40 + db $F8,$F9,$F9,$B7,$FF,$FF,$E0,$00,$E8,$71,$01,$4B,$03,$03,$00,$00 + db $07,$07,$0F,$3F,$3F,$3F,$26,$04,$05,$03,$01,$30,$30,$30,$26,$04 + db $F0,$F0,$F0,$E0,$C0,$00,$00,$00,$FE,$FC,$E0,$00,$00,$00,$00,$00 + db $07,$07,$0F,$1F,$3F,$0F,$1C,$18,$05,$03,$01,$10,$30,$0C,$1C,$18 + db $E0,$E0,$E0,$E0,$C0,$80,$00,$00,$C0,$E0,$F0,$78,$18,$08,$00,$00 + db $07,$0F,$1F,$0F,$3F,$0F,$1C,$18,$07,$0F,$3E,$7C,$30,$0C,$1C,$18 + db $E0,$E0,$E0,$40,$C0,$80,$00,$00,$60,$60,$60,$80,$00,$00,$00,$00 + db $7F,$FF,$FF,$FB,$0F,$0F,$0F,$1F,$73,$F3,$F0,$F4,$F0,$F0,$70,$60 + db $3F,$7E,$7C,$7C,$3C,$3C,$FC,$FC,$00,$00,$00,$00,$3C,$3C,$FC,$FC + db $60,$70,$18,$08,$0F,$1F,$3F,$7F,$7F,$7F,$1F,$07,$0B,$1B,$3B,$7B + db $FC,$7C,$00,$20,$F0,$F8,$FC,$FE,$FC,$FC,$F8,$E0,$D0,$D8,$DC,$DE + db $0B,$0F,$1F,$1E,$3C,$3C,$3C,$7C,$C4,$E0,$E0,$40,$00,$3C,$3C,$7C + db $1F,$3F,$0D,$07,$0F,$0E,$1C,$3C,$1D,$3C,$3A,$38,$30,$00,$1C,$3C + db $00,$00,$00,$00,$00,$00,$00,$00,$22,$55,$55,$55,$55,$55,$77,$22 + db $00,$07,$1F,$FF,$07,$1F,$0F,$06,$00,$00,$00,$00,$00,$00,$00,$00 + db $3F,$FF,$FF,$FF,$FF,$FF,$FB,$76,$00,$00,$CF,$07,$7F,$00,$00,$00 + db $20,$F8,$FF,$C3,$FD,$FE,$F0,$40,$00,$00,$3C,$FC,$FE,$E0,$00,$00 + db $40,$E0,$40,$40,$41,$41,$4F,$47,$40,$E0,$40,$3F,$3E,$3E,$30,$38 + db $00,$00,$00,$00,$00,$00,$E0,$C0,$00,$00,$00,$F8,$F8,$F8,$18,$38 + db $43,$46,$44,$40,$40,$40,$40,$40,$3C,$39,$3B,$3F,$00,$00,$00,$00 + db $80,$C0,$40,$00,$00,$00,$00,$00,$78,$38,$B8,$F8,$00,$00,$00,$00 + db $31,$30,$38,$7C,$7F,$FF,$FF,$FB,$3F,$3F,$0F,$77,$77,$F7,$F7,$F7 + db $10,$7E,$3E,$00,$1E,$FE,$FF,$FF,$FF,$FE,$FE,$FE,$FA,$FA,$F3,$E7 + db $FF,$FF,$E3,$C3,$87,$48,$3C,$FC,$F0,$F8,$FC,$7C,$78,$38,$3C,$FC + db $00,$FF,$C3,$83,$83,$FF,$FF,$FF,$FF,$00,$C3,$81,$81,$C3,$FF,$00 + db $1F,$1F,$0F,$07,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $F0,$FB,$FF,$FF,$FE,$3E,$0C,$04,$00,$0B,$1F,$1F,$1E,$3E,$0C,$04 + db $1F,$1F,$0F,$0F,$07,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FB,$FF,$FF,$FF,$FF,$00,$00,$00,$03,$0F,$0F,$0F,$0F,$00,$00,$00 + db $00,$18,$3C,$7E,$6E,$DF,$DF,$DF,$00,$18,$3C,$7E,$76,$FB,$FB,$FB + db $00,$18,$18,$3C,$3C,$3C,$3C,$1C,$00,$10,$10,$20,$20,$20,$20,$20 + db $00,$08,$08,$08,$08,$08,$08,$00,$00,$08,$08,$08,$08,$08,$08,$08 + db $00,$08,$08,$04,$04,$04,$04,$04,$00,$10,$10,$38,$38,$38,$38,$38 + db $3C,$7E,$77,$FB,$9F,$5F,$8E,$20,$00,$18,$3C,$0E,$0E,$04,$00,$00 + db $5C,$2E,$8F,$3F,$7B,$77,$7E,$3C,$00,$00,$04,$06,$1E,$3C,$18,$00 + db $13,$4F,$3F,$BF,$3F,$7A,$F8,$F8,$00,$00,$01,$0A,$17,$0F,$2F,$1F + db $00,$08,$05,$0F,$2F,$1D,$1C,$3C,$00,$00,$00,$00,$05,$07,$0F,$07 + db $00,$00,$00,$00,$02,$0B,$07,$0F,$00,$00,$00,$00,$00,$00,$01,$03 + db $00,$00,$00,$00,$00,$08,$04,$04,$00,$60,$F0,$F8,$7C,$3E,$7E,$7F + db $02,$02,$02,$05,$71,$7F,$7F,$7F,$3F,$5F,$7F,$3E,$0E,$0A,$51,$20 + db $00,$00,$00,$00,$00,$00,$00,$04,$00,$00,$00,$00,$00,$00,$0E,$1F + db $02,$02,$00,$01,$13,$3F,$7F,$7F,$3F,$7F,$7F,$FE,$EC,$CA,$51,$20 + db $00,$40,$60,$70,$73,$27,$0F,$1F,$00,$40,$63,$77,$7C,$38,$F8,$E4 + db $00,$00,$00,$00,$03,$07,$0F,$1F,$00,$00,$03,$07,$0C,$18,$F8,$E4 + db $7F,$7F,$3F,$3F,$1F,$1F,$0F,$07,$03,$44,$28,$10,$08,$04,$03,$04 + db $03,$07,$0F,$1F,$3F,$77,$77,$F5,$03,$07,$0F,$1F,$27,$7B,$78,$FB + db $C0,$E0,$F0,$F8,$FC,$EE,$EE,$AF,$C0,$E0,$F0,$F8,$E4,$DE,$1E,$DF + db $F1,$FF,$78,$00,$00,$18,$1C,$0E,$FF,$FF,$7F,$0F,$0F,$07,$03,$00 + db $8F,$FF,$1E,$00,$0C,$3E,$7E,$7C,$FF,$FF,$FE,$F0,$F0,$C0,$80,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$18,$24,$24,$18,$00,$00 + db $00,$02,$41,$41,$61,$33,$06,$3C,$3C,$7E,$FF,$FF,$FF,$FF,$7E,$3C + db $03,$07,$0F,$1F,$3F,$7F,$7F,$FF,$03,$07,$0F,$1F,$3F,$63,$41,$C1 + db $C0,$E0,$F0,$F8,$FC,$FE,$FE,$FF,$C0,$80,$00,$00,$8C,$FE,$FE,$F3 + db $FF,$FF,$FF,$78,$00,$00,$00,$00,$C1,$E3,$FF,$47,$0F,$0F,$0F,$07 + db $FF,$FF,$FF,$1E,$00,$20,$20,$40,$F1,$F9,$FF,$E2,$F0,$F0,$F0,$E0 + db $16,$1F,$3F,$7F,$3D,$1D,$3F,$1F,$16,$1F,$00,$00,$05,$0D,$3F,$1F + db $80,$80,$C0,$E0,$F0,$F0,$F0,$F8,$80,$80,$00,$00,$00,$A0,$A0,$E0 + db $3C,$FA,$B1,$72,$F2,$DB,$DF,$5F,$00,$04,$4E,$8C,$0C,$7F,$FF,$FF + db $00,$00,$00,$01,$01,$01,$06,$1E,$00,$00,$00,$00,$00,$00,$01,$01 + db $00,$00,$00,$00,$00,$00,$00,$00,$FF,$7F,$3F,$1F,$0F,$07,$03,$01 + db $00,$7C,$D6,$92,$BA,$EE,$FE,$38,$FF,$83,$29,$6D,$45,$11,$01,$C7 + db $00,$15,$3F,$62,$5F,$FF,$9F,$7D,$08,$08,$02,$1F,$22,$02,$02,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$08,$08,$08,$08,$08,$08,$08,$08 + db $2F,$1E,$2F,$2F,$2F,$15,$0D,$0E,$10,$1E,$10,$50,$10,$08,$00,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FE,$00,$00,$00,$00 + db $1C,$3E,$7F,$FF,$FF,$FE,$7C,$38,$1C,$2A,$77,$EE,$DD,$AA,$74,$28 + db $00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FE,$FE,$00,$EF,$EF,$EF,$00 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FE,$FE,$FE,$00,$EF,$EF,$EF,$00 + db $7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$7F,$5F,$7F,$7F,$7F,$7F,$7F + db $68,$4E,$E0,$E0,$E0,$F0,$F8,$FC,$B8,$9E,$80,$C0,$E0,$F0,$F8,$7C + db $3F,$5C,$39,$3B,$BB,$F9,$FC,$FE,$00,$23,$57,$4F,$57,$27,$C3,$21 + db $C0,$F0,$F0,$F0,$F0,$E0,$C0,$00,$00,$30,$70,$70,$F0,$E0,$C0,$00 + db $FE,$FC,$61,$0F,$FF,$FE,$F0,$E0,$13,$0F,$1E,$F0,$FC,$F8,$F0,$E0 + db $6E,$40,$E0,$E0,$E0,$E0,$E0,$C0,$BE,$90,$80,$C0,$C0,$80,$00,$00 + db $01,$01,$03,$03,$07,$7F,$7F,$3F,$01,$01,$03,$03,$07,$7F,$7D,$3D + db $06,$07,$3F,$3C,$19,$7B,$7F,$3F,$06,$04,$30,$23,$06,$64,$60,$00 + db $3F,$7F,$7F,$1F,$3F,$3F,$07,$06,$00,$60,$60,$00,$20,$30,$04,$06 + db $03,$07,$0F,$0F,$0F,$0F,$07,$03,$00,$01,$01,$00,$00,$00,$00,$00 + db $F8,$F8,$F8,$A0,$E1,$FF,$FF,$FF,$FE,$FF,$FF,$40,$01,$03,$03,$03 + db $0F,$0F,$0F,$1F,$1F,$1F,$0F,$07,$01,$01,$00,$00,$00,$00,$00,$00 + db $E0,$F8,$F8,$F8,$FF,$FE,$F0,$C0,$E0,$FE,$FF,$7F,$03,$02,$00,$00 + db $01,$0F,$0F,$1F,$39,$33,$37,$7F,$01,$0D,$08,$00,$36,$2C,$08,$60 + db $7F,$3F,$3F,$3F,$1F,$0F,$0F,$01,$60,$00,$20,$30,$00,$08,$0D,$01 + db $00,$00,$03,$03,$47,$67,$77,$77,$01,$01,$03,$43,$67,$77,$7B,$78 + db $00,$00,$00,$00,$88,$98,$F8,$F0,$00,$00,$80,$84,$CC,$DC,$BC,$3C + db $7E,$7F,$FF,$1F,$07,$30,$1C,$0C,$33,$07,$07,$E3,$38,$3F,$1C,$0C + db $7E,$38,$F6,$ED,$DF,$38,$70,$60,$98,$C7,$C8,$92,$30,$F8,$70,$60 + db $00,$00,$00,$03,$03,$47,$67,$77,$00,$01,$01,$03,$43,$67,$77,$7B + db $00,$00,$00,$00,$00,$88,$98,$F8,$00,$00,$00,$80,$84,$CC,$DC,$BC + db $77,$7E,$7F,$FF,$1F,$07,$70,$F0,$78,$33,$07,$07,$E3,$38,$7F,$F0 + db $F0,$7E,$38,$F6,$ED,$DF,$38,$3C,$3C,$98,$C7,$C8,$92,$30,$F8,$3C + db $03,$07,$0A,$1A,$1C,$1E,$0B,$08,$00,$10,$7F,$7F,$7F,$1F,$0F,$0F + db $1C,$3F,$3F,$3D,$3F,$1F,$00,$00,$03,$33,$39,$3A,$38,$18,$00,$00 + db $00,$00,$04,$4C,$4E,$4E,$46,$6F,$10,$38,$3C,$74,$76,$76,$7E,$7D + db $00,$1F,$3F,$3F,$4F,$5F,$7F,$7F,$00,$00,$11,$0A,$34,$2A,$51,$20 + db $7F,$67,$A3,$B0,$D8,$DE,$DC,$C8,$7F,$67,$63,$70,$38,$3E,$7C,$B8 + db $7F,$7F,$7F,$1F,$47,$70,$70,$39,$51,$0A,$04,$EA,$79,$7F,$70,$39 + db $E8,$E8,$E0,$C0,$10,$70,$E0,$C0,$58,$38,$10,$30,$F0,$F0,$E0,$C0 + db $00,$00,$00,$20,$66,$66,$66,$62,$00,$08,$1C,$3C,$7A,$7A,$7A,$7E + db $00,$00,$1F,$3F,$7F,$4F,$5F,$7F,$00,$00,$00,$11,$0A,$34,$2A,$51 + db $77,$7F,$3F,$B7,$B3,$DB,$DA,$D8,$7F,$7D,$3F,$37,$33,$3B,$3A,$78 + db $7F,$7F,$7F,$7F,$1F,$07,$70,$F0,$20,$51,$0A,$04,$EA,$39,$7F,$F0 + db $CC,$E8,$E8,$E0,$C0,$18,$7C,$3E,$BC,$58,$38,$10,$30,$F8,$FC,$3E + db $03,$0F,$1F,$3F,$3B,$3F,$7F,$7F,$00,$00,$00,$06,$0E,$0C,$00,$00 + db $80,$F0,$F8,$FC,$FE,$FE,$FF,$FE,$00,$00,$00,$00,$00,$00,$0F,$18 + db $7F,$7F,$7F,$7F,$FF,$0F,$03,$00,$00,$00,$00,$00,$F8,$3E,$3B,$18 + db $FE,$FB,$FF,$FF,$F6,$E0,$C0,$00,$10,$14,$10,$10,$38,$78,$F8,$30 + db $00,$03,$0F,$1F,$3F,$3B,$3F,$7F,$00,$00,$00,$00,$06,$0E,$0C,$00 + db $00,$C0,$F0,$F8,$FC,$FE,$FE,$FF,$00,$00,$00,$00,$00,$00,$00,$0F + db $7F,$7F,$7F,$7F,$7F,$FF,$0F,$03,$00,$00,$00,$00,$00,$F8,$7E,$F3 + db $FE,$FE,$FB,$FF,$FF,$F6,$E0,$C0,$18,$10,$14,$10,$10,$38,$7C,$DE + db $00,$01,$01,$01,$01,$00,$00,$08,$00,$0D,$1E,$1E,$1E,$1F,$0F,$07 + db $78,$F0,$F8,$E4,$C0,$CA,$CA,$C0,$78,$F0,$00,$1A,$3F,$35,$35,$3F + db $0F,$1F,$9F,$FF,$FF,$7F,$74,$20,$00,$00,$80,$E0,$E0,$70,$73,$21 + db $E4,$FF,$FE,$FC,$9C,$1E,$00,$00,$1A,$07,$0C,$18,$78,$FE,$FC,$F0 + db $00,$01,$03,$03,$07,$03,$01,$00,$00,$01,$02,$00,$38,$7C,$7E,$3F + db $00,$5F,$7F,$7F,$3F,$3F,$14,$00,$3F,$40,$60,$60,$20,$30,$13,$01 + db $C0,$E0,$F0,$30,$38,$3C,$3C,$FC,$C0,$E0,$30,$D0,$D0,$D0,$D0,$00 + db $07,$0F,$1F,$22,$20,$25,$25,$1F,$07,$0F,$02,$1D,$1F,$1A,$1A,$02 + db $FE,$FE,$7E,$3A,$02,$01,$41,$41,$38,$7C,$FC,$FC,$FC,$FE,$BE,$BE + db $1F,$3F,$7E,$5C,$40,$80,$82,$82,$1C,$3E,$3F,$3F,$3F,$7F,$7D,$7D + db $82,$80,$A0,$44,$43,$40,$21,$1E,$7D,$7F,$5F,$3B,$3C,$3F,$1E,$00 + db $1C,$3F,$3E,$3C,$40,$80,$82,$82,$1C,$3E,$3F,$1F,$3F,$7F,$7D,$7D + db $00,$00,$80,$80,$92,$9D,$C7,$EF,$00,$00,$00,$60,$62,$65,$3F,$1F + db $00,$23,$33,$3F,$3F,$7F,$7F,$7F,$70,$3C,$3C,$18,$00,$00,$02,$07 + db $FE,$F8,$A0,$00,$00,$00,$80,$80,$CF,$7A,$5A,$10,$00,$00,$C0,$80 + db $7E,$7F,$7D,$3F,$1E,$8F,$8F,$19,$85,$84,$86,$C6,$E7,$73,$73,$E1 + db $E0,$0E,$73,$F3,$F9,$F9,$F8,$70,$80,$4E,$77,$F3,$FB,$F9,$FA,$78 + db $0E,$66,$E2,$F6,$FF,$FF,$1F,$98,$11,$39,$7D,$39,$00,$00,$E0,$E7 + db $00,$00,$00,$04,$0F,$0F,$1F,$07,$00,$00,$07,$07,$16,$10,$00,$38 + db $F3,$E7,$EE,$EC,$CD,$CF,$CF,$DF,$CF,$1F,$17,$10,$33,$30,$30,$20 + db $27,$3F,$3F,$78,$3C,$1F,$1F,$73,$38,$30,$40,$C7,$07,$66,$E0,$6C + db $9F,$3E,$7C,$FC,$F8,$F8,$C0,$40,$60,$C0,$80,$04,$9E,$FF,$F0,$F8 + db $7F,$7E,$78,$01,$07,$1F,$3C,$7C,$24,$01,$07,$FE,$FF,$7F,$3F,$7F + db $FC,$F8,$A0,$FE,$FC,$F0,$80,$00,$CF,$7A,$0A,$FE,$FC,$00,$00,$00 + db $7E,$7F,$7F,$3F,$1F,$8F,$8F,$18,$85,$86,$83,$C3,$E1,$70,$70,$E0 + db $9F,$3E,$7C,$F8,$F8,$3C,$18,$F8,$60,$C0,$80,$00,$98,$FC,$FE,$FF + db $7F,$7F,$78,$01,$07,$13,$F1,$03,$24,$00,$07,$FE,$FF,$7F,$FF,$03 + db $00,$00,$1C,$1D,$1B,$C3,$E3,$E1,$03,$0F,$23,$62,$64,$3C,$1C,$1E + db $E0,$CD,$1D,$4F,$EE,$FF,$3F,$3F,$1F,$3D,$6D,$4F,$EE,$F3,$20,$03 + db $3F,$3F,$00,$00,$70,$B8,$FC,$FC,$07,$07,$1F,$3F,$0F,$47,$03,$00 + db $07,$0F,$1F,$3F,$3E,$7C,$78,$78,$00,$00,$03,$07,$0F,$0F,$1F,$1F + db $3F,$5C,$39,$3B,$BF,$FF,$FE,$FE,$00,$23,$57,$4F,$57,$2F,$DF,$21 + db $C0,$C0,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$80,$80,$00,$00 + db $FE,$FC,$61,$0F,$7F,$3F,$1F,$1E,$23,$0F,$1E,$F0,$1C,$3F,$1F,$1E + db $F0,$78,$E4,$C8,$CC,$BE,$BE,$3E,$00,$80,$18,$30,$34,$FE,$FE,$FE + db $00,$01,$00,$07,$07,$07,$07,$1F,$00,$00,$01,$04,$06,$06,$07,$07 + db $00,$00,$0F,$3F,$3F,$0F,$00,$00,$0F,$3F,$7F,$F8,$F8,$7F,$3F,$0F + db $78,$7C,$7E,$7F,$3F,$3F,$1B,$09,$1F,$1F,$1F,$0B,$01,$01,$00,$00 + db $0C,$00,$00,$00,$07,$7F,$7C,$00,$03,$1F,$3F,$3F,$78,$00,$03,$FF + db $01,$E1,$71,$79,$3D,$3D,$1F,$03,$00,$00,$00,$00,$00,$00,$00,$00 + db $3F,$3F,$1F,$1B,$36,$30,$7F,$3F,$23,$27,$1F,$07,$0F,$1F,$7F,$3F + db $F8,$F8,$F8,$B8,$18,$D8,$D8,$B8,$E0,$80,$80,$40,$E0,$E0,$E0,$C0 + db $01,$02,$04,$04,$08,$08,$10,$10,$03,$07,$0F,$1F,$3F,$7F,$FF,$1F + db $00,$0F,$13,$0D,$0D,$13,$0C,$20,$1F,$10,$0C,$12,$12,$2C,$3F,$3F + db $00,$24,$00,$24,$00,$04,$00,$00,$37,$36,$36,$36,$16,$16,$12,$02 + db $0F,$41,$00,$88,$00,$44,$00,$00,$10,$7E,$FF,$FF,$F6,$76,$3A,$1A + db $38,$7C,$FE,$FE,$3B,$03,$03,$03,$00,$00,$38,$04,$00,$00,$00,$00 + db $03,$33,$7B,$7F,$FF,$FB,$03,$03,$00,$00,$00,$38,$40,$00,$00,$00 + db $DC,$C0,$E0,$E0,$E0,$E0,$E0,$C0,$FC,$A0,$80,$80,$00,$00,$00,$00 + db $3F,$5F,$3F,$3F,$BB,$F8,$FE,$FE,$07,$27,$57,$4F,$57,$27,$C1,$21 + db $1F,$0F,$0F,$1F,$1F,$1E,$38,$30,$1D,$0F,$0F,$1F,$1F,$1E,$38,$30 + db $00,$20,$60,$60,$70,$F0,$F8,$F8,$00,$00,$38,$10,$4C,$18,$86,$24 + db $F8,$FC,$FC,$7E,$7E,$3E,$1F,$07,$00,$42,$0A,$40,$10,$02,$08,$02 + db $00,$C0,$70,$B8,$F4,$F2,$F5,$7B,$00,$00,$80,$40,$08,$0C,$0A,$84 + db $00,$DF,$10,$FF,$DF,$FF,$FF,$F9,$00,$00,$CF,$20,$20,$20,$26,$2E + db $1F,$1F,$3E,$FC,$F8,$F0,$C0,$00,$E0,$E0,$C0,$00,$00,$00,$00,$00 + db $F8,$FC,$FE,$FF,$FF,$DF,$DF,$00,$2F,$23,$21,$20,$20,$00,$00,$00 + db $C1,$F1,$79,$7D,$3D,$3F,$1F,$03,$C1,$B1,$59,$6D,$35,$3B,$1F,$03 + db $02,$06,$0E,$0E,$1E,$1E,$3E,$3E,$00,$02,$00,$08,$02,$00,$28,$00 + db $3E,$3E,$3E,$3E,$1E,$1E,$0E,$02,$04,$10,$02,$10,$04,$00,$0A,$00 + db $C1,$F1,$79,$7D,$3D,$3F,$1F,$03,$C1,$B1,$59,$6D,$35,$3B,$1F,$03 + db $7C,$00,$00,$FF,$C3,$7F,$1F,$03,$00,$0F,$1F,$FF,$FC,$63,$1F,$03 + db $FF,$FF,$7C,$00,$00,$7C,$FF,$FF,$00,$00,$FE,$C6,$C6,$FE,$00,$00 + db $FF,$FF,$00,$04,$0C,$18,$30,$00,$00,$00,$06,$06,$0C,$18,$70,$60 + db $FF,$FF,$00,$04,$04,$04,$08,$08,$00,$00,$06,$06,$04,$04,$08,$08 + db $08,$10,$10,$00,$00,$10,$10,$08,$08,$10,$30,$30,$30,$30,$10,$08 + db $7F,$3F,$3F,$3E,$1F,$0F,$03,$00,$00,$00,$01,$03,$01,$00,$00,$00 + db $03,$0F,$FF,$7F,$7F,$7F,$7F,$7F,$03,$0E,$F8,$00,$00,$00,$00,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$22,$65,$25,$25,$25,$25,$77,$72 + db $00,$00,$00,$00,$00,$00,$00,$00,$62,$95,$15,$25,$45,$85,$F7,$F2 + db $00,$00,$00,$00,$00,$00,$00,$00,$A2,$A5,$A5,$A5,$F5,$F5,$27,$22 + db $00,$00,$00,$00,$00,$00,$00,$00,$F2,$85,$85,$E5,$15,$15,$F7,$E2 + db $00,$00,$00,$00,$00,$00,$00,$00,$62,$95,$55,$65,$B5,$95,$97,$62 + db $00,$00,$00,$00,$00,$00,$00,$00,$20,$50,$50,$50,$50,$50,$70,$20 + db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + 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 + 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 + db $7E,$0C,$18,$3C,$06,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $1C,$3C,$6C,$CC,$FE,$0C,$0C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FC,$C0,$FC,$06,$06,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $3C,$60,$C0,$FC,$C6,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FE,$C6,$0C,$18,$30,$30,$30,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $7C,$C6,$C6,$7C,$C6,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $7C,$C6,$C6,$7E,$06,$0C,$78,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $38,$6C,$C6,$C6,$FE,$C6,$C6,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FC,$C6,$C6,$FC,$C6,$C6,$FC,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $3C,$66,$C0,$C0,$C0,$66,$3C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + 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 + 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 + db $1E,$06,$06,$06,$C6,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $C6,$CC,$D8,$F0,$F8,$DC,$CE,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $60,$60,$60,$60,$60,$60,$7E,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $C6,$EE,$FE,$FE,$D6,$C6,$C6,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $C6,$E6,$F6,$FE,$DE,$CE,$C6,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $7C,$C6,$C6,$C6,$C6,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FC,$C6,$C6,$C6,$FC,$C0,$C0,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $7C,$C6,$C6,$C6,$DE,$CC,$7A,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FC,$C6,$C6,$CE,$F8,$DC,$CE,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $78,$CC,$C0,$7C,$06,$C6,$7C,$00,$00,$00,$00,$00,$00,$00,$00,$00 + 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 + 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 + db $FE,$0E,$1C,$38,$70,$E0,$FE,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00 + db $00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $00,$00,$00,$7E,$7E,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $00,$00,$44,$28,$10,$28,$44,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$7F,$7F,$7F,$7F,$7F,$7F,$7F,$7F + db $18,$3C,$3C,$3C,$18,$18,$00,$18,$00,$00,$00,$00,$00,$00,$00,$00 + db $FF,$7F,$7F,$7F,$7F,$FF,$E3,$C1,$FF,$80,$80,$80,$80,$00,$1C,$3E + 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 + 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 + db $80,$40,$20,$10,$08,$04,$02,$01,$80,$C0,$E0,$F0,$F8,$FC,$FE,$FF + db $04,$0E,$0E,$0E,$6E,$64,$60,$60,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $07,$0F,$1F,$1F,$7F,$FF,$FF,$7F,$07,$08,$10,$00,$60,$80,$80,$40 + db $03,$07,$1F,$3F,$3F,$3F,$79,$F7,$03,$04,$18,$20,$20,$20,$46,$88 + db $C0,$E0,$F0,$F4,$FE,$BF,$DF,$FF,$C0,$20,$10,$14,$0A,$41,$21,$01 + db $90,$B8,$F8,$FA,$FF,$FF,$FF,$FE,$90,$A8,$48,$0A,$05,$01,$01,$02 + db $3B,$1D,$0E,$0F,$07,$00,$00,$00,$24,$12,$09,$08,$07,$00,$00,$00 + db $FF,$BF,$1C,$C0,$F3,$FF,$7E,$1C,$00,$40,$E3,$3F,$0C,$81,$62,$1C + db $BF,$7F,$3D,$83,$C7,$FF,$FF,$3C,$40,$80,$C2,$7C,$38,$00,$C3,$3C + db $FC,$FE,$FF,$FE,$FE,$F8,$60,$00,$04,$02,$01,$00,$06,$98,$60,$00 + 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 + 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 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$01,$01,$01,$01,$01,$01,$01,$01 + db $7F,$80,$80,$98,$9C,$8C,$80,$80,$00,$7F,$7F,$67,$67,$7F,$7F,$7F + db $FF,$01,$01,$FF,$10,$10,$10,$FF,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $80,$80,$80,$80,$80,$80,$80,$80,$7F,$7F,$7F,$7F,$7F,$7F,$7F,$7F + db $01,$01,$01,$FF,$10,$10,$10,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FF,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FE,$01,$01,$19,$1D,$0D,$01,$01,$00,$FF,$FF,$E7,$E7,$FF,$FF,$FF + db $01,$01,$01,$01,$01,$01,$01,$01,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $3F,$7F,$7F,$FF,$FF,$FF,$FF,$FF,$3F,$60,$40,$C0,$80,$80,$80,$80 + 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 + 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 + db $00,$08,$08,$08,$10,$10,$10,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $00,$7F,$7F,$78,$73,$73,$73,$7F,$7F,$80,$A0,$87,$8F,$8E,$8E,$86 + db $00,$FF,$FF,$3F,$9F,$9F,$9F,$1F,$FE,$01,$05,$C1,$E1,$71,$71,$F1 + db $7E,$7E,$7F,$7E,$7E,$7F,$7F,$FF,$81,$81,$80,$81,$81,$A0,$80,$FF + db $7F,$7F,$FF,$7F,$7F,$FF,$FF,$FF,$F1,$C1,$C1,$81,$C1,$C5,$01,$FF + db $7F,$80,$A0,$80,$80,$80,$80,$80,$7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FE,$01,$05,$01,$01,$01,$01,$01,$FE,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $80,$80,$80,$80,$80,$A0,$80,$7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$7F + db $01,$01,$01,$01,$01,$05,$01,$FE,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FE + db $00,$00,$00,$00,$FC,$FE,$07,$03,$00,$00,$00,$00,$00,$00,$38,$7C + 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 + 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 + db $FF,$FF,$00,$00,$00,$00,$00,$00,$FF,$00,$FF,$FF,$FF,$FF,$FF,$FF + db $FF,$FF,$01,$57,$2F,$57,$2F,$57,$FF,$01,$FF,$A9,$D1,$A9,$D1,$A9 + db $F3,$F3,$F3,$F3,$F3,$F3,$FF,$3F,$8C,$8C,$8C,$8C,$8C,$8C,$FF,$3F + db $F6,$F6,$F6,$F6,$F6,$F6,$FF,$FF,$09,$09,$09,$09,$09,$09,$FF,$FF + db $00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $2F,$57,$2F,$57,$2F,$57,$FF,$FC,$D1,$A9,$D1,$A9,$D1,$A9,$FF,$FC + db $3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$23,$23,$23,$23,$23,$23,$23,$23 + db $FB,$FB,$FB,$FB,$FB,$FB,$FB,$FB,$04,$04,$04,$04,$04,$04,$04,$04 + db $BC,$5C,$BC,$5C,$BC,$5C,$BC,$5C,$44,$A4,$44,$A4,$44,$A4,$44,$A4 + db $1F,$20,$40,$40,$80,$80,$80,$81,$1F,$3F,$7F,$7F,$FF,$FF,$FF,$FE + 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 + 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 + db $01,$01,$01,$01,$03,$03,$07,$FF,$FE,$FE,$FE,$FE,$FC,$FC,$F8,$FF + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$FF + db $81,$C1,$E3,$FF,$FF,$FF,$FF,$FE,$7F,$3F,$1D,$01,$01,$01,$03,$FE + db $FF,$FF,$FF,$FF,$FF,$FB,$B5,$CE,$80,$80,$80,$80,$80,$84,$CA,$B1 + db $FF,$FF,$FF,$FF,$FF,$DF,$AD,$73,$01,$01,$01,$01,$01,$21,$53,$8D + db $77,$77,$77,$77,$77,$77,$77,$77,$00,$00,$00,$00,$77,$FF,$FF,$FF + db $00,$00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $77,$77,$77,$77,$00,$00,$00,$00,$FF,$FF,$FF,$77,$77,$77,$77,$77 + db $01,$01,$01,$19,$1D,$0D,$01,$FE,$FF,$FF,$FF,$E7,$E7,$FF,$FF,$FE + db $20,$78,$7F,$FE,$FE,$FE,$FE,$FE,$00,$21,$21,$41,$41,$41,$41,$41 + 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 + 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 + db $3F,$78,$E7,$CF,$58,$58,$50,$90,$C0,$87,$18,$B0,$E7,$E7,$EF,$EF + db $B0,$FC,$E2,$C1,$C1,$83,$8F,$7E,$6F,$43,$5D,$3F,$3F,$7F,$7F,$FF + db $FE,$03,$0F,$91,$70,$60,$20,$31,$03,$FF,$F1,$6E,$CF,$DF,$FF,$FF + db $3F,$3F,$1D,$39,$7B,$F3,$86,$FE,$FD,$FB,$FB,$F7,$F7,$0F,$7F,$FF + db $FF,$FF,$FF,$FF,$FF,$80,$80,$FF,$FF,$80,$80,$80,$80,$FF,$FF,$80 + db $FE,$FF,$FF,$FF,$FF,$03,$03,$FF,$FE,$03,$03,$03,$03,$FF,$FF,$03 + db $00,$FF,$FF,$FF,$FF,$FF,$00,$00,$00,$FF,$00,$00,$00,$00,$FF,$FF + db $3C,$FC,$FC,$FC,$FC,$FC,$04,$04,$23,$F3,$0B,$0B,$0B,$07,$FF,$FF + db $FF,$FF,$FF,$FF,$80,$FF,$FF,$FF,$80,$80,$80,$80,$FF,$80,$80,$80 + db $FF,$FF,$FF,$FF,$03,$FF,$FF,$FF,$03,$03,$03,$03,$FF,$03,$03,$03 + 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 + 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 + db $03,$03,$AB,$57,$AB,$FF,$FF,$FE,$FF,$FF,$57,$AB,$57,$03,$03,$FE + db $00,$55,$AA,$55,$FF,$FF,$FF,$00,$FF,$AA,$55,$AA,$00,$00,$FF,$00 + db $04,$54,$AC,$5C,$FC,$FC,$FC,$3C,$FF,$AF,$57,$AB,$0B,$0B,$F3,$23 + db $3F,$3F,$3F,$3F,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $7E,$7C,$7C,$78,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $1F,$0F,$0F,$07,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FE,$FC,$FC,$F8,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $00,$00,$00,$00,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + db $18,$18,$18,$18,$18,$18,$18,$18,$00,$00,$00,$00,$00,$00,$00,$00 + db $07,$1F,$3F,$FF,$7F,$7F,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + 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 + 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 + db $01,$01,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00 + db $80,$80,$80,$80,$80,$80,$80,$80,$00,$00,$00,$00,$00,$00,$00,$00 + db $08,$88,$91,$D1,$53,$53,$73,$3F,$FF,$FF,$FF,$FF,$FF,$FE,$BE,$CE + db $00,$00,$07,$0F,$0C,$1B,$1B,$1B,$00,$00,$00,$00,$03,$04,$04,$04 + db $00,$00,$E0,$F0,$F0,$F8,$F8,$F8,$00,$00,$60,$30,$30,$98,$98,$98 + db $1B,$1B,$1B,$1B,$1B,$0F,$0F,$07,$04,$04,$04,$04,$04,$03,$00,$00 + 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 $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 + 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 + db $F8,$FC,$FE,$FE,$FE,$FF,$FF,$FF,$F8,$04,$02,$02,$02,$01,$41,$41 + db $FF,$FF,$FF,$FE,$FE,$FE,$FC,$78,$41,$01,$05,$22,$C2,$02,$84,$78 + db $7F,$80,$80,$80,$80,$80,$80,$80,$80,$7F,$7F,$7F,$7F,$7F,$7F,$7F + db $DE,$61,$61,$61,$71,$5E,$7F,$61,$61,$DF,$DF,$DF,$DF,$FF,$C1,$DF + db $80,$80,$C0,$F0,$BF,$8F,$81,$7E,$7F,$7F,$FF,$3F,$4F,$71,$7F,$FF + db $61,$61,$C1,$C1,$81,$81,$83,$FE,$DF,$DF,$BF,$BF,$7F,$7F,$7F,$7F + db $00,$00,$03,$0F,$1F,$3F,$7F,$7F,$00,$00,$03,$0C,$10,$20,$40,$40 + db $00,$00,$C0,$F0,$F8,$FC,$FE,$FE,$00,$00,$C0,$30,$08,$04,$02,$02 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$80,$80,$80,$80,$80,$80,$80,$80 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$01,$01,$01,$01,$01,$01,$01,$01 + 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 + 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 + db $00,$00,$07,$0F,$0C,$1B,$1B,$1B,$FF,$FF,$F8,$F0,$F0,$E0,$E0,$E0 + db $00,$00,$E0,$F0,$F0,$F8,$F8,$F8,$FF,$FF,$7F,$3F,$3F,$9F,$9F,$9F + db $1B,$1B,$1B,$1B,$1B,$0F,$0F,$07,$E0,$E0,$E0,$E0,$E0,$F3,$F0,$F8 + db $F8,$F8,$F8,$F8,$F8,$F0,$F0,$E0,$9F,$9F,$9F,$9F,$9F,$3F,$3F,$7F + db $E0,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$70,$1F,$10,$70,$7F,$7F,$7F + db $07,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$00,$03,$F8,$00,$03,$FB,$FB,$FB + db $FF,$FF,$FF,$FF,$FF,$FE,$FF,$EF,$7C,$7B,$76,$75,$75,$77,$17,$67 + db $FF,$DF,$EF,$AF,$AF,$6F,$EF,$E7,$3B,$FB,$7B,$FB,$FB,$F3,$F8,$F3 + db $1F,$1F,$3F,$3F,$70,$63,$E7,$E5,$0F,$0F,$1F,$1F,$3F,$3C,$78,$7A + db $F0,$F0,$F8,$F8,$0C,$C4,$E4,$A6,$F8,$F8,$FC,$FC,$FE,$3E,$1E,$5F + 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 + 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 + db $7F,$7F,$3F,$3F,$3F,$3F,$1F,$1F,$80,$80,$C0,$C0,$E0,$F8,$FE,$FF + db $FE,$FF,$FF,$FF,$FC,$FC,$FE,$FE,$FF,$7F,$1F,$07,$03,$03,$01,$81 + db $7F,$7F,$7F,$3F,$3F,$3F,$3F,$1F,$80,$80,$80,$C0,$C0,$E0,$E0,$F0 + db $FE,$FE,$FF,$FF,$FF,$FF,$FF,$FE,$01,$01,$01,$03,$03,$07,$07,$0F + db $1F,$0F,$0F,$07,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FE,$FC,$FC,$F8,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $7E,$7E,$7E,$7E,$7F,$7F,$7F,$7F,$81,$81,$81,$81,$81,$81,$81,$81 + db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FE,$01,$01,$01,$03,$03,$07,$07,$0F + db $FE,$FE,$FE,$FE,$FF,$FF,$FF,$FF,$01,$01,$01,$01,$01,$01,$01,$01 + db $7F,$7F,$7F,$7F,$7F,$7F,$7F,$7F,$81,$81,$81,$81,$81,$81,$81,$81 + 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 + 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 + db $7E,$7C,$7C,$78,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF + db $FE,$FE,$FF,$FF,$7F,$7F,$7F,$7F,$81,$81,$81,$81,$81,$81,$81,$81 + db $7F,$7F,$3F,$3F,$3F,$3F,$1F,$1F,$80,$80,$C0,$C0,$E0,$F8,$FE,$FF + db $3F,$BF,$FF,$FF,$FC,$FC,$FE,$FE,$FF,$7F,$1F,$07,$03,$03,$01,$81 + db $7F,$7F,$7E,$7E,$7F,$7F,$7F,$7F,$81,$81,$81,$81,$81,$81,$81,$81 + db $7E,$7E,$7E,$7E,$7F,$7F,$7F,$7F,$81,$81,$81,$81,$81,$81,$81,$81 + db $81,$C3,$C3,$E7,$E7,$FF,$FF,$FF,$7E,$3C,$3C,$18,$18,$00,$00,$00 + db $0F,$43,$5B,$53,$31,$19,$0F,$07,$F2,$FE,$FE,$FF,$FF,$EF,$F7,$F8 + db $C1,$C3,$C6,$84,$FC,$FC,$0E,$02,$BF,$BE,$BD,$7B,$7B,$07,$F3,$FD + db $10,$20,$22,$BA,$E6,$E1,$C0,$C0,$FF,$FF,$FF,$67,$59,$9E,$BF,$BF + 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 + 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 + db $DE,$D1,$D8,$D0,$D1,$26,$DE,$D1,$DE,$D1,$D0,$D1,$D0,$D1,$26,$21 + db $46,$14,$DB,$42,$42,$DB,$42,$DB,$42,$DB,$DB,$42,$26,$DB,$42,$DB + db $42,$DB,$42,$DB,$42,$26,$21,$66,$46,$DB,$21,$6C,$0E,$DF,$DB,$DB + db $DB,$26,$DB,$DF,$DB,$DF,$DB,$DB,$E4,$E5,$26,$21,$86,$14,$DB,$DB + db $DB,$DE,$43,$DB,$E0,$DB,$DB,$DB,$26,$DB,$E3,$DB,$E0,$DB,$DB,$E6 + db $E3,$26,$21,$A6,$14,$DB,$DB,$DB,$DB,$42,$DB,$DB,$DB,$D4,$D9,$26 + db $DB,$D9,$DB,$DB,$D4,$D9,$D4,$D9,$E7,$21,$C5,$16,$5F,$95,$95,$95 + db $95,$95,$95,$95,$95,$97,$98,$78,$95,$96,$95,$95,$97,$98,$97,$98 + db $95,$7A,$21,$ED,$0E,$CF,$01,$09,$08,$05,$24,$17,$12,$17,$1D,$0E + db $17,$0D,$18,$22,$4B,$0D,$01,$24,$19,$15,$0A,$22,$0E,$1B,$24,$10 + 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 $00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF diff --git a/demos/smb/package.json b/demos/smb/package.json index e675ab7..a9cd71b 100644 --- a/demos/smb/package.json +++ b/demos/smb/package.json @@ -8,13 +8,17 @@ "cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe", "gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe", "macros": "../../macros", - "crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe" + "crossrunner": "C:\\Program Files\\Crossrunner\\Crossrunner.exe" }, "scripts": { "test": "npm run build && npm run build:image && npm run gsport", "gsport": "%npm_package_config_gsport%", - "build": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s", - "build:image": "build-image.bat %npm_package_config_cadius%" + "build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s", + "build": "npm run build:tool && npm run build:sys16", + "build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s", + "build:image": "build-image.bat %npm_package_config_cadius%", + "debug": "\"%npm_package_config_crossrunner%\" SuperMarioGS -Source SuperMarioGS_S02__Output.txt -Source SuperMarioGS_S03__Output.txt -Debug -CompatibilityLayer" + }, "repository": { "type": "git", diff --git a/demos/smb/palette.s b/demos/smb/palette.s new file mode 100644 index 0000000..f83afc2 --- /dev/null +++ b/demos/smb/palette.s @@ -0,0 +1,69 @@ +; NES Palette (52 entries) +nesPalette + dw $0888 + dw $004A + dw $001B + dw $0409 + dw $0A06 + dw $0C02 + dw $0C10 + dw $0910 + dw $0630 + dw $0140 + dw $0050 + dw $0043 + dw $0046 + dw $0000 + dw $0111 + dw $0111 + + dw $0CCC + dw $007F + dw $025F + dw $083F + dw $0F3B + dw $0F35 + dw $0F20 + dw $0D30 + dw $0C60 + dw $0380 + dw $0190 + dw $0095 + dw $00AD + dw $0222 + dw $0111 + dw $0111 + + dw $0FFF + dw $01DF + dw $07AF + dw $0D8F + dw $0F4F + dw $0F69 + dw $0F93 + dw $0F91 + dw $0FC2 + dw $0AE1 + dw $03F3 + dw $01FA + dw $00FF + dw $0666 + dw $0111 + dw $0111 + + dw $0FFF + dw $0AFF + dw $0BEF + dw $0DAF + dw $0FBF + dw $0FAB + dw $0FDB + dw $0FEA + dw $0FF9 + dw $0DE9 + dw $0AEB + dw $0AFD + dw $09FF + dw $0EEE + dw $0111 + dw $0111 diff --git a/demos/smb/ppu.s b/demos/smb/ppu.s new file mode 100644 index 0000000..71b79fd --- /dev/null +++ b/demos/smb/ppu.s @@ -0,0 +1,521 @@ +; PPU simulator +; +; Any read/write to the PPU registers in the ROM is intercepted and passed here. + + mx %11 + dw $a5a5 ; marker to find in memory +ppuaddr ds 2 ; 16-bit ppu address +w_bit dw 1 ; currently writing to high or low to the address latch +vram_buff dw 0 ; latched data when reading VRAM ($0000 - $3EFF) + +ppuincr dw 1 ; 1 or 32 depending on bit 2 of PPUCTRL +spadr dw $0000 ; Sprite pattern table ($0000 or $1000) depending on bit 3 of PPUCTRL +ntaddr dw $2000 ; Base nametable address ($2000, $2400, $2800, $2C00), bits 0 and 1 of PPUCTRL +bgadr dw $0000 ; Background pattern table address +ppuctrl dw 0 ; Copy of the ppu ctrl byte +ppumask dw 0 ; Copy of the ppu mask byte +ppustatus dw 0 +oamaddr dw 0 ; Typically this will always be 0 +ppuscroll dw 0 ; Y X coordinates + +ntbase db $20,$24,$28,$2c + +assert_lt mac + cmp ]1 + bcc ok + brk ]2 +ok + <<< + +assert_x_lt mac + cpx ]1 + bcc ok + brk ]2 +ok + <<< + +cond mac + bit ]1 + beq cond_0 + lda ]3 + bra cond_s +cond_0 lda ]2 +cond_s sta ]4 + <<< + +; $2000 - PPUCTRL (Write only) +PPUCTRL_WRITE ENT + php + phb + phk + plb + + sta ppuctrl + phx + +; Set the pattern table base address + and #$03 + tax + lda ntbase,x + sta ntaddr+1 + +; Set the vram increment + lda ppuctrl + cond #$04;#$01;#$20;ppuincr + +; Set the sprite table address + lda ppuctrl + cond #$08;#$00;#$10;spadr+1 + +; Set the background table address + lda ppuctrl + cond #$10;#$00;#$10;bgadr+1 + + plx + lda ppuctrl + plb + plp + rtl + +; $2001 - PPUMASK (Write only) +PPUMASK_WRITE ENT + stal ppumask + rtl + + +; $2002 - PPUSTATUS For "ldx ppustatus" +PPUSTATUS_READ_X ENT + php + pha + + lda #1 + stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR + + ldal ppustatus + tax + and #$7F ; Clear the VBL flag + stal ppustatus + + pla ; Restore the accumulator (return value in X) + plp + phx ; re-read x to set any relevant flags + plx + + rtl + +PPUSTATUS_READ ENT + php + + lda #1 + stal w_bit ; Reset the address latch used by PPUSCROLL and PPUADDR + + ldal ppustatus + pha + and #$7F ; Clear the VBL flag + stal ppustatus + + pla ; pop the return value + plp + pha ; re-read accumulator to set any relevant flags + pla + rtl + +; $2003 +OAMADDR_WRITE ENT + stal oamaddr + rtl + +; $2005 - PPU SCROLL +PPUSCROLL_WRITE ENT + php + phb + phk + plb + phx + pha + + ldx w_bit + sta ppuscroll,x + txa + eor #$01 + sta w_bit + + pla + plx + plb + plp + rtl + +; $2006 - PPUADDR +PPUADDR_WRITE ENT + php + phb + phk + plb + phx + pha + + ldx w_bit + sta ppuaddr,x +; assert_lt #$40;$D0 + txa + eor #$01 + sta w_bit + + pla + plx + plb + 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 +; post-fetch. +PPUDATA_READ ENT + php + phb + phk + plb + phx + + rep #$30 ; do a 16-bit update of the address + ldx ppuaddr + txa +; assert_lt #$4000;$d1 + + clc + adc ppuincr + sta ppuaddr + sep #$20 ; back to 8-bit acc for the read itself + + cpx #$3F00 ; check which range of memory we are accessing? + bcc :buff_read + + lda PPU_MEM,x + bra :out + +:buff_read + lda vram_buff ; read from the buffer + pha + lda PPU_MEM,x ; put the data in the buffer for the next read + sta vram_buff + pla ; pop the return value + +:out + sep #$10 + plx + plb + plp + + pha + pla + rtl + +PPUDATA_WRITE ENT + php + phb + phk + plb + pha + phx + + rep #$10 + ldx ppuaddr + sta PPU_MEM,x + + rep #$30 + txa + clc + adc ppuincr + sta ppuaddr + + cpx #$3F00 + bcs :extra + + 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 +; +; NES Description IIgs Palette +; ---------------------------------------- +; BG0 Background color 0 +; BG0,1 Light Green 1 +; BG0,2 Dark Green 2 +; BG0,3 Black 3 +; BG1,1 Peach 4 +; BG1,2 Brown 5 +; BG1,3 Black 3 +; BG2,1 White 6 +; BG2,2 Light Blue 7 +; BG2,3 Black 3 +; BG3,1 Cycle 8 ; Coins / Blocks +; BG3,2 Brown 5 +; BG3,3 Black 3 +; SP0 0 +; SP0,1 Red 9 +; SP0,2 Orange 10 +; SP0,3 Olive 11 +; SP1,1 Dark Green 2 +; SP1,2 White 6 +; SP1,3 Orange 10 +; SP2,1 Red 9 +; SP2,2 White 6 +; SP2,3 Orange 10 +; SP3,1 Black 3 +; SP3,2 Peach 4 +; SP3,3 Brown 5 +; +; There are 4 color to spare in case we need to add more entries. This mapping table is important because +; we have to have a custom tile rendering function and custom sprite rendering function that will dynamically +; map the 2-bit tile data into the proper palette range. This will likely be implemented with an 8-bit +; swizzle table. Possible optimization later on is to pre-swizzle certain tiles assuming that the palette +; assignments never change. +; +; BG Palette 2 can probably be ignored because it's just for the top of the screen and we can use a separate +; SCB palette for that line + mx %00 +:extra + txa + and #$001F + asl + tax + jmp (palTbl,x) + +palTbl dw ppu_3F00,ppu_3F01,ppu_3F02,ppu_3F03 + dw ppu_3F04,ppu_3F05,ppu_3F06,ppu_3F07 + dw ppu_3F08,ppu_3F09,ppu_3F0A,ppu_3F0B + dw ppu_3F0C,ppu_3F0D,ppu_3F0E,ppu_3F0F + dw ppu_3F10,ppu_3F11,ppu_3F12,ppu_3F13 + dw ppu_3F14,ppu_3F15,ppu_3F16,ppu_3F17 + dw ppu_3F18,ppu_3F19,ppu_3F1A,ppu_3F1B + dw ppu_3F1C,ppu_3F1D,ppu_3F1E,ppu_3F1F + +ppu_3F00 + lda PPU_MEM+$3F00 + ldx #0 + brl extra_out + +ppu_3F01 + lda PPU_MEM+$3F01 + ldx #2 + brl extra_out + +ppu_3F02 + lda PPU_MEM+$3F02 + ldx #4 + brl extra_out + +ppu_3F03 + lda PPU_MEM+$3F03 + ldx #6 + brl extra_out + +ppu_3F05 + lda PPU_MEM+$3F05 + ldx #8 + brl extra_out + +ppu_3F06 + lda PPU_MEM+$3F06 + ldx #10 + brl extra_out + +ppu_3F07 + lda PPU_MEM+$3F07 + ldx #12 + brl extra_out + +ppu_3F09 + lda PPU_MEM+$3F05 + ldx #14 + brl extra_out + +ppu_3F0A + lda PPU_MEM+$3F06 + ldx #16 + brl extra_out + +ppu_3F0B + lda PPU_MEM+$3F07 + ldx #18 + brl extra_out + +ppu_3F0D + lda PPU_MEM+$3F05 + ldx #20 + brl extra_out + +ppu_3F0E + lda PPU_MEM+$3F06 + ldx #22 + brl extra_out + +ppu_3F0F + lda PPU_MEM+$3F07 + ldx #24 + brl extra_out + +ppu_3F10 + lda PPU_MEM+$3F10 + ldx #0 + brl extra_out + +ppu_3F04 +ppu_3F08 +ppu_3F0C +ppu_3F11 +ppu_3F12 +ppu_3F13 +ppu_3F14 +ppu_3F15 +ppu_3F16 +ppu_3F17 +ppu_3F18 +ppu_3F19 +ppu_3F1A +ppu_3F1B +ppu_3F1C +ppu_3F1D +ppu_3F1E +ppu_3F1F + +; Exit code to set a IIgs palette entry from the PPU memory +; +; A = NES palette value +; X = IIgs Palette index +extra_out + phy + and #$00FF + asl + tay + lda nesPalette,y + ply + stal $E19E00,x + + sep #$30 + plx + pla + plb + plp + rtl + +; Trigger a copy from a page of memory to OAM. Since this is a DMA operation, we can cheat and do a 16-bit copy +PPUDMA_WRITE ENT + php + phb + phk + plb + + phx + pha + + rep #$30 + xba + and #$FF00 + tax + +]n equ 0 + lup 128 + ldal ROMBase+]n,x + sta PPU_OAM+]n +]n = ]n+2 + --^ + + sep #$30 + + pla + plx + plb + plp + rtl + +y_offset equ 16 +x_offset equ 16 + +drawOAMSprites +:tmp equ 238 + phb + php + + phk + plb + + sep #$30 ; 8-bit cpu + ldx #4 ; Ok to always skip sprite 0 + +:oam_loop + lda PPU_OAM+3,x ; remove this test once we can clip sprites + cmp #241 + bcs :hidden + + lda PPU_OAM,x ; Y-coordinate + cmp #200+y_offset-9 + bcs :hidden + + phx + inc ; Compensate for PPU delayed scanline + rep #$30 + and #$00FF + asl + asl + asl + asl + asl + sta :tmp + asl + asl + clc + adc :tmp + clc + adc #$2000-{y_offset*160}+x_offset + sta :tmp + + lda PPU_OAM+3,x + lsr + and #$007F + clc + adc :tmp + tay + + lda PPU_OAM+2,x + bit #$0040 ; horizontal flip + bne :hflip + + lda PPU_OAM,x ; Load the tile index into the high byte (x256) + and #$FF00 + lsr ; multiple by 128 + tax + bra drawTilePatch + +:hflip + lda PPU_OAM,x ; Loda the tile index into the high byte (x256) + and #$FF00 + lsr ; multiple by 128 + adc #64 ; horizontal flip + tax + +drawTilePatch + jsl $000000 ; Draw the tile on the graphics screen + +:hop + sep #$30 + plx + +:hidden + inx + inx + inx + inx + bne :oam_loop + + plp + plb + rtl \ No newline at end of file diff --git a/demos/smb/rom.s b/demos/smb/rom.s index 2185b5c..bfb7137 100644 --- a/demos/smb/rom.s +++ b/demos/smb/rom.s @@ -668,23 +668,79 @@ GameOverModeValue = 3 ; .mem 8 ;------------------------------------------------------------------------------------- - mx %11 -; External wrapper is responsible for setting the stack - put chr.s - ds $6000 +; External wrapper is responsible for setting the stack +PPUCTRL_WRITE EXT +PPUMASK_WRITE EXT +PPUSTATUS_READ EXT +PPUSTATUS_READ_X EXT +OAMADDR_WRITE EXT +PPUSCROLL_WRITE EXT +PPUADDR_WRITE EXT +PPUDATA_READ EXT +PPUDATA_WRITE EXT +PPUDMA_WRITE EXT + +ROMBase ENT + ds $8000-14-50 + +; Hooks to call back to the GTE harness for PPU memory-mapped accesses + mx %11 +PPU_CTRL_W + jsl PPUCTRL_WRITE + rts +PPU_MASK_W + jsl PPUMASK_WRITE + rts +PPU_STATUS_R + jsl PPUSTATUS_READ + rts +PPU_STATUS_RX + jsl PPUSTATUS_READ_X + rts +OAM_ADDR_W + jsl OAMADDR_WRITE + rts +PPU_SCROLL_W + jsl PPUSCROLL_WRITE + rts +PPU_ADDRESS_W + jsl PPUADDR_WRITE + rts +PPU_DATA_R + jsl PPUDATA_READ + rts +PPU_DATA_W + jsl PPUDATA_WRITE + rts +SPR_DMA_W + jsl PPUDMA_WRITE + rts + +; Enter via a JML. X = target address, Stack and Direct page set up properly. B = ROM bank. Called in 16-bit native mode + mx %00 + +ExtRtn EXT +ExtIn ENT + stx :patch+1 + sep #$30 +:patch jsr $0000 + rep #$30 + jml ExtRtn + + mx %11 SMBStart ENT Start ; sei ;pretty standard 6502 type init here ; cld lda #%00010000 ;init PPU control register 1 - sta PPU_CTRL_REG1 + jsr PPU_CTRL_W ; ldx #$ff ;reset stack pointer ; txs -VBlank1 lda PPU_STATUS ;wait two frames - bpl VBlank1 -VBlank2 lda PPU_STATUS - bpl VBlank2 +;VBlank1 jsr PPU_STATUS_R ;wait two frames +; bpl VBlank1 +;VBlank2 jsr PPU_STATUS_R +; bpl VBlank2 ldy #ColdBootOffset ;load default cold boot pointer ldx #$05 ;this is where we check for a warm boot WBootCheck lda TopScoreDisplay,x ;check each score digit in the top score @@ -696,7 +752,8 @@ WBootCheck lda TopScoreDisplay,x ;check each score d cmp #$a5 ;another location has a specific value bne ColdBoot ldy #WarmBootOffset ;if passed both, load warm boot pointer -ColdBoot jsr InitializeMemory ;clear memory using pointer in Y +ColdBoot + jsr InitializeMemory ;clear memory using pointer in Y sta SND_DELTA_REG+1 ;reset delta counter load register sta OperMode ;reset primary mode of operation lda #$a5 ;set warm boot flag @@ -705,7 +762,7 @@ ColdBoot jsr InitializeMemory ;clear memory using lda #%00001111 sta SND_MASTERCTRL_REG ;enable all sound channels except dmc lda #%00000110 - sta PPU_CTRL_REG2 ;turn off clipping for OAM and background + jsr PPU_MASK_W ;turn off clipping for OAM and background jsr MoveAllSpritesOffscreen jsr InitializeNameTables ;initialize both name tables inc DisableScreenFlag ;set flag to disable screen output @@ -713,41 +770,41 @@ ColdBoot jsr InitializeMemory ;clear memory using ora #%10000000 ;enable NMIs jsr WritePPUReg1 ; EndlessLoop jmp EndlessLoop ;endless loop, need I say more? - rtl ; GTE - Return to caller - +InternalRts rts ; GTE - Return to caller + ds 17 ; Add back inthe bytes we commented out ;------------------------------------------------------------------------------------- ;$00 - vram buffer address table low, also used for pseudorandom bit ;$01 - vram buffer address table high VRAM_AddrTable_Low - db VRAM_Buffer1,>WaterPaletteData, - db >UndergroundPaletteData,>CastlePaletteData, - db >VRAM_Buffer2,>VRAM_Buffer2, - db >DaySnowPaletteData,>NightSnowPaletteData, - db >MarioThanksMessage,>LuigiThanksMessage, - db >PrincessSaved1,>PrincessSaved2, - db >WorldSelectMessage2 + db >VRAM_Buffer1, >WaterPaletteData, >GroundPaletteData + db >UndergroundPaletteData, >CastlePaletteData, >VRAM_Buffer1_Offset + db >VRAM_Buffer2, >VRAM_Buffer2, >BowserPaletteData + db >DaySnowPaletteData, >NightSnowPaletteData, >MushroomPaletteData + db >MarioThanksMessage, >LuigiThanksMessage, >MushroomRetainerSaved + db >PrincessSaved1, >PrincessSaved2, >WorldSelectMessage1 + db >WorldSelectMessage2 VRAM_Buffer_Offset db TitleScreenDataOffset ;load address $1ec0 into - sta PPU_ADDRESS ;the vram address register + jsr PPU_ADDRESS_W ;the vram address register lda #Palette0_MTiles,>Palette1_MTiles, + db >Palette0_MTiles, >Palette1_MTiles, >Palette2_MTiles, >Palette3_MTiles Palette0_MTiles db $24,$24,$24,$24 ;blank @@ -2384,15 +2457,21 @@ JumpEngine iny lda ($04),y ;load pointer from indirect sta $06 ;note that if an RTS is performed in next routine + sta :je_patch+1 iny ;it will return to the execution before the sub lda ($04),y ;that called this routine sta $07 - jmp ($06) ;jump to the address we loaded + sta :je_patch+2 +; jmp ($06) ;jump to the address we loaded + +; GTE Note: We run in a different bank with a direct page != 0, so jmp (abs) cannot work, but we're in RAM now +; so self-modifying code to the rescue +:je_patch jmp $0000 ;------------------------------------------------------------------------------------- InitializeNameTables - lda PPU_STATUS ;reset flip-flop + jsr PPU_STATUS_R ;reset flip-flop lda Mirror_PPU_CTRL_REG1 ;load mirror of ppu reg $2000 ora #%00010000 ;set sprites for first 4k and background for second 4k and #%11110000 ;clear rest of lower nybble, leave higher alone @@ -2400,13 +2479,13 @@ InitializeNameTables lda #$24 ;set vram address to start of name table 1 jsr WriteNTAddr lda #$20 ;and then set it to name table 0 -WriteNTAddr sta PPU_ADDRESS +WriteNTAddr jsr PPU_ADDRESS_W lda #$00 - sta PPU_ADDRESS + jsr PPU_ADDRESS_W ldx #$04 ;clear name table with blank tile #24 ldy #$c0 lda #$24 -InitNTLoop sta PPU_DATA ;count out exactly 768 tiles +InitNTLoop jsr PPU_DATA_W ;count out exactly 768 tiles dey bne InitNTLoop dex @@ -2415,7 +2494,7 @@ InitNTLoop sta PPU_DATA ;count out exactly txa sta VRAM_Buffer1_Offset ;init vram buffer 1 offset sta VRAM_Buffer1 ;init vram buffer 1 -InitATLoop sta PPU_DATA +InitATLoop jsr PPU_DATA_W dey bne InitATLoop sta HorizontalScroll ;reset scroll variables @@ -2424,7 +2503,7 @@ InitATLoop sta PPU_DATA ;------------------------------------------------------------------------------------- ;$00 - temp joypad bit - +native_joy EXT ReadJoypads lda #$01 ;reset and clear strobe of joypad ports sta JOYPAD_PORT @@ -2433,17 +2512,20 @@ ReadJoypads sta JOYPAD_PORT jsr ReadPortBits inx ;increment for joypad 2's port -ReadPortBits ldy #$08 -PortLoop pha ;push previous bit onto stack - lda JOYPAD_PORT,x ;read current bit on joypad port - sta $00 ;check d1 and d0 of port output - lsr ;this is necessary on the old - ora $00 ;famicom systems in japan - lsr - pla ;read bits from stack - rol ;rotate bit from carry flag - dey - bne PortLoop ;count down bits left +ReadPortBits +; ldy #$08 +;PortLoop pha ;push previous bit onto stack +; lda JOYPAD_PORT,x ;read current bit on joypad port +; sta $00 ;check d1 and d0 of port output +; lsr ;this is necessary on the old +; ora $00 ;famicom systems in japan +; lsr +; pla ;read bits from stack +; rol ;rotate bit from carry flag +; dey +; bne PortLoop ;count down bits left + ldal native_joy,x + sta SavedJoypadBits,x ;save controller status here always pha and #%00110000 ;check for select or start @@ -2462,10 +2544,10 @@ Save8Bits pla ;$01 - vram buffer address table high WriteBufferToScreen - sta PPU_ADDRESS ;store high byte of vram address + jsr PPU_ADDRESS_W ;store high byte of vram address iny lda ($00),y ;load next byte (second) - sta PPU_ADDRESS ;store low byte of vram address + jsr PPU_ADDRESS_W ;store low byte of vram address iny lda ($00),y ;load next byte (third) asl ;shift to left and save in stack @@ -2486,7 +2568,7 @@ GetLength lsr ;shift back to the OutputToVRAM bcs RepeatByte ;if carry set, repeat loading the same byte iny ;otherwise increment Y to load next byte RepeatByte lda ($00),y ;load more data from buffer and write to vram - sta PPU_DATA + jsr PPU_DATA_W dex ;done writing? bne OutputToVRAM sec @@ -2497,23 +2579,23 @@ RepeatByte lda ($00),y ;load more data fro adc $01 sta $01 lda #$3f ;sets vram address to $3f00 - sta PPU_ADDRESS + jsr PPU_ADDRESS_W lda #$00 - sta PPU_ADDRESS - sta PPU_ADDRESS ;then reinitializes it for some reason - sta PPU_ADDRESS -UpdateScreen ldx PPU_STATUS ;reset flip-flop + jsr PPU_ADDRESS_W + jsr PPU_ADDRESS_W ;then reinitializes it for some reason + jsr PPU_ADDRESS_W +UpdateScreen jsr PPU_STATUS_RX ;reset flip-flop ldy #$00 ;load first byte from indirect as a pointer lda ($00),y bne WriteBufferToScreen ;if byte is zero we have no further updates to make here -InitScroll sta PPU_SCROLL_REG ;store contents of A into scroll registers - sta PPU_SCROLL_REG ;and end whatever subroutine led us here +InitScroll jsr PPU_SCROLL_W ;store contents of A into scroll registers + jsr PPU_SCROLL_W ;and end whatever subroutine led us here rts ;------------------------------------------------------------------------------------- WritePPUReg1 - sta PPU_CTRL_REG1 ;write contents of A to PPU register 1 + jsr PPU_CTRL_W ;write contents of A to PPU register 1 sta Mirror_PPU_CTRL_REG1 ;and its mirror rts @@ -2763,8 +2845,8 @@ ISpr0Loop lda Sprite0Data,y sta Sprite_Data,y dey bpl ISpr0Loop - jsr DoNothing2 ;these jsrs doesn't do anything useful - jsr DoNothing1 +; jsr DoNothing2 ;these jsrs doesn't do anything useful +; jsr DoNothing1 inc Sprite0HitDetectFlag ;set sprite #0 check flag inc OperMode_Task ;increment to next task rts @@ -4329,8 +4411,8 @@ GetAreaObjYPosition ;$06-$07 - used to store block buffer address used as indirect BlockBufferAddr - db Block_Buffer_1, >Block_Buffer_2 + db Block_Buffer_1, >Block_Buffer_2 GetBlockBufferAddr pha ;take value of A, save @@ -4492,39 +4574,39 @@ EnemyAddrHOffsets db $1f,$06,$1c,$00 EnemyDataAddrLow - db E_CastleArea1, >E_CastleArea2, - db >E_GroundArea1, >E_GroundArea2, - db >E_GroundArea7, >E_GroundArea8, - db >E_GroundArea13, >E_GroundArea14, - db >E_GroundArea19, >E_GroundArea20, - db >E_UndergroundArea2, >E_UndergroundArea3, + db >E_CastleArea1, >E_CastleArea2, >E_CastleArea3, >E_CastleArea4, >E_CastleArea5, >E_CastleArea6 + db >E_GroundArea1, >E_GroundArea2, >E_GroundArea3, >E_GroundArea4, >E_GroundArea5, >E_GroundArea6 + db >E_GroundArea7, >E_GroundArea8, >E_GroundArea9, >E_GroundArea10, >E_GroundArea11, >E_GroundArea12 + db >E_GroundArea13, >E_GroundArea14, >E_GroundArea15, >E_GroundArea16, >E_GroundArea17, >E_GroundArea18 + db >E_GroundArea19, >E_GroundArea20, >E_GroundArea21, >E_GroundArea22, >E_UndergroundArea1 + db >E_UndergroundArea2, >E_UndergroundArea3, >E_WaterArea1, >E_WaterArea2, >E_WaterArea3 AreaDataHOffsets db $00,$03,$19,$1c AreaDataAddrLow - db L_WaterArea1, >L_WaterArea2, - db >L_GroundArea4, >L_GroundArea5, - db >L_GroundArea10, >L_GroundArea11, - db >L_GroundArea16, >L_GroundArea17, - db >L_GroundArea22, >L_UndergroundArea1, - db >L_CastleArea2, >L_CastleArea3, + db >L_WaterArea1, >L_WaterArea2, >L_WaterArea3, >L_GroundArea1, >L_GroundArea2, >L_GroundArea3 + db >L_GroundArea4, >L_GroundArea5, >L_GroundArea6, >L_GroundArea7, >L_GroundArea8, >L_GroundArea9 + db >L_GroundArea10, >L_GroundArea11, >L_GroundArea12, >L_GroundArea13, >L_GroundArea14, >L_GroundArea15 + db >L_GroundArea16, >L_GroundArea17, >L_GroundArea18, >L_GroundArea19, >L_GroundArea20, >L_GroundArea21 + db >L_GroundArea22, >L_UndergroundArea1, >L_UndergroundArea2, >L_UndergroundArea3, >L_CastleArea1 + db >L_CastleArea2, >L_CastleArea3, >L_CastleArea4, >L_CastleArea5, >L_CastleArea6 ;ENEMY OBJECT DATA @@ -15987,16 +16069,16 @@ MusicHeaderData db Star_CloudHdr-MHD db SilenceHdr-MHD - db GroundLevelLeadInHdr-MHD ;ground level music layout - db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD - db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, - db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, - db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, - db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD - db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, - db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, - db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, - db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, + db GroundLevelLeadInHdr-MHD ;ground level music layout + db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD + db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, GroundLevelPart2AHdr-MHD, GroundLevelPart2CHdr-MHD + db GroundLevelPart2AHdr-MHD, GroundLevelPart2BHdr-MHD, GroundLevelPart2AHdr-MHD, GroundLevelPart2CHdr-MHD + db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, GroundLevelPart3AHdr-MHD, GroundLevelLeadInHdr-MHD + db GroundLevelPart1Hdr-MHD, GroundLevelPart1Hdr-MHD + db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD + db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD + db GroundLevelPart3AHdr-MHD, GroundLevelPart3BHdr-MHD, GroundLevelPart3AHdr-MHD, GroundLevelLeadInHdr-MHD + db GroundLevelPart4AHdr-MHD, GroundLevelPart4BHdr-MHD, GroundLevelPart4AHdr-MHD, GroundLevelPart4CHdr-MHD ;music headers ;header format is as follows @@ -16006,28 +16088,28 @@ MusicHeaderData ;1 byte - square 1 data offset ;1 byte - noise data offset (not used by secondary music) -TimeRunningOutHdr db $08, TimeRunOutMusData, $27, $18 +Star_CloudHdr db $20, Star_CloudMData, $2e, $1a, $40 +EndOfLevelMusHdr db $20, WinLevelMusData, $3d, $21 +ResidualHeaderData db $20, $c4, $fc, $3f, $1d +UndergroundMusHdr db $18, UndergroundMusData, $00, $00 +SilenceHdr db $08, SilenceData, $00 +CastleMusHdr db $00, CastleMusData, $93, $62 +VictoryMusHdr db $10, VictoryMusData, $24, $14 +GameOverMusHdr db $18, GameOverMusData, $1e, $14 +WaterMusHdr db $08, WaterMusData, $a0, $70, $68 +WinCastleMusHdr db $08, EndOfCastleMusData, $4c, $24 +GroundLevelPart1Hdr db $18, GroundM_P1Data, $2d, $1c, $b8 +GroundLevelPart2AHdr db $18, GroundM_P2AData, $20, $12, $70 +GroundLevelPart2BHdr db $18, GroundM_P2BData, $1b, $10, $44 +GroundLevelPart2CHdr db $18, GroundM_P2CData, $11, $0a, $1c +GroundLevelPart3AHdr db $18, GroundM_P3AData, $2d, $10, $58 +GroundLevelPart3BHdr db $18, GroundM_P3BData, $14, $0d, $3f +GroundLevelLeadInHdr db $18, GroundMLdInData, $15, $0d, $21 +GroundLevelPart4AHdr db $18, GroundM_P4AData, $18, $10, $7a +GroundLevelPart4BHdr db $18, GroundM_P4BData, $19, $0f, $54 +GroundLevelPart4CHdr db $18, GroundM_P4CData, $1e, $12, $2b +DeathMusHdr db $18, DeathMusData, $1e, $0f, $2d ;-------------------------------- diff --git a/macros/GTE.Macs.s b/macros/GTE.Macs.s index 5b8610f..e46fd98 100644 --- a/macros/GTE.Macs.s +++ b/macros/GTE.Macs.s @@ -180,6 +180,8 @@ scanlineHorzOffset equ $0001 scanlineHorzOffset2 equ $0002 tileStore equ $0003 vblCallback equ $0004 +extSpriteRenderer equ $0005 +rawDrawTile equ $0006 ; 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 21a364f..c540bd4 100644 --- a/src/Defs.s +++ b/src/Defs.s @@ -193,6 +193,8 @@ scanlineHorzOffset equ $0001 ; Table of 416 words, a double-array o scanlineHorzOffset2 equ $0002 ; Table of 416 words, a double-array of scanline offset values. Values must be in range [0, 163] 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 ; 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 @@ -307,6 +309,7 @@ ObjectList EXT StartXMod164Tbl EXT LastOffsetTbl EXT BG1StartXMod164Tbl EXT +ExtSpriteRenderer EXT ; Tool error codes NO_TIMERS_AVAILABLE equ 10 diff --git a/src/Render.s b/src/Render.s index cd2b052..2a8be22 100644 --- a/src/Render.s +++ b/src/Render.s @@ -60,7 +60,7 @@ _Render jsr _ApplyTiles ; This function actually draws the new tiles into the code field - jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode + jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode lda #RENDER_BG1_ROTATION bit RenderFlags @@ -153,6 +153,87 @@ _DoOverlay :disp jsl $000000 rts +; Special NES renderer that externalizes the sprite rendreing in order to exceed the internal limit of 16 sprites +_RenderNES + jsr _ApplyBG0YPos + jsr _ApplyBG0XPosPre + jsr _ApplyTiles ; This function actually draws the new tiles into the code field +; jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode + + stz tmp1 ; virt_line_x2 + lda #16*2 + sta tmp2 ; lines_left_x2 + lda #0 ; Xmod164 + jsr _ApplyBG0XPosAlt + lda tmp4 ; :exit_offset + stal nesTopOffset + + lda #16*2 + sta tmp1 ; virt_line_x2 + lda ScreenHeight + sec + sbc #16 + asl + sta tmp2 ; lines_left_x2 + lda StartXMod164 ; Xmod164 + jsr _ApplyBG0XPosAlt + lda tmp4 + stal nesBottomOffset + + ldx #0 ; Blit the full virtual buffer to the screen + ldy ScreenHeight + jsr _BltRange + + lda ExtSpriteRenderer + ora ExtSpriteRenderer+2 + beq :no_sprite + + lda ExtSpriteRenderer + stal :patch+1 + lda ExtSpriteRenderer+1 + stal :patch+2 +:patch jsl $000000 + +:no_sprite + + stz tmp1 ; :virt_line_x2 + lda #16*2 + sta tmp2 ; :lines_left_x2 + ldal nesTopOffset + sta tmp4 ; :exit_offset + jsr _RestoreBG0OpcodesAlt + + lda #16*2 + sta tmp1 ; :virt_line_x2 + lda ScreenHeight + sec + sbc #16 + asl + sta tmp2 ; lines_left_x2 + ldal nesBottomOffset + sta tmp4 ; :exit_offset + jsr _RestoreBG0OpcodesAlt + +; lda StartYMod208 ; Restore the fields back to their original state +; ldx ScreenHeight +; jsr _RestoreBG0Opcodes + + lda StartY + sta OldStartY + lda StartX + sta OldStartX + + lda BG1StartY + sta OldBG1StartY + lda BG1StartX + sta OldBG1StartX + + stz DirtyBits + stz LastRender ; Mark that a full render was just performed + rts + +nesTopOffset ds 2 +nesBottomOffset ds 2 ; Use the per-scanline tables to set the screen. This is really meant to be used without the built-in tilemap ; support and is more of a low-level way to control the background rendering diff --git a/src/SpriteRender.s b/src/SpriteRender.s index aaf8b57..d2c60eb 100644 --- a/src/SpriteRender.s +++ b/src/SpriteRender.s @@ -137,6 +137,33 @@ RTL_OPCODE equ $6B lda :rtnval ; Address in the compile memory rts +; Draw a tile directly to the graphics screen as a sprite +; +; Y = screen address +; X = tile address +; A = $0001 = ignore mask + +_DrawTileToScreen + phb + pea $0101 + plb + plb + +]line equ 0 + lup 8 + lda: {]line*SHR_LINE_WIDTH}+2,y + andl tiledata+{]line*4}+32+2,x + oral tiledata+{]line*4}+2,x + sta: {]line*SHR_LINE_WIDTH}+2,y + lda: {]line*SHR_LINE_WIDTH},y + andl tiledata+{]line*4}+32,x + oral tiledata+{]line*4},x + sta: {]line*SHR_LINE_WIDTH},y +]line equ ]line+1 + --^ + plb + rtl ; special exit + ; Draw a sprite directly to the graphics screen. If sprite is clipped at all, do not draw. ; ; X = sprite record index diff --git a/src/Tool.s b/src/Tool.s index af13baf..28b1554 100644 --- a/src/Tool.s +++ b/src/Tool.s @@ -298,6 +298,9 @@ _TSRender _TSEntry lda :flags,s + cmp #$FFFF ; Hack! Special mode... + beq :nes + bit #RENDER_WITH_SHADOWING beq :no_shadowing jsr _RenderWithShadowing @@ -311,6 +314,10 @@ _TSRender :no_scanline jsr _Render + bra :done + +:nes + jsr _RenderNES :done _TSExit #0;#2 @@ -915,7 +922,16 @@ _TSGetAddress lda BG1StartXMod164Tbl+2 sta :output+2,s bra :out -:next_2 + +:next_2 cmp #rawDrawTile + bne :next_3 + + lda #_DrawTileToScreen + sta :output,s + lda #^_DrawTileToScreen + sta :output+2,s + bra :out +:next_3 :out _TSExit #0;#2 @@ -933,7 +949,7 @@ _TSSetAddress sta StartXMod164Tbl lda :ptr+2,s sta StartXMod164Tbl+2 - bra :out + brl :out :next_1 cmp #scanlineHorzOffset2 @@ -943,7 +959,7 @@ _TSSetAddress sta BG1StartXMod164Tbl lda :ptr+2,s sta BG1StartXMod164Tbl+2 - bra :out + brl :out :next_2 cmp #vblCallback bne :next_3 @@ -956,15 +972,25 @@ _TSSetAddress stal _VblTaskPatch+1 ; long addressing because we're patching code in the K bank lda :ptr+1,s stal _VblTaskPatch+2 - bra :out + brl :out :vbl_restore lda #_TaskStub stal _VblTaskPatch+1 lda #>_TaskStub stal _VblTaskPatch+2 + brl :out + +:next_3 cmp #extSpriteRenderer + bne :next_4 + + lda :ptr,s + sta ExtSpriteRenderer + lda :ptr+2,s + sta ExtSpriteRenderer+2 bra :out -:next_3 + +:next_4 :out _TSExit #0;#6 diff --git a/src/blitter/Horz.s b/src/blitter/Horz.s index 5e3f4aa..4b850a9 100644 --- a/src/blitter/Horz.s +++ b/src/blitter/Horz.s @@ -153,11 +153,11 @@ _ApplyBG0XPos ; If there are saved opcodes that have not been restored, do not run this routine lda LastPatchOffset - beq :ok + beq *+3 rts ; This code is fairly succinct. See the corresponding code in Vert.s for more detailed comments. -:ok + lda StartYMod208 ; This is the base line of the virtual screen asl sta :virt_line_x2 ; Keep track of it @@ -228,7 +228,8 @@ _ApplyBG0XPos lda StartXMod164 ; Alternate entry point if the virt_line_x2 and lines_left_x2 and XMod164 values are passed in externally -_ApplyBG0XPosAlt + +_RestoreBG0OpcodesAlt :stk_save equ tmp0 :virt_line_x2 equ tmp1 :lines_left_x2 equ tmp2 diff --git a/src/static/TileStore.s b/src/static/TileStore.s index c4690ed..da65cab 100644 --- a/src/static/TileStore.s +++ b/src/static/TileStore.s @@ -560,6 +560,9 @@ _stamp_step ENT BG1YCache ENT ds 32 +ExtSpriteRenderer ENT + dw 0,0 + ; Scaling tables for the BG1 rotation tables. ScalingTables ENT dw Scale0,Scale1,Scale2,Scale3