loadstone_config/
memory.rs

1use serde::{Deserialize, Serialize};
2
3use crate::port::Port;
4
5/// Helper macro for kilobytes in any type (simply multiplies by 1024).
6#[macro_export(local_inner_macros)]
7macro_rules! KB {
8    ($val:expr) => {
9        $val * 1024
10    };
11}
12
13/// Firmware bank. Meant to store firmware images, but can also store other
14/// kinds of data if the application requires it.
15#[derive(Default, Debug, Clone, Serialize, Deserialize)]
16pub struct Bank {
17    /// Bank address in flash memory.
18    pub start_address: u32,
19    /// Bank size in kilobytes.
20    pub size_kb: u32,
21}
22
23impl Bank {
24    /// Address immediately after the end of this bank.
25    pub fn end_address(&self) -> u32 { self.start_address + self.size_kb * 1024 }
26}
27
28/// Memory map for an internal (MCU) flash. This must contain the loadstone bootloader itself
29/// and a bootable bank.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct InternalMemoryMap {
32    pub bootloader_location: u32,
33    pub bootloader_length_kb: u32,
34    pub banks: Vec<Bank>,
35    pub bootable_index: Option<usize>,
36}
37
38/// Memory map for an optional external flash chip. This cannot contain a bootable
39/// bank, but it may contain a golden bank.
40#[derive(Debug, Clone, Default, Serialize, Deserialize)]
41pub struct ExternalMemoryMap {
42    pub banks: Vec<Bank>,
43}
44
45impl Default for InternalMemoryMap {
46    fn default() -> Self {
47        Self {
48            bootloader_location: 0,
49            bootloader_length_kb: 64,
50            banks: Vec::new(),
51            bootable_index: None,
52        }
53    }
54}
55
56/// Configuration struct that fully defines the memory layout managed by loadstone,
57/// including the mandatory internal memory map, an optional external memory map,
58/// and golden/bookt bank information.
59#[derive(Default, Clone, Serialize, Deserialize, Debug)]
60pub struct MemoryConfiguration {
61    pub internal_memory_map: InternalMemoryMap,
62    pub external_memory_map: ExternalMemoryMap,
63    pub external_flash: Option<FlashChip>,
64    pub golden_index: Option<usize>,
65}
66
67impl MemoryConfiguration {
68    /// Address from where the application image will boot, coinciding
69    /// with the start address of the bootable bank.
70    pub fn bootable_address(&self) -> Option<u32> {
71        Some(
72            self.internal_memory_map
73                .banks
74                .get(self.internal_memory_map.bootable_index?)?
75                .start_address,
76        )
77    }
78}
79
80/// Definition of a flash chip's hardware.
81#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
82pub struct FlashChip {
83    /// Tag to identify the hardware.
84    pub name: String,
85    /// Whether the flash chip is internal (MCU flash) or external (QSPI, etc)
86    pub internal: bool,
87    /// Start address of the user writable area of flash.
88    pub start: u32,
89    /// End address of the user writable area of flash.
90    pub end: u32,
91    /// Size of the smallest erasable region
92    pub region_size: u32,
93}
94
95/// The MCU flash available for a port. All ports must have exactly one
96/// main MCU flash for Loadstone to correctly function.
97pub fn internal_flash(port: &Port) -> FlashChip {
98    match port {
99        Port::Stm32F412 => FlashChip {
100            name: "STM32F412 MCU Flash".to_owned(),
101            internal: true,
102            start: 0x0800_0000,
103            end: 0x0810_0000,
104            region_size: KB!(16),
105        },
106        Port::Wgm160P => FlashChip {
107            name: "EFM32GG11 MCU Flash".to_owned(),
108            internal: true,
109            start: 0x0000_0000,
110            end: 512 * KB!(4),
111            region_size: KB!(4),
112        },
113    }
114}
115
116/// Returns an iterator over all the flash chips compatible with the current
117/// port (a driver exists for them).
118pub fn external_flash(port: &Port) -> impl Iterator<Item = FlashChip> {
119    match port {
120        Port::Stm32F412 => Some(FlashChip {
121            name: "Micron n25q128a".to_owned(),
122            internal: false,
123            start: 0x0000_0000,
124            end: 0x00FF_FFFF,
125            region_size: KB!(4),
126        })
127        .into_iter(),
128        Port::Wgm160P => None.into_iter(),
129    }
130}