Skip to content

MMC1 512K PRG support #396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
28ab2c9
MMC1 512K PRG support
sebastienvezina Apr 28, 2025
17b9b48
Fixed double __ in register names
sebastienvezina Apr 28, 2025
88e2cb5
vscode plugin ignore - not needed
sebastienvezina Apr 28, 2025
a00393e
skip set CHR bits if switch to bank < 16
sebastienvezina Apr 28, 2025
9993ac2
fix switching to a high bank was exiting early in the middle of the b…
sebastienvezina Apr 28, 2025
d11ec30
replaced cmp/bne w and/beq
sebastienvezina Apr 28, 2025
085fec1
update actual registers
sebastienvezina Apr 28, 2025
659a4a0
nes-mmc1 prg 512 unit tests
sebastienvezina Apr 28, 2025
2610b30
hex to lowercase + removed references to prg 15
sebastienvezina Apr 28, 2025
cc334b9
jrowboy's set_prg_bank
sebastienvezina Apr 29, 2025
af1dc55
review https://github.com/llvm-mos/llvm-mos-sdk/pull/396#discussion_r…
sebastienvezina Apr 29, 2025
1661294
fix https://github.com/llvm-mos/llvm-mos-sdk/pull/396#discussion_r206…
sebastienvezina Apr 29, 2025
a93c409
fix https://github.com/llvm-mos/llvm-mos-sdk/pull/396#discussion_r206…
sebastienvezina Apr 29, 2025
48992f0
latest version of set_prg_bank but still use prg_rom_is_512 which sho…
sebastienvezina Apr 29, 2025
a1a1df2
attempt at fixing the fixed bank output format
sebastienvezina Apr 29, 2025
ed2856d
added __ prefix to prg_rom_is_512
sebastienvezina Apr 29, 2025
181ecda
try to preserve the PRG RAM bit
sebastienvezina Apr 29, 2025
500564c
Added prg-rom-512 test to list
sebastienvezina Apr 30, 2025
b62a60f
banked_call fiddling because set_prg_bank clobbers rc2 and/or rc3
sebastienvezina May 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 51 additions & 14 deletions mos-platform/nes-mmc1/mapper.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
82 changes: 82 additions & 0 deletions mos-platform/nes-mmc1/prg-rom-banked.ld
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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. */
Expand Down Expand Up @@ -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
}

Expand All @@ -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)
Expand All @@ -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)
}
1 change: 1 addition & 0 deletions test/nes-mmc1/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
77 changes: 77 additions & 0 deletions test/nes-mmc1/prg-rom-512.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <mapper.h>
#include <peekpoke.h>
#include <stdlib.h>

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;
}