diff --git a/demos/smb/Main.s b/demos/smb/Main.s index 793e8ad..9a861df 100644 --- a/demos/smb/Main.s +++ b/demos/smb/Main.s @@ -87,6 +87,7 @@ FTblTmp equ 228 ; Initialize the sound hardware for APU emulation + lda #2 ; 0 = 240Hz, 1 = 120Hz, 2 = 60Hz (external) jsr APUStartUp ; Start up GTE to drive the graphics @@ -119,6 +120,12 @@ FTblTmp equ 228 pea #NESTileBlitter _GTESetAddress +; Install a custom tile callback to draw tiles directly on the screen w/proper palettes +; pea userTileDirectCallback +; pea #^NESDirectTileBlitter +; pea #NESDirectTileBlitter +; _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 @@ -132,8 +139,12 @@ FTblTmp equ 228 ; Initialize the graphics screen playfield (256x160). The NES is 240 lines high, so 160 ; is a reasonable compromise. +; pea #128 +; pea #184 + pea #128 pea #200 + ; pea #80 ; pea #144 _GTESetScreenMode @@ -183,6 +194,9 @@ FTblTmp equ 228 pla sta OldOneSec +; Show the configuration screen +; jsr ShowConfig + ; 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 @@ -368,8 +382,15 @@ EvtLoop ldy #33 jsr CopyNametable brl EvtLoop - :not_v + cmp #'t' ; show VBL interrupt time + bne :not_t + lda show_vbl_cpu + eor #1 + sta show_vbl_cpu + brl EvtLoop +:not_t + cmp #'q' beq Exit brl EvtLoop @@ -393,7 +414,9 @@ singleStepMode dw 0 nmiCount dw 0 DPSave dw 0 LastAreaType dw 0 -frameCount dw 0 +frameCount dw 0 +show_vbl_cpu dw 0 + ; Toggle an APU control bit ToggleAPUChannel pha @@ -472,6 +495,17 @@ RenderFrame sta OldROMScrollEdge ; Stash a copy for the next round through lsr pha + +; Get the player's Y coordinate and determine of we need to adjust the camera based on the physical play field size +; sep #$20 +; ldal ROMBase+$b5 ; Player_Y_HighPos +; xba +; ldal ROMBase+$ce ; Player_Y_Position +; rep #$20 +; +; sec +; sbc TopClip ; If we're hiding the + pea $0000 _GTESetBG0Origin @@ -535,6 +569,122 @@ AreaPalettes dw WaterPalette,Area1Palette,Area2Palette,Area3Palette,Area4Pale SwizzleTables adrl AT0_T0,AT1_T0,AT2_T0,AT3_T0,AT2_T0 SwizzlePtr adrl AT1_T0 +; Draw PPU tiles to the screen for a UI +; +; 0 - 9 starts at tile 256 +; A - Z starts at tile 266 +; mushroom is $1CE = 462 +TILE_ZERO equ 256 +TILE_A equ 266 +TILE_SHROOM equ 462 +ShowConfig + lda #0 + jsr SetAreaType + lda #$0000 + stal $E19E00 + + ldx #TILE_SHROOM+TILE_USER_BIT +:loop + phx + + phx + pea $2000 + pea $0000 ; Bits 1-2, 5 and 7 are valid + _GTEDrawTileToScreen + + ldx #msg1 + ldy #$2000+{8*160} + lda #$0000 + jsr ConfigDrawString + + ldx #msg1 + ldy #$2000+{16*160} + lda #$0001 + jsr ConfigDrawString + + ldx #msg1 + ldy #$2000+{24*160} + lda #$0002 + jsr ConfigDrawString + + ldx #msg1 + ldy #$2000+{32*160} + lda #$0003 + jsr ConfigDrawString + +:waitloop + pha + _GTEReadControl + pla + bit #PAD_KEY_DOWN + beq :waitloop + + plx + and #$007F + cmp #LEFT_ARROW + beq :decrement + cmp #RIGHT_ARROW + beq :increment + rts + +:increment + inx + inx +:decrement dex + bra :loop + +; X = string pointer +; Y = address + +ConfigDrawString + stx Tmp0 + sty Tmp1 + sta Tmp2 + lda (Tmp0) + and #$00FF + tax + ldy #1 +:loop + phx + phy + + lda (Tmp0),y + and #$007F + cmp #'A' + bcc :not_letter + sbc #'A' + clc + adc #TILE_A + bra :draw +:not_letter + cmp #'0' + bcc :skip + sbc #'0' + clc + adc #TILE_ZERO +:draw + ora #TILE_USER_BIT + pha + pei Tmp1 + pei Tmp2 ; palette select + _GTEDrawTileToScreen + +:skip + lda Tmp1 + clc + adc #4 + sta Tmp1 + + ply + plx + + iny + dex + bne :loop + rts + +msg1 str 'HELLO 123' + ; Take a PPU address and convert it to a tile store coordinate ; ; Inputs @@ -1021,7 +1171,7 @@ CopyNametable ldx Tmp2 ; Nametable address lda PPU_MEM+$2000,x and #$00FF - ora #$0100+TILE_USER_BIT ; USe top 256 tiles and set as a user-defined tile + ora #$0100+TILE_USER_BIT ; Use top 256 tiles and set as a user-defined tile pha jsr GetPaletteSelect ora 1,s ; Merge bits 9 and 10 into the Tile ID that's on the stack @@ -1072,6 +1222,10 @@ CopyNametable ; Trigger an NMI in the ROM triggerNMI + sep #$30 + jsl quarter_speed_driver + rep #$30 + ldal ppuctrl ; If the ROM has not enabled VBL NMI, also skip bit #$80 beq :skip @@ -1617,20 +1771,25 @@ nmiTask ldal singleStepMode bne :no_nmi -; lda #1 -; jsr setborder + + ldal show_vbl_cpu + beq :no_show_1 + jsr incborder +:no_show_1 jsr triggerNMI -; lda #0 -; jsr setborder -:no_nmi + ldal show_vbl_cpu + beq :no_nmi + jsr decborder +:no_nmi pld plb plp :skip rtl + mx %00 readInput diff --git a/demos/smb/apu.s b/demos/smb/apu.s index 133161c..38df7e4 100644 --- a/demos/smb/apu.s +++ b/demos/smb/apu.s @@ -31,6 +31,7 @@ access_doc_ram_no_inc = * mx %00 APUStartUp + stal apu_mode sei phd pea $c000 @@ -51,11 +52,16 @@ APUShutDown = * jsr stop_playing + ldal apu_mode + cmp #2 + beq :no_doc_interrupts + lda backup_interrupt_ptr ; restore old interrupt ptr stal sound_interrupt_ptr lda backup_interrupt_ptr+2 stal sound_interrupt_ptr+2 +:no_doc_interrupts cli pld clc @@ -109,7 +115,7 @@ copy_instruments_to_doc lda #$0600 jsr copy_noise - lda #$8000 +; lda #$8000 ; jsr gen_noise rts @@ -313,6 +319,10 @@ copy_register_config ;-------------------------- setup_interrupt = * + ldal apu_mode + cmp #2 ; mode 2 = external driver at 60Hz + beq :no_doc_interrupts + ldal sound_interrupt_ptr sta backup_interrupt_ptr ldal sound_interrupt_ptr+2 @@ -330,6 +340,19 @@ setup_interrupt = * sep #$20 mx %10 + ldal apu_mode + beq :do_240hz + lda #598 + ldy #598/256 + bra :set_timer_freq +:do_240hz lda #1195 + ldy #1195/256 + +:set_timer_freq + stal timer_sound_settings+1 ; low byte of timer frequency + tya + stal timer_sound_settings+3 ; high byte of timer frequency + jsr access_doc_registers ldy #0 @@ -344,7 +367,7 @@ setup_interrupt = * rep #$20 mx %00 - +:no_doc_interrupts rts interrupt_oscillator = 31 @@ -398,6 +421,7 @@ noise_sound_settings = * dfb $a0+noise_oscillator,0 ; mode register, set to free run backup_interrupt_ptr ds 4 +apu_mode ds 2 ;----------------------------------------------------------------------------------------- ; APU internals @@ -557,6 +581,45 @@ PULSE_CONST_VOL_FLAG equ $10 NOISE_CONST_VOL_FLAG equ $10 TRIANGLE_HALT_FLAG equ $80 + mx %11 +quarter_speed_driver = * + + phb + phd + + phk + plb + + pea $c000 + pld + + ldx apu_frame_counter + inx + inx + cpx #2*apu_frame_steps ; TODO: This is set by MSB in $4017 (4 or 5). 4 = PAL, 5 = NTSC. + bcc *+4 + ldx #0 + stx apu_frame_counter + jmp (:frame_counter_proc,x) +:frame_counter_proc da :quarter_frame,:half_frame,:quarter_frame,:no_frame_60,:half_frame + +; Quarter-speed interrupts (60Hz) -- clock four times in each handler +:half_frame +:quarter_frame + jsr half_frame_clock + jsr quarter_frame_clock + jsr quarter_frame_clock + jsr half_frame_clock + jsr quarter_frame_clock + jsr quarter_frame_clock + + brl update_doc_registers +:no_frame_60 + pld + plb + clc + rtl + mx %11 interrupt_handler = * @@ -588,9 +651,7 @@ interrupt_handler = * beq *+5 brl :not_timer ; Only service timer interrupts -; Update the frame counter. We double-count so that frame counter can be used directly to dispatch to the -; appropriate tick handler - +; Update the frame counter and leave the doubled countin x-register for dispatch ldx apu_frame_counter inx inx @@ -598,31 +659,30 @@ interrupt_handler = * bcc *+4 ldx #0 stx apu_frame_counter - jmp (:frame_counter_proc,x) -:frame_counter_proc da :quarter_frame,:half_frame,:quarter_frame,:no_frame,:half_frame + +; Figure out which speed we are dispatching + lda apu_mode + beq :do_240hz_mode + jmp (:apu_120hz_table,x) +:do_240hz_mode jmp (:apu_240hz_table,x) +:apu_240hz_table da :quarter_frame_240,:half_frame_240,:quarter_frame_240,no_frame,:half_frame_240 +:apu_120hz_table da :quarter_frame_120,:half_frame_120,:quarter_frame_120,no_frame,:half_frame_120 ; Full speed emulation (240Hz) -:half_frame jsr half_frame_clock -:quarter_frame jsr quarter_frame_clock +:half_frame_240 jsr half_frame_clock +:quarter_frame_240 jsr quarter_frame_clock + bra update_doc_registers ; Half-speed interrupts (120Hz) -- clock twice in each handler -;:half_frame -;:quarter_frame -; jsr half_frame_clock -; jsr quarter_frame_clock -; jsr quarter_frame_clock - -; Quarter-speed interrupts (60Hz) -- clock four times in each handler -;:half_frame -;:quarter_frame -; jsr half_frame_clock -; jsr quarter_frame_clock -; jsr quarter_frame_clock -; jsr half_frame_clock -; jsr quarter_frame_clock -; jsr quarter_frame_clock +:half_frame_120 +:quarter_frame_120 + jsr half_frame_clock + jsr quarter_frame_clock + jsr quarter_frame_clock ; Apply any changes to the DOC registers +update_doc_registers + jsr access_doc_registers ; Set the parameters for the first square wave channel. @@ -802,8 +862,8 @@ interrupt_handler = * :high_pitch pla sta sound_data -:no_frame :not_timer +no_frame ldal show_border beq :no_show2 ldal border_color