diff --git a/src/crab/gba/apu.cr b/src/crab/gba/apu.cr index 1c711d3..57e4e2d 100644 --- a/src/crab/gba/apu.cr +++ b/src/crab/gba/apu.cr @@ -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 diff --git a/src/crab/gba/apu/channel1.cr b/src/crab/gba/apu/channel1.cr index d8097c5..d731d8a 100644 --- a/src/crab/gba/apu/channel1.cr +++ b/src/crab/gba/apu/channel1.cr @@ -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 diff --git a/src/crab/gba/apu/channel2.cr b/src/crab/gba/apu/channel2.cr index 8ca9fa4..508512a 100644 --- a/src/crab/gba/apu/channel2.cr +++ b/src/crab/gba/apu/channel2.cr @@ -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 diff --git a/src/crab/gba/apu/channel3.cr b/src/crab/gba/apu/channel3.cr index 379cc7a..3ce88e9 100644 --- a/src/crab/gba/apu/channel3.cr +++ b/src/crab/gba/apu/channel3.cr @@ -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 diff --git a/src/crab/gba/apu/channel4.cr b/src/crab/gba/apu/channel4.cr index 89ebe07..fde63f5 100644 --- a/src/crab/gba/apu/channel4.cr +++ b/src/crab/gba/apu/channel4.cr @@ -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 diff --git a/src/crab/gba/apu/dma_channels.cr b/src/crab/gba/apu/dma_channels.cr index 46434aa..ff444bf 100644 --- a/src/crab/gba/apu/dma_channels.cr +++ b/src/crab/gba/apu/dma_channels.cr @@ -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 diff --git a/src/crab/gba/bus.cr b/src/crab/gba/bus.cr index 6cfbdeb..5f8fba5 100644 --- a/src/crab/gba/bus.cr +++ b/src/crab/gba/bus.cr @@ -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 diff --git a/src/crab/gba/cpu.cr b/src/crab/gba/cpu.cr index d24ffeb..d53ea10 100644 --- a/src/crab/gba/cpu.cr +++ b/src/crab/gba/cpu.cr @@ -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 diff --git a/src/crab/gba/dma.cr b/src/crab/gba/dma.cr index 62d0332..dfe81b7 100644 --- a/src/crab/gba/dma.cr +++ b/src/crab/gba/dma.cr @@ -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 diff --git a/src/crab/gba/mmio.cr b/src/crab/gba/mmio.cr index 22490c0..bca5b15 100644 --- a/src/crab/gba/mmio.cr +++ b/src/crab/gba/mmio.cr @@ -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 diff --git a/src/crab/gba/ppu.cr b/src/crab/gba/ppu.cr index 1c8d4da..565d4fd 100644 --- a/src/crab/gba/ppu.cr +++ b/src/crab/gba/ppu.cr @@ -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 diff --git a/src/crab/gba/reg.cr b/src/crab/gba/reg.cr index 390ddb1..ee3cd8f 100644 --- a/src/crab/gba/reg.cr +++ b/src/crab/gba/reg.cr @@ -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