NESpire/source/memory.S

373 lines
7.7 KiB
ArmAsm
Raw Permalink Normal View History

2024-05-18 18:43:54 +01:00
#include "nes.inc"
.globl mem_read_split
.globl mem_read
.globl mem_write_split
.globl mem_write
.globl mem_jump_split
.globl mem_jump
@ Input:
@ r2 = address low byte (split), full address (unsplit)
@ r3 = address high byte (split)
@ Output:
@ r0 = byte read
@ r2 = full address
@ r3 invalidated
@ All other registers preserved
mem_read_split:
add r2, r2, r3, lsl #8
mem_read:
mov r3, r2, lsr #13
add pc, pc, r3, lsl #4
nop
mem_read_ram:
@ 0000-1FFF: RAM
bic r3, r2, #0x11800
ldrb r0, [r9, r3]
bx lr
nop
@ 2000-3FFF: PPU registers
and r3, r2, #7
add r3, pc, r3, lsl #2
add pc, r3, #ppu_read_table - (. + 4)
nop
@ 4000-5FFF: 2A03 registers
sub r3, r2, #0x4000
cmp r3, #0x16
beq mem_read_4016
b mem_read_bad
@ 6000-7FFF: SRAM
add r3, r9, #s_sram - 0x6000
ldrb r0, [r3, r2]
bx lr
nop
@ 8000-9FFF: ROM
ldr r3, [r9, #s_mem_map + 0x10]
ldrb r0, [r3, r2]
bx lr
nop
@ A000-BFFF: ROM
ldr r3, [r9, #s_mem_map + 0x14]
ldrb r0, [r3, r2]
bx lr
nop
@ C000-DFFF: ROM
ldr r3, [r9, #s_mem_map + 0x18]
ldrb r0, [r3, r2]
bx lr
nop
@ E000-FFFF: ROM
ldr r3, [r9, #s_mem_map + 0x1C]
ldrb r0, [r3, r2]
bx lr
nop
@ 10000-100FE: RAM (overflow)
b mem_read_ram
mem_read_bad:
@ TODO: print debug message
mov r0, #0
bx lr
ppu_read_table:
b mem_read_bad
b mem_read_bad
b mem_read_2002
b mem_read_bad
b mem_read_2004
b mem_read_bad
b mem_read_bad
mem_read_2007:
ldr r2, [r9, #s_ppu_address]
bic r2, r2, #0xC000
mov r3, r2, lsr #10
add r3, r9, r3, lsl #2
@ Buffered VRAM read
ldr r3, [r3, #s_ppu_mem_map]
ldrb r0, [r9, #s_ppu_data]
ldrb r3, [r3, r2]
strb r3, [r9, #s_ppu_data]
@ Palette is read directly
cmp r2, #0x3F00
andcs r2, r2, #0x1F
addcs r3, r9, #s_ppu_palette
ldrcsb r0, [r3, r2]
@ Advance ppu_address by 1 or 32
ldr r3, [r9, #s_ppu_control]
ldr r2, [r9, #s_ppu_address]
tst r3, #0x04
addeq r2, r2, #0x0001
addne r2, r2, #0x0020
bic r2, r2, #0x8000
str r2, [r9, #s_ppu_address]
@ Fix our flagrant mangling of r2
mov r2, #0x2000
add r2, r2, #0x7
bx lr
mem_read_2004:
ldrb r3, [r9, #s_ppu_oam_addr]
add r0, r9, #s_ppu_oam_ram
ldrb r0, [r0, r3]
and r3, r3, #0x03
cmp r3, #0x02
andeq r0, r0, #0xE3
bx lr
mem_read_2002:
ldrb r0, [r9, #s_ppu_status]
mov r3, #0x00
strb r3, [r9, #s_ppu_scroll+2]
bic r3, r0, #0x80
strb r3, [r9, #s_ppu_status]
bx lr
mem_read_4016:
ldr r3, [r9, #s_input_queue]
and r0, r3, #1
mov r3, r3, asr #1
str r3, [r9, #s_input_queue]
bx lr
@ Input:
@ r0 = byte to write (high bits ignored)
@ r2 = address low byte (split), full address (unsplit)
@ r3 = address high byte (split)
@ Output:
@ r0, r2, r3 invalidated
@ All other registers preserved
mem_write_split:
add r2, r2, r3, lsl #8
mem_write:
@push {r0}
@mov r3, r2, lsr #13
@add r3, r9, r3, lsl #2
@ldr r0, [r3, #0xC00]
@add r0, r0, #1
@str r0, [r3, #0xC00]
@pop {r0}
mov r3, r2, lsr #13
add pc, pc, r3, lsl #4
nop
@ 0000-1FFF: RAM
mem_write_ram:
bic r3, r2, #0x11800
strb r0, [r9, r3]
bx lr
nop
@ 2000-3FFF: PPU registers
and r3, r2, #7
add r3, pc, r3, lsl #2
add pc, r3, #ppu_write_table - (. + 4)
nop
@ 4000-5FFF: APU registers
sub r3, r2, #0x4000
b mem_write_4000_to_4017
nop
nop
@ 6000-7FFF: SRAM
add r3, r9, #s_sram - 0x6000
strb r0, [r3, r2]
bx lr
nop
@ 8000-FFFF: Mapper registers
.rept 4
str lr, [sp, #-4]!
adr lr, return_from_mapper
ldr pc, [r9, #s_mapper]
nop
.endr
@ 10000-100FE: RAM (overflow)
b mem_write_ram
return_from_mapper:
ldr r0, [r9, #s_pc_base]
ldr lr, [sp], #4
sub r4, r4, #1
sub r2, r4, r0
b mem_jump
ppu_write_table:
b mem_write_2000
b mem_write_2001
bx lr @ No-op
b mem_write_2003
b mem_write_2004
b mem_write_2005
b mem_write_2006
@ Reg 2007:
mem_write_2007:
ldr r2, [r9, #s_ppu_address]
bic r2, r2, #0xC000
cmp r2, #0x3F00
bcs mem_write_2007_palette
mov r3, r2, lsr #10
add r3, r9, r3, lsl #2
ldr r3, [r3, #s_ppu_mem_map]
strb r0, [r3, r2] @ TODO: don't allow write to CHR-ROM
b mem_write_2007_common
mem_write_2007_palette:
and r0, r0, #0x3F
and r2, r2, #0x1F
@ +00/+10, +04/+14, +08/+18, +0C/+1C are mirrored pairs
add r3, r9, #s_ppu_palette
tst r2, #0x03
strb r0, [r3, r2]
eoreq r2, r2, #0x10
streqb r0, [r3, r2]
mov r0, #0
strb r0, [r9, #s_palette_cache_valid]
mem_write_2007_common:
@ Advance ppu_address by 1 or 32
ldr r3, [r9, #s_ppu_control]
ldr r2, [r9, #s_ppu_address]
tst r3, #0x04
addeq r2, r2, #0x0001
addne r2, r2, #0x0020
bic r2, r2, #0x8000
str r2, [r9, #s_ppu_address]
bx lr
@ Reg 2006: Set PPU address, first hi byte, then lo
mem_write_2006:
ldr r3, [r9, #s_ppu_scroll]
tst r3, #0x10000
eor r3, r3, #0x10000
str r3, [r9, #s_ppu_scroll]
bne mem_write_2006_second
mem_write_2006_first:
and r0, r0, #0x3F
strb r0, [r9, #s_ppu_scroll + 1]
bx lr
mem_write_2006_second:
strb r0, [r9, #s_ppu_scroll]
strb r0, [r9, #s_ppu_address]
mov r0, r3, lsr #8
strb r0, [r9, #s_ppu_address + 1]
bx lr
@ Reg 2005: Set scroll position, first x, then y
mem_write_2005:
ldr r3, [r9, #s_ppu_scroll]
and r0, r0, #0xFF
tst r3, #0x10000
eor r3, r3, #0x10000
bne mem_write_2005_second
mem_write_2005_first:
bic r3, r3, #0xE0000000
bic r3, r3, #0x0000001F
orr r3, r3, r0, ror #3
str r3, [r9, #s_ppu_scroll]
bx lr
mem_write_2005_second:
mov r0, r0, ror #3
bic r3, r3, #0x03E0
orr r3, r3, r0, lsl #5
bic r3, r3, #0x7000
orr r3, r3, r0, lsr #17
str r3, [r9, #s_ppu_scroll]
bx lr
@ Reg 2004: Sprite data
mem_write_2004:
ldrb r3, [r9, #s_ppu_oam_addr]
add r2, r9, #s_ppu_oam_ram
strb r0, [r2, r3]
add r3, r3, #1
strb r3, [r9, #s_ppu_oam_addr]
mov r0, #0
strb r0, [r9, #s_spr_loc_table_valid]
bx lr
@ Reg 2003: Sprite address
mem_write_2003:
strb r0, [r9, #s_ppu_oam_addr]
bx lr
@ Reg 2001: PPU Mask
mem_write_2001:
strb r0, [r9, #s_ppu_mask]
bx lr
@ Reg 2000: PPU Control
mem_write_2000:
@ TODO: if sprites changed 8x8 <-> 8x16, invalidate table
ldr r3, [r9, #s_ppu_scroll]
strb r0, [r9, #s_ppu_control]
bic r3, #0x0C00
and r0, r0, #0x03
orr r3, r3, r0, lsl #10
str r3, [r9, #s_ppu_scroll]
@ TODO: Generate NMI if 2002.b7 set and 2000.b7 changed from 0 to 1
bx lr
mem_write_4000_to_4017:
cmp r3, #0x14
beq mem_write_4014
cmp r3, #0x16
bxne lr
mem_write_4016:
ldr r0, [r9, #s_input_status]
str r0, [r9, #s_input_queue]
bx lr
mem_write_4014:
push {r1}
@ Store 256 bytes to OAM RAM
mov r0, r0, lsl #8
mov r2, r0, lsr #13
add r2, r9, r2, lsl #2
ldr r2, [r2, #s_mem_map]
add r0, r2, r0
ldrb r3, [r9, #s_ppu_oam_addr]
add r2, r9, #s_ppu_oam_ram
add r2, r2, r3
rsb r3, r3, #0x100
mem_write_4014_loop:
ldrb r1, [r0], #1
subs r3, r3, #1
strb r1, [r2], #1
bne mem_write_4014_loop
ldrb r3, [r9, #s_ppu_oam_addr]
add r2, r9, #s_ppu_oam_ram
cmp r3, #0
beq mem_write_4014_done
mem_write_4014_loop2:
ldrb r1, [r0], #1
subs r3, r3, #1
strb r1, [r2], #1
bne mem_write_4014_loop2
mem_write_4014_done:
mov r0, #0
strb r0, [r9, #s_spr_loc_table_valid]
pop {r1}
@ CPU is paused for 513 cycles while the transfer completes
sub cpu_cycles, cpu_cycles, #512 * CPU_CYCLE_LENGTH
sub cpu_cycles, cpu_cycles, #1 * CPU_CYCLE_LENGTH
bx lr
mem_jump_split:
add r2, r2, r3, lsl #8
mem_jump:
@ Most jumps will probably be to ROM. Optimize for higher addresses
cmp r2, #0x6000
bcc mem_jump_low
mem_jump_ok:
mov r0, r2, lsr #13
add r0, r9, r0, lsl #2
ldr r0, [r0, #s_mem_map]
str r0, [r9, #s_pc_base]
add cpu_pc, r0, r2
ldrb r1, [cpu_pc], #1
bx lr
mem_jump_low:
cmp r2, #0x2000
biccc r2, r2, #0x1800 @ RAM mirroring
bcc mem_jump_ok
@ Jump to 2000-5FFF range - should never happen.
ERROR 0x0001