; Killer TXROM X IN 1 Multicart Menu ; By Farid (2015/05/07) ; WWW.Microbaz.Blogfa.Com ; Use Notepad++ for the best view ;;;;;;;;;;;;;iNES Header;;;;;;;;;;;;; .inesprg 2 ; 2 x 16KB PRG code .ineschr 1 ; 1 x 8KB CHR data .inesmap 0 ; Mapper 0 = NROM .inesmir 1 ; Background mirroring , 0=Horizontal , 1=Vertical ;;;;;;;;;;;;;Host game hacking data;;;;;;;;;;;;; PRG_BANK = $07 ; PRG bank number (PRG free address / 2000 = PRG bank number) (need 600h free bytes) CHR_BANK = $80 ; CHR bank number (TLP Page down count * 4 --> Convert to hex) ORG_RST = $FFF0 ; Original reset vector of the host game HARD_FREE = $F9E0 ; Address of free space on the hard wired bank of the host game (need 30h free bytes) X_IN_ONE = $06 ; How many games are inside the cartridge (Min:$02, Max:$08) ;;;;;;;;;;;;;RAM Info;;;;;;;;;;;;; nam_low = $0000 ; Name table address pointer low byte nam_high = $0001 ; Name table address pointer high byte joy_pad = $0002 ; Joy pad1 data rom_sel = $0003 ; Current selected ROM, first one is ROM0 switch_code = $0004 ; Game switch code ($0004 ~ $0009) spr_ram = $0200 ; Arrow sprite data ($0200 ~ $0203) ;****************************Raw Data****************************** ;;;;;;;;;;;;;Bank0 8000~9FFF;;;;;;;;;;;;; .bank 0 .org $9A00 ; It is easy to find a bank with enough free space at the end of it ;;;;;;;;;;;;;Name table + Attribute data;;;;;;;;;;;;; nam_att: .incbin "menu.nam" ;;;;;;;;;;;;;Palette data;;;;;;;;;;;;; pal_data: .incbin "menu.pal" ;;;;;;;;;;;;;Arrow sprite data;;;;;;;;;;;;; arrow_spr: .db $36,$1F,$00,$30 ; Vertical, Tile, Effects, Horizontal ;;;;;;;;;;;;;Pointer vertical move data;;;;;;;;;;;;; ver_mov: .db $36,$46,$56,$66,$76,$86,$96,$A6 ; Arrow on ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, [ROM6, ROM7] ;;;;;;;;;;;;;Games switch registers;;;;;;;;;;;; switch_reg .db $01,$21,$41,$61,$81,$C1,$FF,$FF ; Register of ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, [ROM6, ROM7] ;;;;;;;;;;;;;Game switch data will run on ram;;;;;;;;;;;; game_switch: .db $8D,$00,$68 ; STA $6800 .db $6C,$FC,$FF ; JMP ($FFFC) ;****************************Main Code****************************** main_code: ;;;;;;;;;;;;;Warm up;;;;;;;;;;;;; LDX #$00 warmup_loop: BIT $2002 BPL warmup_loop ; Do loop until vblank starts INX CPX #$04 ; How many frames for warm up BNE warmup_loop ;;;;;;;;;;;;;Clear CPU ram;;;;;;;;;;;;; LDA #$00 LDX #$00 clear_loop: STA $0000,x STA $0100,x STA $0200,x STA $0300,x STA $0400,x STA $0500,x STA $0600,x STA $0700,x INX BNE clear_loop ;;;;;;;;;;;;;Save game switch data to ram;;;;;;;;;;;;; LDX #$00 transfer_loop: LDA game_switch,x STA switch_code,x INX CPX #$06 ; How many bytes for game switch code BNE transfer_loop ;;;;;;;;;;;;;Save arrow sprites data to ram;;;;;;;;;;;;; LDX #$00 spr_loop: LDA arrow_spr,x ; Load arrow sprite data STA spr_ram,x ; Save arrow sprite data to ram INX CPX #$04 ; How many bytes for arrow sprites data BNE spr_loop ;;;;;;;;;;;;;CHR bank switch;;;;;;;;;;;;; JSR vblank_wait LDA #$00 ; Select PPU 0000 ~ 0800 STA $8000 LDA #CHR_BANK ; CHR bank number (TLP Page down count * 4 --> Convert to hex) STA $8001 ;;;;;;;;;;;;;Palette routine;;;;;;;;;;;;; JSR vblank_wait LDA $2002 ; read PPU status to reset the high/low latch LDA #$3F STA $2006 LDA #$00 STA $2006 LDX #$00 palette_loop: LDA pal_data,x STA $2007 INX CPX #$20 ; How many bytes for palette data BNE palette_loop ;;;;;;;;;;;;;Name table + Attribute;;;;;;;;;;;;; JSR vblank_wait LDA $2002 ; Read PPU status to reset the high/low latch LDA #$20 STA $2006 ; Write the high byte of $2000 address LDA #$00 STA $2006 ; Write the low byte of $2000 address LDA #$00 ; Name table address pointer low byte STA nam_low LDA #$9A ; Name table address pointer high byte STA nam_high LDX #$00 LDY #$00 nam_loop: LDA [nam_low], y ; Load name table and attribute data STA $2007 INY CPY #$00 ; Small loop runs 100 times BNE nam_loop INC nam_high INX CPX #$04 ; Big loop runs 4 times BNE nam_loop ;;;;;;;;;;;;;Show screen;;;;;;;;;;;;; JSR vblank_wait JSR spr_to_oam JSR no_scroll LDA #$00 STA $2000 ; Disable NMI LDA #%00011000 ; Show background , Show sprites STA $2001 ; Enable rendering LDA #$00 STA rom_sel ; On start up arrow is on the first game ;;;;;;;;;;;;;Infinite Loop;;;;;;;;;;;;; infinit_loop: JSR pad_read JSR pad_check JMP infinit_loop ;****************************Sub Routines****************************** ;;;;;;;;;;;;;Vblank wait;;;;;;;;;;;;; vblank_wait: BIT $2002 ; Skip any halfway vblank vblank_loop: BIT $2002 BPL vblank_loop ; Do loop until a new vblank starts RTS ;----------------------- ;;;;;;;;;;;;;Sprites to OAM;;;;;;;;;;;;; spr_to_oam: LDA #$00 ; Sprites to OAM Transfer STA $2003 LDA #$02 ; Sprites address on the ram ($0200) STA $4014 RTS ;----------------------- ;;;;;;;;;;;;;Scroll reset;;;;;;;;;;;;; no_scroll: LDA #$00 STA $2005 STA $2005 RTS ;----------------------- ;;;;;;;;;;;;;Sound routine;;;;;;;;;;;;; sound: LDA #$0F STA $4015 ; Enable sound channels LDA #$1F STA $4004 LDA #$99 STA $4005 LDA #$EF STA $4006 LDA #$08 STA $4007 RTS ;----------------------- ;;;;;;;;;;;;;Controller pad read;;;;;;;;;;;;; pad_read: LDA #$01 STA $4016 LDA #$00 STA $4016 LDX #$00 pad_loop: LDA $4016 LSR A ROL joy_pad ; Controller pad read buffer INX CPX #$08 ; Read status of all eight keys BNE pad_loop RTS ;----------------------- ;;;;;;;;;;;;;Controller pad check;;;;;;;;;;;;; pad_check: LDA #$08 ; Check for up button press CMP joy_pad BEQ up_press LDA #$04 ; Check for down button press CMP joy_pad BEQ down_press LDA #$10 ; Check for start button press CMP joy_pad BEQ start_press ; If start button was pressed then time to run a game! RTS ;----------------------- ;;;;;;;;;;;;;Button release;;;;;;;;;;;;; button_release: JSR pad_read LDA #$00 CMP joy_pad BNE button_release ; Do loop until all buttons are released LDX #$00 delay_loop: JSR vblank_wait INX CPX #$0A ; How many frames for delay BNE delay_loop RTS ;----------------------- ;;;;;;;;;;;;;Up button press;;;;;;;;;;;;; up_press: LDA rom_sel ; Current selected ROM CMP #$00 ; Up limit BEQ is_first ; Check if arrow was on the first game DEC rom_sel ; Update selected ROM LDX rom_sel LDA ver_mov,x ; Load arrow move data STA spr_ram ; Update arrow vertical position JSR vblank_wait JSR spr_to_oam JSR no_scroll JSR sound JSR button_release ; Check if the button is released is_first: RTS ;----------------------- ;;;;;;;;;;;;;Down button press;;;;;;;;;;;;; down_press: LDA rom_sel ; Current selected ROM CMP #X_IN_ONE-1 ; Down limit BEQ is_last ; Check if arrow was on the last game INC rom_sel ; Update selected ROM LDX rom_sel LDA ver_mov,x ; Load arrow move data STA spr_ram ; Update arrow vertical position JSR vblank_wait JSR spr_to_oam JSR no_scroll JSR sound JSR button_release ; Check if the button is released is_last RTS ;----------------------- ;;;;;;;;;;;;;Start button press;;;;;;;;;;;;; start_press: JSR button_release ; Check if the button is released LDA #$00 STA $2000 STA $2001 STA $4004 STA $4005 STA $4006 STA $4007 STA $4015 LDA #$80 STA $A001 ; Enable WRAM LDX rom_sel LDA switch_reg,x CPX #$00 BEQ game1 ; Check if ROM0 is going to run JMP switch_code ; Game switch routine game1: STA $6800 ; Multicart game select register JMP ORG_RST ; Original reset vector of the host game ;;;;;;;;;;;;;Bank1 A000~BFFF;;;;;;;;;;;;; .bank 1 .org $A000 ;;;Empty ;;;;;;;;;;;;;Bank2 C000~DFFF;;;;;;;;;;;;; .bank 2 .org $C000 ;;;Empty ;;;;;;;;;;;;;Bank3 E000~FFFF;;;;;;;;;;;;; .bank 3 .org HARD_FREE RESET: SEI ; Disable IRQs CLD ; Disable decimal mode LDA #$40 STA $4017 ; Disable APU frame IRQ LDX #$FF TXS ; Set up stack LDA #$00 STA $2000 ; Disable NMI STA $2001 ; Disable rendering STA $4010 ; Disable DMC IRQs STA $E000 ; Disable IRQ STA $A000 ; Set mirroring to vertical STA $A001 ; Disable WRAM ;;;;;;;;;;;;;PRG Bank Switch;;;;;;;;;;;;; LDA #$06 ; Select 8000 ~ 9FFF for bank switch STA $8000 LDA #PRG_BANK ; PRG bank number (PRG free address / 2000 = PRG bank number) STA $8001 JMP main_code NMI: RTI ; Original NMI routine of the host game IRQ: RTI ; Original IRQ routine of the host game ;;;;;;;;;;;;;Vectors;;;;;;;;;;;;; .org $FFFA .dw NMI .dw RESET .dw IRQ ;;;;;;;;;;;;;CHR Data;;;;;;;;;;;;; .bank 4 .org $0000 .incbin "menu.chr"