Skip to content
Snippets Groups Projects
Select Git revision
  • 8c4a3c34930f3615624be3f765e4da68737bdcef
  • student default protected
2 results

bare0.rs

Blame
  • Forked from Per Lindgren / e7020e_2019
    Source project has a limited visibility.
    bare0.rs 3.48 KiB
    //! bare0.rs
    //!
    //! Simple bare metal application
    //! What it covers:
    //! - constants
    //! - global (static) variables
    //! - checked vs. wrapping arithmetics
    //! - safe and unsafe code
    //! - making a safe API
    
    // build without the Rust standard library
    #![no_std]
    // no standard main, we declare main using [entry]
    #![no_main]
    
    extern crate panic_halt;
    
    // Minimal runtime / startup for Cortex-M microcontrollers
    use cortex_m_rt::entry;
    
    use core::cell::UnsafeCell;
    struct U32 {
        data: UnsafeCell<u32>,
    }
    
    // a constant (cannot be changed at run-time)
    const X_INIT: u32 = 0xffffffff;
    
    // global mutabale variables (changed using unsafe code)
    static X: U32 = U32 {
        data: UnsafeCell::new(X_INIT),
    };
    static Y: U32 = U32 {
        data: UnsafeCell::new(0),
    };
    
    unsafe impl Sync for U32 {}
    
    #[entry]
    fn main() -> ! {
        // local mutabale variable (changed in safe code)
        let mut x = read_u32(&X);
        
        loop {
            x = x.wrapping_add(1); // <- place breakpoint here (3)
                write_u32(&X, read_u32(&X).wrapping_add(1) );
                write_u32(&Y, read_u32(&X));
                assert!(x == read_u32(&X) && read_u32(&X) == read_u32(&Y) );
        }
    }
    
    fn read_u32(uint: &U32) -> u32 {
        return unsafe{ *uint.data.get()};
    }
    
    fn write_u32(write_to: &U32, value: u32) {
        unsafe{ *write_to.data.get() = value };
    }
    
    // 0. Compile/build the example in debug (dev) mode.
    //
    //    > cargo build --example bare0
    //    (or use the vscode build task)
    //
    // 1. Run the program in the debugger, let the program run for a while and
    //    then press pause. Look in the (Local -vscode) Variables view what do you find.
    //
    //    *** x: 962669 ***
    //
    //    In the Expressions (WATCH -vscode) view add X and Y
    //    what do you find
    //    
    //    *** Watch X and Y didn't work, added watch to 'bare0::X::h2583a8be644794f3' and 'bare0::Y::hef3986a5288bec08' to be able to read the variables
    //          X  = 962669, Y = 962668 ***
    //
    //    Step through one complete iteration of the loop
    //    and see how the (Local) Variables are updated
    //    can you foresee what will eventually happen?
    //
    // 	  *** x is incremented. Eventually x will wrap. ***
    //
    //    Commit your answers (bare0_1)
    //
    // 2. Alter the constant X_INIT so that `x += 1` directly causes `x` to wrap
    // 	  what happens when `x` wraps
    //
    //    ** We end up in the panic handler **
    //
    //    Commit your answers (bare0_2)
    //
    // 3. Place a breakpoint at `x += 1`
    //
    //    Change (both) += opertions to use wrapping_add
    //    load and run the progam, what happens
    //    ** x value wraps around u32 max 4294967295 and get value 0**
    //
    //    Now continue exectution, what happens
    //    ** X,Y and x is incremented and wraps around max **
    //
    //    Commit your answers (bare0_3)
    //
    //    (If the program did not succeed back to the breakpoint
    //    you have some fault in the program and go back to 3.)
    //
    // 4. Change the asserion to `assert!(x == X && X == Y + 1)`, what happens?
    //
    //    ** The assert fails and we go into panic handler **
    //
    //    Commit your answers (bare0_4)
    //
    // 5. Remove the assertion and implement "safe" functions for
    //    reading and writing X and Y
    //    e.g. read_x, read_y, write_x, write_y
    //
    //    Rewrite the program to use ONLY "safe" code besides the
    //    read/write functions (which are internally "unsafe")
    //
    //    Commit your solution (bare0_5)
    //
    // 6. *Optional
    //    Implement a read_u32/write_u32, taking a reference to a
    //    "static" variable
    //
    //    Rewrite the program to use this abstraction instead of "read_x", etc.
    //
    //    Commit your solution (bare0_6)
    //