From e29bde0bcf4540b4f66a54e824cd1b5414b5fda4 Mon Sep 17 00:00:00 2001 From: Matthew Berry Date: Wed, 7 Oct 2020 08:19:14 -0700 Subject: [PATCH] arm fix single data transfer imm offset, add mmio/interrupt writes this hits the fps by ~15 for some reason on tonc's m3_demo... --- src/crab/arm/single_data_transfer.cr | 18 ++++++------- src/crab/bus.cr | 16 ++---------- src/crab/gba.cr | 4 +++ src/crab/interrupts.cr | 29 +++++++++++++++++++++ src/crab/mmio.cr | 38 ++++++++++++++++++++++++++++ src/crab/ppu.cr | 28 ++++++++++---------- 6 files changed, 95 insertions(+), 38 deletions(-) create mode 100644 src/crab/interrupts.cr create mode 100644 src/crab/mmio.cr diff --git a/src/crab/arm/single_data_transfer.cr b/src/crab/arm/single_data_transfer.cr index 5b787ad..23aa9e0 100644 --- a/src/crab/arm/single_data_transfer.cr +++ b/src/crab/arm/single_data_transfer.cr @@ -9,19 +9,19 @@ module ARM load = bit?(instr, 20) rn = bits(instr, 16..19) rd = bits(instr, 12..15) - operand_2 = if imm_flag # Operand 2 is a register (opposite of data procesing for some reason) - rotate_register bits(instr, 0..11), set_conditions: false, allow_register_shifts: false - else # Operand 2 is an immediate offset - immediate_offset bits(instr, 0..11) - end + offset = if imm_flag # Operand 2 is a register (opposite of data processing for some reason) + rotate_register bits(instr, 0..11), set_conditions: false, allow_register_shifts: false + else # Operand 2 is an immediate offset + bits(instr, 0..11) + end address = @r[rn] if pre_indexing if add_offset - address &+= operand_2 + address &+= offset else - address &-= operand_2 + address &-= offset end end @@ -33,9 +33,9 @@ module ARM if !pre_indexing if add_offset - @r[rn] &+= operand_2 + @r[rn] &+= offset else - @r[rn] &-= operand_2 + @r[rn] &-= offset end elsif write_back @r[rn] = address diff --git a/src/crab/bus.cr b/src/crab/bus.cr index 3edcfa4..ef71194 100644 --- a/src/crab/bus.cr +++ b/src/crab/bus.cr @@ -10,13 +10,7 @@ class Bus case bits(index, 24..27) when 0x2 then @wram_board[index & 0x3FFFF] when 0x3 then @wram_chip[index & 0x7FFF] - when 0x4 - io_addr = 0x0FFF_u16 & index - if io_addr <= 0x05F - @gba.ppu[index] - else - raise "Unmapped i/o read: #{hex_str index.to_u32}" - end + when 0x4 then @gba.mmio[index] when 0x5 then @gba.ppu.pram[index] when 0x6 address = 0x1FFFF_u32 & index @@ -45,13 +39,7 @@ class Bus case bits(index, 24..27) when 0x2 then @wram_board[index & 0x3FFFF] = value when 0x3 then @wram_chip[index & 0x7FFF] = value - when 0x4 - io_addr = 0x0FFF_u16 & index - if io_addr <= 0x05F - @gba.ppu[index] = value - else - raise "Unmapped i/o write: #{hex_str index.to_u32}" - end + when 0x4 then @gba.mmio[index] = value when 0x5 then @gba.ppu.pram[index & 0x3FF] = value when 0x6 address = 0x1FFFF_u32 & index diff --git a/src/crab/gba.cr b/src/crab/gba.cr index c2a9b77..c0e7faf 100644 --- a/src/crab/gba.cr +++ b/src/crab/gba.cr @@ -1,14 +1,18 @@ require "./types" require "./util" require "./cartridge" +require "./mmio" require "./bus" +require "./interrupts" require "./cpu" require "./display" require "./ppu" class GBA getter cartridge : Cartridge + getter mmio : MMIO { MMIO.new self } getter bus : Bus { Bus.new self } + getter interrupts : Interrupts { Interrupts.new } getter cpu : CPU { CPU.new self } getter display : Display { Display.new } getter ppu : PPU { PPU.new self } diff --git a/src/crab/interrupts.cr b/src/crab/interrupts.cr new file mode 100644 index 0000000..1c0645a --- /dev/null +++ b/src/crab/interrupts.cr @@ -0,0 +1,29 @@ +class Interrupts + getter reg_ie : UInt16 = 0 + getter reg_if : UInt16 = 0 + getter reg_ime : Bool = false + + def read_io(io_addr : Int) : Byte + case io_addr + when 0x200 then (@reg_ie >> 8).to_u8 + when 0x201 then @reg_ie.to_u8! + when 0x202 then (@reg_if >> 8).to_u8 + when 0x203 then @reg_if.to_u8! + when 0x208 then @reg_ime ? 1_u8 : 0_u8 + when 0x209 then @reg_ime ? 1_u8 : 0_u8 + else raise "Unimplemented interrupts read ~ addr:#{hex_str io_addr.to_u8}" + end + end + + def write_io(io_addr : Int, value : Byte) : Nil + case io_addr + when 0x200 then @reg_ie = (@reg_ie & 0x00FF) | value.to_u16 << 8 + when 0x201 then @reg_ie = (@reg_ie & 0xFF00) | value + when 0x202 then @reg_ie = (@reg_if & 0x00FF) | value.to_u16 << 8 + when 0x203 then @reg_ie = (@reg_if & 0xFF00) | value + when 0x208 then @reg_ime = bit?(value, 0) + when 0x209 then @reg_ime = bit?(value, 0) + else raise "Unimplemented interrupts write ~ addr:#{hex_str io_addr.to_u8!}, val:#{value}" + end + end +end diff --git a/src/crab/mmio.cr b/src/crab/mmio.cr new file mode 100644 index 0000000..267d2db --- /dev/null +++ b/src/crab/mmio.cr @@ -0,0 +1,38 @@ +class MMIO + def initialize(@gba : GBA) + end + + def [](index : Int) : Byte + io_addr = 0x0FFF_u16 & index + if io_addr <= 0x05F + @gba.ppu.read_io io_addr + elsif (io_addr >= 0x200 & io_addr <= 0x203) || (io_addr >= 0x208 && io_addr <= 0x209) + @gba.interrupts.read_io io_addr + elsif not_used? io_addr + 0xFF_u8 # todo what is returned here? + else + raise "Unmapped MMIO read: #{hex_str index.to_u32}" + end + end + + def []=(index : Int, value : Byte) : Nil + io_addr = 0x0FFF_u16 & index + if io_addr <= 0x05F + @gba.ppu.write_io io_addr, value + elsif (io_addr >= 0x200 && io_addr <= 0x203) || (io_addr >= 0x208 && io_addr <= 0x209) + @gba.interrupts.write_io io_addr, value + elsif not_used? io_addr + else + raise "Unmapped MMIO write: #{hex_str index.to_u32}" + end + end + + def not_used?(io_addr : Int) : Bool + (0x0E0..0x0FE).includes?(io_addr) || (0x110..0x11E).includes?(io_addr) || + (0x12C..0x12E).includes?(io_addr) || (0x138..0x13E).includes?(io_addr) || + (0x142..0x14E).includes?(io_addr) || (0x15A..0x1FE).includes?(io_addr) || + 0x206 == io_addr || (0x20A..0x2FF).includes?(io_addr) || + (0x302..0x40F).includes?(io_addr) || (0x441..0x7FF).includes?(io_addr) || + (0x804..0xFFFF).includes?(io_addr) + end +end diff --git a/src/crab/ppu.cr b/src/crab/ppu.cr index aae63ad..af580cb 100644 --- a/src/crab/ppu.cr +++ b/src/crab/ppu.cr @@ -28,7 +28,7 @@ class PPU getter pram = Bytes.new 0x400 getter vram = Bytes.new 0x18000 - @dispcnt : DISPCNT = DISPCNT.new 0 + getter dispcnt : DISPCNT = DISPCNT.new 0 @cycles = 0 @@ -43,23 +43,21 @@ class PPU end end - def [](index : Int) : Byte - case index - when 0x04000000 then (@dispcnt.value >> 8).to_u8 - when 0x04000001 then @dispcnt.value.to_u8! - when 0x04000002 then 0_u8 - when 0x04000003 then 0_u8 - else raise "Unimplemented PPU read ~ addr:#{hex_str index.to_u32}" + def read_io(io_addr : Int) : Byte + case io_addr + when 0x000 then (@dispcnt.value >> 8).to_u8 + when 0x001 then @dispcnt.value.to_u8! + else raise "Unimplemented PPU read ~ addr:#{hex_str io_addr.to_u8}" end end - def []=(index : Int, value : Byte) : Nil - case index - when 0x04000000 then @dispcnt.value = (@dispcnt.value & 0x00FF) | value.to_u16 << 8 - when 0x04000001 then @dispcnt.value = (@dispcnt.value & 0xFF00) | value - when 0x04000002 - when 0x04000003 - else raise "Unimplemented PPU write ~ addr:#{hex_str index.to_u32}, val:#{value}" + def write_io(io_addr : Int, value : Byte) : Nil + case io_addr + when 0x000 then @dispcnt.value = (@dispcnt.value & 0x00FF) | value.to_u16 << 8 + when 0x001 then @dispcnt.value = (@dispcnt.value & 0xFF00) | value + when 0x002 # undocumented - green swap + when 0x003 # undocumented - green swap + else raise "Unimplemented PPU write ~ addr:#{hex_str io_addr.to_u8}, val:#{value}" end end end