NESpire/source/rom.S

610 lines
14 KiB
ArmAsm

#include "nes.inc"
map_prg_32kB:
ldr r1, [r9, #s_prg_size]
ldr r2, [r9, #s_prg_ptr]
and r0, r1, r0, lsl #15
add r0, r0, r2
map_prg_32kB_from_pointer:
sub r0, r0, #0x8000
str r0, [r9, #s_mem_map + 16] @ 8000
str r0, [r9, #s_mem_map + 20] @ A000
str r0, [r9, #s_mem_map + 24] @ C000
str r0, [r9, #s_mem_map + 28] @ E000
bx lr
map_prg_16kB_to_8000:
ldr r1, [r9, #s_prg_size]
ldr r2, [r9, #s_prg_ptr]
and r0, r1, r0, lsl #14
add r0, r0, r2
sub r0, r0, #0x8000
str r0, [r9, #s_mem_map + 16] @ 8000
str r0, [r9, #s_mem_map + 20] @ A000
bx lr
map_prg_16kB_to_C000:
ldr r1, [r9, #s_prg_size]
ldr r2, [r9, #s_prg_ptr]
and r0, r1, r0, lsl #14
add r0, r0, r2
sub r0, r0, #0xC000
str r0, [r9, #s_mem_map + 24] @ C000
str r0, [r9, #s_mem_map + 28] @ E000
bx lr
map_prg_8kB:
ldr r2, [r9, #s_prg_size]
ldr r3, [r9, #s_prg_ptr]
and r0, r2, r0, lsl #13
add r0, r0, r3
sub r0, r0, r1
add r1, r9, r1, lsr #11
str r0, [r1, #s_mem_map]
bx lr
map_chr_8kB:
ldr r2, [r9, #s_chr_size]
ldr r3, [r9, #s_chr_ptr]
and r0, r2, r0, lsl #13
add r0, r0, r3
str r0, [r9, #s_ppu_mem_map + 0x00] @ 0000
str r0, [r9, #s_ppu_mem_map + 0x04] @ 0400
str r0, [r9, #s_ppu_mem_map + 0x08] @ 0800
str r0, [r9, #s_ppu_mem_map + 0x0C] @ 0C00
str r0, [r9, #s_ppu_mem_map + 0x10] @ 1000
str r0, [r9, #s_ppu_mem_map + 0x14] @ 1400
str r0, [r9, #s_ppu_mem_map + 0x18] @ 1800
str r0, [r9, #s_ppu_mem_map + 0x1C] @ 1C00
bx lr
map_chr_4kB_to_0000:
mov r1, #0x0000
b map_chr_4kB
map_chr_4kB_to_1000:
mov r1, #0x1000
map_chr_4kB:
ldr r2, [r9, #s_chr_size]
ldr r3, [r9, #s_chr_ptr]
and r0, r2, r0, lsl #12
add r0, r0, r3
sub r0, r0, r1
add r1, r9, r1, lsr #8
str r0, [r1, #s_ppu_mem_map + 0x00] @ +0000
str r0, [r1, #s_ppu_mem_map + 0x04] @ +0400
str r0, [r1, #s_ppu_mem_map + 0x08] @ +0800
str r0, [r1, #s_ppu_mem_map + 0x0C] @ +0C00
bx lr
map_chr_2kB:
ldr r2, [r9, #s_chr_size]
ldr r3, [r9, #s_chr_ptr]
and r0, r2, r0, lsl #10
add r0, r0, r3
sub r0, r0, r1
add r1, r9, r1, lsr #8
str r0, [r1, #s_ppu_mem_map + 0x00] @ +0000
str r0, [r1, #s_ppu_mem_map + 0x04] @ +0400
bx lr
map_chr_1kB:
ldr r2, [r9, #s_chr_size]
ldr r3, [r9, #s_chr_ptr]
and r0, r2, r0, lsl #10
add r0, r0, r3
sub r0, r0, r1
add r1, r9, r1, lsr #8
str r0, [r1, #s_ppu_mem_map]
bx lr
mirror_1screen_lo:
add r0, r9, #s_name_table_ram - 0x2000
b mirror_1screen
mirror_1screen_hi:
add r0, r9, #s_name_table_ram + 0x0400 - 0x2000
mirror_1screen:
str r0, [r9, #s_ppu_mem_map + 0x20] @ 2000
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x24] @ 2400
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x28] @ 2800
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x2C] @ 2C00
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x30] @ 3000
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x34] @ 3400
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x38] @ 3800
sub r0, r0, #0x0400
str r0, [r9, #s_ppu_mem_map + 0x3C] @ 3C00
bx lr
mirror_vert:
add r0, r9, #s_name_table_ram - 0x2000
str r0, [r9, #s_ppu_mem_map + 0x20] @ 2000
str r0, [r9, #s_ppu_mem_map + 0x24] @ 2400
add r0, r9, #s_name_table_ram - 0x2800
str r0, [r9, #s_ppu_mem_map + 0x28] @ 2800
str r0, [r9, #s_ppu_mem_map + 0x2C] @ 2C00
add r0, r9, #s_name_table_ram - 0x3000
str r0, [r9, #s_ppu_mem_map + 0x30] @ 3000
str r0, [r9, #s_ppu_mem_map + 0x34] @ 3400
add r0, r9, #s_name_table_ram - 0x3800
str r0, [r9, #s_ppu_mem_map + 0x38] @ 3800
str r0, [r9, #s_ppu_mem_map + 0x3C] @ 3C00
bx lr
mirror_horiz:
add r0, r9, #s_name_table_ram - 0x2000
str r0, [r9, #s_ppu_mem_map + 0x20] @ 2000
add r0, r9, #s_name_table_ram - 0x2400
str r0, [r9, #s_ppu_mem_map + 0x24] @ 2400
str r0, [r9, #s_ppu_mem_map + 0x28] @ 2800
add r0, r9, #s_name_table_ram - 0x2800
str r0, [r9, #s_ppu_mem_map + 0x2C] @ 2C00
add r0, r9, #s_name_table_ram - 0x3000
str r0, [r9, #s_ppu_mem_map + 0x30] @ 2000
add r0, r9, #s_name_table_ram - 0x3400
str r0, [r9, #s_ppu_mem_map + 0x34] @ 2400
str r0, [r9, #s_ppu_mem_map + 0x38] @ 2800
add r0, r9, #s_name_table_ram - 0x3800
str r0, [r9, #s_ppu_mem_map + 0x3C] @ 2C00
bx lr
mirror_4screen:
add r0, r9, #s_name_table_ram - 0x2000
str r0, [r9, #s_ppu_mem_map + 0x20] @ 2000
str r0, [r9, #s_ppu_mem_map + 0x24] @ 2400
str r0, [r9, #s_ppu_mem_map + 0x28] @ 2800
str r0, [r9, #s_ppu_mem_map + 0x2C] @ 2C00
add r0, r9, #s_name_table_ram - 0x3000
str r0, [r9, #s_ppu_mem_map + 0x30] @ 3000
str r0, [r9, #s_ppu_mem_map + 0x34] @ 3400
str r0, [r9, #s_ppu_mem_map + 0x38] @ 3800
str r0, [r9, #s_ppu_mem_map + 0x3C] @ 3C00
bx lr
.globl load_rom
load_rom:
push {r4-r11, lr}
adr r1, file_mode
swi e_fopen
movs r4, r0
moveq r5, #error_open - error_messages
beq error
@ Read ROM header
add r0, r9, #s_rom_header
mov r1, #16
mov r2, #1
mov r3, r4
swi e_fread
mov r5, #error_bad_header - error_messages
movs r0, r0
beq error_fclose
ldr r1, [r9, #s_rom_header]
ldr r2, =0x1A53454E
cmp r1, r2
bne error_fclose
ldrb r5, [r9, #s_rom_header + 4] @ Number of PRG-ROM banks
movs r5, r5, lsl #14
moveq r5, #0x400000
sub r0, r5, #1
str r0, [r9, #s_prg_size]
ldrb r7, [r9, #s_rom_header + 5] @ Number of CHR-ROM banks
movs r6, r7, lsl #13
moveq r6, #0x2000
sub r0, r6, #1
str r0, [r9, #s_chr_size]
add r0, r5, r6
swi e_malloc
movs r0, r0
moveq r5, #error_no_memory - error_messages
beq error_fclose
str r0, [r9, #s_prg_ptr]
add r0, r5
str r0, [r9, #s_chr_ptr]
@ Clear CHR-RAM if present
movs r1, r7
moveq r2, #0x2000
moveq r6, #0
swieq e_memset
@ Read PRG-ROM and CHR-ROM from file
ldr r0, [r9, #s_prg_ptr]
add r1, r5, r6
mov r2, #1
mov r3, r4
swi e_fread
movs r0, r0
moveq r5, #error_rom_read - error_messages
beq error_fclose
mov r0, r4
swi e_fclose
@ Initialize CPU memory map
@ RAM
str r9, [r9, #s_mem_map + 0] @ 0000
@ SRAM
add r1, r9, #s_sram - 0x6000
str r1, [r9, #s_mem_map + 12] @ 6000
@ ROM low
mov r0, #0
bl map_prg_16kB_to_8000
@ ROM high
mov r0, #-1
bl map_prg_16kB_to_C000
@ RAM wraparound
sub r1, r9, #0x10000
str r1, [r9, #s_mem_map + 32] @ 10000
@ Initialize PPU memory map
mov r0, #0
bl map_chr_8kB
@ Name table
ldrb r6, [r9, #s_rom_header + 6]
adr lr, 1f
tst r6, #8
bne mirror_4screen
tst r6, #1
bne mirror_vert
beq mirror_horiz
1:
@ Get low 4 bits of mapper number
mov r0, r6, lsr #4
@ Get high 4 bits of mapper number (unless it looks like
@ there's junk in the header, in which case ignore them)
ldr r1, [r9, #s_rom_header + 12]
movs r1, r1
ldreqb r1, [r9, #s_rom_header + 7]
andeq r1, r1, #0xF0
orreq r0, r0, r1
adr r1, mapper_table
adr r2, mapper_table_end
1: cmp r2, r1
moveq r5, #error_bad_mapper - error_messages
beq error
ldrh r5, [r2, #-2]!
ldrh r4, [r2, #-2]!
cmp r0, r4
bne 1b
add r0, r1, r5
str r0, [r9, #s_mapper]
mov r0, #0
pop {r4-r11, pc}
.pool
file_mode:
.string "rb"
error_open:
.string "couldn't open file"
error_bad_header:
.string "not an NES file"
error_no_memory:
.string "not enough memory"
error_rom_read:
.string "couldn't read ROM"
error_bad_mapper:
.string "unimplemented mapper"
.align 4
error_fclose:
mov r0, r4
swi e_fclose
error:
ldr r0, [r9, #s_prg_ptr]
swi e_free
mov r0, #0
str r0, [r9, #s_prg_ptr]
error_messages = .+8
add r0, pc, r5
pop {r4-r11, pc}
mapper_table:
.macro MAPPER n, addr; .hword \n, \addr - mapper_table; .endm
MAPPER 0, mapper_NROM
MAPPER 1, mapper_MMC1
MAPPER 2, mapper_UxROM
MAPPER 3, mapper_CNROM
MAPPER 4, mapper_MMC3
MAPPER 7, mapper_AxROM
MAPPER 11, mapper_Color_Dreams
MAPPER 34, mapper_BxROM
MAPPER 66, mapper_GxROM
MAPPER 228, mapper_Action_Enterprises
mapper_table_end:
mapper_NROM:
bx lr
#define s_mmc1_shift_reg (s_mapper_state)
#define s_mmc1_control (s_mapper_state+4)
#define s_mmc1_chr0 (s_mapper_state+5)
#define s_mmc1_chr1 (s_mapper_state+6)
#define s_mmc1_prg (s_mapper_state+7)
mapper_MMC1:
push {lr}
ldrb r3, [r9, #s_mmc1_shift_reg]
tst r0, #0x80
bne mmc1_reset
and r0, r0, #1
movs r3, r3, lsr #1
orr r0, r3, r0, lsl #4
strb r0, [r9, #s_mmc1_shift_reg]
popcc {pc}
and r2, r2, #0x6000
add r2, r9, r2, lsr #13
strb r0, [r2, #s_mmc1_control]
b mmc1_update
mmc1_reset:
ldrb r0, [r9, #s_mmc1_control]
orr r0, r0, #0x0C
strb r0, [r9, #s_mmc1_control]
mmc1_update:
mov r0, #0x10
strb r0, [r9, #s_mmc1_shift_reg]
ldrb r3, [r9, #s_mmc1_control]
adr lr, 1f
and r3, r3, #3
add pc, pc, r3, lsl #2
nop
b mirror_1screen_lo
b mirror_1screen_hi
b mirror_vert
b mirror_horiz
1:
@ Update CHR
ldrb r3, [r9, #s_mmc1_control]
ldrb r0, [r9, #s_mmc1_chr0]
tst r3, #0x10
bne 1f
mov r0, r0, lsr #1
bl map_chr_8kB
b 2f
1: bl map_chr_4kB_to_0000
ldrb r0, [r9, #s_mmc1_chr1]
bl map_chr_4kB_to_1000
2:
@ Update PRG
ldrb r3, [r9, #s_mmc1_control]
ldrb r0, [r9, #s_mmc1_prg]
@ Mode 0-1
tst r3, #0x08
bne 1f
mov r0, r0, lsr #1
bl map_prg_32kB
pop {pc}
1:
@ Mode 2
tst r3, #0x04
bne 1f
bl map_prg_16kB_to_C000
mov r0, #0
bl map_prg_16kB_to_8000
pop {pc}
@ Mode 3
1: bl map_prg_16kB_to_8000
mov r0, #-1
bl map_prg_16kB_to_C000
pop {pc}
mapper_UxROM:
b map_prg_16kB_to_8000
mapper_CNROM:
b map_chr_8kB
#define s_mmc3_bank (s_mapper_state)
#define s_mmc3_bank_select (s_mapper_state+8)
#define s_mmc3_counter_reload (s_mapper_state+9)
#define s_mmc3_counter (s_mapper_state+10)
#define s_mmc3_counter_reset (s_mapper_state+11)
#define s_mmc3_irq_enabled (s_mapper_state+12)
mapper_MMC3:
and r1, r2, #0x6000
and r2, r2, #0x0001
orr r2, r2, r1, lsr #12
add pc, pc, r2, lsl #2
nop
b mmc3_bank_select
b mmc3_bank_data
b mmc3_mirroring
bx lr
b mmc3_irq_latch
b mmc3_irq_reload
b mmc3_irq_disable
b mmc3_irq_enable
mmc3_bank_select:
strb r0, [r9, #s_mmc3_bank_select]
b mmc3_update
mmc3_bank_data:
ldrb r1, [r9, #s_mmc3_bank_select]
and r3, r1, #7
add r3, r3, r9
strb r0, [r3, #s_mmc3_bank]
b mmc3_update
mmc3_mirroring:
@ Don't do anything if game uses 4-screen mirroring
ldrb r3, [r9, #s_rom_header+6]
tst r3, #8
bxne lr
tst r0, #1
beq mirror_vert
b mirror_horiz
mmc3_irq_latch:
strb r0, [r9, #s_mmc3_counter_reload]
bx lr
mmc3_irq_reload:
mov r0, #0xFF
strb r0, [r9, #s_mmc3_counter_reset]
bx lr
mmc3_irq_disable:
mov r0, #0
strb r0, [r9, #s_irq_from_mapper]
mmc3_irq_enable:
and r0, r2, #1
strb r0, [r9, #s_mmc3_irq_enabled]
bx lr
.globl mmc3_scanline
mmc3_scanline:
ldrb r0, [r9, #s_mmc3_counter]
ldrb r1, [r9, #s_mmc3_counter_reset]
bic r1, r0, r1
subs r1, r1, #1
ldrmib r1, [r9, #s_mmc3_counter_reload]
strb r1, [r9, #s_mmc3_counter]
mov r2, #0
strb r2, [r9, #s_mmc3_counter_reset]
cmp r1, #0
bxne lr
cmp r0, #0
bxeq lr
ldrb r0, [r9, #s_mmc3_irq_enabled]
strb r0, [r9, #s_irq_from_mapper]
bx lr
mmc3_update:
push {r4, r5, lr}
ldrb r5, [r9, #s_mmc3_bank_select]
mov r4, #0x1000
and r4, r4, r5, lsl #5
ldrb r0, [r9, #s_mmc3_bank+0]; eor r1, r4, #0x0000; bl map_chr_2kB
ldrb r0, [r9, #s_mmc3_bank+1]; eor r1, r4, #0x0800; bl map_chr_2kB
ldrb r0, [r9, #s_mmc3_bank+2]; eor r1, r4, #0x1000; bl map_chr_1kB
ldrb r0, [r9, #s_mmc3_bank+3]; eor r1, r4, #0x1400; bl map_chr_1kB
ldrb r0, [r9, #s_mmc3_bank+4]; eor r1, r4, #0x1800; bl map_chr_1kB
ldrb r0, [r9, #s_mmc3_bank+5]; eor r1, r4, #0x1C00; bl map_chr_1kB
mov r4, #0x4000
and r4, r4, r5, lsl #8
ldrb r0, [r9, #s_mmc3_bank+6]; eor r1, r4, #0x8000; bl map_prg_8kB
ldrb r0, [r9, #s_mmc3_bank+7]; mov r1, #0xA000; bl map_prg_8kB
mov r0, #-2; eor r1, r4, #0xC000; bl map_prg_8kB
pop {r4, r5, pc}
mapper_AxROM:
push {r4, lr}
mov r4, r0
tst r4, #0x10
bleq mirror_1screen_lo
blne mirror_1screen_hi
mov r0, r4
pop {r4, lr}
b map_prg_32kB
mapper_Color_Dreams:
push {r4, lr}
mov r4, r0
bl map_prg_32kB
mov r0, r4, lsr #4
pop {r4, lr}
b map_chr_8kB
mapper_BxROM:
b map_prg_32kB
mapper_GxROM:
push {r4, lr}
mov r4, r0
bl map_chr_8kB
mov r0, r4, lsr #4
pop {r4, lr}
b map_prg_32kB
mapper_Action_Enterprises:
push {r4, lr}
mov r4, r2
and r0, r0, #3
orr r0, r0, r2, lsl #2
bl map_chr_8kB
mov r0, r4, lsr #7
and r0, r0, #0x3F
mov r0, r0, lsl #15
ldr r1, [r9, #s_prg_size]
ldr r2, [r9, #s_prg_ptr]
cmp r0, r1
andhi r0, r0, r1
add r0, r0, r2
bl map_prg_32kB_from_pointer
bl mirror_vert
pop {r4, pc}
.globl sram_load
sram_load:
ldrb r0, [r9, #s_rom_header+6]
tst r0, #0x02
bxeq lr
push {r4, lr}
ldr r0, [r9, #s_path_extension]
adr r1, save_ext
swi e_strcpy
add r0, r9, #s_path
adr r1, save_read_mode
swi e_fopen
movs r4, r0
popeq {r4, pc}
add r0, r9, #s_sram
mov r1, #0x2000
mov r2, #1
mov r3, r4
swi e_fread
mov r0, r4
swi e_fclose
pop {r4, pc}
.globl sram_save
sram_save:
push {r4-r5, lr}
ldrb r0, [r9, #s_rom_header+6]
tst r0, #0x02
adreq r5, no_saves
beq 1f
ldr r0, [r9, #s_path_extension]
adr r1, save_ext
swi e_strcpy
add r0, r9, #s_path
adr r1, save_write_mode
swi e_fopen
adr r5, save_error
movs r4, r0
beq 1f
add r0, r9, #s_sram
mov r1, #0x2000
mov r2, #1
mov r3, r4
swi e_fwrite
movs r0, r0
adrne r5, save_success
mov r0, r4
swi e_fclose
1: mov r0, r5
pop {r4-r5, lr}
b display_ingame_message
save_ext:
.string "sav.tns"
save_read_mode:
.string "rb"
save_write_mode:
.string "wb"
no_saves:
.string "Game has no save memory"
save_error:
.string "File error while saving"
save_success:
.string "Saved"
.align 4