# vim:filetype=mips

# memory handlers with banking support for SSF II - The New Challengers
# mostly based on Gens code
# For the MIPS R5900. Based on Memory_amips.s by Notaz.

# (c) Copyright 2007, Grazvydas "notaz" Ignotas
# All Rights Reserved


.set noreorder
.set noat	#$at is currently used in the substitute macro instructions (and some replacement code).

.text
.align 4

.macro ext dest,src,pos,size
	srl	\dest, \src, \pos
	li	$at, ((1 << \size) - 1)
	and	\dest, $at
.endm

# default jump tables

m_read8_def_table:
    .long   m_read8_rom0    # 0x000000 - 0x07FFFF
    .long   m_read8_rom1    # 0x080000 - 0x0FFFFF
    .long   m_read8_rom2    # 0x100000 - 0x17FFFF
    .long   m_read8_rom3    # 0x180000 - 0x1FFFFF
    .long   m_read8_rom4    # 0x200000 - 0x27FFFF
    .long   m_read8_rom5    # 0x280000 - 0x2FFFFF
    .long   m_read8_rom6    # 0x300000 - 0x37FFFF
    .long   m_read8_rom7    # 0x380000 - 0x3FFFFF
    .long   m_read8_rom8    # 0x400000 - 0x47FFFF - for all those large ROM hacks
    .long   m_read8_rom9    # 0x480000 - 0x4FFFFF
    .long   m_read8_romA    # 0x500000 - 0x57FFFF
    .long   m_read8_romB    # 0x580000 - 0x5FFFFF
    .long   m_read8_romC    # 0x600000 - 0x67FFFF
    .long   m_read8_romD    # 0x680000 - 0x6FFFFF
    .long   m_read8_romE    # 0x700000 - 0x77FFFF
    .long   m_read8_romF    # 0x780000 - 0x7FFFFF
    .long   m_read8_rom10   # 0x800000 - 0x87FFFF
    .long   m_read8_rom11   # 0x880000 - 0x8FFFFF
    .long   m_read8_rom12   # 0x900000 - 0x97FFFF
    .long   m_read8_rom13   # 0x980000 - 0x9FFFFF
    .long   m_read8_misc    # 0xA00000 - 0xA7FFFF
    .long   m_read_null     # 0xA80000 - 0xAFFFFF
    .long   m_read_null     # 0xB00000 - 0xB7FFFF
    .long   m_read_null     # 0xB80000 - 0xBFFFFF
    .long   m_read8_vdp     # 0xC00000 - 0xC7FFFF
    .long   m_read8_vdp     # 0xC80000 - 0xCFFFFF
    .long   m_read8_vdp     # 0xD00000 - 0xD7FFFF
    .long   m_read8_vdp     # 0xD80000 - 0xDFFFFF
    .long   m_read8_ram     # 0xE00000 - 0xE7FFFF
    .long   m_read8_ram     # 0xE80000 - 0xEFFFFF
    .long   m_read8_ram     # 0xF00000 - 0xF7FFFF
    .long   m_read8_ram     # 0xF80000 - 0xFFFFFF

