Action 53 mapper/Reference implementations
From Nesdev wiki
(Redirected from User:Tepples/Multi-discrete mapper/Reference implementations)
#!/usr/bin/env python3 from __future__ import print_function bank_size_masks = [(2<<i)-1 for i in range(4)] # 0x01, 0x03, 0x07, 0x0F def calc_prg_bank(address, bank_mode, outer_bank, current_bank): """Calculate the 16K bank on A20-A14 for a given address. address -- current address being accessed by the CPU, in range 0x8000-0xFFFF bank_mode -- last value written to $80 outer_bank -- last value written to $81 current_bank -- last value written to $01 """ cpu_a14 = (address >> 14) & 0x01 outer_bank = outer_bank << 1 bank_mode >>= 2 # discard mirroring bits if (bank_mode ^ cpu_a14) & 0x03 == 0x02: # in UNROM fixed bank? bank_mode = 0 # if so, treat as NROM if (bank_mode & 0x02) == 0: # in 32K bank mode? current_bank = (current_bank << 1) | cpu_a14 bank_size_mask = bank_size_masks[(bank_mode >> 2) & 3] return (current_bank & bank_size_mask) | (outer_bank & ~bank_size_mask) def test_with_bank_mode_size(bank_mode, outer_bank): print("mode $%02x, outer bank $%02x" % (bank_mode, outer_bank)) out80 = [calc_prg_bank(0x8000, bank_mode, outer_bank, current_bank) for current_bank in range(16)] print("$8000 banks:", " ".join("%02x" % i for i in out80)) outC0 = [calc_prg_bank(0xC000, bank_mode, outer_bank, current_bank) for current_bank in range(16)] print("$C000 banks:", " ".join("%02x" % i for i in outC0)) for outer_bank in (0x00, 0x3C, 0x3F): test_with_bank_mode_size(0x28, outer_bank) for outer_bank in (0x00, 0x03, 0x3F): test_with_bank_mode_size(0x2C, outer_bank) for bank_mode in (0x00, 0x08, 0x0C, 0x10, 0x18, 0x1C, 0x20, 0x28, 0x2C, 0x30, 0x38, 0x3C): test_with_bank_mode_size(bank_mode, 0x2A)
This routine appears in the test ROMs "test28" and "Holy Mapperel".
;; ; Determines what 16 KiB PRG ROM bank ought to be mapped into a given ; CPU address with a given set of $80, $81, $00 values. ; For use in a test ROM that verifies mapper 28. ; @param A $80 value ; @param X $01 value ; @param Y $81 value ; @param C CPU A14 value: clear for $8000-$BFFF, set for $C000-$FFFF ; @return PRG bank number in A .proc calc_prg_bank bank_mode = 0 outer_bank = 1 current_bank = 2 stx current_bank sty outer_bank rol outer_bank lsr a ; discard mirroring bits lsr a sta bank_mode ; If the mode is UxROM (10 = mapper 180, 11 = mapper 2), and bit 0 ; of the mode matches CPU A14, then the read is within the fixed ; bank. For such reads, the mapper acts in 32K (NROM) mode. and #$02 beq not_unrom lda outer_bank eor bank_mode ; If bit 0 of the eor result is false, there is a match, so ; fall through to the not-UNROM code. and #$01 bne have_current_bank sta bank_mode not_unrom: ; In 32K switched modes (NROM, CNROM, BNROM, AOROM), ; shift CPU A14 into the current bank lda outer_bank lsr a rol current_bank have_current_bank: lda bank_mode lsr a lsr a and #$03 tax lda current_bank eor outer_bank and bank_size_masks,x eor outer_bank rts .endproc .segment "RODATA" bank_size_masks: .byt $01, $03, $07, $0F