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