Skip to main content

pcode_types/
space.rs

1//! Memory spaces: uniformly-addressed regions that values live in.
2//!
3//! Spaces model distinct address ranges — for example RAM, ROM, and the
4//! processor register file are each their own space. The basic unit for a space
5//! is a byte; this can be changed by setting the space's *word size* (bytes per
6//! addressable unit) and *address size* (bytes needed to hold a pointer into
7//! the space).
8
9use std::fmt::Display;
10
11use jstd::{Identifier, registry::Identified, registry::Registry};
12use serde::{Deserialize, Serialize};
13
14/// A stable, context-unique identifier for a [`Space`].
15#[derive(Identifier)]
16pub struct SpaceId(usize);
17
18/// The const space is used for constant values such as immediate values
19pub const SPACE_CONST: SpaceId = SpaceId(0);
20
21/// The broad category of a memory space.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub enum SpaceType {
24    /// Readable and writable memory (e.g. heap, stack, data segments).
25    Ram,
26    /// Read-only memory (e.g. flash, ROM).
27    Rom,
28    /// Processor registers.
29    Register,
30    /// Per-instruction temporary storage used by raw p-code operations.
31    Unique,
32}
33
34pub type SpaceRef<'ctx> = Identified<SpaceId, &'ctx Space>;
35
36/// A named, uniformly-addressed memory region.
37///
38/// Each space has a *word size* (bytes per addressable unit) and an *address
39/// size* (bytes needed to hold a pointer into the space).  For most RAM spaces
40/// these are 1 and 8 respectively on a 64-bit architecture.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct Space {
43    /// Optional human-readable name (e.g. `"ram"`, `"register"`).
44    pub name: Option<Box<str>>,
45
46    /// The size of a memory location with a single address in this space, in bytes.
47    pub word_size: usize,
48
49    /// The size of addresses in this space, in bytes.
50    pub addr_size: usize,
51
52    /// The kind of this space.
53    pub ty: SpaceType,
54}
55
56/// Anything that can resolve a [`SpaceId`] back to its [`Space`].
57///
58/// Implemented by a consumer's own context types so that [`Space::from_id`]
59/// works against them directly.
60pub trait SpaceStore {
61    /// The space table this store holds.
62    fn spaces(&self) -> &Registry<SpaceId, Space>;
63}
64
65impl Space {
66    /// Creates a new RAM space with the given name (or anonymous if `None`),
67    /// word size, and address size.
68    pub fn new(name: Option<&str>, word_size: usize, addr_size: usize) -> Self {
69        Self {
70            name: name.map(Box::from),
71            word_size,
72            addr_size,
73            ty: SpaceType::Ram,
74        }
75    }
76
77    /// Creates the unique space used for instruction-local p-code temporaries.
78    pub fn unique(addr_size: usize) -> Self {
79        Self {
80            name: Some(Box::from("unique")),
81            word_size: 1,
82            addr_size,
83            ty: SpaceType::Unique,
84        }
85    }
86
87    /// Builds a space reference from an id, against any [`SpaceStore`].
88    pub fn from_id<S: SpaceStore + ?Sized>(src: &S, id: SpaceId) -> SpaceRef<'_> {
89        SpaceRef::new(id, &src.spaces()[id])
90    }
91}
92
93impl Display for Space {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        if let Some(name) = &self.name {
96            write!(f, "{}", name)
97        } else {
98            write!(f, "space")
99        }
100    }
101}