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}