/* #define FT_LIST_NUMBER_ONLY 0x80000000 #define FT_LIST_BY_INDEX 0x40000000 #define FT_LIST_ALL 0x20000000 #define FT_LIST_MASK (FT_LIST_NUMBER_ONLY|FT_LIST_BY_INDEX|FT_LIST_ALL) */ use clap::{App, Arg}; use ftdi_vcp_rs::{mpsse::Command::*, BitMode, VCP}; use std::fs::File; use std::io::Seek; use std::io::{Read, Write}; use std::thread::sleep; use std::time::Duration; 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 disable_verify = false; let disable_protect = false; let mut bitstream = vec![]; let matches = App::new("iCE40 Programmer") .version("1.0") .author("Sean Cross ") .about("Port of Iceprog") .arg( Arg::with_name("FILENAME") .help("Sets the bitstream file to read or write") .required_unless("verbose") .required_unless("test") .index(1), ) .arg( Arg::with_name("verbose") .short("v") .multiple(true) .help("Sets the level of verbosity"), ) .arg( 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 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); vcp.reset()?; vcp.purge()?; let previous_latency = vcp.latency_timer()?; vcp.set_latency_timer(1)?; vcp.set_bitmode(0xff, BitMode::MPSSE)?; // enable clock divide by 5 vcp.write(&[MC_TCK_D5.to_u8()]) .or_else(|_| Err(ftdi_vcp_rs::Error::IoError))?; if slow_clock { // set 50 kHz clock vcp.write(&[MC_SET_CLK_DIV.to_u8(), 119, 0x00]) .or_else(|_| Err(ftdi_vcp_rs::Error::IoError))?; } else { // set 6 MHz clock vcp.write(&[MC_SET_CLK_DIV.to_u8(), 0x00, 0x00]) .or_else(|_| Err(ftdi_vcp_rs::Error::IoError))?; } let mut flash = flash::Flash::new(vcp); flash.set_verbose(verbose); flash.release_reset()?; sleep(Duration::from_micros(100_000)); if test_mode { println!("reset.."); flash.chip_deselect()?; sleep(Duration::from_micros(250_000)); println!("cdone: {}", flash.cdone_str()?); flash.reset()?; flash.power_up()?; flash.read_id()?; flash.power_down()?; flash.release_reset()?; sleep(Duration::from_micros(250_000)); println!("cdone: {}", flash.cdone_str()?); } else { // --------------------------------------------------------- // Reset // --------------------------------------------------------- if verbose { println!("reset.."); } flash.chip_deselect()?; sleep(Duration::from_micros(250_000)); if verbose { println!("cdone: {}", flash.cdone_str()?); } flash.reset()?; flash.power_up()?; flash.read_id()?; // --------------------------------------------------------- // Program // --------------------------------------------------------- if read_size.is_none() && !check_mode { if disable_protect { flash.write_enable()?; flash.disable_protection()?; } if !dont_erase { if bulk_erase { flash.write_enable()?; flash.bulk_erase()?; flash.wait()?; } else { println!("file size: {}", bitstream.len()); let begin_addr = rw_offset & !0xffff; let end_addr = (rw_offset + bitstream.len() + 0xffff) & !0xffff; for addr in (begin_addr..end_addr).step_by(0x10000) { flash.write_enable()?; flash.sector_erase(flash::EraseType::Kb64, addr)?; if verbose { println!("Status after block erase:"); flash.read_status()?; } flash.wait()?; } } } if erase_size.is_none() { println!("programming.."); for (idx, page) in bitstream.chunks(256).enumerate() { flash.write_enable()?; flash.prog(rw_offset + idx * 256, page)?; flash.wait()?; } /* seek to the beginning for second pass */ bitstream_file.as_mut() .expect("no bitstream file was specified") .seek(std::io::SeekFrom::Start(0)) .expect("Couldn't rewind file"); } } // --------------------------------------------------------- // Read/Verify // --------------------------------------------------------- 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) { flash.read(rw_offset + addr, &mut buffer)?; out_file .write_all(&buffer) .expect("couldn't write to bitstream file"); } } 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)?; if !page.iter().zip(buffer_flash.iter()).all(|(a, b)| a == b) { println!("Found difference between flash and file!"); } } println!("VERIFY OK"); } // --------------------------------------------------------- // Reset // --------------------------------------------------------- flash.power_down()?; flash.release_reset()?; sleep(Duration::from_micros(250_000)); println!("cdone: {}", flash.cdone_str()?); } if let Ok(com_port) = flash.vcp.com_port() { println!("VCP COM{}:", com_port); } else { println!("No COM port assigned"); } flash.vcp.set_latency_timer(previous_latency)?; Ok(()) }