Assembly
Table of Contents
Registers
Registers can be used as operands in instructions. For example:
ldi r16, 0x10
stores the value 0x10 into register r16. The r prefix is case-insensitive,
and may also be omitted. For example, the following are equivalent:
ldi r16, 0x10
ldi R16, 0x10
ldi 16, 0x10
Omitting the r prefix is inadvisable, as it may lead to incorrect
interpretation of operands.
In the following code, the operand representing the register is
ambiguous, and one might incorrectly assume that the syntax for the
ldi instruction is ldi K, Rd, rather than ldi Rd, K.
ldi 16, 16
Constants
Constants are used in instructions as operands. For example:
ldi r16, 0x10
stores the value 0x10 into register r16.
Immediate Values
Immediate values are constants that are used as operands in instructions. They differ from register operands in that they do not need to be fetched from memory, and are instead encoded directly into an instructions OP code.
In the case of some instructions, immediate values can be omitted if they appear as the second operand in an instruction. For example:
ldi r16,
implicitly loads the value 0x00 into register r16.
This is inadvisable, as it leads to inconsistent and unreadable code.
Labels
A label is a symbolic name that represents the current value of the
program counter. Labels must be unique within a program, and end with a
colon (:):
label:
More information can be found at GNU binutils Documentation - Labels.
Assembler Directives
All assembler directives have names that begin with a period/dot (.).
These names are case-insensitive, and usually written in lowercase.
Some common assembler directives are defined below:
.global symbolis used to declare a symbol as global..section nameis used to define a section of memory..include "file"is used to include the contents of a file..set symbol, expressionis used to define a constant symbol.
More information can be found at GNU binutils Documentation - Assembler Directives.
Memory Sections
Memory sections are used to organise various sections of a program into memory regions.
- The
.textsection contains program instructions. - The
.datasection contains static data. - The
.bsssection contains uninitialised data. - The
.eepromsection contains data stored in EEPROM. - The
.noinitsection contains uninitialised data which is not zeroed. - The
.initNsections contain startup code from reset up to the start ofmain(). - The
.finiNsections contain code which runs aftermain()returns or after a call toexit().
More information can be found at AVR Libc Documentation - Memory Sections.
Reading a HEX File
The instructions in an assembly file are translated into OP codes, which are organised into a HEX file. The HEX file is a text file which contains an encoded representation of the OP codes in hexadecimal format.
Consider the following program:
; src/main.S
.section .init0
ldi r16, 0xAB
This instruction is encoded as follows:
ldi Rd, K; 16 <= d <= 31; 0 <= K <= 255
KKKK dddd KKKK
0b1110 1010 0000 1011 (0xEA0B)
As the ATtiny1626 uses Little Endian encoding, the data portion of the
HEX file will contain the bytes 0x0B and 0xEA in that order.
The HEX file generated at .pio/build/QUTy/firmware.hex contains the
following text:
:020000000FE00F
:00000001FF
Each record (line) in the HEX file contains the following fields:
- Start code (colon)
- Byte count (two hex digits)
- Address (four hex digits)
- Record type (two hex digits)
- Data (some number of hex digits)
- Checksum (two hex digits)
More information on the HEX file format can be found at Intel HEX.
The following VSCode extension provides syntax highlighting for .hex
files: Intel HEX format.