diff --git a/src/crab/bus.cr b/src/crab/bus.cr index 58817a4..47c5ea2 100644 --- a/src/crab/bus.cr +++ b/src/crab/bus.cr @@ -8,8 +8,6 @@ class Bus end def [](index : Int) : Byte - return 0x62_u8 if index == 0x0E000000 - return 0x13_u8 if index == 0x0E000001 log "read #{hex_str index.to_u32}" case bits(index, 24..27) when 0x0 then @bios[index & 0x3FFF] @@ -25,7 +23,7 @@ class Bus when 0x8, 0x9, 0xA, 0xB, 0xC, 0xD then @gba.cartridge[index & 0x01FFFFFF] - when 0xE then @gba.cartridge.sram[index & 0xFFFF] + when 0xE then @gba.flash[index & 0xFFFF] else abort "Unmapped read: #{hex_str index.to_u32}" end end @@ -80,7 +78,7 @@ class Bus @gba.ppu.vram[address] = value when 0x7 then @gba.ppu.oam[index & 0x3FF] = value when 0x8, 0x9 then log "Writing to cart - #{hex_str index.to_u32}: #{hex_str value}" - when 0xE then @gba.cartridge.sram[index & 0xFFFF] = value + when 0xE then @gba.flash[index & 0xFFFF] = value else abort "Unmapped write: #{hex_str index.to_u32}" end end diff --git a/src/crab/cartridge.cr b/src/crab/cartridge.cr index c87299e..57b0ba0 100644 --- a/src/crab/cartridge.cr +++ b/src/crab/cartridge.cr @@ -1,6 +1,5 @@ class Cartridge getter rom : Bytes - getter sram = Bytes.new 0x10000 getter title : String { io = IO::Memory.new diff --git a/src/crab/flash.cr b/src/crab/flash.cr new file mode 100644 index 0000000..3c775c8 --- /dev/null +++ b/src/crab/flash.cr @@ -0,0 +1,89 @@ +class Flash + enum Type + EEPROM + SRAM + FLASH + FLASH512 + FLASH1M + + def regex : Regex + /#{self}_V\d{3}/ + end + end + + enum State + READY + CMD_1 + CMD_2 + end + + enum Command : Byte + ENTER_IDENT = 0x90 + EXIT_IDENT = 0xF0 + PREPARE_ERASE = 0x80 + ERASE_ALL = 0x10 + ERASE_CHUNK = 0x30 + PREPARE_WRITE = 0xA0 + SET_BANK = 0xB0 + end + + SANYO = 0x1362_u16 + + getter! type : Type + @save_path : String + @sram = Bytes.new 0x10000, 0xFF + @state = State::READY + @identification_mode = false + + def initialize(rom_path : String) + File.open(rom_path, "rb") do |file| + str = file.gets_to_end + Type.each do |type| + if type.regex.matches?(str) + @type = type + break + end + end + end + unless @type + puts "Falling back to SRAM since backup type could not be identified.".colorize.fore(:red) + @type = Type::SRAM + end + puts "Backup type: #{@type}" + @save_path = rom_path.gsub(/\.gba$/, ".sav") + @save_path += ".sav" unless @save_path.ends_with?(".sav") + puts "Save path: #{@save_path}" + end + + def [](index : Int) : Byte + puts "#{hex_str index.to_u16}" + if @identification_mode && 0 <= index <= 1 + (SANYO >> (8 * index) & 0xFF).to_u8! + else + @sram[index] + end + end + + def []=(index : Int, value : Byte) : Nil + puts "#{hex_str index.to_u16} -> #{hex_str value} #{@state}" + case @state + in State::READY + @state = State::CMD_1 if value == 0xAA + in State::CMD_1 + @state = State::CMD_2 if value == 0x55 + in State::CMD_2 + case value + when Command::ENTER_IDENT.value then @identification_mode = true + when Command::EXIT_IDENT.value then @identification_mode = false + when Command::PREPARE_ERASE.value + when Command::ERASE_ALL.value + when Command::ERASE_CHUNK.value + when Command::PREPARE_WRITE.value + when Command::SET_BANK.value + else puts "Unsupported command #{hex_str value}" + end + end + puts " #{@state}" + @sram[index] = value + end +end diff --git a/src/crab/gba.cr b/src/crab/gba.cr index ce20078..5258aa1 100644 --- a/src/crab/gba.cr +++ b/src/crab/gba.cr @@ -3,6 +3,7 @@ require "./reg" require "./util" require "./scheduler" require "./cartridge" +require "./flash" require "./mmio" require "./timer" require "./keypad" @@ -18,6 +19,7 @@ require "./debugger" class GBA getter! scheduler : Scheduler getter! cartridge : Cartridge + getter! flash : Flash getter! mmio : MMIO getter! timer : Timer getter! keypad : Keypad @@ -33,6 +35,7 @@ class GBA def initialize(@bios_path : String, rom_path : String) @scheduler = Scheduler.new @cartridge = Cartridge.new rom_path + @flash = Flash.new rom_path handle_events SDL.init(SDL::Init::VIDEO | SDL::Init::AUDIO | SDL::Init::JOYSTICK)