m_read16_def_table:
    .long   m_read16_rom0    # 0x000000 - 0x07FFFF
    .long   m_read16_rom1    # 0x080000 - 0x0FFFFF
    .long   m_read16_rom2    # 0x100000 - 0x17FFFF
    .long   m_read16_rom3    # 0x180000 - 0x1FFFFF
    .long   m_read16_rom4    # 0x200000 - 0x27FFFF
    .long   m_read16_rom5    # 0x280000 - 0x2FFFFF
    .long   m_read16_rom6    # 0x300000 - 0x37FFFF
    .long   m_read16_rom7    # 0x380000 - 0x3FFFFF
    .long   m_read16_rom8    # 0x400000 - 0x47FFFF
    .long   m_read16_rom9    # 0x480000 - 0x4FFFFF
    .long   m_read16_romA    # 0x500000 - 0x57FFFF
    .long   m_read16_romB    # 0x580000 - 0x5FFFFF
    .long   m_read16_romC    # 0x600000 - 0x67FFFF
    .long   m_read16_romD    # 0x680000 - 0x6FFFFF
    .long   m_read16_romE    # 0x700000 - 0x77FFFF
    .long   m_read16_romF    # 0x780000 - 0x7FFFFF
    .long   m_read16_rom10   # 0x800000 - 0x87FFFF
    .long   m_read16_rom11   # 0x880000 - 0x8FFFFF
    .long   m_read16_rom12   # 0x900000 - 0x97FFFF
    .long   m_read16_rom13   # 0x980000 - 0x9FFFFF
    .long   m_read16_misc    # 0xA00000 - 0xA7FFFF
    .long   m_read_null      # 0xA80000 - 0xAFFFFF
    .long   m_read_null      # 0xB00000 - 0xB7FFFF
    .long   m_read_null      # 0xB80000 - 0xBFFFFF
    .long   m_read16_vdp     # 0xC00000 - 0xC7FFFF
    .long   m_read16_vdp     # 0xC80000 - 0xCFFFFF
    .long   m_read16_vdp     # 0xD00000 - 0xD7FFFF
    .long   m_read16_vdp     # 0xD80000 - 0xDFFFFF
    .long   m_read16_ram     # 0xE00000 - 0xE7FFFF
    .long   m_read16_ram     # 0xE80000 - 0xEFFFFF
    .long   m_read16_ram     # 0xF00000 - 0xF7FFFF
    .long   m_read16_ram     # 0xF80000 - 0xFFFFFF

m_read32_def_table:
    .long   m_read32_rom0    # 0x000000 - 0x07FFFF
    .long   m_read32_rom1    # 0x080000 - 0x0FFFFF
    .long   m_read32_rom2    # 0x100000 - 0x17FFFF
    .long   m_read32_rom3    # 0x180000 - 0x1FFFFF
    .long   m_read32_rom4    # 0x200000 - 0x27FFFF
    .long   m_read32_rom5    # 0x280000 - 0x2FFFFF
    .long   m_read32_rom6    # 0x300000 - 0x37FFFF
    .long   m_read32_rom7    # 0x380000 - 0x3FFFFF
    .long   m_read32_rom8    # 0x400000 - 0x47FFFF
    .long   m_read32_rom9    # 0x480000 - 0x4FFFFF
    .long   m_read32_romA    # 0x500000 - 0x57FFFF
    .long   m_read32_romB    # 0x580000 - 0x5FFFFF
    .long   m_read32_romC    # 0x600000 - 0x67FFFF
    .long   m_read32_romD    # 0x680000 - 0x6FFFFF
    .long   m_read32_romE    # 0x700000 - 0x77FFFF
    .long   m_read32_romF    # 0x780000 - 0x7FFFFF
    .long   m_read32_rom10   # 0x800000 - 0x87FFFF
    .long   m_read32_rom11   # 0x880000 - 0x8FFFFF
    .long   m_read32_rom12   # 0x900000 - 0x97FFFF
    .long   m_read32_rom13   # 0x980000 - 0x9FFFFF
    .long   m_read32_misc    # 0xA00000 - 0xA7FFFF
    .long   m_read_null      # 0xA80000 - 0xAFFFFF
    .long   m_read_null      # 0xB00000 - 0xB7FFFF
    .long   m_read_null      # 0xB80000 - 0xBFFFFF
    .long   m_read32_vdp     # 0xC00000 - 0xC7FFFF
    .long   m_read32_vdp     # 0xC80000 - 0xCFFFFF
    .long   m_read32_vdp     # 0xD00000 - 0xD7FFFF
    .long   m_read32_vdp     # 0xD80000 - 0xDFFFFF
    .long   m_read32_ram     # 0xE00000 - 0xE7FFFF
    .long   m_read32_ram     # 0xE80000 - 0xEFFFFF
    .long   m_read32_ram     # 0xF00000 - 0xF7FFFF
    .long   m_read32_ram     # 0xF80000 - 0xFFFFFF


# #############################################################################

.bss
.align 4

# used tables
m_read8_table:
    .skip 32*4

m_read16_table:
    .skip 32*4

m_read32_table:
    .skip 32*4


# #############################################################################

.text
.align 4

.global PicoMemReset
.global PicoRead8
.global PicoRead16
.global PicoRead32
.global PicoWriteRomHW_SSF2

.global m_read8_def_table
.global m_read8_table

