support open bus for io registers

This commit is contained in:
Matthew Berry 2022-08-19 21:50:12 -07:00
parent 004ff2c197
commit e36b633522
12 changed files with 61 additions and 83 deletions

View file

@ -148,20 +148,19 @@ module GBA
when 0x82 then @soundcnt_h.value.to_u8!
when 0x83 then (@soundcnt_h.value >> 8).to_u8!
when 0x84
0x70_u8 |
(@sound_enabled ? 0x80 : 0) |
(@sound_enabled ? 0x80_u8 : 0_u8) |
(@channel4.enabled ? 0b1000 : 0) |
(@channel3.enabled ? 0b0100 : 0) |
(@channel2.enabled ? 0b0010 : 0) |
(@channel1.enabled ? 0b0001 : 0)
when 0x85 then 0_u8 # unused
when 0x88 then @soundbias.value.to_u8!
when 0x89 then (@soundbias.value >> 8).to_u8!
else puts "Unmapped APU read ~ addr:#{hex_str io_addr.to_u8}".colorize.fore(:red); 0_u8 # todo: open bus
when 0x85, 0x86, 0x87 then 0_u8
when 0x88 then @soundbias.value.to_u8!
when 0x89 then (@soundbias.value >> 8).to_u8!
when 0x8A, 0x8B then 0_u8
else @gba.bus.read_open_bus_value(io_addr)
end
end
# write to apu memory
def []=(io_addr : Int, value : UInt8) : Nil
return unless @sound_enabled || 0x82 <= io_addr <= 0x89 || Channel3::WAVE_RAM_RANGE.includes?(io_addr)
case io_addr
@ -190,7 +189,6 @@ module GBA
when 0x88 then @soundbias.value = (@soundbias.value & 0xFF00) | value
when 0x89 then @soundbias.value = (@soundbias.value & 0x00FF) | value.to_u16 << 8
when 0xA8..0xAF # unused
else puts "Unmapped APU write ~ addr:#{hex_str io_addr.to_u8}, val:#{value}".colorize(:yellow)
end
end
end

View file

@ -79,12 +79,11 @@ module GBA
def [](index : Int) : UInt8
case index
when 0x60 then 0x80_u8 | @sweep_period << 4 | (@negate ? 0x08 : 0) | @shift
when 0x62 then 0x3F_u8 | @duty << 6
when 0x60 then @sweep_period << 4 | (@negate ? 0x08 : 0) | @shift
when 0x62 then @duty << 6
when 0x63 then read_NRx2
when 0x64 then 0xFF_u8 # write-only
when 0x65 then 0xBF_u8 | (@length_enable ? 0x40 : 0)
else puts "Reading from invalid Channel1 register: #{hex_str index.to_u16}".colorize.fore(:red); 0_u8 # todo: open bus
when 0x65 then (@length_enable ? 0x40_u8 : 0_u8)
else 0_u8
end
end

View file

@ -45,11 +45,10 @@ module GBA
def [](index : Int) : UInt8
case index
when 0x68 then 0x3F_u8 | @duty << 6
when 0x68 then @duty << 6
when 0x69 then read_NRx2
when 0x6C then 0xFF_u8 # write-only
when 0x6D then 0xBF_u8 | (@length_enable ? 0x40 : 0)
else puts "Reading from invalid Channel2 register: #{hex_str index.to_u16}".colorize.fore(:red); 0_u8 # todo: open bus
when 0x6D then (@length_enable ? 0x40_u8 : 0_u8)
else 0_u8
end
end

View file

