diff --git a/README.md b/README.md index d1bb158f30fdafbeb7f3dcefa32712061b4d6f85..3a2449d0b16db9d655e68748bcafeeeab1c15c2e 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ The autorun script broken down: The `gdb` tool allows to program and debug the target, e.g., set breakpoints, inspect memory, etc. `gdb` can be highly automated through scripting. In the `DEBUG` console you can interact directly with `gdb`. The integration between the console and `vscode` is rudimentary. The `vscode` `Native Debug` view is in general not notified/updated (by stepping/continuing through `vscode` icons/shortcuts the view gets in synch). Even so, manual interaction with `gdb` can be very useful, an example is to restart the program without reloading it (there is no shortcut/icon for this functionality in the `Native Debug` extension). Enter in the `DEBUG` console: -> source() r +> source r or simply: @@ -132,6 +132,7 @@ In the `examples` folder you find: ## bare0.rs This is a simple bare metal applicaiton: + ``` rust //! bare0.rs //! Simple bare metal application @@ -190,7 +191,7 @@ MEMORY } ``` -## Compilng and Debugging +## Compilng and Inspecting the binary First compile the example either through the `vscode` Tasks (Ctrl-Shift-B) or using the console: @@ -361,6 +362,7 @@ We can compile the `bare0` application in -- release mode instead. ``` The resulting user main now looks like this. + ``` rust 8000476 <_ZN5bare04main17h1039292c3948856dE.llvm.453292E5>: loop { @@ -398,7 +400,9 @@ fn main() { 8000486: defe udf #254 ; 0xfe ``` -So the Rust compiler is able to figure out that the assertion will be violated and merely calls the `panic` routine. So be aware, the Rust compiler is extremely aggressive in optimizing your code. On a side note the semantics of integer additions is slightly different between `dev` (normal/non-optimized) and `--release` (optimized) builds. In `dev` build the arithmics are checked and overflows result in a `panic`, in `--release`, arithmetics are unchecked (for performance reasons), and oveflows wrap (under two's complement semantics). To avoid ambiguity, you may use methods defined in the std/core library: +So the Rust compiler is able to figure out that the assertion will be violated and merely calls the `panic` routine. So be aware, the Rust compiler is extremely aggressive in optimizing your code. + +On a side note: the semantics of integer additions is slightly different between `dev` (normal/non-optimized) and `--release` (optimized) builds. In `dev` build the arithmics are checked and overflows result in a `panic`, in `--release`, arithmetics are unchecked (for performance reasons), and oveflows wrap (under two's complement semantics). To avoid ambiguity, you may use methods defined in the std/core library: - `wrapping_add`, `wrapping_sub`,returns the straight two’s complement result, - `saturating_add`, `saturating_sub`, returns the largest/smallest value (as appropriate) of the type when overflow occurs, @@ -407,9 +411,61 @@ So the Rust compiler is able to figure out that the assertion will be violated a Those methods never `panic`, but code might be verbose, e.g., expressing `x - y + z` under wrapping arithmetics equates to `x.wrapping_sub(y).wrapping_add(z)`. To this end you may choose to use the [Wrapping](https://doc.rust-lang.org/std/num/struct.Wrapping.html) type. +## Debugging the `bare0` example +Openocd should run in a console: + +``` shell +> openocd -f interface/stlink.cfg -f target/stm32f4x.cfg +``` +For this example let us run `gdb` from console: +``` shell +> arm-none-eabi-gdb target/thumbv7em-none-eabihf/debug/examples/bare0 +... +(gdb) target remote :3333 +... +(gdb) monitor reset init +Loading section .vector_table, size 0x400 lma 0x8000000 +Loading section .text, size 0x52e lma 0x8000400 +Loading section .rodata, size 0xb8 lma 0x8000930 +Loading section .data, size 0x4 lma 0x80009e8 +Start address 0x8000400, load size 2538 +Transfer rate: 4 KB/sec, 634 bytes/write. + +(gdb) si +0x08000402 335 unsafe extern "C" fn reset_handler() -> ! { +``` + +- `target remote :3333`, connects `gdb` to the target. +- `monitor reset init`, resets the MCU and sets the clock to 64MHz. +- `load`, loads the `bare0` (`elf`) binary to the target. +- `si`, steps one machine (assembly) instruction. + +We see now that we are in the `reset_handler` (defined in the `cortex-m-rt` crate). + +``` text +(gdb) b bare0::main +Breakpoint 1 at 0x8000494: file examples/bare0.rs, line 19. +(gdb) c +Continuing. +Note: automatically using hardware breakpoints for read-only addresses. + +Breakpoint 1, bare0::main () at examples/bare0.rs:19 +warning: Source file is more recent than executable. +19 let mut x = unsafe { X }; +(gdb) p bare0::X +$1 = 10 +(gdb) p bare0::Y +$2 = 0 +(gdb) p b +No symbol 'b' in current context +(gdb) p x +No symbol 'x' in current context +(gdb) + +``` # License Licensed under either of diff --git a/examples/bare0.rs b/examples/bare0.rs index d099aba0a06751384e6085bc595f555c5341caf4..fdb45a28df683bc4b3cdffb70910d37397f8bcbc 100644 --- a/examples/bare0.rs +++ b/examples/bare0.rs @@ -21,7 +21,7 @@ fn main() { loop { x += 1; unsafe { - //X += 1; + X += 1; Y = X; assert!(x == X && X == Y); }