mirror of
https://github.com/mattrberry/crab.git
synced 2025-01-16 03:41:18 +01:00
passing dennis' eeprom tests
This commit is contained in:
parent
e5ec0eab9f
commit
4ce01591ee
4 changed files with 135 additions and 4 deletions
|
@ -14,6 +14,10 @@ macro set_bit(value, bit)
|
|||
({{value}} | 1 << {{bit}})
|
||||
end
|
||||
|
||||
macro set_bit(value, bit, set)
|
||||
(clear_bit({{value}}, {{bit}}) | {{set}} << {{bit}})
|
||||
end
|
||||
|
||||
macro clear_bit(value, bit)
|
||||
({{value}} & ~(1 << {{bit}}))
|
||||
end
|
||||
|
|
|
@ -23,7 +23,13 @@ module GBA
|
|||
when 0x7 then @gba.ppu.oam[index & 0x3FF]
|
||||
when 0x8, 0x9,
|
||||
0xA, 0xB,
|
||||
0xC, 0xD then @gba.cartridge.rom[index & 0x01FFFFFF]
|
||||
0xC then @gba.cartridge.rom[index & 0x01FFFFFF]
|
||||
when 0xD
|
||||
if @gba.storage.eeprom? index
|
||||
@gba.storage[index]
|
||||
else
|
||||
@gba.cartridge.rom[index & 0x01FFFFFF]
|
||||
end
|
||||
when 0xE, 0xF then @gba.storage[index]
|
||||
else abort "Unmapped read: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
@ -45,7 +51,13 @@ module GBA
|
|||
when 0x7 then (@gba.ppu.oam.to_unsafe + (index & 0x3FF)).as(HalfWord*).value
|
||||
when 0x8, 0x9,
|
||||
0xA, 0xB,
|
||||
0xC, 0xD then (@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(HalfWord*).value
|
||||
0xC then (@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(HalfWord*).value
|
||||
when 0xD
|
||||
if @gba.storage.eeprom? index
|
||||
@gba.storage[index].to_u16!
|
||||
else
|
||||
(@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(HalfWord*).value
|
||||
end
|
||||
when 0xE, 0xF then @gba.storage.read_half(index)
|
||||
else abort "Unmapped read: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
@ -84,7 +96,13 @@ module GBA
|
|||
when 0x7 then (@gba.ppu.oam.to_unsafe + (index & 0x3FF)).as(Word*).value
|
||||
when 0x8, 0x9,
|
||||
0xA, 0xB,
|
||||
0xC, 0xD then (@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(Word*).value
|
||||
0xC then (@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(Word*).value
|
||||
when 0xD
|
||||
if @gba.storage.eeprom? index
|
||||
@gba.storage[index].to_u32!
|
||||
else
|
||||
(@gba.cartridge.rom.to_unsafe + (index & 0x01FFFFFF)).as(Word*).value
|
||||
end
|
||||
when 0xE, 0xF then @gba.storage.read_word(index)
|
||||
else abort "Unmapped read: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
@ -107,6 +125,7 @@ module GBA
|
|||
when 0x6
|
||||
address = 0x1FFFE_u32 & index # todo ignored range is different when in bitmap mode
|
||||
(@gba.ppu.vram.to_unsafe + address).as(HalfWord*).value = 0x0101_u16 * value if address <= 0x0FFFF
|
||||
when 0xD then @gba.storage[index] = value if @gba.storage.eeprom? index
|
||||
when 0xE, 0xF then @gba.storage[index] = value
|
||||
else log "Unmapped write: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
@ -126,6 +145,7 @@ module GBA
|
|||
address -= 0x8000 if address > 0x17FFF
|
||||
(@gba.ppu.vram.to_unsafe + address).as(HalfWord*).value = value
|
||||
when 0x7 then (@gba.ppu.oam.to_unsafe + (index & 0x3FF)).as(HalfWord*).value = value
|
||||
when 0xD then @gba.storage[index] = value.to_u8! if @gba.storage.eeprom? index
|
||||
when 0xE, 0xF then write_half_slow(index, value)
|
||||
else log "Unmapped write: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
@ -145,6 +165,7 @@ module GBA
|
|||
address -= 0x8000 if address > 0x17FFF
|
||||
(@gba.ppu.vram.to_unsafe + address).as(Word*).value = value
|
||||
when 0x7 then (@gba.ppu.oam.to_unsafe + (index & 0x3FF)).as(Word*).value = value
|
||||
when 0xD then @gba.storage[index] = value.to_u8! if @gba.storage.eeprom? index
|
||||
when 0xE, 0xF then write_word_slow(index, value)
|
||||
else log "Unmapped write: #{hex_str index.to_u32}"
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@ module GBA
|
|||
puts "Backup type could not be identified.".colorize.fore(:red) unless type
|
||||
puts "Backup type: #{type}, save path: #{save_path}"
|
||||
storage = case type
|
||||
in Type::EEPROM then abort "todo: Support EEPROM"
|
||||
in Type::EEPROM then EEPROM.new
|
||||
in Type::SRAM, nil then SRAM.new
|
||||
in Type::FLASH, Type::FLASH512, Type::FLASH1M then Flash.new type
|
||||
end
|
||||
|
@ -60,6 +60,10 @@ module GBA
|
|||
|
||||
abstract def []=(index : Int, value : Byte) : Nil
|
||||
|
||||
def eeprom?(index : Int) : Bool
|
||||
self.class == EEPROM && (0x0D000000..0x0DFFFFFF).includes? index
|
||||
end
|
||||
|
||||
private def self.find_type(file : File) : Type?
|
||||
str = file.gets_to_end
|
||||
Type.each { |type| return type if type.regex.matches?(str) }
|
||||
|
|
102
src/crab/gba/storage/eeprom.cr
Normal file
102
src/crab/gba/storage/eeprom.cr
Normal file
|
@ -0,0 +1,102 @@
|
|||
module GBA
|
||||
class EEPROM < Storage
|
||||
@[Flags]
|
||||
enum State
|
||||
READY
|
||||
READ
|
||||
READ_IGNORE
|
||||
WRITE
|
||||
ADDRESS
|
||||
WRITE_FINAL_BIT
|
||||
|
||||
LOCK_ADDRESS
|
||||
|
||||
CMD_1
|
||||
CMD_2
|
||||
IDENTIFICATION
|
||||
PREPARE_WRITE
|
||||
PREPARE_ERASE
|
||||
SET_BANK
|
||||
end
|
||||
|
||||
@memory = Bytes.new(0x2000, 0xFF)
|
||||
@state = State::READY
|
||||
@buffer = Buffer.new
|
||||
@address : UInt32 = 0
|
||||
@ignored_reads = 0
|
||||
|
||||
def [](index : Int) : Byte
|
||||
case @state
|
||||
when .includes? State::READ_IGNORE
|
||||
if (@ignored_reads += 1) == 4
|
||||
@state ^= State::READ_IGNORE
|
||||
@buffer.value = @memory.to_unsafe.as(UInt64*)[@address]
|
||||
@buffer.size = 64
|
||||
end
|
||||
when State::READ
|
||||
value = @buffer.pop.to_u8
|
||||
if @buffer.size == 0
|
||||
@state = State::READY
|
||||
@buffer.clear
|
||||
end
|
||||
return value
|
||||
end
|
||||
1_u8
|
||||
end
|
||||
|
||||
def []=(index : Int, value : Byte) : Nil
|
||||
return if @state == State::READ || @state == State::READ_IGNORE
|
||||
value &= 1
|
||||
@buffer.push value
|
||||
case @state
|
||||
when State::READY
|
||||
if @buffer.size == 2
|
||||
case @buffer.value
|
||||
when 0b10 then @state = State::ADDRESS | State::WRITE | State::WRITE_FINAL_BIT
|
||||
when 0b11 then @state = State::ADDRESS | State::READ | State::READ_IGNORE | State::WRITE_FINAL_BIT; @ignored_reads = 0
|
||||
end
|
||||
@address = 0
|
||||
@buffer.clear
|
||||
end
|
||||
when .includes? State::ADDRESS
|
||||
if @buffer.size == 14 # todo: support 4Kbit eeprom
|
||||
@address = @buffer.value.to_u32
|
||||
@memory.to_unsafe.as(UInt64*)[@address] = 0 if @state.includes? State::WRITE
|
||||
@state ^= State::ADDRESS
|
||||
@buffer.clear
|
||||
end
|
||||
when .includes? State::WRITE
|
||||
index = (@buffer.size - 1) // 8
|
||||
if @buffer.size == 64
|
||||
@memory.to_unsafe.as(UInt64*)[@address] = @buffer.value
|
||||
@buffer.clear
|
||||
@state = State::READY | State::WRITE_FINAL_BIT
|
||||
end
|
||||
when .includes? State::WRITE_FINAL_BIT
|
||||
@buffer.clear
|
||||
@state ^= State::WRITE_FINAL_BIT
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private class Buffer
|
||||
property size = 0
|
||||
property value : UInt64 = 0
|
||||
|
||||
def push(value : Int) : UInt64
|
||||
@size += 1
|
||||
@value = (@value << 1) | (value & 1)
|
||||
end
|
||||
|
||||
def pop : UInt64
|
||||
abort "Invalid buffer size #{@size}" if @size <= 0
|
||||
@size -= 1
|
||||
@value >> @size & 1
|
||||
end
|
||||
|
||||
def clear : Nil
|
||||
@size = 0
|
||||
@value = 0
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue