Microcontrollers   PCs — Embedded Electronics





Projects:  Macros for AVR Assembler Programming








 Projects Home

 Workspace Pictures

 ReAl Computer Projects

 ReAl Computer Architecture

Site in German  



Machines built with AVRs:

16 AVRs:

Up to 16 AVRs, depending on how this platform is populated:

A fully-fledged 3U subrack could accommodate 20 cards or 40 AVRs.

Five AVRs:

This billboard consist of five LED panels, each with its own AVR:

Three AVRs:

Two AVRs:

One AVR:






  • Toolbox to ease assembler programming of AVR microcontrollers.
  • Compensate for peculiarities and eccentricities of the AVR architecture.
  • Example to demonstrate the general approach of small virtual machines and purpose-written macros.

Our virtual machine:

Download this diagram as PDF.

AVR peculiarities:
The AVR architecture is noticeably more advanced than other 8-bit architectures. Nevertheless, it has some grievous restrictions of its own, too. Which are severe, which are merely nuisances? Some conspicuous restrictions are listed in the following table, the most severe first. The degree of severity has been judged according to programming experience and in comparison to other well-renowned architectures.

An exercise for eager students of computer architecture:
How to eliminate these shortcomings without changing the basic architectural principles? – It should remain an 8-bit RISC with 32 general-purpose registers and two-address instructions.


Architectural peculiarity


The flag bits are accessible only via the I/O address space. It is awkward to save and restore the flags. Both operations are required frequently. Hence, other architectures provide dedicated instructions for this purpose (e.g., an instruction pair PUSHF and POPF).


The stack pointer (SP) is accessible only via the I/O address space, impeding stack manipulation and stack-relative addressing with the SP as a base address register.


Only half of the register file can be operated upon by immediate operands. So only 16 registers are true general-purpose registers.


There are only three address registers (X, Y, Z). To boot, they belong to the general-purpose-registers mentioned above. In consequence, there are only 10 register bytes freely available, which can be operated upon by immediate operands and in which individual bits can be set and queried. Three address pointers, base registers, index registers or the like are not enough.  When speaking of a true general-purpose register file, it would be best when each register could be used for addressing. At least, 6 to 8 address registers would be a sufficient minimum.


The instructions to set and clear bits in the register file (SBR, CBR) are only aliases of the instructions ANDI and ORI. Their operands are bytes, serving as bit masks. The skip-type instructions to query individual bits (SBRC, SBRS), however, have bit indices. This gives rise to annoying mistakes. SBR r16,0 does not change anything (corresponds to ORI r16,0), whereas SBRS r16,0 queries bit 0 ... Individual bits can be queried in all 32 registers, but set or cleared in only 16 of the 32 registers.


There is no uniform I/O address space. I/O instructions can address only 64 registers. Instructions to query and set individual bits can be applied only to the first 32 I/O addresses. If the microcontroller's periphery requires more than 64 addresses, the additional registers can be addressed only by memory access instructions.


The branching conditions related to arithmetic comparisons by subtracting (A – B) do not correspond completely to the usual industry standard. For some programming intentions, one has to subtract the other way round (B – A).


The jump distance of the conditional branches (BRANCH instructions) is often too low. In some cases, the traditional combination SKIP and JUMP would do better. However, SKIP can only query the bits of the register file and the first 32 I/O addresses, but not the flag bits in the status register.


To move bits around, a dedicated flag has been provided, the T-flag. In contrast, it has been a industry standard for decades to use the Carry Flag (CF) for this purpose. This convention dovetails with the rotate instructions, thus allowing to assemble bytes from particular bits (gather operation) or to dissect bytes and emit the particular bits (scatter operation).


The important XOR operation (to selectively toggle bits) is not available with an immediate operand.

AVR memory and I/O addressing:

Download this diagram as PDF.

Why AVR?

  • Those microcontrollers are ubiquitous and inexpensive.
  • As integrated circuits, they are exceptionally forgiving with respect to power supply routing and decoupling. Principally, they could be operated when held between two fingers or placed on the table while connected to the power supply and peripheral devices via hookup wire (provided the wire is thin enough). They cause no problems if operated on wire-wrapped boards. SSee the project pics in the column to the left and reference [7].
  • The instruction set is comparatively well-suited to learn the basics of machine programming. After a few hours, one can have first positive experiences. I
  • AVR is neither as complicated and difficult to program like a 32-bit architecture, nor as minimalist as some other 8-bit architectures.

But AVR is only an 8-bit architecture?
This fact does not matter. Any arbitrarily small universal processor can execute any algorithm, provided the storage capacity is sufficient and execution time does not matter. This is called "Turing-completeness".

For most educational and fun projects, problem complexity and size are rather modest. We talk about educational and fun projects a single person can tackle within a few hours to a few weeks. For this purpose, 8-bit processing with a clock speed between 4 to 32 MHz should be by far enough, especially since an AVR requires only a single clock cycle for most instructions. The computers aboard an Apollo moonship had less speed and memory capacity ..

Why program in assembler?

  • Those who cannot program at the machine level do not really know how a computer works.
  • To be familiar with the basics helps writing truly efficient high-level code, too.
  •  You should be able to read and to judge the efficiency of the machine code the compilers generate. If you have a notion about how the machine code will look like, you will be able to write programs running faster and requiring less memory space. In short (to paraphrase a statement in [1]): think low-level, write high-level.
  • When writing programs for embedded systems, device drivers and the like, it is occasionally a necessity, especially if tight timing requirements are to be met.
  • One can pursue assembler programming projects just for fun.





Hyde, Randall: Writing Great Code, Voume 2: Thinking Low-Level, Writing High-Level. No Starch Press, San Francisco, 2006.


Dalrymple, Monte: Microprocessor Design Using Verilog HDL. Circuit Cellar, 2017.


Li, Yamin: Computer Principles and Design in Verilog HDL. Wiley, 2015..


Hyde, Randall: The Art of Assembly Language. No Starch Press, San Francisco, 2003.


Margush, Timothy S.: Some Assembly Required: Assembly Language Programming with the AVR Microcontroller. CRC Press, 2016.


Lyashko, Alexey: Mastering Assembly Programming. Packt Publishing, 2017.


Matthes, Wolfgang: Microcontroller Modules for the Ambitious. Circuit Cellar, Issue 312, July 2016, p. 24-33.











July 10, 2019

Download references and sources:

Macro_reference.pdf is the reference manual.
Macro_Platform_01 is an AVR studio project provided for viewing the sources and experimenting.

The source files are:

x denotes the release number.
In a project, both sources are to be included.

is an additional source containing macros with alternative word-register mnemonics. When using, all three sources are to be included within the project.