Table of Contents

Basic program breakdown

Program overview

Sample project titled LED Flash provided by Kanda is as follows, with PORT B pins connected to an LED segment display. Assembly code used is here:

; Comments are prefixed with ';', '//', or wrapped '/*...*/'
; Spaces between variables are ignored
 
; Include directive similar to C
; This library for ATMega16
.include "m16def.inc"
 
  ; Label registers for easy reference using define
  .def TEMP=r16    ; temporary (scratch) register
  .def ON=r23      ; store value for LED on
  .def OFF=r24     ; store value for LED off
  .def coarse=r17  ; delay subroutine, has largest effect
  .def medium=r18  ; delay subroutine, has medium effect
  .def fine=r19    ; delay subroutine, has smallesteffect
 
  .cseg       ; indicates this is code and to be stored in Flash
  .org 0      ; switch to address 0x00 (reset address)...
  rjmp INIT   ; ...and add jump instruction to label INIT
  .org 0x60   ; switch to address 0x60  (padding for interrupt vectors)...
INIT:         ; ...and add location of label INIT
 
  ; Up to this point is typically the same assembly boilerplate
  ; Now we define the stack space by populating SPH (Stack Pointer High byte)
  ; and SPL with the high and low address boundaries respectively.
  ; Since we cannot write directly to Special Function Registers (SFR)
  ; nor to bottom 16 registers (R0 to R15), we first load the required
  ; value into a register between R16 and R31 inclusive.
  ;
  ; The end of SRAM is defined in the header file as RAMEND,
  ; which corresponds to 0x045f for ATmega16. This is a 16-bit
  ; address, so we write both the high and low bytes, where
  ; LOW(0x045f) == 0x5f and HIGH(0x045f) == 0x04
 
  ; Set Stack Pointer to top of SRAM
  ldi TEMP, LOW(RAMEND)  ; (load intermediate value)
  out SPL, TEMP          ; (write to SFR)
  ldi TEMP, HIGH(RAMEND)
  out SPH, TEMP
 
  ; Set all pins in Port B as output (instead of input)
  ldi TEMP, 0xff
  out DDRB, TEMP  ; data direction register for Port B
 
  ; Load 1s into all pins in Port B
  ; Dependent on electronic wiring - here it switches LEDs off
  out PORTB, TEMP
 
  ; Store off and on values for LED
  ldi OFF, 0xff
  ldi ON, 0x00
 
MAIN:
  rcall DELAY     ; do (relative) call to subroutine
  out PORTB, ON   ; switch LED ON
  rcall DELAY
  out PORTB, OFF  ; switch LED OFF
  rjmp MAIN       ; repeat main loop
 
DELAY:
  ldi coarse, 0x07
delay1:
  ldi medium, 0xff
delay2:
  ldi fine, 0xff
delay3:
  dec fine
  brne delay3  ; skips only if previous decrement goes to zero
  dec medium
  brne delay2
  dec coarse
  brne delay1
  ret

Note a couple of additional comments:

The corresponding Flash program written to the chip corresponds to:

prog 0x0000  5f c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0010  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0020  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0030  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0080  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0090  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x00A0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x00B0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x00C0  0f e5 0d bf 04 e0 0e bf 0f ef 07 bb 08 bb 8f ef  
prog 0x00D0  70 e0 04 d0 78 bb 02 d0 88 bb fb cf 17 e0 2f ef  
prog 0x00E0  3f ef 3a 95 f1 f7 2a 95 d9 f7 1a 95 c1 f7 08 95  
prog 0x00F0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0100  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0110  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0120  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0130  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
prog 0x0140  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
... 
prog 0x1FF0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

while the SRAM is initially the following (courtesy of the Microchip Studio ATmega16 simulator):

data 0x0000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0020  00 f8 fe ff 00 00 00 00 00 00 00 20 00 00 00 00  
data 0x0030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0050  00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00  
data 0x0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
data 0x0080  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
... 
data 0x045F  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  

A more detailed look

Some extremely helpful references:

  1. ATmega16 datasheet, which also contains the registry values in section 29.
  2. AVR instruction set, which goes into detail the instruction effects and operation codes.

SRAM

Breaking down the SRAM values first:

Address Name Value Remark
0x0021 TWSR 0xf8 In datasheet§20.7.5, indicates no relevant state information available, because the device is not using the Twin-Wire Interface (TWI) for serial transfer. See datasheet§20 for details on what TWI does.
0x0022 TWAR 0xfe Default value. Indicates slave address of current TWI unit.
0x0023 TWDR 0xff Default value. Used for TWI, which is not used.
0x002b UCSRA 0x20 Default value. For USART status, see datasheet§19.
0x0054 MCUCSR 0x01 Bit 0 corresponds to a power-on reset flag.

In conclusion, nothing really fancy, all initialization values.

Flash

The flash program looks to be a little fancier. The reset address is set to 0x5fc0, before the rest of the program begins at 0x00c0. The first instruction is rjmp INIT. Playing around with the .org 0x60 indicates two things:

  1. The 0x60 corresponds to the position of the instruction in the program. Since instructions are 16-bits, this corresponds to a memory address of 0xc0 (0x60 * 2), where the first instruction resides.
  2. The instruction at the reset address corresponds to the RJMP instruction, which has a 16-bit opcode of 1100_kkkk_kkkk_kkkk, where K is the relative distance to jump (less 1), in units of words (2 bytes). The initial program counter starts from 0x0000. This matches only if the first instruction is 0xc05f and not 0x5fc0.

This means the memory is little-endian. Given the word size of 2 bytes, the flash memory is thus better represented as:

prog 0x0000  c05f ffff ffff ffff ffff ffff ffff ffff  
prog 0x0010  ffff ffff ffff ffff ffff ffff ffff ffff  
...
prog 0x00B0  ffff ffff ffff ffff ffff ffff ffff ffff  
prog 0x00C0  e50f bf0d e004 bf0e ef0f bb07 bb08 ef8f  
prog 0x00D0  e070 d004 bb78 d002 bb88 cffb e017 ef2f  
prog 0x00E0  ef3f 953a f7f1 952a f7d9 951a f7c1 9508  
prog 0x00F0  ffff ffff ffff ffff ffff ffff ffff ffff
...

Breaking down the flash memory, with address in units of words:

Address Value Remark
0x60 0xe50f Opcode: 0xe. Loads value 0x5f to register 0x0 (+16), i.e. R16.
0x61 0xbf0d Opcode: 0b10111. Copy value from register 0b10000 (16) to IO port 0b111101 (0x3d, in IO-only address space).
0x62 0xe004 Same LDI instruction, load 0x04.
0x63 0xbf0e OUT.
0x64 0xef0f Same LDI instruction, load 0xff.
0x65 0xbb07 OUT.
0x66 0xbb08 OUT.
0x67 0xef8f LDI.
0x68 0xe070 LDI.
0x69 0xd004 RCALL to (0x04+1) relative jump.
0x6a 0xbb78 OUT.
... ... ...
0x71 0x953a
... ... ...
0x77 0x9508 RET instruction.

At the RCALL instruction, the stack pointer changes to 5d 04 while the stack has value 20 6a. The program counter is at 0x69 for the RCALL, but there is a stray 0x20 appearing in the stack, not sure why.