parent
02416a9786
commit
f07a6d2714
@ -47,6 +47,7 @@ pub struct Device {
|
||||
ai: ai::Ai,
|
||||
si: si::Si,
|
||||
ri: ri::Ri,
|
||||
flashram: sram::Flashram,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
@ -270,6 +271,13 @@ impl Device {
|
||||
count_per_scanline: 0,
|
||||
limiter: None,
|
||||
},
|
||||
flashram: sram::Flashram {
|
||||
status: 0,
|
||||
erase_page: 0,
|
||||
page_buf: [0xff; 128],
|
||||
silicon_id: [sram::FLASHRAM_TYPE_ID, sram::MX29L1100_ID],
|
||||
mode: sram::FlashramMode::ReadArray,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,29 @@ use crate::ui;
|
||||
|
||||
pub const SRAM_MASK: usize = 0xFFFF;
|
||||
pub const SRAM_SIZE: usize = 0x8000;
|
||||
//pub const FLASHRAM_SIZE: usize = 0x20000;
|
||||
pub const FLASHRAM_SIZE: usize = 0x20000;
|
||||
pub const FLASHRAM_TYPE_ID: u32 = 0x11118001;
|
||||
pub const MX29L1100_ID: u32 = 0x00c2001e;
|
||||
pub const MX29L0000_ID: u32 = 0x00c20000;
|
||||
pub const MX29L0001_ID: u32 = 0x00c20001;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum FlashramMode {
|
||||
ReadArray,
|
||||
ReadSiliconId,
|
||||
Status,
|
||||
SectorErase,
|
||||
ChipErase,
|
||||
PageProgram,
|
||||
}
|
||||
|
||||
pub struct Flashram {
|
||||
pub status: u32,
|
||||
pub mode: FlashramMode,
|
||||
pub erase_page: u16,
|
||||
pub page_buf: [u8; 128],
|
||||
pub silicon_id: [u32; 2],
|
||||
}
|
||||
|
||||
pub fn format_sram(device: &mut device::Device) {
|
||||
if device.ui.saves.sram.len() < SRAM_SIZE {
|
||||
@ -11,6 +33,12 @@ pub fn format_sram(device: &mut device::Device) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_flash(device: &mut device::Device) {
|
||||
if device.ui.saves.flash.len() < FLASHRAM_SIZE {
|
||||
device.ui.saves.flash.resize(FLASHRAM_SIZE, 0xFF)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_mem_sram(device: &mut device::Device, address: u64) -> u32 {
|
||||
let masked_address = address as usize & SRAM_MASK;
|
||||
|
||||
@ -23,6 +51,20 @@ pub fn read_mem_sram(device: &mut device::Device, address: u64) -> u32 {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn read_mem_flash(device: &mut device::Device, address: u64) -> u32 {
|
||||
if (address & 0x1ffff) == 0x00000 && device.flashram.mode == FlashramMode::Status {
|
||||
/* read Status register */
|
||||
return device.flashram.status;
|
||||
} else if (address & 0x1ffff) == 0x0000 && device.flashram.mode == FlashramMode::ReadArray {
|
||||
/* flashram MMIO read are not supported except for the "dummy" read @0x0000 done before DMA.
|
||||
* returns a "dummy" value. */
|
||||
return 0;
|
||||
} else {
|
||||
/* other accesses are not implemented */
|
||||
panic!("unknown flashram read")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_mem(
|
||||
device: &mut device::Device,
|
||||
address: u64,
|
||||
@ -34,7 +76,7 @@ pub fn read_mem(
|
||||
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
|
||||
return read_mem_sram(device, address);
|
||||
} else {
|
||||
panic!("flash read")
|
||||
return read_mem_flash(device, address);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,11 +96,25 @@ pub fn write_mem_sram(device: &mut device::Device, address: u64, value: u32, mas
|
||||
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Sram);
|
||||
}
|
||||
|
||||
pub fn write_mem_flash(device: &mut device::Device, address: u64, value: u32, mask: u32) {
|
||||
if (address & 0x1ffff) == 0x00000 && device.flashram.mode == FlashramMode::Status {
|
||||
/* clear/set Status register */
|
||||
device.flashram.status = (value & mask) & 0xff;
|
||||
} else if (address & 0x1ffff) == 0x10000 {
|
||||
/* set command */
|
||||
format_flash(device);
|
||||
flashram_command(device, value & mask);
|
||||
} else {
|
||||
/* other accesses are not implemented */
|
||||
panic!("unknown flashram write")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) {
|
||||
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
|
||||
write_mem_sram(device, address, value, mask)
|
||||
} else {
|
||||
panic!("flash write")
|
||||
write_mem_flash(device, address, value, mask)
|
||||
}
|
||||
|
||||
device.pi.regs[device::pi::PI_STATUS_REG as usize] |= device::pi::PI_STATUS_IO_BUSY;
|
||||
@ -94,12 +150,30 @@ pub fn dma_read_sram(
|
||||
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Sram);
|
||||
}
|
||||
|
||||
pub fn dma_read_flash(device: &mut device::Device, cart_addr: u32, dram_addr: u32, length: u32) {
|
||||
format_flash(device);
|
||||
|
||||
if (cart_addr & 0x1ffff) == 0x00000
|
||||
&& length == 128
|
||||
&& device.flashram.mode == FlashramMode::PageProgram
|
||||
{
|
||||
/* load page buf using DMA */
|
||||
for i in 0..length {
|
||||
device.flashram.page_buf[i as usize] =
|
||||
device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap];
|
||||
}
|
||||
} else {
|
||||
/* other accesses are not implemented */
|
||||
panic!("unknown flash dma read")
|
||||
}
|
||||
}
|
||||
|
||||
// cart is big endian, rdram is native endian
|
||||
pub fn dma_read(device: &mut device::Device, cart_addr: u32, dram_addr: u32, length: u32) -> u64 {
|
||||
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
|
||||
dma_read_sram(device, cart_addr, dram_addr, length)
|
||||
} else {
|
||||
panic!("flash dma read")
|
||||
dma_read_flash(device, cart_addr, dram_addr, length)
|
||||
}
|
||||
return device::pi::calculate_cycles(device, 2, length);
|
||||
}
|
||||
@ -124,12 +198,138 @@ pub fn dma_write_sram(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dma_write_flash(
|
||||
device: &mut device::Device,
|
||||
mut cart_addr: u32,
|
||||
mut dram_addr: u32,
|
||||
length: u32,
|
||||
) {
|
||||
dram_addr &= device::rdram::RDRAM_MASK as u32;
|
||||
|
||||
if (cart_addr & 0x1ffff) == 0x00000
|
||||
&& length == 8
|
||||
&& device.flashram.mode == FlashramMode::ReadSiliconId
|
||||
{
|
||||
/* read Silicon ID using DMA */
|
||||
device.rdram.mem[dram_addr as usize..dram_addr as usize + 4]
|
||||
.copy_from_slice(&device.flashram.silicon_id[0].to_ne_bytes());
|
||||
dram_addr += 4;
|
||||
device.rdram.mem[dram_addr as usize..dram_addr as usize + 4]
|
||||
.copy_from_slice(&device.flashram.silicon_id[1].to_ne_bytes());
|
||||
} else if (cart_addr & 0x1ffff) < 0x10000 && device.flashram.mode == FlashramMode::ReadArray {
|
||||
format_flash(device);
|
||||
/* adjust flashram address before starting DMA. */
|
||||
if device.flashram.silicon_id[1] == MX29L1100_ID
|
||||
|| device.flashram.silicon_id[1] == MX29L0000_ID
|
||||
|| device.flashram.silicon_id[1] == MX29L0001_ID
|
||||
{
|
||||
/* "old" flash needs special address adjusting */
|
||||
cart_addr = (cart_addr & 0xffff) * 2;
|
||||
} else {
|
||||
/* "new" flash doesn't require special address adjusting at DMA start. */
|
||||
cart_addr &= 0xffff;
|
||||
}
|
||||
|
||||
/* do actual DMA */
|
||||
for i in 0..length {
|
||||
device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap] =
|
||||
device.ui.saves.flash[(cart_addr + i) as usize];
|
||||
}
|
||||
} else {
|
||||
/* other accesses are not implemented */
|
||||
panic!("unknown flash dma write")
|
||||
}
|
||||
}
|
||||
|
||||
// cart is big endian, rdram is native endian
|
||||
pub fn dma_write(device: &mut device::Device, cart_addr: u32, dram_addr: u32, length: u32) -> u64 {
|
||||
if device.ui.save_type.contains(&ui::storage::SaveTypes::Sram) {
|
||||
dma_write_sram(device, cart_addr, dram_addr, length)
|
||||
} else {
|
||||
panic!("flash dma write")
|
||||
dma_write_flash(device, cart_addr, dram_addr, length)
|
||||
}
|
||||
return device::pi::calculate_cycles(device, 2, length);
|
||||
}
|
||||
|
||||
pub fn flashram_command(device: &mut device::Device, command: u32) {
|
||||
match command & 0xff000000 {
|
||||
0x3c000000 => {
|
||||
/* set chip erase mode */
|
||||
device.flashram.mode = FlashramMode::ChipErase;
|
||||
}
|
||||
|
||||
0x4b000000 => {
|
||||
/* set sector erase mode, set erase sector */
|
||||
device.flashram.mode = FlashramMode::SectorErase;
|
||||
device.flashram.erase_page = command as u16;
|
||||
}
|
||||
|
||||
0x78000000 => {
|
||||
/* set erase busy flag */
|
||||
device.flashram.status |= 0x02;
|
||||
|
||||
/* do chip/sector erase */
|
||||
if device.flashram.mode == FlashramMode::SectorErase {
|
||||
let offset = (device.flashram.erase_page & 0xff80) * 128;
|
||||
for i in 0..128 * 128 {
|
||||
device.ui.saves.flash[offset as usize + i] = 0xFF;
|
||||
}
|
||||
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Flash);
|
||||
} else if device.flashram.mode == FlashramMode::ChipErase {
|
||||
for i in 0..FLASHRAM_SIZE {
|
||||
device.ui.saves.flash[i] = 0xFF;
|
||||
}
|
||||
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Flash);
|
||||
} else {
|
||||
panic!("Unexpected flash erase command")
|
||||
}
|
||||
|
||||
/* clear erase busy flag, set erase success flag, transition to status mode */
|
||||
device.flashram.status &= !0x02;
|
||||
device.flashram.status |= 0x08;
|
||||
device.flashram.mode = FlashramMode::Status;
|
||||
}
|
||||
|
||||
0xa5000000 => {
|
||||
/* set program busy flag */
|
||||
device.flashram.status |= 0x01;
|
||||
|
||||
/* program selected page */
|
||||
let offset = (command as u16) * 128;
|
||||
for i in 0..128 {
|
||||
device.ui.saves.flash[(offset + i) as usize] = device.flashram.page_buf[i as usize];
|
||||
}
|
||||
ui::storage::write_save(&mut device.ui, ui::storage::SaveTypes::Flash);
|
||||
|
||||
/* clear program busy flag, set program success flag, transition to status mode */
|
||||
device.flashram.status &= !0x01;
|
||||
device.flashram.status |= 0x04;
|
||||
device.flashram.mode = FlashramMode::Status;
|
||||
}
|
||||
|
||||
0xb4000000 => {
|
||||
/* set page program mode */
|
||||
device.flashram.mode = FlashramMode::PageProgram;
|
||||
}
|
||||
|
||||
0xd2000000 => {
|
||||
/* set status mode */
|
||||
device.flashram.mode = FlashramMode::Status;
|
||||
}
|
||||
|
||||
0xe1000000 => {
|
||||
/* set silicon_id mode */
|
||||
device.flashram.mode = FlashramMode::ReadSiliconId;
|
||||
device.flashram.status |= 0x01; /* Needed for Pokemon Puzzle League */
|
||||
}
|
||||
|
||||
0xf0000000 => {
|
||||
/* set read mode */
|
||||
device.flashram.mode = FlashramMode::ReadArray;
|
||||
}
|
||||
|
||||
_ => {
|
||||
panic!("unknown flash command")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user