Browse Source
* First draft of the config structure for cmsis pack based flashing configuration * Remove repositories module as we don't need it for now * Add range extension function testing * Updated some types * Add config parsing * Fix target selection * Change everything to the new config structure. * Add fixed algorithm. It is slow as hell now (example blinky takes 68s) * Add extracted LPC845 * Clean up flash builder module * Clean up download.rs & add hex flashing * Removal of old types that were moved to the config module * Add LPC55 series * Add STM32F103 targets * Combine all chip configs into one family config. * Clean up code, comment, remove pyocd artifacts * Improve logging * Add some docs * Clean up some real ugly code * Update cargo-flash/README.md * Add the m33 to the get_core() methoddouble-buffering

committed by
GitHub

55 changed files with 8173 additions and 2144 deletions
@ -1,3 +1,8 @@ |
|||
/target |
|||
**/*.rs.bk |
|||
Cargo.lock |
|||
|
|||
# Needed for RLS |
|||
probe-rs/target |
|||
cli/target |
|||
cargo-flash/target |
@ -1,7 +1,6 @@ |
|||
[workspace] |
|||
members = [ |
|||
"probe-rs", |
|||
"probe-rs-targets", |
|||
"cli", |
|||
"cargo-flash", |
|||
] |
@ -1,25 +0,0 @@ |
|||
[package] |
|||
name = "probe-rs-targets" |
|||
version = "0.2.0" |
|||
authors = ["Noah Hรผsser <yatekii@yatekii.ch>", "Dominik Boehi <dominik.boehi@gmail.ch>"] |
|||
edition = "2018" |
|||
description = "A collection of on chip debugging tools to comminicate with ARM chips." |
|||
documentation = "https://docs.rs/probe-rs-targets/" |
|||
homepage = "https://github.com/probe-rs/probe-rs" |
|||
repository = "https://github.com/probe-rs/probe-rs" |
|||
readme = "../README.md" |
|||
categories = ["embedded", "hardware-support", "development-tools::debugging"] |
|||
keywords = ["embedded"] |
|||
license = "MIT OR Apache-2.0" |
|||
|
|||
build = "build.rs" |
|||
|
|||
[dependencies] |
|||
phf = { version = "0.7.24", default-features = false } |
|||
probe-rs = { path = "../probe-rs", version = "0.2.0" } |
|||
lazy_static = "1.4.0" |
|||
|
|||
[build-dependencies] |
|||
quote = "1.0.2" |
|||
log = "0.4.6" |
|||
probe-rs = { path = "../probe-rs", version = "0.2.0" } |
@ -1,27 +0,0 @@ |
|||
load_address: 0x20000000 |
|||
instructions: [ |
|||
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, |
|||
0x49544853, 0x48546048, 0x20006048, 0xb5104770, 0x20344603, 0x60e04c4f, 0xbd102000, 0x20004601, |
|||
0xb5004770, 0x23002200, 0x6902484a, 0x40102080, 0xd1012880, 0xffe4f7ff, 0x4846bf00, 0x07d868c3, |
|||
0xd1fa0fc0, 0x69024843, 0x43022004, 0x61024841, 0x20406902, 0x483f4302, 0xbf006102, 0x68c3483d, |
|||
0x0fc007d8, 0x483bd1fa, 0x21046902, 0x43884610, 0x48384602, 0x20006102, 0xb510bd00, 0x22004603, |
|||
0x48342400, 0x20806902, 0x28804010, 0xf7ffd101, 0xbf00ffb7, 0x68c4482f, 0x0fc007e0, 0x482dd1fa, |
|||
0x20026902, 0x482b4302, 0x61436102, 0x20406902, 0x48284302, 0xbf006102, 0x68c44826, 0x0fc007e0, |
|||
0x4824d1fa, 0x21026902, 0x43884610, 0x48214602, 0x20006102, 0xb5f7bd10, 0x22004615, 0x27002600, |
|||
0x462c9b00, 0x6902481b, 0x40102080, 0xd1012880, 0xff86f7ff, 0x4817bf00, 0x07f068c6, 0xd1fa0fc0, |
|||
0x4814e01b, 0x20016902, 0x48124302, 0x88206102, 0xbf008018, 0x68c6480f, 0x0fc007f0, 0x8820d1fa, |
|||
0x42888819, 0x480bd006, 0x08526902, 0x61020052, 0xbdfe2001, 0x1ca41c9b, 0x98011c7f, 0x42b80840, |
|||
0x4804d8df, 0x08526902, 0x61020052, 0xe7f02000, 0x45670123, 0x40022000, 0xcdef89ab, 0x00000000, |
|||
] |
|||
pc_init: 0x2000002F |
|||
pc_uninit: null |
|||
pc_program_page: 0x200000F7 |
|||
pc_erase_sector: 0x2000009B |
|||
pc_erase_all: 0x20000043 |
|||
static_base: 0x200001A0 |
|||
begin_stack: 0x20001000 |
|||
begin_data: 0x20000400 |
|||
page_buffers: [0x20000400, 0x20000800] |
|||
min_program_length: 2 |
|||
analyzer_supported: true |
|||
analyzer_address: 0x20001400 |
@ -1,27 +0,0 @@ |
|||
load_address: 0x20000000 |
|||
instructions: [ |
|||
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, |
|||
0x03004601, 0x28200e00, 0x0940d302, 0xe0051d00, 0xd3022810, 0x1cc00900, 0x0880e000, 0xd50102c9, |
|||
0x43082110, 0x48464770, 0x60414944, 0x60414945, 0x60012100, 0x22f068c1, 0x60c14311, 0x06806940, |
|||
0x4842d406, 0x60014940, 0x60412106, 0x60814940, 0x47702000, 0x6901483a, 0x43110542, 0x20006101, |
|||
0xb5304770, 0x69014836, 0x43212404, 0x69016101, 0x43290365, 0x69016101, 0x431103a2, 0x49356101, |
|||
0xe0004a32, 0x68c36011, 0xd4fb03db, 0x43a16901, 0x69016101, 0x610143a9, 0xbd302000, 0xf7ffb530, |
|||
0x4927ffaf, 0x23f068ca, 0x60ca431a, 0x610c2402, 0x06c0690a, 0x43020e00, 0x6908610a, 0x431003e2, |
|||
0x48246108, 0xe0004a21, 0x68cd6010, 0xd4fb03ed, 0x43a06908, 0x68c86108, 0x0f000600, 0x68c8d003, |
|||
0x60c84318, 0xbd302001, 0x4d15b570, 0x08891cc9, 0x008968eb, 0x433326f0, 0x230060eb, 0x4b16612b, |
|||
0x692ce017, 0x612c431c, 0x60046814, 0x03e468ec, 0x692cd4fc, 0x00640864, 0x68ec612c, 0x0f240624, |
|||
0x68e8d004, 0x60e84330, 0xbd702001, 0x1d121d00, 0x29001f09, 0x2000d1e5, 0x0000bd70, 0x45670123, |
|||
0x40023c00, 0xcdef89ab, 0x00005555, 0x40003000, 0x00000fff, 0x0000aaaa, 0x00000201, 0x00000000, |
|||
] |
|||
pc_init: 0x20000047 |
|||
pc_uninit: 0x20000075 |
|||
pc_program_page: 0x20000109 |
|||
pc_erase_sector: 0x200000bd |
|||
pc_erase_all: 0x20000083 |
|||
static_base: 0x20000171 |
|||
begin_stack: 0x20000800 |
|||
begin_data: 0x20001000 |
|||
page_buffers: [0x20001000, 0x20002000] |
|||
min_program_length: 1 |
|||
analyzer_supported: true |
|||
analyzer_address: 0x20002000 |
@ -1,23 +0,0 @@ |
|||
load_address: 0x20000000 |
|||
instructions: [ |
|||
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, |
|||
0x47702000, 0x47702000, 0x4c26b570, 0x60602002, 0x60e02001, 0x68284d24, 0xd00207c0, 0x60602000, |
|||
0xf000bd70, 0xe7f6f82c, 0x4c1eb570, 0x60612102, 0x4288491e, 0x2001d302, 0xe0006160, 0x4d1a60a0, |
|||
0xf81df000, 0x07c06828, 0x2000d0fa, 0xbd706060, 0x4605b5f8, 0x4813088e, 0x46142101, 0x4f126041, |
|||
0xc501cc01, 0x07c06838, 0x1e76d006, 0x480dd1f8, 0x60412100, 0xbdf84608, 0xf801f000, 0x480ce7f2, |
|||
0x06006840, 0xd00b0e00, 0x6849490a, 0xd0072900, 0x4a0a4909, 0xd00007c3, 0x1d09600a, 0xd1f90840, |
|||
0x00004770, 0x4001e500, 0x4001e400, 0x10001000, 0x40010400, 0x40010500, 0x40010600, 0x6e524635, |
|||
0x00000000, |
|||
] |
|||
pc_init: 0x20000021 |
|||
pc_uninit: null |
|||
pc_program_page: 0x20000071 |
|||
pc_erase_sector: 0x20000049 |
|||
pc_erase_all: 0x20000029 |
|||
static_base: 0x20000170 |
|||
begin_stack: 0x20001000 |
|||
begin_data: 0x20002000 |
|||
page_buffers: [0x20002000, 0x20002400] |
|||
min_program_length: 4 |
|||
analyzer_supported: true |
|||
analyzer_address: 0x20003000 |
@ -1,23 +0,0 @@ |
|||
load_address: 0x20000000 |
|||
instructions: [ |
|||
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, |
|||
0x47702000, 0x47702000, 0x4c26b570, 0x60602002, 0x60e02001, 0x68284d24, 0xd00207c0, 0x60602000, |
|||
0xf000bd70, 0xe7f6f82c, 0x4c1eb570, 0x60612102, 0x4288491e, 0x2001d302, 0xe0006160, 0x4d1a60a0, |
|||
0xf81df000, 0x07c06828, 0x2000d0fa, 0xbd706060, 0x4605b5f8, 0x4813088e, 0x46142101, 0x4f126041, |
|||
0xc501cc01, 0x07c06838, 0x1e76d006, 0x480dd1f8, 0x60412100, 0xbdf84608, 0xf801f000, 0x480ce7f2, |
|||
0x06006840, 0xd00b0e00, 0x6849490a, 0xd0072900, 0x4a0a4909, 0xd00007c3, 0x1d09600a, 0xd1f90840, |
|||
0x00004770, 0x4001e500, 0x4001e400, 0x10001000, 0x40010400, 0x40010500, 0x40010600, 0x6e524635, |
|||
0x00000000, |
|||
] |
|||
pc_init: 0x20000021 |
|||
pc_uninit: null |
|||
pc_program_page: 0x20000071 |
|||
pc_erase_sector: 0x20000049 |
|||
pc_erase_all: 0x20000029 |
|||
static_base: 0x20000170 |
|||
begin_stack: 0x20001000 |
|||
begin_data: 0x20002000 |
|||
page_buffers: [0x20002000, 0x20003000] |
|||
min_program_length: 4 |
|||
analyzer_supported: true |
|||
analyzer_address: 0x20004000 |
@ -1,23 +0,0 @@ |
|||
load_address: 0x20000000 |
|||
instructions: [ |
|||
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2, |
|||
0x47702000, 0x47702000, 0x4c26b570, 0x60602002, 0x60e02001, 0x68284d24, 0xd00207c0, 0x60602000, |
|||
0xf000bd70, 0xe7f6f82c, 0x4c1eb570, 0x60612102, 0x4288491e, 0x2001d302, 0xe0006160, 0x4d1a60a0, |
|||
0xf81df000, 0x07c06828, 0x2000d0fa, 0xbd706060, 0x4605b5f8, 0x4813088e, 0x46142101, 0x4f126041, |
|||
0xc501cc01, 0x07c06838, 0x1e76d006, 0x480dd1f8, 0x60412100, 0xbdf84608, 0xf801f000, 0x480ce7f2, |
|||
0x06006840, 0xd00b0e00, 0x6849490a, 0xd0072900, 0x4a0a4909, 0xd00007c3, 0x1d09600a, 0xd1f90840, |
|||
0x00004770, 0x4001e500, 0x4001e400, 0x10001000, 0x40010400, 0x40010500, 0x40010600, 0x6e524635, |
|||
0x00000000, |
|||
] |
|||
pc_init: 0x20000021 |
|||
pc_uninit: null |
|||
pc_program_page: 0x20000071 |
|||
pc_erase_sector: 0x20000049 |
|||
pc_erase_all: 0x20000029 |
|||
static_base: 0x20000170 |
|||
begin_stack: 0x20001000 |
|||
begin_data: 0x20002000 |
|||
page_buffers: [0x20002000, 0x20003000] |
|||
min_program_length: 4 |
|||
analyzer_supported: true |
|||
analyzer_address: 0x20004000 |
@ -1,118 +0,0 @@ |
|||
use std::env; |
|||
use std::fs::{read_dir, read_to_string, File}; |
|||
use std::io::{self, Write}; |
|||
use std::path::{Path, PathBuf}; |
|||
|
|||
use probe_rs::{probe::flash::FlashAlgorithm, target::Target}; |
|||
|
|||
fn main() { |
|||
let out_dir = env::var("OUT_DIR").unwrap(); |
|||
let dest_path = Path::new(&out_dir).join("targets.rs"); |
|||
let mut f = File::create(&dest_path).unwrap(); |
|||
|
|||
// TARGETS
|
|||
let mut files = vec![]; |
|||
visit_dirs(Path::new("algorithms"), &mut files).unwrap(); |
|||
|
|||
let mut algorithm_names = vec![]; |
|||
let mut algorithm_files = vec![]; |
|||
|
|||
let root_dir = Path::new(env!("CARGO_MANIFEST_DIR")); |
|||
|
|||
for file in files { |
|||
let string = read_to_string(&file).expect( |
|||
"Algorithm definition file could not be read. This is a bug. Please report it.", |
|||
); |
|||
|
|||
match FlashAlgorithm::new(&string) { |
|||
Ok(_algorithm) => { |
|||
let abs_path = root_dir.join(&file); |
|||
|
|||
algorithm_files.push(abs_path.to_str().unwrap().to_owned()); |
|||
|
|||
algorithm_names.push( |
|||
file.strip_prefix("algorithms") |
|||
.unwrap() |
|||
.to_str() |
|||
.expect("Non UTF-8 Filename!") |
|||
.to_owned(), |
|||
); |
|||
} |
|||
Err(e) => { |
|||
panic!("Failed to parse target file: {:?} because:\n{}", file, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
dbg!(&algorithm_names); |
|||
dbg!(&algorithm_files); |
|||
|
|||
// TARGETS
|
|||
let mut files = vec![]; |
|||
visit_dirs(Path::new("targets"), &mut files).unwrap(); |
|||
|
|||
let mut target_names = vec![]; |
|||
let mut target_files = vec![]; |
|||
|
|||
for file in files { |
|||
let string = read_to_string(&file) |
|||
.expect("Chip definition file could not be read. This is a bug. Please report it."); |
|||
match Target::new(&string) { |
|||
Ok(target) => { |
|||
if let Some(algo) = target.flash_algorithm { |
|||
assert!( |
|||
algorithm_names.contains(&algo), |
|||
"Algorithm {} does not exist.", |
|||
algo |
|||
); |
|||
} |
|||
|
|||
target_files.push(root_dir.join(file).to_str().unwrap().to_owned()); |
|||
|
|||
target_names.push(target.name.to_ascii_lowercase()); |
|||
} |
|||
Err(e) => { |
|||
panic!("Failed to parse target file: {:?} because:\n{}", file, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
dbg!(&target_names); |
|||
dbg!(&target_files); |
|||
|
|||
let stream: String = format!( |
|||
"{}", |
|||
quote::quote! { |
|||
// START QUOTE
|
|||
lazy_static::lazy_static! { |
|||
static ref FLASH_ALGORITHMS: HashMap<&'static str, &'static str> = vec![ |
|||
#((#algorithm_names, include_str!(#algorithm_files)),)* |
|||
].into_iter().collect(); |
|||
|
|||
static ref TARGETS: HashMap<&'static str, &'static str> = vec![ |
|||
#((#target_names, include_str!(#target_files)),)* |
|||
].into_iter().collect(); |
|||
} |
|||
// END QUOTE
|
|||
} |
|||
); |
|||
|
|||
f.write_all(stream.as_bytes()) |
|||
.expect("Writing build.rs output failed."); |
|||
} |
|||
|
|||
// one possible implementation of walking a directory only visiting files
|
|||
fn visit_dirs(dir: &Path, targets: &mut Vec<PathBuf>) -> io::Result<()> { |
|||
if dir.is_dir() { |
|||
for entry in read_dir(dir)? { |
|||
let entry = entry?; |
|||
let path = entry.path(); |
|||
if path.is_dir() { |
|||
visit_dirs(&path, targets)?; |
|||
} else { |
|||
targets.push(path.to_owned()); |
|||
} |
|||
} |
|||
} |
|||
Ok(()) |
|||
} |
@ -1,70 +0,0 @@ |
|||
use std::collections::HashMap; |
|||
|
|||
use probe_rs::{ |
|||
collection, |
|||
probe::flash::flasher::{AlgorithmSelectionError, FlashAlgorithm}, |
|||
target::{info::ChipInfo, Target, TargetSelectionError}, |
|||
}; |
|||
|
|||
include!(concat!(env!("OUT_DIR"), "/targets.rs")); |
|||
|
|||
pub fn get_built_in_target(name: impl AsRef<str>) -> Result<Target, TargetSelectionError> { |
|||
let name = name.as_ref().to_string().to_ascii_lowercase(); |
|||
TARGETS |
|||
.get(&name[..]) |
|||
.ok_or(TargetSelectionError::TargetNotFound(name)) |
|||
.and_then(|target| Target::new(target).map_err(From::from)) |
|||
} |
|||
|
|||
pub fn get_built_in_target_by_chip_id(chip_info: &ChipInfo) -> Option<Target> { |
|||
for target in TARGETS.values() { |
|||
let target = Target::new(target).unwrap(); |
|||
if target.manufacturer == chip_info.manufacturer && target.part == chip_info.part { |
|||
return Some(target); |
|||
} |
|||
} |
|||
|
|||
None |
|||
} |
|||
|
|||
pub enum SelectionStrategy { |
|||
Name(String), |
|||
ChipInfo(ChipInfo), |
|||
} |
|||
|
|||
pub fn select_target(strategy: &SelectionStrategy) -> Result<Target, TargetSelectionError> { |
|||
match strategy { |
|||
SelectionStrategy::Name(name) => match collection::get_target(name) { |
|||
Some(target) => Ok(target), |
|||
None => get_built_in_target(name), |
|||
}, |
|||
SelectionStrategy::ChipInfo(chip_info) => get_built_in_target_by_chip_id(&chip_info) |
|||
.ok_or_else(|| { |
|||
TargetSelectionError::TargetNotFound(format!( |
|||
"No target info found for device: {}", |
|||
chip_info |
|||
)) |
|||
}), |
|||
} |
|||
} |
|||
|
|||
pub fn get_built_in_algorithm( |
|||
name: impl AsRef<str>, |
|||
) -> Result<FlashAlgorithm, AlgorithmSelectionError> { |
|||
let name = name.as_ref().to_string(); |
|||
FLASH_ALGORITHMS |
|||
.get(&name[..]) |
|||
.ok_or(AlgorithmSelectionError::AlgorithmNotFound(name)) |
|||
.and_then(|definition| FlashAlgorithm::new(definition).map_err(From::from)) |
|||
} |
|||
|
|||
pub fn select_algorithm(name: impl AsRef<str>) -> Result<FlashAlgorithm, AlgorithmSelectionError> { |
|||
let algorithm = match collection::get_algorithm(name.as_ref()) { |
|||
Some(algorithm) => Some(algorithm), |
|||
None => None, |
|||
}; |
|||
match algorithm { |
|||
Some(algorithm) => Ok(algorithm), |
|||
None => get_built_in_algorithm(name), |
|||
} |
|||
} |
@ -1,31 +0,0 @@ |
|||
name: "STM32F042" |
|||
# TODO: Manufacturer and Part are not correct yet. They are only needed for autodetection. |
|||
manufacturer: |
|||
cc: 0x00 |
|||
id: 0x20 |
|||
part: 0x1991 |
|||
flash_algorithm: "STM32F042.yaml" |
|||
memory_map: |
|||
- Flash: |
|||
range: |
|||
start: 0x08000000 |
|||
end: 0x08010000 |
|||
is_boot_memory: true |
|||
is_testable: true |
|||
blocksize: 0x400 |
|||
sector_size: 0x400 |
|||
page_size: 0x400 |
|||
phrase_size: 0x400 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Ram: |
|||
range: |
|||
start: 0x20000000 |
|||
end: 0x20002000 |
|||
is_boot_memory: false |
|||
is_testable: true |
|||
core: "M0" |
@ -1,32 +0,0 @@ |
|||
name: "STM32F429xI" |
|||
# TODO: Manufacturer and Part are not correct yet. They are only needed for autodetection. |
|||
manufacturer: |
|||
cc: 0x00 |
|||
id: 0x20 |
|||
part: 0x000411 |
|||
flash_algorithm: "STM32F429xI.yaml" |
|||
memory_map: |
|||
- Flash: |
|||
range: |
|||
start: 0x08000000 |
|||
end: 0x08010000 |
|||
is_boot_memory: true |
|||
is_testable: true |
|||
blocksize: 0x4000 |
|||
sector_size: 0x4000 |
|||
page_size: 0x1000 |
|||
phrase_size: 0x1000 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
# TODO: There is many more Flash areas. |
|||
- Ram: |
|||
range: |
|||
start: 0x20000000 |
|||
end: 0x20030000 |
|||
is_boot_memory: false |
|||
is_testable: true |
|||
core: "M0" |
@ -1,46 +0,0 @@ |
|||
name: "nRF51822" |
|||
manufacturer: |
|||
cc: 0x02 |
|||
id: 0x44 |
|||
part: 0x000001 |
|||
flash_algorithm: "nRF51822.yaml" |
|||
memory_map: |
|||
- Flash: |
|||
range: |
|||
start: 0 |
|||
end: 0x40000 |
|||
is_boot_memory: true |
|||
is_testable: true |
|||
blocksize: 0x400 |
|||
sector_size: 0x400 |
|||
page_size: 0x400 |
|||
phrase_size: 0x400 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Flash: |
|||
range: |
|||
start: 0x10001000 |
|||
end: 0x10001100 |
|||
is_boot_memory: false |
|||
is_testable: false |
|||
blocksize: 0x100 |
|||
sector_size: 0x100 |
|||
page_size: 0x100 |
|||
phrase_size: 0x100 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Ram: |
|||
range: |
|||
start: 0x20000000 |
|||
end: 0x20004000 |
|||
is_boot_memory: false |
|||
is_testable: true |
|||
core: "M0" |
@ -1,46 +0,0 @@ |
|||
name: "nRF52832" |
|||
manufacturer: |
|||
cc: 0x02 |
|||
id: 0x44 |
|||
part: 0x000006 |
|||
flash_algorithm: "nRF52832.yaml" |
|||
memory_map: |
|||
- Flash: |
|||
range: |
|||
start: 0 |
|||
end: 0x80000 |
|||
is_boot_memory: true |
|||
is_testable: true |
|||
blocksize: 0x1000 |
|||
sector_size: 0x1000 |
|||
page_size: 0x1000 |
|||
phrase_size: 0x100 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Flash: |
|||
range: |
|||
start: 0x10001000 |
|||
end: 0x10001100 |
|||
is_boot_memory: false |
|||
is_testable: false |
|||
blocksize: 0x100 |
|||
sector_size: 0x100 |
|||
page_size: 0x100 |
|||
phrase_size: 0x100 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Ram: |
|||
range: |
|||
start: 0x20000000 |
|||
end: 0x20010000 |
|||
is_boot_memory: false |
|||
is_testable: true |
|||
core: "M4" |
@ -1,47 +0,0 @@ |
|||
name: "nRF52840" |
|||
# TODO: Manufacturer and Part are not correct yet. They are only needed for autodetection. |
|||
manufacturer: |
|||
cc: 0x02 |
|||
id: 0x44 |
|||
part: 0x000008 |
|||
flash_algorithm: "nRF52840.yaml" |
|||
memory_map: |
|||
- Flash: |
|||
range: |
|||
start: 0 |
|||
end: 0x100000 |
|||
is_boot_memory: true |
|||
is_testable: true |
|||
blocksize: 0x1000 |
|||
sector_size: 0x1000 |
|||
page_size: 0x1000 |
|||
phrase_size: 0x1000 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Flash: |
|||
range: |
|||
start: 0x10001000 |
|||
end: 0x10001100 |
|||
is_boot_memory: false |
|||
is_testable: false |
|||
blocksize: 0x100 |
|||
sector_size: 0x100 |
|||
page_size: 0x100 |
|||
phrase_size: 0x100 |
|||
erase_all_weight: 0.174 # TODO: Replace with proper constant later. |
|||
erase_sector_weight: 0.048 # TODO: Replace with proper constant later. |
|||
program_page_weight: 0.130 # TODO: Replace with proper constant later. |
|||
erased_byte_value: 0xFF |
|||
access: 0b00000101 # TODO: Replace with proper constant later. |
|||
are_erased_sectors_readable: true |
|||
- Ram: |
|||
range: |
|||
start: 0x20000000 |
|||
end: 0x20040000 |
|||
is_boot_memory: false |
|||
is_testable: true |
|||
core: "M4" |
@ -0,0 +1,283 @@ |
|||
use std::env; |
|||
use std::fs::{read_dir, read_to_string, File}; |
|||
use std::io::{self, Write}; |
|||
use std::path::{Path, PathBuf}; |
|||
|
|||
fn main() { |
|||
let out_dir = env::var("OUT_DIR").unwrap(); |
|||
let dest_path = Path::new(&out_dir).join("targets.rs"); |
|||
let mut f = File::create(&dest_path).unwrap(); |
|||
|
|||
// Determine all config files to parse.
|
|||
let mut files = vec![]; |
|||
visit_dirs(Path::new("targets"), &mut files).unwrap(); |
|||
|
|||
let mut configs: Vec<proc_macro2::TokenStream> = vec![]; |
|||
for file in files { |
|||
let string = read_to_string(&file).expect( |
|||
"Algorithm definition file could not be read. This is a bug. Please report it.", |
|||
); |
|||
|
|||
let yaml: Result<serde_yaml::Value, _> = serde_yaml::from_str(&string); |
|||
|
|||
match yaml { |
|||
Ok(chip) => { |
|||
let chip = extract_chip_family(&chip); |
|||
configs.push(chip); |
|||
} |
|||
Err(e) => { |
|||
panic!("Failed to parse target file: {:?} because:\n{}", file, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
let stream: String = format!( |
|||
"{}", |
|||
quote::quote! { |
|||
vec![ |
|||
#(#configs,)* |
|||
] |
|||
} |
|||
); |
|||
|
|||
f.write_all(stream.as_bytes()) |
|||
.expect("Writing build.rs output failed."); |
|||
} |
|||
|
|||
// one possible implementation of walking a directory only visiting files
|
|||
fn visit_dirs(dir: &Path, targets: &mut Vec<PathBuf>) -> io::Result<()> { |
|||
if dir.is_dir() { |
|||
for entry in read_dir(dir)? { |
|||
let entry = entry?; |
|||
let path = entry.path(); |
|||
if path.is_dir() { |
|||
visit_dirs(&path, targets)?; |
|||
} else { |
|||
targets.push(path.to_owned()); |
|||
} |
|||
} |
|||
} |
|||
Ok(()) |
|||
} |
|||
|
|||
/// Creates a properly quoted Option<T>` `TokenStream` from an `Option<T>`.
|
|||
fn quote_option<T: quote::ToTokens>(option: Option<T>) -> proc_macro2::TokenStream { |
|||
if let Some(value) = option { |
|||
quote::quote! { |
|||
Some(#value) |
|||
} |
|||
} else { |
|||
quote::quote! { |
|||
None |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// Extracts a list of algorithm token streams from a yaml value.
|
|||
fn extract_algorithms(chip: &serde_yaml::Value) -> Vec<proc_macro2::TokenStream> { |
|||
// Get an iterator over all the algorithms contained in the chip value obtained from the yaml file.
|
|||
let algorithm_iter = chip |
|||
.get("flash_algorithms") |
|||
.unwrap() |
|||
.as_sequence() |
|||
.unwrap() |
|||
.iter(); |
|||
|
|||
algorithm_iter |
|||
.map(|algorithm| { |
|||
// Extract all values and form them into a struct.
|
|||
let name = algorithm |
|||
.get("name") |
|||
.unwrap() |
|||
.as_str() |
|||
.unwrap() |
|||
.to_ascii_lowercase(); |
|||
let description = algorithm |
|||
.get("description") |
|||
.unwrap() |
|||
.as_str() |
|||
.unwrap() |
|||
.to_ascii_lowercase(); |
|||
let default = algorithm.get("default").unwrap().as_bool().unwrap(); |
|||
let instructions = algorithm |
|||
.get("instructions") |
|||
.unwrap() |
|||
.as_sequence() |
|||
.unwrap() |
|||
.iter() |
|||
.map(|v| v.as_u64().unwrap() as u32); |
|||
let pc_init = |
|||
quote_option(algorithm.get("pc_init").unwrap().as_u64().map(|v| v as u32)); |
|||
let pc_uninit = quote_option( |
|||
algorithm |
|||
.get("pc_uninit") |
|||
.unwrap() |
|||
.as_u64() |
|||
.map(|v| v as u32), |
|||
); |
|||
let pc_program_page = |
|||
algorithm.get("pc_program_page").unwrap().as_u64().unwrap() as u32; |
|||
let pc_erase_sector = |
|||
algorithm.get("pc_erase_sector").unwrap().as_u64().unwrap() as u32; |
|||
let pc_erase_all = quote_option( |
|||
algorithm |
|||
.get("pc_erase_all") |
|||
.unwrap() |
|||
.as_u64() |
|||
.map(|v| v as u32), |
|||
); |
|||
let data_section_offset = algorithm |
|||
.get("data_section_offset") |
|||
.unwrap() |
|||
.as_u64() |
|||
.unwrap() as u32; |
|||
|
|||
// Quote the algorithm struct.
|
|||
let algorithm = quote::quote! { |
|||
RawFlashAlgorithm { |
|||
name: #name.to_owned(), |
|||
description: #description.to_owned(), |
|||
default: #default, |
|||
instructions: vec![ |
|||
#(#instructions,)* |
|||
], |
|||
pc_init: #pc_init, |
|||
pc_uninit: #pc_uninit, |
|||
pc_program_page: #pc_program_page, |
|||
pc_erase_sector: #pc_erase_sector, |
|||
pc_erase_all: #pc_erase_all, |
|||
data_section_offset: #data_section_offset, |
|||
} |
|||
}; |
|||
|
|||
algorithm |
|||
}) |
|||
.collect() |
|||
} |
|||
|
|||
/// Extracts a list of algorithm token streams from a yaml value.
|
|||
fn extract_memory_map(chip: &serde_yaml::Value) -> Vec<proc_macro2::TokenStream> { |
|||
// Get an iterator over all the algorithms contained in the chip value obtained from the yaml file.
|
|||
let memory_map_iter = chip |
|||
.get("memory_map") |
|||
.unwrap() |
|||
.as_sequence() |
|||
.unwrap() |
|||
.iter(); |
|||
|
|||
memory_map_iter |
|||
.filter_map(|memory_region| { |
|||
// Check if it's a RAM region. If yes, parse it into a TokenStream.
|
|||
memory_region |
|||
.get("Ram") |
|||
.map(|region| { |
|||
let range = region.get("range").unwrap(); |
|||
let start = range.get("start").unwrap().as_u64().unwrap() as u32; |
|||
let end = range.get("end").unwrap().as_u64().unwrap() as u32; |
|||
let is_boot_memory = region.get("is_boot_memory").unwrap().as_bool().unwrap(); |
|||
|
|||
quote::quote! { |
|||
MemoryRegion::Ram(RamRegion { |
|||
range: #start..#end, |
|||
is_boot_memory: #is_boot_memory, |
|||
}) |
|||
} |
|||
}) |
|||
.or_else(|| { |
|||
memory_region.get("Flash").map(|region| { |
|||
let range = region.get("range").unwrap(); |
|||
let start = range.get("start").unwrap().as_u64().unwrap() as u32; |
|||
let end = range.get("end").unwrap().as_u64().unwrap() as u32; |
|||
let is_boot_memory = |
|||
region.get("is_boot_memory").unwrap().as_bool().unwrap(); |
|||
let sector_size = |
|||
region.get("sector_size").unwrap().as_u64().unwrap() as u32; |
|||
let page_size = region.get("page_size").unwrap().as_u64().unwrap() as u32; |
|||
let erased_byte_value = |
|||
region.get("erased_byte_value").unwrap().as_u64().unwrap() as u8; |
|||
|
|||
quote::quote! { |
|||
MemoryRegion::Flash(FlashRegion { |
|||
range: #start..#end, |
|||
is_boot_memory: #is_boot_memory, |
|||
sector_size: #sector_size, |
|||
page_size: #page_size, |
|||
erased_byte_value: #erased_byte_value, |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
}) |
|||
.collect() |
|||
} |
|||
|
|||
/// Extracts a list of algorithm token streams from a yaml value.
|
|||
fn extract_variants(chip_family: &serde_yaml::Value) -> Vec<proc_macro2::TokenStream> { |
|||
// Get an iterator over all the algorithms contained in the chip value obtained from the yaml file.
|
|||
let variants_iter = chip_family |
|||
.get("variants") |
|||
.unwrap() |
|||
.as_sequence() |
|||
.unwrap() |
|||
.iter(); |
|||
|
|||
variants_iter |
|||
.map(|variant| { |
|||
let name = variant.get("name").unwrap().as_str().unwrap(); |
|||
|
|||
// Extract all the memory regions into a Vec of TookenStreams.
|
|||
let memory_map = extract_memory_map(&variant); |
|||
|
|||
quote::quote! { |
|||
Chip { |
|||
name: #name.to_owned(), |
|||
memory_map: vec![ |
|||
#(#memory_map,)* |
|||
], |
|||
} |
|||
} |
|||
}) |
|||
.collect() |
|||
} |
|||
|
|||
/// Extracts a chip family token stream from a yaml value.
|
|||
fn extract_chip_family(chip: &serde_yaml::Value) -> proc_macro2::TokenStream { |
|||
// Extract all the algorithms into a Vec of TokenStreams.
|
|||
let algorithms = extract_algorithms(&chip); |
|||
|
|||
// Extract all the available variants into a Vec of TokenStreams.
|
|||
let variants = extract_variants(&chip); |
|||
|
|||
let name = chip |
|||
.get("name") |
|||
.unwrap() |
|||
.as_str() |
|||
.unwrap() |
|||
.to_ascii_lowercase(); |
|||
let manufacturer = quote_option(chip.get("manufacturer").map(|v| v.as_str())); |
|||
let part = quote_option(chip.get("part").map(|v| v.as_str())); |
|||
let core = chip |
|||
.get("core") |
|||
.unwrap() |
|||
.as_str() |
|||
.unwrap() |
|||
.to_ascii_lowercase(); |
|||
|
|||
// Quote the chip.
|
|||
let chip_family = quote::quote! { |
|||
ChipFamily { |
|||
name: #name.to_owned(), |
|||
manufacturer: #manufacturer, |
|||
part: #part, |
|||
flash_algorithms: vec![ |
|||
#(#algorithms,)* |
|||
], |
|||
variants: vec![ |
|||
#(#variants,)* |
|||
], |
|||
core: #core.to_owned(), |
|||
} |
|||
}; |
|||
|
|||
chip_family |
|||
} |
@ -1,20 +0,0 @@ |
|||
pub mod m0; |
|||
pub mod m33; |
|||
pub mod m4; |
|||
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)] |
|||
pub struct CortexDump { |
|||
pub regs: [u32; 16], |
|||
stack_addr: u32, |
|||
stack: Vec<u8>, |
|||
} |
|||
|
|||
impl CortexDump { |
|||
pub fn new(stack_addr: u32, stack: Vec<u8>) -> CortexDump { |
|||
CortexDump { |
|||
regs: [0u32; 16], |
|||
stack_addr, |
|||
stack, |
|||
} |
|||
} |
|||
} |
@ -1,126 +0,0 @@ |
|||
pub mod cores; |
|||
|
|||
use std::collections::HashMap; |
|||
use std::fs::File; |
|||
use std::fs::{self, DirEntry}; |
|||
use std::io; |
|||
use std::io::BufReader; |
|||
use std::path::Path; |
|||
|
|||
use crate::probe::flash::flasher::FlashAlgorithm; |
|||
use crate::target::Core; |
|||
use crate::target::Target; |
|||
|
|||
pub fn get_target(name: impl AsRef<str>) -> Option<Target> { |
|||
let mut map: HashMap<String, Target> = HashMap::new(); |
|||
|
|||
load_targets( |
|||
dirs::home_dir() |
|||
.map(|home| home.join(".config/probe-rs/targets")) |
|||
.as_ref() |
|||
.map(|path| path.as_path()), |
|||
&mut |