2022-03-04
This was the class time activity for day18
1. Check if code gets optimized away
Specific example: a while()
loop waits for some external condition (pin state or some other input) and the code just sits in a "busy loop" doing nothing else besides checking for the variable to change.
1.1. Version A
Code example is from: https://github.com/etihwnad/short-squawker
Consider this block of code:

Compile this for the ATtiny85
using the ATTinyCore
board package and the following settings:

Get a copy of the .lst
, disassembled code back to assembly with Sketch -> Export compiled Binary.
Search in that file attiny_shortsquawker.ino.lst
for the corresponding code (I searched for PLLCSR
) and see the following section:

Line 934 says that the following assembly originates from the .ino
line 126.
PLLCSR |= (1 << PLLE);
gets translated to three instructions.
This is called a "read, modify, write" and simply sets the PLLE
bit in the PLLCSR
register without changing any other of the register’s bits.
Listing lines 946—952 show what got compiled for the busy loop that waits for the PLOCK
bit to go high in the PLLCSR
register.
-
Line 947, code at flash address 0x3a6, loads the
PLLCSR
register (at address 0x27) into registerr0
. -
sbrs r0, 0
— "skip next if bit in I/O register is set"-
Check if bit 0 (the lsb) is set. If yes, the break out of the loop by skipping the
rjmp
. -
If the bit is still 0, then
sbrs
does not skip and therjmp
jumps the Program Counter to flash address 0x3a6, which is the start of thewhile()
loop.
-
Conclusion: this time, the loop did not get optimized away and things work as you expect.
1.2. Version B
This is a version ported to C
and being built using the ..._valpo2.zip
version of the WinAVR portable distribution.

Use the WinAVR tools to compile, link, and export a .lst
file from this code.
The while condition is different (and has several bugs in one line!). It is kept here for demonstration purposes.
|

Listing lines 135—138 show that the code to set the PLLE
bit in the PLLCSR
register is unsurprising.
The only difference is the compiler’s choice of temporary register (r24
versus r0
).
Listing lines 141—145 show what happened with the while()
loop.
-
At flash address 0x78 is an instruciton to read I/O register at address 0x27 (
PLLCSR
) into registerr24
. -
Then there are no more assembly instructions! The
_NOP()
is from theC
version but has no correspondingnop
CPU instruction in assembly.
Conclusion: this particular version in fact optimizes the busy loop away.
Not quite completely away because Listing line 142 has an instruction to read PLLCSR
into a register, but nothing is done about that value.
1.3. Version C
Fix the bugs in the while()
in the WinAVR C
version:

Re-build the project:

and look at the new listing:

Pay attention to listing lines 151—154. This exactly the same instructions for the "good" result from Version A.
The generated assembly is slightly longer because of the _NOP()
that was in this version of the C
code.
So, the busy loop related assembly starts at listing line 139 at Flash address 0x78.
-
Immediate jump to address 0x7c which reads and checks the
PLLCSR
bit. -
Same "skip if set" instruction.
-
rjmp
jumps back farther to address 0x7a -
which is a
nop
instruction, which has no effect on the CPU state (including the all-importantSREG
CPU status register bits). -
Next instruction is back to the
while()
loop’s reading of thePLLCSR
I/O register into a CPU register.
Conclusion: Don’t have bugs in your conditions! The compiler assumes you wrote correct code. The Version B code’s condition is always false
(figure out why!) and therefore the compiler did the nothing that you asked to happen.
2. Error generating .lst
using WinAVR and a Makefile
Do you see this? :

Instead of this? :

The difference is the first version used the _valpo1.zip
or earlier version of the WinAVR distribution.
The second screenshot was using the _valpo2.zip
version.
The difference is a single file:
WinAVR-20100110\utils\bin\msys-1.0.dll
(Don’t ask why, it took 2+ hours to figure this out, confirm the fix, and generate a the new _valpo2.zip
. Prof. White will not be thwarted by some random DLL bug from the 90’s ;)
-
Direct link to winavr-setup.html which has a link to the current version of the WinAVR Portable
.zip
distribution.
3. Compiling asm / C / Cpp
What incantations are needed to create an object file from a source file in assembly, C, or Cpp into a HEX file for programming?
That day13 page has been modified for better navigation to emphasize the five steps that happen in building an Arduino sketch.
day13 § 1.2 is the beginning of the _non-Arduino specific parts of the process that are common to any GCC-based flow. Any other compiler will have a very similar flow, but with potentially different tool names and options.
The example code comes from day12, which used an .ino (translated to Cpp by the Arduino platform’s preprocessing), an assembly file asmOne.S holding the assembly implementation of a function called from the .ino , and a trivial C file foo.c to show how C compilation differs from Cpp.
|
4. Calling assembly from C
This was from class times
-
day10 — Introduction about how GCC uses registers, and where to find that type of information.
-
day11 — Demo by comparing
.ino
with resulting assembly in the.lst
for functions of 1—4 (char
orint
) arguments. -
day12 — Demo of using assembly
.S
with the Arduino IDE, to create a function in assembly that is called from C (technically the.ino
, which is Cpp).
Assembling with the GNU toolchain is a little different that avr_sim !
|
Two references that can help translate:
5. Links to avr-gcc toolchain
day15 - §3. avr-gcc references collects links to the major documentation for avr-gcc and related tools.
The tools are many in number, but that is on purpose according to the "Unix philosophy". Read more about that at