From 1300f8ac330f13e0eadbb1db0411f99b44732ac2 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Sat, 11 Mar 2023 23:44:21 +0100 Subject: [PATCH] disk stuff cleanup --- docs/00_quick_startup_guide.md | 74 +++++++++++--------- sw/deployer/src/disk.rs | 120 ++++++++++++++------------------- sw/deployer/src/main.rs | 4 +- 3 files changed, 98 insertions(+), 100 deletions(-) diff --git a/docs/00_quick_startup_guide.md b/docs/00_quick_startup_guide.md index 98bd3da..6190405 100644 --- a/docs/00_quick_startup_guide.md +++ b/docs/00_quick_startup_guide.md @@ -1,7 +1,6 @@ - [First time setup](#first-time-setup) - [Firmware backup/update](#firmware-backupupdate) -- [Internal flashcart state](#internal-flashcart-state) -- [Uploading game/save](#uploading-gamesave) +- [Uploading game and/or save](#uploading-game-andor-save) - [Downloading save](#downloading-save) - [Running 64DD games](#running-64dd-games) - [Direct boot option](#direct-boot-option) @@ -12,81 +11,96 @@ ## First time setup -**Windows platform: replace `./sc64` in examples below with `sc64.exe`** +**Windows platform: replace `./sc64deployer` in examples below with `sc64deployer.exe`** -1. Download the latest `sc64-{os}-{version}.{ext}` (choose OS matching your system) and `sc64-firmware-{version}.bin` from GitHub releases page -2. Extract `sc64-{os}-{version}.{ext}` package contents to a folder and place `sc64-firmware-{version}.bin` inside it -3. Update SC64 firmware to the latest version with `./sc64 --update-firmware sc64-firmware-{version}.bin` -4. Run `./sc64 --print-state` to check if update process finished successfully and SC64 is detected correctly +1. Download the latest deployer tool (`sc64-deployer-{os}-{version}.{ext}`) and firmware (`sc64-firmware-{version}.bin`) from GitHub releases page +2. Extract deployer tool package contents to a folder and place firmware file inside it +3. Connect SC64 device to your computer with USB type C cable +4. Run `./sc64deployer list` to check if device is detected in the system +5. Update SC64 firmware to the latest version with `./sc64deployer firmware update sc64-firmware-{version}.bin` +6. Run `./sc64deployer info` to check if update process finished successfully and SC64 is detected correctly --- ## Firmware backup/update -Keeping SC64 firmware up to date is highly recommended. `sc64` executable is tightly coupled with specific firmware versions and will error out when it detects unsupported firmware version. +Keeping SC64 firmware up to date is highly recommended. +`sc64deployer` application is tightly coupled with specific firmware versions and will error out when it detects unsupported firmware version. -To download and backup current version of SC64 firmware run `./sc64 --backup-firmware sc64-firmware-backup.bin` +To download and backup current version of the SC64 firmware run `./sc64deployer firmware backup sc64-firmware-backup.bin` -To update SC64 firmware run `./sc64 --update-firmware sc64-firmware-{version}.bin` +To update SC64 firmware run `./sc64deployer firmware update sc64-firmware-{version}.bin` + +To print firmware metadata run `./sc64deployer firmware info sc64-firmware-{version}.bin` --- -## Internal flashcart state +## Uploading game and/or save -SC64 holds some internal configuration options after `sc64` executable finished running. To reset it simply run: `./sc64 --reset-state`. Internal flashcart state can be checked by running: `./sc64 --print-state` +`./sc64deployer upload path_to_rom.n64 --save-type eeprom4k --save path_to_save.sav` ---- - -## Uploading game/save - -`./sc64 --boot rom path_to_rom.n64 --save-type eeprom-4k --save path_to_save.sav` - -Replace `path_to_rom.n64` / `eeprom-4k` / `path_to_save.sav` with appropriate values for desired game. Script will try to autodetect used save type so explicitly setting save type usually isn't needed. Check included help in program to list available save types. -Arguments `--save-type` and/or `--save` can be omitted if game doesn't require any save or you want to start fresh. +Replace `path_to_rom.n64` / `eeprom4k` / `path_to_save.sav` with appropriate values for desired game. +Application will try to autodetect used save type so explicitly setting save type usually isn't needed. +Check included help in the application to list available save types. +Arguments `--save-type` and/or `--save` can be omitted if game doesn't require any save or you want to start with fresh save file. --- ## Downloading save -`./sc64 --backup-save path_to_save.sav` +`./sc64deployer download save path_to_save.sav` -Replace `path_to_save.sav` with appropriate value. Specifying save type isn't required when set correctly previously. +Replace `path_to_save.sav` with appropriate value. +Command will raise error when no save type is currently enabled in the SC64 device. --- ## Running 64DD games -64DD games require DDIPL ROM and disk images. To run disk game type `./sc64 --boot ddipl --ddipl path_to_ddipl.n64 --disk path_to_disk_1.ndd --disk path_to_disk_2.ndd`. +64DD games require DDIPL ROM and disk images. +To run disk game type `./sc64deployer 64dd path_to_ddipl.n64 path_to_disk_1.ndd path_to_disk_2.ndd`. -Replace `path_to_ddipl.n64` / `path_to_disk_x.ndd` with appropriate values. Argument `--disk` can be specified multiple times. Only `.ndd` disk format is supported currently. To change inserted disk press button on the back of SC64 flashcart. Make sure retail and development disks aren't mixed together. 64DD IPL can handle only one drive type at a time. +Replace `path_to_ddipl.n64` / `path_to_disk_x.ndd` with appropriate values. +Multiple disk files can be passed to the command. +Only `.ndd` disk format is supported. +To change inserted disk press button on the back of SC64 device. +Make sure retail and development disks formats aren't mixed together. +64DD IPL can handle only one drive type at a time. + +If disk game supports running in conjunction with cartridge game then `--rom path_to_rom.n64` argument can be added to command above. +N64 will boot cartridge game instead of 64DD IPL. --- ## Direct boot option If booting game through included bootloader isn't a desired option then flashcart can be put in special mode that omits this step. -Run `./sc64 --boot direct-rom path_to_rom.n64` to disable bootloader during boot and console reset. This option is useful only for very specific cases (e.g. testing custom IPL3 or running SC64 on top of GameShark). +Pass `--direct` option in `upload` or `64dd` command to disable bootloader during boot and console reset. +This option is useful only for very specific cases (e.g. testing custom IPL3 or running SC64 on top of GameShark). +TV type cannot be forced when direct boot mode is enabled. --- ## Debug terminal -`sc64` executable supports UNFLoader protocol and has same functionality implemented as aforementioned program. Use argument `--debug` to activate it. +`sc64deployer` application supports UNFLoader protocol and has same functionality implemented as aforementioned program. +Type `./sc64deployer debug` to activate it. --- ## LED blink patters -LED on SC64 board can blink in certain situations. Most of them during normal use are related to SD card access. Here's list of blink patters meaning: +LED on SC64 board can blink in certain situations. Most of them during normal use are related to SD card access. Here's list of blink patterns: | Pattern | Meaning | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------ | -| Nx [Short ON - Short OFF] | SD card is being accessed (initialization or data read/write) or save writeback is in progress | -| Nx [Medium ON - Long OFF] | CIC region didn't match, please power off console and power on again | +| Nx [Short ON - Short OFF] | SD card access is in progress (initialization or data read/write) or save writeback is in progress | +| Nx [Medium ON - Long OFF] | CIC region did not match, please power off console and power on again | | 2x [Very short ON - Short OFF] | Pattern used during firmware update process, it means that specific part of firmware has started programming | | 10x [Very short ON - Very short OFF] | Firmware has been successfully updated | | 30x [Long ON - Long OFF] | There was serious problem during firmware update, device is most likely bricked | Nx means that blink count is varied. -LED blinking on SD card access can be disabled through `sc64` executable. Please refer to included help for option to change the LED behavior. +LED blinking on SD card access can be disabled through `sc64deployer` application. +Please refer to included help for option to change the LED behavior. diff --git a/sw/deployer/src/disk.rs b/sw/deployer/src/disk.rs index a8ec0c7..127261f 100644 --- a/sw/deployer/src/disk.rs +++ b/sw/deployer/src/disk.rs @@ -58,7 +58,7 @@ macro_rules! zone { }; } -const DISK_ZONES: [DiskZone; 16] = [ +const ZONE_MAPPING: [DiskZone; 16] = [ zone!(0, 232, 158, 0), zone!(0, 216, 158, 158), zone!(0, 208, 149, 316), @@ -67,17 +67,17 @@ const DISK_ZONES: [DiskZone; 16] = [ zone!(0, 160, 149, 763), zone!(0, 144, 149, 912), zone!(0, 128, 114, 1061), - zone!(1, 216, 158, 157), - zone!(1, 208, 158, 315), - zone!(1, 192, 149, 464), - zone!(1, 176, 149, 613), - zone!(1, 160, 149, 762), - zone!(1, 144, 149, 911), - zone!(1, 128, 149, 1060), - zone!(1, 112, 114, 1174), + zone!(1, 216, 158, 0), + zone!(1, 208, 158, 158), + zone!(1, 192, 149, 316), + zone!(1, 176, 149, 465), + zone!(1, 160, 149, 614), + zone!(1, 144, 149, 763), + zone!(1, 128, 149, 912), + zone!(1, 112, 114, 1061), ]; -const DISK_VZONE_TO_PZONE: [[usize; 16]; 7] = [ +const VZONE_TO_PZONE: [[usize; 16]; 7] = [ [0, 1, 2, 9, 8, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10], [0, 1, 2, 3, 10, 9, 8, 4, 5, 6, 7, 15, 14, 13, 12, 11], [0, 1, 2, 3, 4, 11, 10, 9, 8, 5, 6, 7, 15, 14, 13, 12], @@ -87,6 +87,8 @@ const DISK_VZONE_TO_PZONE: [[usize; 16]; 7] = [ [0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8], ]; +const ROM_ZONES: [usize; 7] = [5, 7, 9, 11, 13, 15, 16]; + struct Mapping { lba: usize, offset: usize, @@ -162,51 +164,47 @@ pub fn open(path: &str) -> Result { pub fn open_multiple(paths: &[String]) -> Result, Error> { let mut disks: Vec = Vec::new(); - for path in paths { let disk = open(path)?; disks.push(disk); } - if !disks.windows(2).all(|d| d[0].format == d[1].format) { return Err(Error::new("Disk format mismatch")); } - Ok(disks) } fn load_ndd(file: &mut File) -> Result<(Format, HashMap), Error> { let mut disk_format: Option = None; - let mut disk_type: u8 = 0; + let mut disk_type: usize = 0; let mut sys_data = vec![0u8; SYSTEM_SECTOR_LENGTH]; - let mut bad_lba: Vec = Vec::new(); + let mut bad_lbas: Vec = Vec::new(); for info in SYSTEM_AREA { - bad_lba.clear(); + bad_lbas.clear(); for &lba in info.sys_lba { let data = load_sys_lba(file, lba)?; if verify_sys_lba(&data, info.sector_length) { if (data[4] != 0x10) || ((data[5] & 0xF0) != 0x10) { - bad_lba.push(lba); + bad_lbas.push(lba); } else { disk_format = Some(info.format); - disk_type = data[5] & 0x0F; + disk_type = (data[5] & 0x0F) as usize; sys_data = data[0..SYSTEM_SECTOR_LENGTH].to_vec(); } } else { - bad_lba.push(lba); + bad_lbas.push(lba); } } if disk_format.is_some() { - bad_lba.append(&mut info.bad_lba.to_vec()); + bad_lbas.append(&mut info.bad_lba.to_vec()); break; } } - if disk_format.is_none() { return Err(Error::new("Provided 64DD disk file is not valid")); } - if disk_type >= DISK_VZONE_TO_PZONE.len() as u8 { + if disk_type >= VZONE_TO_PZONE.len() { return Err(Error::new("Unknown disk type")); } @@ -215,18 +213,17 @@ fn load_ndd(file: &mut File) -> Result<(Format, HashMap), Error> let data = load_sys_lba(file, lba)?; let valid = verify_sys_lba(&data, SYSTEM_SECTOR_LENGTH); if !valid { - bad_lba.push(lba); + bad_lbas.push(lba); } id_lba_valid |= valid; } - if !id_lba_valid { return Err(Error::new("No valid ID LBA found")); } let mut zone_bad_tracks: Vec> = Vec::new(); - for (zone, info) in DISK_ZONES.iter().enumerate() { + for (zone, info) in ZONE_MAPPING.iter().enumerate() { let mut bad_tracks: Vec = Vec::new(); let start = if zone == 0 { 0 } else { sys_data[0x07 + zone] }; let stop = sys_data[0x07 + zone + 1]; @@ -241,60 +238,47 @@ fn load_ndd(file: &mut File) -> Result<(Format, HashMap), Error> let mut mapping = HashMap::new(); - let mut current_lba: usize = 0; + let mut lba: usize = 0; + let mut offset: usize = 0; let mut starting_block: usize = 0; - let mut file_offset: usize = 0; - for zone in DISK_VZONE_TO_PZONE[disk_type as usize] { + for (vzone, &pzone) in VZONE_TO_PZONE[disk_type].iter().enumerate() { let DiskZone { head, sector_length, tracks, track_offset, - } = DISK_ZONES[zone]; + } = ZONE_MAPPING[pzone]; - let mut track = track_offset; + let zone_tracks: Box> = if head == 0 { + Box::new(0..tracks) + } else { + Box::new((0..tracks).rev()) + }; - for zone_track in 0..tracks { - let current_zone_track = if head == 0 { - zone_track - } else { - (tracks - 1) - zone_track - }; - - if zone_bad_tracks[zone].contains(¤t_zone_track) { - track = if head == 0 { - track + 1 - } else { - track.saturating_sub(1) - }; - continue; - } - - for block in 0..BLOCKS_PER_TRACK { - let location = track << 2 | head << 1 | (starting_block ^ block); - let length = sector_length * SECTORS_PER_BLOCK; - if !bad_lba.contains(¤t_lba) { - mapping.insert( - location, - Mapping { - lba: current_lba, - offset: file_offset, - length, - writable: true, - }, - ); + for zone_track in zone_tracks { + if !zone_bad_tracks[pzone].contains(&zone_track) { + for block in 0..BLOCKS_PER_TRACK { + let track = track_offset + zone_track; + let location = (track << 2) | (head << 1) | (starting_block ^ block); + let length = sector_length * SECTORS_PER_BLOCK; + if !bad_lbas.contains(&lba) { + let writable = vzone >= ROM_ZONES[disk_type]; + mapping.insert( + location, + Mapping { + lba, + offset, + length, + writable, + }, + ); + } + lba += 1; + offset += length; } - file_offset += length; - current_lba += 1; + starting_block ^= 1; } - - track = if head == 0 { - track + 1 - } else { - track.saturating_sub(1) - }; - starting_block ^= 1; } } diff --git a/sw/deployer/src/main.rs b/sw/deployer/src/main.rs index 3188d9d..a1c7aff 100644 --- a/sw/deployer/src/main.rs +++ b/sw/deployer/src/main.rs @@ -501,14 +501,14 @@ fn handle_64dd_command(connection: Connection, args: &_64DDArgs) -> Result<(), s if let Some(ref mut disk) = selected_disk { let reply_packet = match packet.kind { sc64::DiskPacketKind::Read => { - print!("[R]"); + print!("{}", "[R]".cyan()); disk.read_block(track, head, block)?.map(|data| { packet.info.set_data(&data); packet }) } sc64::DiskPacketKind::Write => { - print!("[W]"); + print!("{}", "[W]".yellow()); let data = &packet.info.data; disk.write_block(track, head, block, data)?.map(|_| packet) }