.macro PicoMemResetCopyDef dst_table src_table
    lui     $t0, %hi(\dst_table)
    addiu   $t0, %lo(\dst_table)
    lui     $t1, %hi(\src_table)
    addiu   $t1, %lo(\src_table)
    li      $t2, 32
1:
    lw      $t3, 0($t1)
    sw      $t3, 0($t0)
    addiu   $t2, -1
    addiu   $t1, 4
    nop	#Workaround for the R5900 short-loop bug.
    bnez    $t2, 1b
    addiu   $t0, 4
.endm

# $t4 = 4
.macro PicoMemResetRomArea dst_table ar_label
    lui     $t0, %hi(\dst_table)
    addiu   $t0, %lo(\dst_table)
    lui     $t1, %hi(\ar_label)
    addiu   $t1, %lo(\ar_label)
    li      $t2, 20
1:
    beq     $t2, $v1, 2f
    addiu   $t2, -1
    sll     $t3, $t2, 2
    beq     $t2, $t4, 1b           # do not touch the SRAM area
    addu    $t3, $t0
    j       1b
    sw      $t1, 0($t3)
2:
.endm


PicoMemReset:
    lui     $v1, %hi(Pico+0x22204)
    lw      $v1, %lo(Pico+0x22204)($v1)  # romsize
    lui     $t0, 8
    addu    $v1, $t0
    addiu   $v1, -1
    srl     $v1, 19

    PicoMemResetCopyDef m_read8_table  m_read8_def_table
    PicoMemResetCopyDef m_read16_table m_read16_def_table
    PicoMemResetCopyDef m_read32_table m_read32_def_table

    # update memhandlers according to ROM size
    li      $t4, 4
    PicoMemResetRomArea m_read8_table  m_read8_above_rom
    PicoMemResetRomArea m_read16_table m_read16_above_rom
    PicoMemResetRomArea m_read32_table m_read32_above_rom

    jr      $ra
    nop

# #############################################################################

.macro PicoReadJump table
    lui     $t0, %hi(\table)
    srl     $t1, $a0, 19
	li		$at, 0xFFFFFF83
	and		$t0, $t0, $at
	andi	$t1, $t1, 0x1F
	sll		$t1, $t1, 2
	or		$t0, $t0, $t1

    lw      $t0, %lo(\table)($t0)
	sll		$a0, $a0, 8
    jr      $t0
	srl		$a0, $a0, 8
.endm

PicoRead8: # u32 a
    PicoReadJump m_read8_table

PicoRead16: # u32 a
    PicoReadJump m_read16_table

PicoRead32: # u32 a
    PicoReadJump m_read32_table

# #############################################################################

m_read_null:
    jr      $ra
    li      $v0, 0

m_read_neg1:
    jr      $ra
    addiu   $v0, $0, 0xffff

# loads &Pico.rom to $t3
.macro m_read_rom_try_sram is200000 size
    lui     $t2, %hi(SRam)
    addiu   $t2, %lo(SRam)
    lui     $t3, %hi(Pico+0x22200)
    lw      $t1, 8($t2)     # SRam.end
.if \is200000
	sll		$a0, $a0, 13
	srl		$a0, $a0, 13
    lui     $t4, 0x20
    or      $a0, $t4
.endif
    subu    $t4, $a0, $t1
    bgtz    $t4, 1f
    addiu   $t3, %lo(Pico+0x22200)
    lw      $t1, 4($t2)     # SRam.start
    subu    $t4, $t1, $a0
    bgtz    $t4, 1f
    nop
    lb      $t1, 0x11($t3)  # Pico.m.sram_reg
    andi    $t4, $t1, 5
    beqz    $t4, 1f
    nop
.if \size == 8
    j       SRAMRead
    nop
.elseif \size == 16
    sd      $ra, -16($sp)
    jal     SRAMRead16
    addiu   $sp, -16
    ld      $ra, 0($sp)
    jr      $ra
    addiu   $sp, 16
.else
    addiu   $sp, -32
    sd      $ra, 0($sp)
    sd      $a0, 16($sp)
    jal     SRAMRead16
    nop
    ld      $a0, 16($sp)
    sd      $v0, 16($sp)
    jal     SRAMRead16
    addiu   $a0, 2
    ld      $v1, 16($sp)
    ld      $ra, 0($sp)
	andi	$v0, $v0, 0xFFFF
	srl		$v1, $v1, 16
	or		$v0, $v1
    jr      $ra
    addiu   $sp, 32