@ -51,18 +51,16 @@ module GBA
def [](index : Int) : UInt8
case index
when 0x70 then 0x7F_u8 | (@dac_enabled ? 0x80 : 0)
when 0x72 then 0xFF_u8
when 0x73 then 0x9F_u8 | @volume_code << 5
when 0x74 then 0xFF_u8
when 0x75 then 0xBF_u8 | (@length_enable ? 0x40 : 0)
when 0x70 then (@dac_enabled ? 0x80_u8 : 0_u8) | @wave_ram_bank << 6 | (@wave_ram_dimension ? 0x20 : 0)
when 0x73 then (@volume_force ? 0x80_u8 : 0_u8) | @volume_code << 5
when 0x75 then (@length_enable ? 0x40_u8 : 0_u8)
when WAVE_RAM_RANGE
if @enabled
@wave_ram[@wave_ram_bank][@wave_ram_position // 2]
else
@wave_ram[@wave_ram_bank][index - WAVE_RAM_RANGE.begin]
end
else puts "Reading from invalid Channel3 register: #{hex_str index.to_u16}".colorize.fore(:red); 0_u8 # todo: open bus
else 0_u8
end
end

View file

@ -45,11 +45,10 @@ module GBA
def [](index : Int) : UInt8
case index
when 0x78 then 0xFF_u8
when 0x79 then read_NRx2
when 0x7C then @clock_shift << 4 | @width_mode << 3 | @divisor_code
when 0x7D then 0xBF_u8 | (@length_enable ? 0x40 : 0)
else puts "Reading from invalid Channel4 register: #{hex_str index.to_u16}".colorize.fore(:red); 0_u8 # todo: open bus
when 0x7D then (@length_enable ? 0x40_u8 : 0_u8)
else 0_u8
end
end

View file

@ -20,7 +20,7 @@ module GBA
end
def [](index : Int) : UInt8
0_u8
@gba.bus.read_open_bus_value(index)
end
def []=(index : Int, value : Byte) : Nil

View file

@ -266,5 +266,19 @@ module GBA
write_byte_internal(index + 2, (value >> 16).to_u8!)
write_byte_internal(index + 3, (value >> 24).to_u8!)
end
def read_open_bus_value(index : Int, _file = __FILE__) : Byte
log "Reading open bus at #{hex_str index.to_u32} from #{_file}"
shift = (index & 3) * 8
if @gba.cpu.cpsr.thumb
# todo: special handling for 16-bit vs 32-bit regions
# todo: does this need to have both of the previous opcodes?
opcode = read_half_internal(@gba.cpu.r[15] & ~1).to_u32!
word = opcode << 16 | opcode
else
word = read_word_internal(@gba.cpu.r[15] & ~3)
end
(word >> shift).to_u8!
end
end
end

View file

@ -43,7 +43,7 @@ module GBA
end
getter r = Slice(Word).new 16
@cpsr : PSR = PSR.new CPU::Mode::SYS.value
getter cpsr : PSR = PSR.new CPU::Mode::SYS.value
@spsr : PSR = PSR.new CPU::Mode::SYS.value
getter pipeline = Pipeline.new
getter lut : Slice(Proc(Word, Nil)) { fill_lut }
@ -100,12 +100,12 @@ module GBA
def fill_pipeline : Nil
if @cpsr.thumb
pc = @r[15] & ~1
@pipeline.push @gba.bus.read_half(@r[15] &- 2).to_u32! if @pipeline.size == 0
@pipeline.push @gba.bus.read_half(@r[15]).to_u32! if @pipeline.size == 1
@pipeline.push @gba.bus.read_half(pc &- 2).to_u32! if @pipeline.size == 0
@pipeline.push @gba.bus.read_half(pc).to_u32! if @pipeline.size == 1
else
pc = @r[15] & ~3
@pipeline.push @gba.bus.read_word(@r[15] &- 4) if @pipeline.size == 0
@pipeline.push @gba.bus.read_word(@r[15]) if @pipeline.size == 1
@pipeline.push @gba.bus.read_word(pc &- 4) if @pipeline.size == 0
@pipeline.push @gba.bus.read_word(pc) if @pipeline.size == 1
end
end

View file

@ -46,17 +46,12 @@ module GBA
channel = (io_addr - 0xB0) // 12
reg = (io_addr - 0xB0) % 12
case reg
when 0, 1, 2, 3 # dmasad
0_u8 # todo: OOB read
when 4, 5, 6, 7 # dmadad
0_u8 # todo: OOB read
when 8, 9 # dmacnt_l
0_u8 # write-only
when 10, 11 # dmacnt_h
when 8, 9 then 0_u8 # dmacnt_l write-only
when 10, 11
val = @dmacnt_h[channel].read_byte(io_addr & 1)
val |= 0b1000 if io_addr == 0xDF && @dmacnt_h[3].game_pak # DMA3 only
val
else abort "Unmapped DMA read ~ addr:#{hex_str io_addr.to_u8}"
else @gba.bus.read_open_bus_value(io_addr)
end
end

View file

@ -7,29 +7,23 @@ module GBA
def [](index : Int) : Byte
io_addr = 0xFFFFFF_u32 & index
if io_addr <= 0x05F
@gba.ppu[io_addr]
elsif io_addr <= 0xAF
@gba.apu[io_addr]
elsif io_addr <= 0xFF
@gba.dma[io_addr]
elsif 0x100 <= io_addr <= 0x10F
@gba.timer[io_addr]
elsif 0x130 <= io_addr <= 0x133
@gba.keypad[io_addr]
elsif 0x120 <= io_addr <= 0x12F || 0x134 <= io_addr <= 0x1FF
case io_addr
when 0x000..0x055 then @gba.ppu[io_addr]
when 0x060..0x0A7 then @gba.apu[io_addr]
when 0x0B0..0x0DF then @gba.dma[io_addr]
when 0x100..0x10F then @gba.timer[io_addr]
when 0x120..0x12B, 0x134..0x159
# todo: serial
if io_addr == 0x135
0x80_u8
else
0_u8
end
elsif 0x200 <= io_addr <= 0x203 || 0x208 <= io_addr <= 0x209
@gba.interrupts[io_addr]
elsif 0x204 <= io_addr <= 0x205
@waitcnt.read_byte(io_addr & 1)
else
0_u8 # todo: oob reads
when 0x130..0x133 then @gba.keypad[io_addr]
when 0x200..0x203,
0x208..0x209 then @gba.interrupts[io_addr]
when 0x204..0x205 then @waitcnt.read_byte(io_addr & 1)
else @gba.bus.read_open_bus_value(io_addr)
end
end

View file

@ -402,34 +402,16 @@ module GBA
when 0x002..0x003 then 0_u8 # todo green swap
when 0x004..0x005 then @dispstat.read_byte(io_addr & 1)
when 0x006..0x007 then (@vcount >> (8 * (io_addr & 1))).to_u8!
when 0x008..0x00F then @bgcnt[(io_addr - 0x008) >> 1].read_byte(io_addr & 1)
when 0x010..0x01F
bg_num = (io_addr - 0x010) >> 2
if bit?(io_addr, 1)
@bgvofs[bg_num].read_byte(io_addr & 1)
else
@bghofs[bg_num].read_byte(io_addr & 1)
end
when 0x020..0x03F
bg_num = (io_addr & 0x10) >> 4 # (bg 0/1 represents bg 2/3, since those are the only aff bgs)
offs = io_addr & 0xF
if offs >= 8
offs -= 8
@bgref[bg_num][offs >> 2].read_byte(offs & 3)
else
@bgaff[bg_num][offs >> 1].read_byte(offs & 1)
end
when 0x040..0x041 then @win0h.read_byte(io_addr & 1)
when 0x042..0x043 then @win1h.read_byte(io_addr & 1)
when 0x044..0x045 then @win0v.read_byte(io_addr & 1)
when 0x046..0x047 then @win1v.read_byte(io_addr & 1)
when 0x008..0x00F
bg_num = (io_addr - 0x008) >> 1
val = @bgcnt[bg_num].read_byte(io_addr & 1)
val |= 0x20 if (io_addr == 0xD || io_addr == 0xF) && @bgcnt[bg_num].affine_wrap
val
when 0x048..0x049 then @winin.read_byte(io_addr & 1)
when 0x04A..0x04B then @winout.read_byte(io_addr & 1)
when 0x04C..0x04D then @mosaic.read_byte(io_addr & 1)
when 0x050..0x051 then @bldcnt.read_byte(io_addr & 1)
when 0x052..0x053 then @bldalpha.read_byte(io_addr & 1)
when 0x054..0x055 then @bldy.read_byte(io_addr & 1)
else log "Unmapped PPU read ~ addr:#{hex_str io_addr.to_u8}"; 0_u8 # todo: open bus
else @gba.bus.read_open_bus_value(io_addr)
end
end

View file

@ -169,11 +169,11 @@ module GBA
class BGCNT < BitField(UInt16)
include Base16
num screen_size, 2
bool affine_wrap
bool affine_wrap, write_only: true # used only in bg2 and bg3
num screen_base_block, 5
bool color_mode_8bpp
bool mosaic
num not_used, 2, read_only: true
num not_used, 2
num character_base_block, 2
num priority, 2
end