flp_framework/lib.rs
1//! # The `flp_framework` Crate
2//!
3//! This module contains the Rust binding for the Floorplan compiler
4//! to generate address types in terms of. These interfaces support
5//! basic arithmetic operations, address comparisons, pretty printing,
6//! and direct memory access.
7//!
8//! For information on acquiring the Floorplan compiler itself,
9//! go see the [GitHub project here][github-project].
10//!
11//! [github-project]: https://github.com/RedlineResearch/floorplan
12
13#![allow(dead_code)]
14use std::mem;
15use std::marker::Sized;
16
17/// The `Address` trait exposes all the basic operations (arithmetic, etc.) that
18/// can be performed on an address of a Floorplan type. These are all intrinsically
19/// unsafe operations, and intended for use by developers of the Floorplan compiler, or other developers extending the capability of Floorplan. Directly accessing these
20/// trait functions from memory management code is ill-advised, and unsupported.
21pub trait Address: PartialOrd + Copy + Sized {
22
23 /// An address can be constructed from a `usize` value.
24 ///
25 /// *Accessing this function directly from [memory management code is
26 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
27 #[inline(always)] fn as_usize(&self) -> usize;
28
29 /// An address can be decronstructed into a raw `usize` value.
30 ///
31 /// *Accessing this function directly from [memory management code is
32 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
33 #[inline(always)] fn from_usize(usize) -> Self;
34
35 /// Does this address appear valid accoring to the layout / address type?
36 ///
37 /// *Accessing this function directly from [memory management code is
38 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
39 fn verify(self) -> bool;
40
41 /// Add some number of `bytes` to this address, producing an address of type `A`.
42 ///
43 /// *Accessing this function directly from [memory management code is
44 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
45 #[inline(always)] fn plus<A : Address>(&self, bytes: usize) -> A { Address::from_usize(self.as_usize() + bytes) }
46
47 /// Subtract some number of `bytes` from this address, producing an address of type `A`.
48 ///
49 /// *Accessing this function directly from [memory management code is
50 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
51 #[allow(dead_code)]
52 #[inline(always)] fn sub<A : Address>(&self, bytes: usize) -> A { Address::from_usize(self.as_usize() - bytes) }
53
54 /// Offset this `&self` address some number of instances of type `T`, producing an address of
55 /// type `A`.
56 ///
57 /// *Accessing this function directly from [memory management code is
58 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
59 #[inline(always)] fn offset<T, A : Address>(&self, offset: usize) -> A {
60 Address::from_usize(self.as_usize() + (mem::size_of::<T>() as usize) * offset)
61 }
62
63 /// Read a single instance of a value of type `T` from this address.
64 ///
65 /// *Accessing this function directly from [memory management code is
66 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
67 #[inline(always)] fn load<T: Copy> (&self) -> T { unsafe { *(self.as_usize() as *mut T) } }
68
69 /// Store a single instance `value` into the memory at this address.
70 ///
71 /// *Accessing this function directly from [memory management code is
72 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
73 #[inline(always)] fn store<T> (&self, value: T) { unsafe { *(self.as_usize() as *mut T) = value; } }
74
75 /// Is the value of this address equivalent to the (universal) null value?
76 ///
77 /// *Accessing this function directly from [memory management code is
78 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
79 #[inline(always)] fn is_zero(&self) -> bool { self.as_usize() == 0 }
80
81 /// Align this pointer up (increasing value) to the nearest address with a value
82 /// aligned to `align` bytes. For example the following properties hold:
83 ///
84 /// ```rust
85 /// # use flp_framework::*;
86 /// let a = WordAddr::from_usize(0xff);
87 /// assert!(a.align_up::<WordAddr>(2).as_usize() == 0x100);
88 /// assert!(a.align_up::<WordAddr>(16).as_usize() == 0x100);
89 /// assert!(a.align_up::<WordAddr>(512).as_usize() == 0x200);
90 /// let b = WordAddr::from_usize(0x100);
91 /// assert!(b.align_up::<WordAddr>(256).as_usize() == 0x100);
92 /// ```
93 ///
94 /// *Accessing this function directly from [memory management code is
95 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
96 #[inline(always)] fn align_up<A : Address>(&self, align: usize) -> A {
97 Address::from_usize((self.as_usize() + align - 1) & !(align - 1))
98 }
99
100 /// Is the value of this address greater than or equal to the value of the given address?
101 ///
102 /// *Accessing this function directly from [memory management code is
103 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
104 #[inline(always)] fn gte<A: Address>(&self, addr: A) -> bool { self.as_usize() >= addr.as_usize() }
105
106 /// Is the value of this address greater than the value of the given address?
107 ///
108 /// *Accessing this function directly from [memory management code is
109 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
110 #[inline(always)] fn greater<A: Address>(&self, addr: A) -> bool { self.as_usize() > addr.as_usize() }
111
112 /// Is the value of this address less than or equal to the value of the given address?
113 ///
114 /// *Accessing this function directly from [memory management code is
115 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
116 #[inline(always)] fn lte<A: Address>(&self, addr: A) -> bool { self.as_usize() <= addr.as_usize() }
117
118 /// Is the value of this address less than the value of the given address?
119 ///
120 /// *Accessing this function directly from [memory management code is
121 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
122 #[inline(always)] fn less<A: Address>(&self, addr: A) -> bool { self.as_usize() < addr.as_usize() }
123
124 /// Is the value of this address exactly aligned to the given alignment?
125 ///
126 /// ```rust
127 /// # use flp_framework::*;
128 /// assert!(WordAddr::from_usize(0xFF).is_aligned_to(2) == false);
129 /// assert!(WordAddr::from_usize(0xF0).is_aligned_to(2) == true);
130 /// ```
131 ///
132 /// *Accessing this function directly from [memory management code is
133 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
134 #[inline(always)] fn is_aligned_to(&self, align: usize) -> bool { self.as_usize() % align == 0 }
135
136 /// Construct an address from an immutable constant Rust pointer type.
137 ///
138 /// *Accessing this function directly from [memory management code is
139 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
140 #[inline(always)] fn from_ptr<T> (ptr: *const T) -> Self { unsafe {Address::from_usize(mem::transmute(ptr))} }
141
142 /// Deconstruct an address into an immutable constant Rust pointer type.
143 ///
144 /// *Accessing this function directly from [memory management code is
145 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
146 #[inline(always)] fn to_ptr<T> (&self) -> *const T { unsafe {mem::transmute(self.as_usize())} }
147
148 /// Construct an address from a **mutable** constant Rust pointer type.
149 ///
150 /// *Accessing this function directly from [memory management code is
151 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
152 #[inline(always)] fn to_ptr_mut<T> (&self) -> *mut T { unsafe {mem::transmute(self.as_usize())} }
153
154 /// Construct the (universal) null address.
155 ///
156 /// *Accessing this function directly from [memory management code is
157 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
158 #[inline(always)] fn zero() -> Self { Address::from_usize(0) }
159
160 /// Compute the number of bytes before this address (exclusive) and after
161 /// `another` address (inclusive).
162 ///
163 /// ```rust
164 /// # use flp_framework::*;
165 /// let wa1 : WordAddr = WordAddr::from_usize(0xFF);
166 /// let wa2 : WordAddr = WordAddr::zero(); // The null address
167 /// assert!(wa1.diff(wa2) == 0xFF)
168 /// ```
169 ///
170 /// *Accessing this function directly from [memory management code is
171 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
172 #[inline(always)] fn diff<A : Address>(&self, another: A) -> usize {
173 debug_assert!(self.as_usize() >= another.as_usize(), "for a.diff(b), a needs to be larger than b");
174 self.as_usize() - another.as_usize()
175 }
176
177 /// Set the first `length` bytes pointed to by this address to the byte `val`.
178 ///
179 /// *Accessing this function directly from [memory management code is
180 /// unsupported](https://redlineresearch.github.io/floorplan/unsupported-operations)*
181 fn memset(&self, val: u8, length: usize) {
182 let mut cur : *mut u8 = self.as_usize() as *mut u8;
183 for _ in 0..length {
184 unsafe {
185 *cur = val;
186 cur = cur.offset(1);
187 }
188 }
189 }
190}
191
192#[allow(unused_macros)]
193#[macro_export]
194macro_rules! deriveAddrSized {
195 ( $addr:ident, $addrSized:ident ) => {
196
197 impl $addrSized {
198 /// Construct a sized address from the given unsized address type.
199 pub fn from_addr(ptr : $addr, size : usize) -> $addrSized {
200 $addrSized {
201 start: ptr,
202 end: ptr.plus(size)
203 }
204 }
205
206 /// Deconstruct a sized address into just its unsized type.
207 pub fn to_addr(&self) -> $addr { self.start }
208
209 /// Construct a void address pointing to the first byte of memory
210 /// past the end of this sized type.
211 pub fn end(&self) -> VoidAddr { self.end }
212 }
213
214 };
215}
216
217/// Derives just the necessary pieces of code to satisfy the Rust type
218/// checker when it comes to the default implementation of an instance
219/// of a type supporting the `Address` trait. This includes address comparisons
220/// and printf formatting support.
221#[macro_export]
222macro_rules! deriveAddrReqs {
223 ( $addr:ident ) => {
224
225 impl Ord for $addr {
226 /// Address ordinality delegates to usize ordinality.
227 #[inline(always)] fn cmp(&self, other: &$addr) -> cmp::Ordering {
228 self.as_usize().cmp(& other.as_usize())
229 }
230 }
231
232 impl PartialOrd for $addr {
233 /// Address ordinality delegates to usize ordinality.
234 #[inline(always)] fn partial_cmp(&self, other: &$addr) -> Option<cmp::Ordering> {
235 Some(self.as_usize().cmp(& other.as_usize()))
236 }
237 }
238
239 impl PartialEq for $addr {
240 /// Address equality delegates to `usize` equality
241 #[inline(always)] fn eq(&self, other: &$addr) -> bool {
242 self.as_usize() == other.as_usize()
243 }
244 /// Address inequality delegates to `usize` equality
245 #[inline(always)] fn ne(&self, other: &$addr) -> bool {
246 self.as_usize() != other.as_usize()
247 }
248 }
249
250 impl fmt::UpperHex for $addr {
251 /// Format this address as an alphanumeric hex string.
252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 write!(f, "{:X}", self.as_usize())
254 }
255 }
256
257 impl fmt::Display for $addr {
258 /// Display this address as a prettified alphanumeric hex string.
259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 write!(f, "0x{:X}", self.as_usize())
261 }
262 }
263
264 impl fmt::Debug for $addr {
265 /// Display this address as a prettified alphanumeric hex string for debugging.
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267 write!(f, "0x{:X}", self.as_usize())
268 }
269 }
270 impl fmt::Pointer for $addr {
271 /// Display this address as a prettified alphanumeric hex string.
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 write!(f, "0x{:X}", self.as_usize())
274 }
275 }
276 };
277}
278
279/// Derives just the necessary pieces of code for the `Address` trait
280/// so that all functions have a definition. This formulates the most
281/// basic implementation of an address type to get functioning code.
282#[macro_export]
283macro_rules! deriveAddrTrait {
284 ( $addr:ident, $align:expr ) => {
285 impl Address for $addr {
286
287 /// Construct an address of this type from a raw `usize` value.
288 fn from_usize(val : usize) -> $addr { $addr(val) }
289
290 /// Deconstruct this address into a raw `usize` value.
291 fn as_usize(&self) -> usize { self.0 }
292
293 /// Default verification of proper address alignment.
294 fn verify(self) -> bool { self.0 % ($align) == 0 }
295
296 }
297
298 };
299}
300
301/// Derive all the boilerplate traits necessary to make a Floorplan-generated
302/// address type support all the necessary basic operations. These operations include:
303///
304/// - Arithmetic operations
305/// - Comparison operations
306/// - Alignment verification
307/// - Construction and deconstruction from a `usize`
308/// - Pretty printing and other formatters
309///
310/// This macro is the main entrypoint for all Floorplan types, and will
311/// suffice in general for any new address types.
312#[macro_export]
313macro_rules! deriveAddr {
314 ( $addr:ident, $align:expr ) => {
315 deriveAddrReqs!($addr);
316 deriveAddrTrait!($addr, $align);
317 };
318}
319
320pub mod address;
321pub use address::*;
322