.endif
# m_read_nosram:
1:
.endm

.macro m_read8_rom sect
    lui     $t0, %hi(Pico+0x22200)
    lw      $t0, %lo(Pico+0x22200)($t0)  # rom
    xori    $a0, 1
	sll		$a0, $a0, 13
	srl		$a0, $a0, 13
.if \sect
    lui     $t1, 8*\sect
    addu    $a0, $t1
.endif
    addu    $t0, $a0
    jr      $ra
    lb      $v0, 0($t0)
.endm


m_read8_rom0: # 0x000000 - 0x07ffff
    m_read8_rom 0

m_read8_rom1: # 0x080000 - 0x0fffff
    m_read8_rom 1

m_read8_rom2: # 0x100000 - 0x17ffff
    m_read8_rom 2

m_read8_rom3: # 0x180000 - 0x1fffff
    m_read8_rom 3

m_read8_rom4: # 0x200000 - 0x27ffff, SRAM area
    m_read_rom_try_sram 1 8
    lw      $t1, 4($t3)     # romsize
    subu    $t4, $t1, $a0
    blez    $t4, m_read_null
    lw      $t1, 0($t3)     # rom
    xori    $a0, 1
    addu    $t1, $a0
    jr      $ra
    lb      $v0, 0($t1)

m_read8_rom5: # 0x280000 - 0x2fffff
    m_read8_rom 5

m_read8_rom6: # 0x300000 - 0x37ffff
    m_read8_rom 6

m_read8_rom7: # 0x380000 - 0x3fffff
    m_read8_rom 7

m_read8_rom8: # 0x400000 - 0x47ffff
    m_read8_rom 8

m_read8_rom9: # 0x480000 - 0x4fffff
    m_read8_rom 9

m_read8_romA: # 0x500000 - 0x57ffff
    m_read8_rom 0xA

m_read8_romB: # 0x580000 - 0x5fffff
    m_read8_rom 0xB

m_read8_romC: # 0x600000 - 0x67ffff
    m_read8_rom 0xC

m_read8_romD: # 0x680000 - 0x6fffff
    m_read8_rom 0xD

m_read8_romE: # 0x700000 - 0x77ffff
    m_read8_rom 0xE

m_read8_romF: # 0x780000 - 0x7fffff
    m_read8_rom 0xF

m_read8_rom10: # 0x800000 - 0x87ffff
    m_read8_rom 0x10

m_read8_rom11: # 0x880000 - 0x8fffff
    m_read8_rom 0x11

m_read8_rom12: # 0x900000 - 0x97ffff
    m_read8_rom 0x12

m_read8_rom13: # 0x980000 - 0x9fffff
    m_read8_rom 0x13


m_read8_misc:
    srl     $t0, $a0, 5
    sll     $t0, $t0, 5
    lui     $t1, 0xa1
    bne     $t0, $t1, m_read8_misc2
    andi    $t0, $a0, 0x1e
m_read8_misc_io:
    beqz    $t0, m_read8_misc_hwreg
    sub     $t1, $t0, 4
    bgtz    $t1, m_read8_misc_ioports
    nop
    slti    $a0, $t0, 4
    xori    $a0, 1
    j       PadRead
    nop

m_read8_misc_hwreg:
    lui     $v0, %hi(Pico+0x2220f)
    jr      $ra
    lb      $v0, %lo(Pico+0x2220f)($v0)

m_read8_misc_ioports:
    lui     $v0, %hi(Pico+0x22000)
	sra		$v0, $v0, 5
	sll		$v0, $v0, 5
	andi	$t0, $t0, 0x1F
	or		$v0, $v0, $t0
    jr      $ra
    lb      $v0, %lo(Pico+0x22000)($v0)

m_read8_misc2:
    lui     $t0, 0xa1
    ori     $t0, 0x1100
    bne     $a0, $t0, m_read8_misc3
    srl     $t0, $a0, 16
    j       z80ReadBusReq

m_read8_misc3:
    addiu   $t0, 0xff60       # expecting 0xa0 to get 0
    bnez    $t0, m_read8_misc4

    # z80 area
    andi    $t0, $a0, 0x4000
    bnez    $t0, m_read8_z80_misc
    andi    $t0, $a0, 0x6000
    j       z80Read8          # z80 RAM

