diff --git a/CHANGELOG.md b/CHANGELOG.md index b0df4be..f97445c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Rename ChipUID response to ESignature, #58 +- Add `--skip-gap` as a experimental option for `flash` subcommand to write a firmware which has more than 1 section, #40 & #56 ## [0.0.8] - 2024-03-30 @@ -22,10 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use loaded memory address from ELF file or ihex file - Add timestamp in serial output -### Fixed - -- Merge gaps in firmware sections, #56 - ### Changed - No erase by default when flashing diff --git a/src/firmware.rs b/src/firmware.rs index 64896dc..38bcda6 100644 --- a/src/firmware.rs +++ b/src/firmware.rs @@ -38,39 +38,35 @@ pub enum Firmware { Sections(Vec
), } -impl Firmware { - /// Merge sections, and fill gap with 0xff - pub fn merge_sections(self) -> Result { - if let Firmware::Sections(mut sections) = self { - sections.sort_by_key(|s| s.address); - let mut merged = vec![]; - - let mut it = sections.drain(0..); - let mut last = it - .next() - .expect("firmware must has at least one section; qed"); - - for sect in it { - if let Some(gap) = sect.address.checked_sub(last.end_address()) { - if gap > 0 { - log::debug!("Merge firmware sections with gap: {}", gap); - } - last.data.resize(last.data.len() + gap as usize, 0xff); // fill gap with 0xff - last.data.extend_from_slice(§.data); - } else { - return Err(anyhow::format_err!( - "section address overflow: {:#010x} + {:#x}", - last.address, - last.data.len() - )); - } +/// Merge sections w/ <= max_tiny_gap bytes gap +pub fn fill_tiny_gap_between_sections(mut sections: Vec
, max_tiny_gap: u32) -> Result> { + sections.sort_by_key(|s| s.address); + let mut merged = vec![]; + + let mut it = sections.drain(0..); + let mut last = it + .next() + .expect("firmware must has at least one section; qed"); + for sect in it { + if let Some(gap) = sect.address.checked_sub(last.end_address()) { + if gap > max_tiny_gap { + merged.push(last); + last = sect.clone(); + continue; + } else { + last.data.resize(last.data.len() + gap as usize, 0xFF); + last.data.extend_from_slice(§.data); } - merged.push(last); - Ok(Firmware::Sections(merged)) } else { - Ok(self) + return Err(anyhow::format_err!( + "section address overflow: {:#010x} + {:#x}", + last.address, + last.data.len() + )); } } + merged.push(last); + Ok(merged) } pub fn read_firmware_from_file>(path: P) -> Result { @@ -90,9 +86,9 @@ pub fn read_firmware_from_file>(path: P) -> Result { } FirmwareFormat::Binary => Ok(Firmware::Binary(raw)), FirmwareFormat::IntelHex => { - read_ihex(str::from_utf8(&raw)?).and_then(|f| f.merge_sections()) + read_ihex(str::from_utf8(&raw)?) } - FirmwareFormat::ELF => read_elf(&raw).and_then(|f| f.merge_sections()), + FirmwareFormat::ELF => read_elf(&raw), } } diff --git a/src/main.rs b/src/main.rs index 8e5f90d..cd9f8e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use anyhow::Result; use wlink::{ commands, dmi::DebugModuleInterface, - firmware::{read_firmware_from_file, Firmware}, + firmware::{fill_tiny_gap_between_sections, read_firmware_from_file, Firmware}, operations::ProbeSession, probe::WchLink, regs, RiscvChip, @@ -93,6 +93,9 @@ enum Commands { /// Erase flash before flashing #[arg(long, short, default_value = "false")] erase: bool, + /// Skip gap between sections + #[arg(long, short, default_value = "false")] + skip_gap: bool, /// Do not reset and run after flashing #[arg(long, short = 'R', default_value = "false")] no_run: bool, @@ -325,6 +328,7 @@ fn main() -> Result<()> { Flash { address, erase, + skip_gap, no_run, path, enable_sdi_print, @@ -341,25 +345,38 @@ fn main() -> Result<()> { match firmware { Firmware::Binary(data) => { + if skip_gap { + log::warn!("Skip gap is ignored when flashing binary"); + } let start_address = address.unwrap_or_else(|| sess.chip_family.code_flash_start()); log::info!("Flashing {} bytes to 0x{:08x}", data.len(), start_address); sess.write_flash(&data, start_address)?; } Firmware::Sections(sections) => { - // Flash section by section + let mut sections = sections.clone(); if address != None { log::warn!("--address is ignored when flashing ELF or ihex"); } + if skip_gap { + log::warn!("Skip gap is a experimental feature using a trait of wchlink!"); + sections = fill_tiny_gap_between_sections(sections, 4096)?; + } else { + // merge sections + sections = fill_tiny_gap_between_sections(sections, 0xFFFFFFFF)?; + } + let mut offset = 0; // may a trait of wchlink for section in sections { let start_address = sess.chip_family.fix_code_flash_start(section.address); log::info!( - "Flashing {} bytes to 0x{:08x}", - section.data.len(), - start_address - ); - sess.write_flash(§ion.data, start_address)?; + "Flashing {} bytes to 0x{:08x}", + section.data.len(), + start_address + ); + log::debug!("offset: 0x{:08x}", offset); + sess.write_flash(§ion.data, start_address - offset)?; + offset += ((section.data.len() as u32 + 4095) / 4096) * 4096; } } }