diff --git a/src/crab/arm/arm.cr b/src/crab/arm/arm.cr index bb27456..e246d20 100644 --- a/src/crab/arm/arm.cr +++ b/src/crab/arm/arm.cr @@ -31,7 +31,7 @@ module ARM elsif idx & 0b111000000000 == 0b101000000000 lut[idx] = ->arm_branch(Word) elsif idx & 0b111000000000 == 0b100000000000 - # block data transfer + lut[idx] = ->arm_block_data_transfer(Word) elsif idx & 0b111000000001 == 0b011000000001 # undefined elsif idx & 0b110000000000 == 0b010000000000 diff --git a/src/crab/arm/block_data_transfer.cr b/src/crab/arm/block_data_transfer.cr new file mode 100644 index 0000000..b4e63e0 --- /dev/null +++ b/src/crab/arm/block_data_transfer.cr @@ -0,0 +1,34 @@ +module ARM + def arm_block_data_transfer(instr : Word) : Nil + pre_index = bit?(instr, 24) + add = bit?(instr, 23) + s_bit = bit?(instr, 22) # todo respect this bit + write_back = bit?(instr, 21) + load = bit?(instr, 20) + rn = bits(instr, 16..19) + list = bits(instr, 0..15) + + address = @r[rn] + + if load + 16.times do |idx| + if bit?(list, idx) + address &+= add ? 4 : -4 if pre_index + @r[idx] = @gba.bus.read_word(address) + address &+= add ? 4 : -4 unless pre_index + end + end + else + 16.times do |idx| + if bit?(list, idx) + address &+= add ? 4 : -4 if pre_index + @gba.bus[address] = @r[idx] + address &+= add ? 4 : -4 unless pre_index + end + end + end + + @r[rn] = address if write_back + # todo reset pipeline if r15 is written (this needs to be done in all other instrs that write to r15 as well) + end +end