mirror of
https://github.com/gopher64/gopher64.git
synced 2026-11-12 09:09:01 +01:00
UNFLoader improvements (#1372)
This commit is contained in:
1 parent
19b03c96a7
commit
55fa0836ab
3 files changed
+62
-74
No files matched your search
@@ -427,6 +427,9 @@ impl Device {
|
||||
buffer: vec![0; 8192],
|
||||
writeback_sector: vec![0; 256],
|
||||
usb_buffer: vec![],
|
||||
usb_read_type: 0,
|
||||
usb_read_size: 0,
|
||||
usb_next_read: 0,
|
||||
},
|
||||
flashram: cart::sram::Flashram {
|
||||
mode: cart::sram::FlashramMode::ReadArray,
|
||||
|
||||
+32
-21
@@ -19,6 +19,7 @@ pub const SC64_CFG_COUNT: usize = 15;
|
||||
|
||||
const SC64_BUFFER_MASK: usize = 0x1FFF;
|
||||
const SC64_EEPROM_MASK: usize = 0xFFF;
|
||||
const USB_PACKET_DELAY: u64 = 93750 * 2; // ~2ms of COUNT (CPU cycles at 93.75 MHz)
|
||||
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Sc64 {
|
||||
@@ -29,6 +30,9 @@ pub struct Sc64 {
|
||||
pub sector: u32,
|
||||
pub writeback_sector: Vec<u32>,
|
||||
pub usb_buffer: Vec<u8>,
|
||||
pub usb_read_type: u32,
|
||||
pub usb_read_size: u32, // non-zero while a received packet is waiting to be read by 'm'
|
||||
pub usb_next_read: u64, // COUNT at which the next received packet becomes visible
|
||||
}
|
||||
|
||||
fn format_sdcard(device: &mut device::Device) {
|
||||
@@ -217,24 +221,23 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
|
||||
device.cart.sc64.regs[SC64_DATA0_REG] = 0;
|
||||
}
|
||||
'u' => {
|
||||
// used to notify the game that there is data to read
|
||||
if let Some(cart_rx) = device.ui.usb.cart_rx.as_mut() {
|
||||
match cart_rx.try_recv() {
|
||||
Ok(data) => {
|
||||
device.cart.sc64.regs[SC64_DATA0_REG] = data.data_type & 0xFF; // read_status/type
|
||||
device.cart.sc64.regs[SC64_DATA1_REG] =
|
||||
data.data_size & 0xFFFFFF; // length
|
||||
device.cart.sc64.usb_buffer = data.data; // store the data to be read
|
||||
}
|
||||
Err(_err) => {
|
||||
device.cart.sc64.regs[SC64_DATA0_REG] = 0; // read_status/type
|
||||
device.cart.sc64.regs[SC64_DATA1_REG] = 0; // length
|
||||
}
|
||||
}
|
||||
} else {
|
||||
device.cart.sc64.regs[SC64_DATA0_REG] = 0; // read_status/type
|
||||
device.cart.sc64.regs[SC64_DATA1_REG] = 0; // length
|
||||
// used to notify the game that there is data to read.
|
||||
// Status reads don't consume the packet, only 'm' does.
|
||||
// Packets from the PC arrive with some USB latency in between, so don't make
|
||||
// the next one visible right away (games may rely on this, NetLib examples do)
|
||||
let count = device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG];
|
||||
if device.cart.sc64.usb_read_size == 0
|
||||
&& (count >= device.cart.sc64.usb_next_read
|
||||
|| device.cart.sc64.usb_next_read - count > USB_PACKET_DELAY)
|
||||
&& let Some(cart_rx) = device.ui.usb.cart_rx.as_mut()
|
||||
&& let Ok(data) = cart_rx.try_recv()
|
||||
{
|
||||
device.cart.sc64.usb_read_type = data.data_type & 0xFF;
|
||||
device.cart.sc64.usb_read_size = data.data_size & 0xFFFFFF;
|
||||
device.cart.sc64.usb_buffer = data.data; // store the data to be read
|
||||
}
|
||||
device.cart.sc64.regs[SC64_DATA0_REG] = device.cart.sc64.usb_read_type; // read_status/type
|
||||
device.cart.sc64.regs[SC64_DATA1_REG] = device.cart.sc64.usb_read_size; // length
|
||||
}
|
||||
'M' => {
|
||||
// Send data from from flashcart to USB
|
||||
@@ -299,7 +302,8 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
|
||||
'm' => {
|
||||
// Receive data from USB to flashcart
|
||||
let address = device.cart.sc64.regs[SC64_DATA0_REG] as u64 & 0x1FFFFFFF;
|
||||
let length = device.cart.sc64.regs[SC64_DATA1_REG] as usize;
|
||||
let length = device.cart.sc64.regs[SC64_DATA1_REG] as usize & 0xFFFFFF;
|
||||
let usb_buffer = std::mem::take(&mut device.cart.sc64.usb_buffer);
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
@@ -309,8 +313,7 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
|
||||
.rdram
|
||||
.mem
|
||||
.get_mut((address as usize + i) ^ device.byte_swap)
|
||||
.unwrap_or(&mut 0) =
|
||||
*device.cart.sc64.usb_buffer.get(i).unwrap_or(&0);
|
||||
.unwrap_or(&mut 0) = *usb_buffer.get(i).unwrap_or(&0);
|
||||
i += 1;
|
||||
}
|
||||
} else if address >= device::memory::MM_CART_ROM as u64
|
||||
@@ -319,13 +322,21 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u
|
||||
while i < length {
|
||||
device.ui.storage.saves.romsave.data.insert(
|
||||
((address as usize + i) & device::cart::rom::CART_MASK) as u32,
|
||||
*device.cart.sc64.usb_buffer.get(i).unwrap_or(&0),
|
||||
*usb_buffer.get(i).unwrap_or(&0),
|
||||
);
|
||||
i += 1;
|
||||
}
|
||||
} else {
|
||||
panic!("Unknown address {address:#x} for SC64 m command");
|
||||
}
|
||||
// packet consumed
|
||||
if device.cart.sc64.usb_read_size != 0 {
|
||||
device.cart.sc64.usb_read_type = 0;
|
||||
device.cart.sc64.usb_read_size = 0;
|
||||
device.cart.sc64.usb_next_read = device.cpu.cop0.regs
|
||||
[device::cop0::COP0_COUNT_REG]
|
||||
+ USB_PACKET_DELAY;
|
||||
}
|
||||
}
|
||||
'w' => {
|
||||
// SD card writeback pending
|
||||
|
||||
+27
-53
@@ -35,69 +35,38 @@ async fn handle_connection(
|
||||
) {
|
||||
let (mut incoming, mut outgoing) = conn.into_split();
|
||||
|
||||
let mut shutdown_rx_clone = shutdown_rx.clone();
|
||||
|
||||
while usb_rx.try_recv().is_ok() {} // drain stale USB messages
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut reader = tokio::spawn(async move {
|
||||
let mut incoming_buffer = vec![0u8; 4096];
|
||||
let mut data_type: Option<u32> = None;
|
||||
let mut data_size: Option<u32> = None;
|
||||
let mut usb_buffer: Vec<u8> = vec![];
|
||||
loop {
|
||||
tokio::select! {
|
||||
result = incoming.read(&mut incoming_buffer) => {
|
||||
match result {
|
||||
Ok(0) => {
|
||||
match incoming.read(&mut incoming_buffer).await {
|
||||
Ok(0) | Err(_) => break,
|
||||
Ok(n) => {
|
||||
usb_buffer.extend_from_slice(&incoming_buffer[0..n]);
|
||||
// A single read can contain several packets, handle all complete ones
|
||||
while usb_buffer.len() >= 8 {
|
||||
let d_type = u32::from_be_bytes(usb_buffer[0..4].try_into().unwrap());
|
||||
let d_size = u32::from_be_bytes(usb_buffer[4..8].try_into().unwrap());
|
||||
let length = d_size as usize;
|
||||
if usb_buffer.len() < 8 + length {
|
||||
break;
|
||||
}
|
||||
Ok(n) => {
|
||||
usb_buffer.extend_from_slice(&incoming_buffer[0..n]);
|
||||
if data_type.is_none() {
|
||||
if usb_buffer.len() < 4 {
|
||||
continue;
|
||||
} else {
|
||||
data_type = Some(u32::from_be_bytes(usb_buffer[0..4].try_into().unwrap()));
|
||||
usb_buffer.drain(0..4);
|
||||
}
|
||||
let data: Vec<u8> = usb_buffer.drain(..8 + length).skip(8).collect();
|
||||
match d_type {
|
||||
DATATYPE_TCPTEST => respond_to_handshake(&usb_tx, data),
|
||||
DATATYPE_ROMUPLOAD => {} // The ROM is booted by the user in the emulator, ignore uploads
|
||||
_ => {
|
||||
let _ = cart_tx.send(UsbData {
|
||||
data,
|
||||
data_type: d_type,
|
||||
data_size: d_size,
|
||||
});
|
||||
}
|
||||
if data_type.is_some() && data_size.is_none() {
|
||||
if usb_buffer.len() < 4 {
|
||||
continue;
|
||||
} else {
|
||||
data_size = Some(u32::from_be_bytes(usb_buffer[0..4].try_into().unwrap()));
|
||||
usb_buffer.drain(0..4);
|
||||
}
|
||||
}
|
||||
if let Some(d_type) = data_type && let Some(d_size) = data_size {
|
||||
let length = d_size as usize;
|
||||
if usb_buffer.len() >= length {
|
||||
let usb_data = UsbData {
|
||||
data: usb_buffer[0..length].to_vec(),
|
||||
data_type: d_type,
|
||||
data_size: d_size,
|
||||
};
|
||||
usb_buffer.drain(0..length);
|
||||
if usb_data.data_type == DATATYPE_TCPTEST {
|
||||
respond_to_handshake(&usb_tx,usb_data.data);
|
||||
} else if usb_data.data_type == DATATYPE_ROMUPLOAD {
|
||||
panic!("ROM upload not supported");
|
||||
} else {
|
||||
cart_tx.send(usb_data).unwrap();
|
||||
}
|
||||
data_type = None;
|
||||
data_size = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_e) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = shutdown_rx.changed() => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -120,11 +89,16 @@ async fn handle_connection(
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = shutdown_rx_clone.changed() => {
|
||||
_ = &mut reader => {
|
||||
// client disconnected
|
||||
break;
|
||||
}
|
||||
_ = shutdown_rx.changed() => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.abort();
|
||||
}
|
||||
|
||||
pub fn init() -> (
|
||||
|
||||
Reference in new issue
Block a user