diff --git a/Cargo.toml b/Cargo.toml index bb8046c..80b761f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] ftdi-vcp-rs = { path = "ftdi-vcp-rs" } -clap = "*" +clap = "2.33" [build-dependencies] # cc = { version = "1.0", features = ["parallel"] } diff --git a/src/flash.rs b/src/flash.rs index 54be22b..5d4cadd 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -8,11 +8,16 @@ pub enum EraseType { pub struct Flash { pub vcp: VCP, + verbose: bool, } impl Flash { pub fn new(vcp: VCP) -> Flash { - Flash { vcp } + Flash { vcp, verbose: false } + } + + pub fn set_verbose(&mut self, verbose: bool) { + self.verbose = verbose; } fn set_cs_creset(&mut self, cs_asserted: bool, reset_asserted: bool) -> Result<(), Error> { @@ -64,7 +69,7 @@ impl Flash { Ok(()) } - pub fn read_id(&mut self, verbose: bool) -> Result<(), Error> { + pub fn read_id(&mut self) -> Result<(), Error> { /* JEDEC ID structure: * Byte No. | Data Type * ---------+---------- @@ -78,7 +83,7 @@ impl Flash { data[0] = 0x9Fu8 /* FC_JEDECID - Read JEDEC ID */; let mut len = 5usize; // command + 4 response bytes - if verbose { + if self.verbose { println!("read flash ID.."); } @@ -127,10 +132,10 @@ impl Flash { } } - pub fn write_enable(&mut self, verbose: bool) -> Result<(), Error> { - if verbose { + pub fn write_enable(&mut self) -> Result<(), Error> { + if self.verbose { println!("status before enable:"); - self.read_status(verbose)?; + self.read_status()?; println!("write enable.."); } @@ -139,9 +144,9 @@ impl Flash { self.vcp.xfer_spi(&mut data)?; self.chip_deselect()?; - if verbose { + if self.verbose { println!("status after enable:"); - self.read_status(verbose)?; + self.read_status()?; } Ok(()) } @@ -168,14 +173,14 @@ impl Flash { Ok(()) } - pub fn read_status(&mut self, verbose: bool) -> Result { + pub fn read_status(&mut self) -> Result { let mut data = [0x05 /* FC_RSR1 // Read Status Register 1 */, 0x00]; self.chip_select()?; self.vcp.xfer_spi(&mut data)?; self.chip_deselect()?; - if verbose { + if self.verbose { println!("SR1: 0x{:02X}", data[1]); println!( " - SPRL: {}", @@ -251,7 +256,7 @@ impl Flash { self.vcp.xfer_spi(&mut data)?; self.chip_deselect()?; - self.wait(false)?; + self.wait()?; // Read Status Register 1 data[0] = 0x05; // FC_RSR1; @@ -270,8 +275,8 @@ impl Flash { Ok(()) } - pub fn wait(&mut self, verbose: bool) -> Result<(), Error> { - if verbose { + pub fn wait(&mut self) -> Result<(), Error> { + if self.verbose { println!("waiting.."); } @@ -286,19 +291,19 @@ impl Flash { if (data[1] & 0x01) == 0 { if count < 2 { count += 1; - if verbose { + if self.verbose { print!("r"); //fflush(stderr); } } else { - if verbose { + if self.verbose { print!("R"); // fflush(stderr); } break; } } else { - if verbose { + if self.verbose { print!("."); // fflush(stderr); } @@ -308,15 +313,15 @@ impl Flash { sleep(Duration::from_micros(1_000)); } - if verbose { + if self.verbose { println!(); } Ok(()) } - pub fn prog(&mut self, addr: usize, data: &[u8], verbose: bool) -> Result<(), Error> { - if verbose { + pub fn prog(&mut self, addr: usize, data: &[u8]) -> Result<(), Error> { + if self.verbose { println!("prog 0x{:06X} +0x{:03X}..", addr, data.len()); } @@ -339,8 +344,8 @@ impl Flash { Ok(()) } - pub fn read(&mut self, addr: usize, data: &mut [u8], verbose: bool) -> Result<(), Error> { - if verbose { + pub fn read(&mut self, addr: usize, data: &mut [u8]) -> Result<(), Error> { + if self.verbose { println!("read 0x{:06X} +0x{:03X}..", addr, data.len()); } diff --git a/src/main.rs b/src/main.rs index a4910f1..5c996c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,27 +5,55 @@ #define FT_LIST_MASK (FT_LIST_NUMBER_ONLY|FT_LIST_BY_INDEX|FT_LIST_ALL) */ -use clap::{App, Arg, SubCommand}; +use clap::{App, Arg}; use ftdi_vcp_rs::{mpsse::Command::*, BitMode, VCP}; -use std::io::{Write, Read}; +use std::fs::File; +use std::io::Seek; +use std::io::{Read, Write}; use std::thread::sleep; use std::time::Duration; -use std::fs::File; mod flash; +fn parse_size(input: &str) -> Result { + let multiple_index = input + .chars() + .position(|c| !(c.is_numeric() || c == '.')) + .unwrap_or(input.len()); + + let (value, multiple) = &input.split_at(multiple_index); + let value = value.parse::().map_err(|_| "unable to parse")?; + let multiple = match multiple.trim().to_lowercase().as_str() { + "m" | "mib" => 1024 * 1024, + "k" | "kib" => 1024, + "b" | "" | "bytes" => 1, + "g" | "gib" => 1024 * 1024 * 1024, + x => { + println!("Unrecognized suffix {}", x); + return Err("unrecognized suffix") + }, + }; + Ok(value * multiple) +} + +#[test] +fn parse_size_sanity() { + assert_eq!(parse_size("0").unwrap(), 0); + assert_eq!(parse_size("1024").unwrap(), 1024); + assert_eq!(parse_size("1k").unwrap(), 1024); + assert_eq!(parse_size("1K").unwrap(), 1024); + assert_eq!(parse_size("1 K").unwrap(), 1024); + assert_eq!(parse_size("1 k").unwrap(), 1024); + assert_eq!(parse_size("1 kiB").unwrap(), 1024); + assert_eq!(parse_size("1 M").unwrap(), 1024*1024); + assert_eq!(parse_size("2 M").unwrap(), 1024*1024*2); +} + fn main() -> Result<(), ftdi_vcp_rs::Error> { let mut vcp = VCP::new_from_name("iCEBreaker V1.0e A").expect("couldn't open vcp"); let slow_clock = false; - let read_mode = false; - let check_mode = false; - let dont_erase = false; - let bulk_erase = false; let disable_verify = false; - let erase_mode = false; - let rw_offset = 0; let disable_protect = false; - let read_size = 256 * 1024; let mut bitstream = vec![]; @@ -36,30 +64,89 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { .arg( Arg::with_name("FILENAME") .help("Sets the bitstream file to read or write") - .required(true) + .required_unless("verbose") + .required_unless("test") .index(1), ) .arg( - Arg::with_name("v") + Arg::with_name("verbose") .short("v") .multiple(true) .help("Sets the level of verbosity"), ) .arg( - Arg::with_name("test") - .short("t") - .help("Run tests"), + Arg::with_name("bulk_erase") + .short("b") + .help("bulk erase entire flash before writing"), ) + .arg( + Arg::with_name("check_mode") + .short("c") + .help("do not write flash, only verify (`check')"), + ) + .arg( + Arg::with_name("no_erase") + .short("n") + .help("do not erase flash before writing"), + ) + .arg( + Arg::with_name("erase_size") + .short("e") + .takes_value(true) + .help("erase flash as if we were writing that number of bytes"), + ) + .arg( + Arg::with_name("read_256") + .short("r") + .help("read first 256 kB from flash and write to file"), + ) + .arg( + Arg::with_name("read_file") + .short("R") + .takes_value(true) + .conflicts_with("read_256") + .help("read the specified number of bytes from flash"), + ) + .arg( + Arg::with_name("offset") + .short("o") + .takes_value(true) + .default_value("0") + .help("start address for read/write"), + ) + .arg(Arg::with_name("test").short("t").help("Run tests")) .get_matches(); let verbose = matches.is_present("verbose"); let test_mode = matches.is_present("test"); + let bulk_erase = matches.is_present("bulk_erase"); + let check_mode = matches.is_present("check_mode"); + let dont_erase = matches.is_present("no_erase"); + let rw_offset = matches.value_of("offset").map_or(0, |e: &str| { + parse_size(e).expect("unable to parse size") + }); + let erase_size = matches.value_of("erase_size").map(|e| { + Some(parse_size(e).unwrap()) + }); + let read_size = if matches.is_present("read_256") { + Some(256 * 1024) + } else if let Some(size) = matches.value_of("read_file") { + Some(parse_size(size).unwrap()) + } else { + None + }; - let bitstream = { - let filename = matches.value_of("FILENAME").unwrap(); - let mut file = File::open(filename).expect("Couldn't open path"); - file.read_to_end(&mut bitstream).expect("couldn't read to end"); - bitstream + let mut bitstream_file = if let Some(filename) = matches.value_of("FILENAME") { + if read_size.is_none() && !test_mode { + let mut file = File::open(filename).expect("Couldn't open path"); + file.read_to_end(&mut bitstream) + .expect("couldn't read to end"); + Some(file) + } else { + Some(File::create(filename).expect("Couldn't create output file")) + } + } else { + None }; println!("Opened VCP: {:?}", vcp); @@ -86,6 +173,7 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { } let mut flash = flash::Flash::new(vcp); + flash.set_verbose(verbose); flash.release_reset()?; sleep(Duration::from_micros(100_000)); @@ -101,7 +189,7 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { flash.reset()?; flash.power_up()?; - flash.read_id(true)?; + flash.read_id()?; flash.power_down()?; @@ -113,34 +201,37 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { // --------------------------------------------------------- // Reset // --------------------------------------------------------- - - println!("reset.."); + if verbose { + println!("reset.."); + } flash.chip_deselect()?; sleep(Duration::from_micros(250_000)); - println!("cdone: {}", flash.cdone_str()?); + if verbose { + println!("cdone: {}", flash.cdone_str()?); + } flash.reset()?; flash.power_up()?; - flash.read_id(true)?; + flash.read_id()?; // --------------------------------------------------------- // Program // --------------------------------------------------------- - if !read_mode && !check_mode { + if read_size.is_none() && !check_mode { if disable_protect { - flash.write_enable(verbose)?; + flash.write_enable()?; flash.disable_protection()?; } if !dont_erase { if bulk_erase { - flash.write_enable(verbose)?; + flash.write_enable()?; flash.bulk_erase()?; - flash.wait(verbose)?; + flash.wait()?; } else { println!("file size: {}", bitstream.len()); @@ -148,28 +239,30 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { let end_addr = (rw_offset + bitstream.len() + 0xffff) & !0xffff; for addr in (begin_addr..end_addr).step_by(0x10000) { - flash.write_enable(verbose)?; + flash.write_enable()?; flash.sector_erase(flash::EraseType::Kb64, addr)?; if verbose { println!("Status after block erase:"); - flash.read_status(verbose)?; + flash.read_status()?; } - flash.wait(verbose)?; + flash.wait()?; } } } - if !erase_mode { + if erase_size.is_none() { println!("programming.."); for (idx, page) in bitstream.chunks(256).enumerate() { - flash.write_enable(verbose)?; - flash.prog(rw_offset + idx*256, page, verbose)?; - flash.wait(verbose)?; + flash.write_enable()?; + flash.prog(rw_offset + idx * 256, page)?; + flash.wait()?; } - /* seek to the beginning for second pass */ - // fseek(f, 0, SEEK_SET); + bitstream_file.as_mut() + .expect("no bitstream file was specified") + .seek(std::io::SeekFrom::Start(0)) + .expect("Couldn't rewind file"); } } @@ -177,19 +270,23 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { // Read/Verify // --------------------------------------------------------- - if read_mode { - println!("reading.."); + if let Some(read_size) = read_size { + println!("reading {} bytes..", read_size); + // uint8_t buffer[256]; + let out_file = bitstream_file.as_mut().expect("no output file found"); + let mut buffer = [0u8; 256]; for addr in (0..read_size).step_by(256) { - // uint8_t buffer[256]; - // flash_read(rw_offset + addr, buffer, 256); - // fwrite(buffer, read_size - addr > 256 ? 256 : read_size - addr, 1, f); + flash.read(rw_offset + addr, &mut buffer)?; + out_file + .write_all(&buffer) + .expect("couldn't write to bitstream file"); } - } else if !erase_mode && !disable_verify { + } else if erase_size.is_none() && !disable_verify { println!("reading.."); for (idx, page) in bitstream.chunks(256).enumerate() { let mut buffer_flash = [0; 256]; - flash.read(rw_offset + idx*256, &mut buffer_flash, verbose); - if ! page.iter().zip(buffer_flash.iter()).all(|(a,b)| a == b) { + flash.read(rw_offset + idx * 256, &mut buffer_flash)?; + if !page.iter().zip(buffer_flash.iter()).all(|(a, b)| a == b) { println!("Found difference between flash and file!"); } } @@ -203,7 +300,7 @@ fn main() -> Result<(), ftdi_vcp_rs::Error> { flash.power_down()?; - flash.release_reset(); + flash.release_reset()?; sleep(Duration::from_micros(250_000)); println!("cdone: {}", flash.cdone_str()?); diff --git a/src/mpsse.rs b/src/mpsse.rs index e69de29..6f62b23 100644 --- a/src/mpsse.rs +++ b/src/mpsse.rs @@ -0,0 +1,7 @@ +pub struct MPSSE { + handle: VCP, +} + +impl MPSSE { + pub fn set_gpio(&mut self, gpio: u8, direction: ) +}