m_read8_z80_misc:
    addiu   $t0, 0xc000       # expecting 0x4000 to get 0
    bnez    $t0, m_read_neg1  # invalid
    nop
    j       ym2612_read_local_68k
    nop

m_read8_fake_ym2612:
    lb      $v0, %lo(Pico+0x22208)($t0) # Pico.m.rotate
    addiu   $t1, $v0, 1
    jr      $ra
    sb      $t1, %lo(Pico+0x22208)($t0)

# delay slot friendly
.macro m_read8_call16 funcname is_func_ptr=0
.if \is_func_ptr
    lui     $t1, %hi(\funcname)
    lw      $t1, %lo(\funcname)($t1)
.endif
    andi    $t0, $a0, 1
    beqz    $t0, 1f
    li      $a1, 8      # not always needed, but shouln't cause problems
.if \is_func_ptr
    jr      $t1
.else
    j       \funcname   # odd address
.endif
    nop
1:
    addiu   $sp, -16
    sd      $ra, 0($sp)
.if \is_func_ptr
    jalr    $t1
.else
    jal     \funcname
.endif
    xori    $a0, 1
    ld      $ra, 0($sp)
    addiu   $sp, 16
    jr      $ra
    srl     $v0, 8
.endm

m_read8_misc4:
    # if everything else fails, use generic handler
    m_read8_call16 OtherRead16

m_read8_vdp:
    ext     $t0, $a0, 16, 3
    andi    $t1, $a0, 0xe0
    or      $t0, $t1
    bnez    $t0, m_read_null # invalid address
    nop
    j       PicoVideoRead8
    nop

m_read8_ram:
    lui     $t0, %hi(Pico)
	andi	$a0, $a0, 0xFFFF
	sra		$t0, $t0, 16
	sll		$t0, $t0, 16
	or		$t0, $t0, $a0
    xori    $t0, 1
    jr      $ra
    lb      $v0, %lo(Pico)($t0)

m_read8_above_rom:
    # might still be SRam (Micro Machines, HardBall '95)
    m_read_rom_try_sram 0 8
    m_read8_call16 PicoRead16Hook 1

# #############################################################################

.macro m_read16_rom sect
    lui     $t0, %hi(Pico+0x22200)
    lw      $t0, %lo(Pico+0x22200)($t0)  # rom
	li		$at, 0x0007FFFE
	and		$a0, $a0, $at
.if \sect
    lui     $t1, 8*\sect
    addu    $a0, $t1
.endif
    addu    $t0, $a0
    jr      $ra
    lh      $v0, 0($t0)
.endm


m_read16_rom0: # 0x000000 - 0x07ffff
    m_read16_rom 0

m_read16_rom1: # 0x080000 - 0x0fffff
    m_read16_rom 1

m_read16_rom2: # 0x100000 - 0x17ffff
    m_read16_rom 2

m_read16_rom3: # 0x180000 - 0x1fffff
    m_read16_rom 3

m_read16_rom4: # 0x200000 - 0x27ffff, SRAM area
    m_read_rom_try_sram 1 16
    lw      $t1, 4($t3)     # romsize
    subu    $t4, $t1, $a0
    blez    $t4, m_read_null
    lw      $t1, 0($t3)     # rom
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    addu    $t1, $a0
    jr      $ra
    lh      $v0, 0($t1)

m_read16_rom5: # 0x280000 - 0x2fffff
    m_read16_rom 5

m_read16_rom6: # 0x300000 - 0x37ffff
    m_read16_rom 6

m_read16_rom7: # 0x380000 - 0x3fffff
    m_read16_rom 7

m_read16_rom8: # 0x400000 - 0x47ffff
    m_read16_rom 8

m_read16_rom9: # 0x480000 - 0x4fffff
    m_read16_rom 9

m_read16_romA: # 0x500000 - 0x57ffff
    m_read16_rom 0xA

m_read16_romB: # 0x580000 - 0x5fffff
    m_read16_rom 0xB

m_read16_romC: # 0x600000 - 0x67ffff
    m_read16_rom 0xC

m_read16_romD: # 0x680000 - 0x6fffff
    m_read16_rom 0xD

m_read16_romE: # 0x700000 - 0x77ffff
    m_read16_rom 0xE

m_read16_romF: # 0x780000 - 0x7fffff
    m_read16_rom 0xF

m_read16_rom10: # 0x800000 - 0x87ffff
    m_read16_rom 0x10

m_read16_rom11: # 0x880000 - 0x8fffff
    m_read16_rom 0x11

m_read16_rom12: # 0x900000 - 0x97ffff
    m_read16_rom 0x12

m_read16_rom13: # 0x980000 - 0x9fffff
    m_read16_rom 0x13

m_read16_misc:
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    j       OtherRead16
    li      $a1, 16

m_read16_vdp:
    ext     $t0, $a0, 16, 3
    andi    $t1, $a0, 0xe0
    or      $t0, $t1
    bnez    $t0, m_read_null # invalid address
	sra		$a0, $a0, 1
    j       PicoVideoRead
	sll		$a0, $a0, 1

m_read16_ram:
    lui     $t0, %hi(Pico)
	srl		$a0, $a0, 1
	sll		$a0, $a0, 17
	srl		$a0, $a0, 16
	sra		$t0, $t0, 16
	sll		$t0, $t0, 16
	or		$t0, $t0, $a0
    jr      $ra
    lh      $v0, %lo(Pico)($t0)

m_read16_above_rom:
    # might still be SRam
    m_read_rom_try_sram 0 16
    lui     $t1, %hi(PicoRead16Hook)
    lw      $t1, %lo(PicoRead16Hook)($t1)
	sra		$a0, $a0, 1
    jr      $t1
	sll		$a0, $a0, 1

# #############################################################################

.macro m_read32_rom sect
    lui     $t0, %hi(Pico+0x22200)
    lw      $t0, %lo(Pico+0x22200)($t0)  # rom
	li		$at, 0x0007FFFE
	and		$a0, $a0, $at
.if \sect
    lui     $t1, 8*\sect
    addu    $a0, $t1
.endif
    addu    $t0, $a0
    lh      $v1, 0($t0)
    lh      $v0, 2($t0)
	andi	$v0, $v0, 0xFFFF
	sll		$v1, $v1, 16
    jr      $ra
	or		$v0, $v0, $v1
.endm


m_read32_rom0: # 0x000000 - 0x07ffff
    m_read32_rom 0

m_read32_rom1: # 0x080000 - 0x0fffff
    m_read32_rom 1

m_read32_rom2: # 0x100000 - 0x17ffff
    m_read32_rom 2

m_read32_rom3: # 0x180000 - 0x1fffff
    m_read32_rom 3

m_read32_rom4: # 0x200000 - 0x27ffff, SRAM area
    m_read_rom_try_sram 1 32
    lw      $t1, 4($t3)     # romsize
    subu    $t4, $t1, $a0
    blez    $t4, m_read_null
    lw      $t1, 0($t3)     # rom
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    addu    $t1, $a0
    lh      $v1, 0($t1)
    lh      $v0, 2($t1)
	andi	$v0, $v0, 0xFFFF
	sll		$v1, $v1, 16
    jr      $ra
	or		$v0, $v0, $v1

m_read32_rom5: # 0x280000 - 0x2fffff
    m_read32_rom 5

m_read32_rom6: # 0x300000 - 0x37ffff
    m_read32_rom 6

m_read32_rom7: # 0x380000 - 0x3fffff
    m_read32_rom 7

m_read32_rom8: # 0x400000 - 0x47ffff
    m_read32_rom 8

m_read32_rom9: # 0x480000 - 0x4fffff
    m_read32_rom 9

m_read32_romA: # 0x500000 - 0x57ffff
    m_read32_rom 0xA

m_read32_romB: # 0x580000 - 0x5fffff
    m_read32_rom 0xB

m_read32_romC: # 0x600000 - 0x67ffff
    m_read32_rom 0xC

m_read32_romD: # 0x680000 - 0x6fffff
    m_read32_rom 0xD

m_read32_romE: # 0x700000 - 0x77ffff
    m_read32_rom 0xE

m_read32_romF: # 0x780000 - 0x7fffff
    m_read32_rom 0xF

m_read32_rom10: # 0x800000 - 0x87ffff
    m_read32_rom 0x10

m_read32_rom11: # 0x880000 - 0x8fffff
    m_read32_rom 0x11

m_read32_rom12: # 0x900000 - 0x97ffff
    m_read32_rom 0x12

m_read32_rom13: # 0x980000 - 0x9fffff
    m_read32_rom 0x13

.macro m_read32_call16 func need_a1=0
    addiu   $sp, -32
    sd      $ra, 0($sp)
    sd      $s0, 16($sp)
.if \need_a1
    li      $a1, 16
.endif
    jal     \func
    move    $s0, $a0

    addu    $a0, $s0, 2
.if \need_a1
    li      $a1, 16
.endif
    jal     \func
    move    $s0, $v0

	sll		$s0, $s0, 16
	andi	$v0, $v0, 0xFFFF
	or		$v0, $v0, $s0
    ld      $ra, 0($sp)
    ld      $s0, 16($sp)
    jr      $ra
    addiu   $sp, 32
.endm

m_read32_misc:
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    m_read32_call16 OtherRead16, 1

m_read32_vdp:
    ext     $t0, $a0, 16, 3
    andi    $t1, $a0, 0xe0
    or      $t0, $t1
    bnez    $t0, m_read_null # invalid address
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    m_read32_call16 PicoVideoRead

m_read32_ram:
    lui     $t0, %hi(Pico)
	sra		$a0, $a0, 1
	sll		$a0, $a0, 17
	srl		$a0, $a0, 16
	sra		$t0, $t0, 16
	sll		$t0, $t0, 16
	or		$t0, $t0, $a0
    lh      $v1, %lo(Pico)($t0)
    lh      $v0, %lo(Pico+2)($t0)
	andi	$v0, $v0, 0xFFFF
	sll		$v1, $v1, 16
    jr      $ra
	or		$v0, $v0, $v1

m_read32_above_rom:
    # might still be SRam
    m_read_rom_try_sram 0 32
	sra		$a0, $a0, 1
	sll		$a0, $a0, 1
    lui     $t1, %hi(PicoRead16Hook)
    lw      $t1, %lo(PicoRead16Hook)($t1)
    addiu   $sp, -16*3
    sd      $ra, 0($sp)
    sd      $s0, 16($sp)
    sd      $t1, 32($sp)
    jalr    $t1
    move    $s0, $a0

    ld      $t1, 32($sp)
    addu    $a0, $s0, 2
    jalr    $t1
    move    $s0, $v0

	andi	$v0, $v0, 0xFFFF
	sll		$s0, $s0, 16
	or		$v0, $v0, $s0
    ld      $ra, 0($sp)
    ld      $s0, 16($sp)
    jr      $ra
    addiu   $sp, 16*3

# #############################################################################

.macro PicoWriteRomHW_SSF2_ls def_table table
    lui     $t3, %hi(\def_table)
	li		$at, 0xFFFFFF83
	and		$t3, $t3, $at
	andi	$at, $a1, 0x1F
	sll		$at, $at, 2
	or		$t3, $t3, $at
    lw      $t0, %lo(\def_table)($t3)
    lui     $t2, %hi(\table)
	li		$at, 0xFFFFFFE3
	and		$t2, $t2, $at
	andi	$at, $a0, 0x07
	sll		$at, $at, 2
	or		$t2, $t2, $at
    sw      $t0, %lo(\table)($t2)
.endm

PicoWriteRomHW_SSF2: # u32 a, u32 d
    ext     $a0, $a0, 1, 3
    bnez    $a0, pwr_banking

    # sram register
    lui     $t0, %hi(Pico+0x22211)
    lb      $t1, %lo(Pico+0x22211)($t0) # Pico.m.sram_reg
	sra		$t1, $t1, 2
	sll		$t1, $t1, 2
	andi	$a1, $a1, 3
	or		$t1, $t1, $a1
    jr      $ra
    sb      $t1, %lo(Pico+0x22211)($t0)

pwr_banking:
    andi    $a1, 0x1f

    PicoWriteRomHW_SSF2_ls m_read8_def_table  m_read8_table
    PicoWriteRomHW_SSF2_ls m_read16_def_table m_read16_table
    PicoWriteRomHW_SSF2_ls m_read32_def_table m_read32_table
 
    jr      $ra
    nop

