# This is a simple guide to using AVR-GDB with simavr First of all, you can use the [Makefile](../Makefile) in the directory above. But for the competeness sake, I'll list commands ## Running simulation QEMU: I don't personally prefer it, but here is a breakdown: ```sh qemu-system-avr -M arduino-uno -bios -nographic -s -S ``` * `-M`: machine to use, shorthand for `--machine`. Self-explanatory. * `-bios`: the thing that you would flash onto your arduino. Note that this is not a hex file, this must be an elf file, the one you get out of `ld`. * `-nographic`: this should be default to be honest * `-s`: shorthand for `-gdb tcp::1234`. Enables GDB debugging * `-S`: suspend execution and wait for debugger to connect. This should be everything you need. [More documentation] (https://www.qemu.org/docs/master/system/target-avr.html) SIMAVR: This is the one I prefer First of all, the `--help` is actually not as big so it's easy to guess everything yourself, but fine, here is the command: ```sh simavr -m atmega328p -g ``` I think you can already see why I like it more. Breakdown of flags: * `-m, --mcu` stands for "MicroController Unit". atmega328p is the processor arduino uno uses * `-g, --gdb`: wait for gdb to connect on `:1234` * `-f, --freq`: optionally specify the clock frequency, arduino uno has 16MHz You can also interrupt the process to kill it! Qemu does not let you do that. ## gdb ```sh $ avr-gdb (gdb) target remote :1234 (gdb) c ``` First of all, load the image. Then connect to the simulation. Since this is not a program in a traditional sense, it's already running and you have to `continue` instead of `run`. * to break at an address, use `b *0x69`. also, 0x69 is odd, so you will not land there. Instructions are either 16 bit or 32 bit on AVR, so almost any even address is a valid instruction. * to print instructions at some address, use `x/16i 0x420`, replace 16 with amount of instructions and 0x420 with an actual address. you can also use `$pc`, which stands for program counter (current instruction) as an address. Also, unlike on intel/arm64, you can safely write `x/4i $pc-4` and get a valid disassembly. * To print register values, use `print $r16`, replace `r16` with any register you want. For formatted printing, see `help x` in gdb shell, it is often useful to `print/x` in hexadecimal or `print/t` in binary. * use `displ` command. You will probably want to track current instruction, 1 or 2 registers and some IO memory addresses. For me, a "must have" is `displ/i $pc`, which displays an instruction to be executed each time the execution avdances. really useful for stepping * `si` command steps 1 assembly insstruction. you will find yourself using it a lot * To print IO registers, use `print *(unsigned char*)0xADD12E55`. NOTE that, if you can use `in/out` instruction to access a memory location, gdb can't, it will always use `sts/lds`. So don't forget `0x20` to all IO locations before `0x3F`. For example, if you want to track `PORTB`, you'd often write `displ/t *(unsigned char)0x25`, even though documentation says the `PORTB` is at `0x05`. * To restart the program without restarting the simulation, you can write `set $pc = 0`. This will trick a processor into thinking that next instruction is at `0x00`, which is a reset vector. Note that state of your registers does not reset. The set command it useful in many places, for example you want a loop to execute for a little longer - you can set the counter register to 0. * you can safely put breakpoints at interrupts, at any labels you defined, anywhere. * I coudn't get `compile code` gdb instruction to work (to execute assembly on-the-fly), because it can't find the avr C compiler. Maybe this is a distribution misconfiguration. Didn't bother setting up stuff in a debian VM. This is it! Hope this was helpful. P.S.: Internet has a lof of `avr-gdb` guides, and even more "just `gdb`" guides, which are as relevant. Search them up and have fun debugging! JAC, 2025