mirror of
https://github.com/mattrberry/crab.git
synced 2024-12-28 09:58:49 +01:00
ldm/stm rewrite & always write incrementing, passing gba-suite/nes
This commit is contained in:
parent
33979013c3
commit
2950d0d0a3
1 changed files with 23 additions and 42 deletions
|
@ -14,55 +14,36 @@ module ARM
|
|||
switch_mode CPU::Mode::USR
|
||||
end
|
||||
|
||||
step_arm # step in advance since str from r15 is 12 ahead
|
||||
address = @r[rn]
|
||||
|
||||
step = add ? 4 : -4
|
||||
idxs = add ? 16.times : 15.downto(0)
|
||||
|
||||
unless list == 0
|
||||
if load
|
||||
idxs.each do |idx|
|
||||
if bit?(list, idx)
|
||||
address &+= step if pre_index
|
||||
set_reg(idx, @gba.bus.read_word(address))
|
||||
address &+= step unless pre_index
|
||||
end
|
||||
bits_set = count_set_bits(list)
|
||||
if bits_set == 0 # odd behavior on empty list, tested in gba-suite
|
||||
bits_set = 16
|
||||
list = 0x8000
|
||||
end
|
||||
final_addr = address + bits_set * (add ? 4 : -4)
|
||||
if add
|
||||
address += 4 if pre_index
|
||||
else
|
||||
address = final_addr
|
||||
address += 4 unless pre_index
|
||||
end
|
||||
first_transfer = false
|
||||
16.times do |idx| # always transfered to/from incrementing addresses
|
||||
if bit?(list, idx)
|
||||
if load
|
||||
set_reg(idx, @gba.bus.read_word(address))
|
||||
else
|
||||
@gba.bus[address] = @r[idx]
|
||||
end
|
||||
else
|
||||
base_addr = nil
|
||||
idxs.each do |idx|
|
||||
if bit?(list, idx)
|
||||
address &+= step if pre_index
|
||||
@gba.bus[address] = @r[idx]
|
||||
@gba.bus[address] &+= 4 if idx == 15
|
||||
base_addr = address if rn == idx
|
||||
address &+= step unless pre_index
|
||||
end
|
||||
end
|
||||
@gba.bus[base_addr] = address if base_addr && first_set_bit(list) != rn # rn is written after first store
|
||||
address += 4 # can always do these post since the address was accounted for up front
|
||||
set_reg(rn, final_addr) if write_back && !first_transfer && !(load && bit?(list, rn))
|
||||
first_transfer = true # writeback happens on second cycle of the instruction
|
||||
end
|
||||
else # https://github.com/jsmolka/gba-suite/blob/master/arm/block_transfer.asm#L214
|
||||
offset = case {add, pre_index} # todo stop hard coding this, but it'll do for now...
|
||||
when {true, true} then 0x4
|
||||
when {true, false} then 0x0
|
||||
when {false, true} then -0x40
|
||||
when {false, false} then -0x3C
|
||||
else abort "Impossible ldm/stm empty list case"
|
||||
end
|
||||
if load
|
||||
set_reg(15, @gba.bus.read_word(address &+ offset))
|
||||
else
|
||||
@gba.bus[address &+ offset] = @r[15] &+ 4
|
||||
end
|
||||
address &+= 0x10 * step
|
||||
end
|
||||
|
||||
if s_bit
|
||||
switch_mode CPU::Mode.from_value mode.not_nil!
|
||||
end
|
||||
|
||||
set_reg(rn, address) if write_back && !(load && bit?(list, rn))
|
||||
|
||||
step_arm unless load && (bit?(list, 15) || list == 0)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue