diff --git a/mos-platform/nes-mmc1/mapper.s b/mos-platform/nes-mmc1/mapper.s index 8774e69a8..e38aa4234 100644 --- a/mos-platform/nes-mmc1/mapper.s +++ b/mos-platform/nes-mmc1/mapper.s @@ -99,9 +99,39 @@ get_prg_bank: .weak set_prg_bank __set_prg_bank: set_prg_bank: - tay + ldx #<__prg_rom_is_512 + beq .Lcontinue_bank_switch + ; save the new bank byte on the stack for safe keeping + pha + ; check which bits changed + eor _PRG_BANK + ; if the outer bank bit changed then we need to set a new outerbank + and #%00010000 + beq .Lset_inner_bank +.Lset_new_outer_bank: + ; Flip the outer bank bit for _CHR_BANK0 and _CHR_BANK1 + lda _CHR_BANK0 + eor #%00010000 + jsr set_chr_bank_0_retry + lda _CHR_BANK1 + eor #%00010000 + jsr set_chr_bank_1_retry +.Lset_inner_bank: + ; restore the bank byte and put it in y so we can reload it on retry + pla +.Lcontinue_bank_switch: + ; bit 4 is PRG RAM en/disable, so use those from the current bank value + ldx __rc2 ; preserve the current __rc2 value in X so we can use it as a temp + and #%00001111 + sta __rc2 ; store the new bank bits + lda _PRG_BANK ; load the current prg_ram enable bit + and #%00010000 + ora __rc2 ; combine them together + stx __rc2 ; restore the tmp register we used + tay + ; original code below .Lset: - inc __reset_mmc1_byte + inc __reset_mmc1_byte ldx #1 stx _IN_PROGRESS mmc1_register_write MMC1_PRG @@ -115,21 +145,28 @@ set_prg_bank: tya jmp .Lset - - .section .text.banked_call,"ax",@progbits .weak banked_call banked_call: - tay - lda _PRG_BANK - pha - tya - jsr __set_prg_bank - lda __rc2 - sta __rc18 - lda __rc3 - sta __rc19 + tay ; save current bank in y + lda _PRG_BANK ; load new bank in A + pha ; push new bank to stack + + lda __rc2 ; push function pointer to stack + pha + lda __rc3 + pha + + tya ; restore current bank from A + + jsr __set_prg_bank ; set the new bank + + pla ; restore function pointer from stack + sta __rc19 + pla + sta __rc18 + jsr __call_indir pla jsr __set_prg_bank - rts + rts \ No newline at end of file diff --git a/mos-platform/nes-mmc1/prg-rom-banked.ld b/mos-platform/nes-mmc1/prg-rom-banked.ld index 42e6af847..56feee054 100644 --- a/mos-platform/nes-mmc1/prg-rom-banked.ld +++ b/mos-platform/nes-mmc1/prg-rom-banked.ld @@ -15,6 +15,21 @@ __prg_rom_11_lma = 0x0b8000; __prg_rom_12_lma = 0x0c8000; __prg_rom_13_lma = 0x0d8000; __prg_rom_14_lma = 0x0e8000; +__prg_rom_16_lma = 0x108000; +__prg_rom_17_lma = 0x118000; +__prg_rom_18_lma = 0x128000; +__prg_rom_19_lma = 0x138000; +__prg_rom_20_lma = 0x148000; +__prg_rom_21_lma = 0x158000; +__prg_rom_22_lma = 0x168000; +__prg_rom_23_lma = 0x178000; +__prg_rom_24_lma = 0x188000; +__prg_rom_25_lma = 0x198000; +__prg_rom_26_lma = 0x1a8000; +__prg_rom_27_lma = 0x1b8000; +__prg_rom_28_lma = 0x1c8000; +__prg_rom_29_lma = 0x1d8000; +__prg_rom_30_lma = 0x1e8000; __prg_rom_fixed_lma = 0xc000; __prg_rom_0_offset = 0x00000; @@ -32,6 +47,21 @@ __prg_rom_11_offset = 0x2c000; __prg_rom_12_offset = 0x30000; __prg_rom_13_offset = 0x34000; __prg_rom_14_offset = 0x38000; +__prg_rom_16_offset = 0x40000; +__prg_rom_17_offset = 0x44000; +__prg_rom_18_offset = 0x48000; +__prg_rom_19_offset = 0x4c000; +__prg_rom_20_offset = 0x50000; +__prg_rom_21_offset = 0x54000; +__prg_rom_22_offset = 0x58000; +__prg_rom_23_offset = 0x5c000; +__prg_rom_24_offset = 0x60000; +__prg_rom_25_offset = 0x64000; +__prg_rom_26_offset = 0x68000; +__prg_rom_27_offset = 0x6c000; +__prg_rom_28_offset = 0x70000; +__prg_rom_29_offset = 0x74000; +__prg_rom_30_offset = 0x78000; __prg_rom_fixed_offset = __prg_rom_size * 1024 - 0x4000; MEMORY { @@ -51,6 +81,21 @@ MEMORY { prg_rom_12 : ORIGIN = __prg_rom_12_lma, LENGTH = __prg_rom_size >= 256 ? 0x4000 - 12 : 0 prg_rom_13 : ORIGIN = __prg_rom_13_lma, LENGTH = __prg_rom_size >= 256 ? 0x4000 - 12 : 0 prg_rom_14 : ORIGIN = __prg_rom_14_lma, LENGTH = __prg_rom_size >= 256 ? 0x4000 - 12 : 0 + prg_rom_16 : ORIGIN = __prg_rom_16_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_17 : ORIGIN = __prg_rom_17_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_18 : ORIGIN = __prg_rom_18_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_19 : ORIGIN = __prg_rom_19_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_20 : ORIGIN = __prg_rom_20_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_21 : ORIGIN = __prg_rom_21_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_22 : ORIGIN = __prg_rom_22_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_23 : ORIGIN = __prg_rom_23_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_24 : ORIGIN = __prg_rom_24_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_25 : ORIGIN = __prg_rom_25_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_26 : ORIGIN = __prg_rom_26_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_27 : ORIGIN = __prg_rom_27_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_28 : ORIGIN = __prg_rom_28_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_29 : ORIGIN = __prg_rom_29_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 + prg_rom_30 : ORIGIN = __prg_rom_30_lma, LENGTH = __prg_rom_size >= 512 ? 0x4000 - 12 : 0 prg_rom_fixed : ORIGIN = __prg_rom_fixed_lma, LENGTH = 0x4000 - 12 /* Reset stub. Arbitrarily put its VMA in the first bank. */ @@ -78,6 +123,21 @@ SECTIONS { .prg_rom_12 : { *(.prg_rom_12 .prg_rom_12.*) } >prg_rom_12 .prg_rom_13 : { *(.prg_rom_13 .prg_rom_13.*) } >prg_rom_13 .prg_rom_14 : { *(.prg_rom_14 .prg_rom_14.*) } >prg_rom_14 + .prg_rom_16 : { *(.prg_rom_16 .prg_rom_16.*) } >prg_rom_16 + .prg_rom_17 : { *(.prg_rom_17 .prg_rom_17.*) } >prg_rom_17 + .prg_rom_18 : { *(.prg_rom_18 .prg_rom_18.*) } >prg_rom_18 + .prg_rom_19 : { *(.prg_rom_19 .prg_rom_19.*) } >prg_rom_19 + .prg_rom_20 : { *(.prg_rom_20 .prg_rom_20.*) } >prg_rom_20 + .prg_rom_21 : { *(.prg_rom_21 .prg_rom_21.*) } >prg_rom_21 + .prg_rom_22 : { *(.prg_rom_22 .prg_rom_22.*) } >prg_rom_22 + .prg_rom_23 : { *(.prg_rom_23 .prg_rom_23.*) } >prg_rom_23 + .prg_rom_24 : { *(.prg_rom_24 .prg_rom_24.*) } >prg_rom_24 + .prg_rom_25 : { *(.prg_rom_25 .prg_rom_25.*) } >prg_rom_25 + .prg_rom_26 : { *(.prg_rom_26 .prg_rom_26.*) } >prg_rom_26 + .prg_rom_27 : { *(.prg_rom_27 .prg_rom_27.*) } >prg_rom_27 + .prg_rom_28 : { *(.prg_rom_28 .prg_rom_28.*) } >prg_rom_28 + .prg_rom_29 : { *(.prg_rom_29 .prg_rom_29.*) } >prg_rom_29 + .prg_rom_30 : { *(.prg_rom_30 .prg_rom_30.*) } >prg_rom_30 .prg_rom_fixed : { *(.prg_rom_fixed .prg_rom_fixed.*) } >prg_rom_fixed } @@ -90,6 +150,8 @@ SECTIONS { PROVIDE(__prg_rom_size = 256); +__prg_rom_is_512 = __prg_rom_size >= 512 ? 1 : 0; + OUTPUT_FORMAT { INCLUDE ines-header.ld FULL(prg_rom_0) FULL(reset, 0, LENGTH(prg_rom_0) ? LENGTH(reset) : 0) @@ -108,5 +170,25 @@ OUTPUT_FORMAT { FULL(prg_rom_13) FULL(reset, 0, LENGTH(prg_rom_13) ? LENGTH(reset) : 0) FULL(prg_rom_14) FULL(reset, 0, LENGTH(prg_rom_14) ? LENGTH(reset) : 0) FULL(prg_rom_fixed) FULL(reset_fixed) + + FULL(prg_rom_16) FULL(reset, 0, LENGTH(prg_rom_16) ? LENGTH(reset) : 0) + FULL(prg_rom_17) FULL(reset, 0, LENGTH(prg_rom_17) ? LENGTH(reset) : 0) + FULL(prg_rom_18) FULL(reset, 0, LENGTH(prg_rom_18) ? LENGTH(reset) : 0) + FULL(prg_rom_19) FULL(reset, 0, LENGTH(prg_rom_19) ? LENGTH(reset) : 0) + FULL(prg_rom_20) FULL(reset, 0, LENGTH(prg_rom_20) ? LENGTH(reset) : 0) + FULL(prg_rom_21) FULL(reset, 0, LENGTH(prg_rom_21) ? LENGTH(reset) : 0) + FULL(prg_rom_22) FULL(reset, 0, LENGTH(prg_rom_22) ? LENGTH(reset) : 0) + FULL(prg_rom_23) FULL(reset, 0, LENGTH(prg_rom_23) ? LENGTH(reset) : 0) + FULL(prg_rom_24) FULL(reset, 0, LENGTH(prg_rom_24) ? LENGTH(reset) : 0) + FULL(prg_rom_25) FULL(reset, 0, LENGTH(prg_rom_25) ? LENGTH(reset) : 0) + FULL(prg_rom_26) FULL(reset, 0, LENGTH(prg_rom_26) ? LENGTH(reset) : 0) + FULL(prg_rom_27) FULL(reset, 0, LENGTH(prg_rom_27) ? LENGTH(reset) : 0) + FULL(prg_rom_28) FULL(reset, 0, LENGTH(prg_rom_28) ? LENGTH(reset) : 0) + FULL(prg_rom_29) FULL(reset, 0, LENGTH(prg_rom_29) ? LENGTH(reset) : 0) + FULL(prg_rom_30) FULL(reset, 0, LENGTH(prg_rom_30) ? LENGTH(reset) : 0) + + FULL(prg_rom_fixed, 0, __prg_rom_size >= 512 ? LENGTH(prg_rom_fixed) : 0) + FULL(reset_fixed, 0, __prg_rom_size >= 512 ? LENGTH(reset_fixed) : 0) + FULL(chr_rom) } diff --git a/test/nes-mmc1/CMakeLists.txt b/test/nes-mmc1/CMakeLists.txt index c9deb2153..49a2cd7fc 100644 --- a/test/nes-mmc1/CMakeLists.txt +++ b/test/nes-mmc1/CMakeLists.txt @@ -19,6 +19,7 @@ add_nes_test(prg-rom-32) add_nes_test(prg-rom-64) add_nes_test(prg-rom-128) add_nes_test(prg-rom-256) +add_nes_test(prg-rom-512) add_nes_test(prg-ram) diff --git a/test/nes-mmc1/prg-rom-512.c b/test/nes-mmc1/prg-rom-512.c new file mode 100644 index 000000000..e5f72f575 --- /dev/null +++ b/test/nes-mmc1/prg-rom-512.c @@ -0,0 +1,77 @@ +#include +#include +#include + +MAPPER_PRG_ROM_KB(512); + +volatile const char c[15000] = {1, [14999] = 2}; + +__attribute__((section(".prg_rom_0.rodata"))) volatile const char d[15000] = { + 3, [14999] = 4}; + +__attribute__((section(".prg_rom_14.rodata"))) volatile const char e[15000] = { + 5, [14999] = 6}; + +__attribute__((section(".prg_rom_29.rodata"))) volatile const char f[15000] = { + 7, [14999] = 8}; + + +__attribute__((noinline, section(".prg_rom_0.text"))) char bank_0_fn(void) { + asm volatile(""); + return 7; +} + +__attribute__((noinline, section(".prg_rom_14.text"))) char bank_14_fn(void) { + asm volatile(""); + return 8; +} + +__attribute__((noinline, section(".prg_rom_29.text"))) char bank_29_fn(void) { + asm volatile(""); + return 10; + } + +int main(void) { + if ((unsigned)c < 0xc000) + return EXIT_FAILURE; + if ((unsigned)d >= 0xc000) + return EXIT_FAILURE; + if ((unsigned)e >= 0xc000) + return EXIT_FAILURE; + if ((unsigned)f >= 0xc000) + return EXIT_FAILURE; + if (c[0] != 1 || c[14999] != 2) + return EXIT_FAILURE; + + set_prg_bank(0); + if (c[0] != 1 || c[14999] != 2) + return EXIT_FAILURE; + if (d[0] != 3 || d[14999] != 4) + return EXIT_FAILURE; + + set_prg_bank(14); + if (c[0] != 1 || c[14999] != 2) + return EXIT_FAILURE; + if (e[0] != 5 || e[14999] != 6) + return EXIT_FAILURE; + + set_prg_bank(29); + if (c[0] != 1 || c[14999] != 2) + return EXIT_FAILURE; + if (e[0] != 7 || e[14999] != 8) + return EXIT_FAILURE; + + set_prg_bank(0); + if ((unsigned)bank_0_fn >= 0xc000 || bank_0_fn() != 7) + return EXIT_FAILURE; + + set_prg_bank(14); + if ((unsigned)bank_14_fn >= 0xc000 || bank_14_fn() != 8) + return EXIT_FAILURE; + + set_prg_bank(29); + if ((unsigned)bank_29_fn >= 0xc000 || bank_29_fn() != 10) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +}