Simple Program
Here is a very simple program that adds two numbers together (23+52):
; Sample program that adds two numbers. ; t a y l o r@msoe.edu, 3-14-2007 ; Modification log: ; t a y l o r@msoe.edu, 12-11-2008: Added .equ and .def .nolist .include "m32def.inc" ; Include the appropriate register definition file .list .equ start = 0x2A ; Assign label start to starting memory address for program .def val1 = r20 ; Assign alias val1 to register 20 .def val2 = r21 ; Assign alias val2 to register 21 .dseg ; DATA SEGMENT .org 0x60 ; Set SRAM address to hex 60, this is right after I/O result: .byte 1 ; Reserve 1 byte in SRAM to store the resulting sum .cseg ; CODE SEGMENT .org 0 ; Set the RESET vector to rjmp start ; The beginning of our code .org start ; Set Program Counter to hex 2A, end of Interrupt Jump Table ldi val1, 23 ; Initialize first value (in r20) ldi val2, 52 ; Initialize second value (in r21) add val1, val2 ; Add two numbers sts result, val1 ; Store the result in SRAM stop: rjmp stop ; Loop forever here (so that it doesn't continue ; executing whatever is stored in program memory ; after this.
Program Components
The assembler recognizes the following items:
- Symbolic labels (aliases).
- Those specified with .def.
- Specifies a mapping of a label to a specific register.
- Examples from above: val1 and val2
- Those specified with .equ.
- Specifies a mapping of a constant to a label.
- May represent a value or a memory address.
- Examples from above: start
- Those appearing in the first column and ending with a colon (:) when declared.
- Specifies a mapping of a constant representing a specific memory address to a label.
- Are resolved into a constant value by the assembler.
- Examples from above: result and stop
- Those specified with .def.
- Pre-processor directives.
- Provide directions for additional tasks to be performed by the assembler prior to assembling the program.
- Appear in the first column.
- Examples from above:
- .nolist — Tells the assembler to begin excluding statements from the listing (.lst) file.
- .list — Tells the assembler to begin including statements from the listing (.lst) file.
- .include — Copy contents from the specified file into the current file before assembling.
- .dseg — Beginning of the data memory (SRAM) specification.
- .cseg — Beginning of the program memory (FLASH) specification.
- .org — Specifies a specific memory address to be used to store the instruction that follows.
- .def — Defines a symbolic label (alias) for a register.
- .equ — Defines a symbolic label (alias) for a constant.
- Operation Mnemonic.
- Identifies the instruction/operation to be performed.
- Appear in the second column.
- Examples from above: LDI, ADD, STS, RJMP
- Operands.
- Parameters needed for an operation to perform correctly.
- Appear in the third column.
- Examples from above: start, r20, r21, result, stop
- Comments.
- Additional information provided to increase the readability of the code.
- Begin with a semicolon (;).
- Extend for the remainder of the line.
- Appear in the fourth column or on a line dedicated entirely to a comment.
- Example from above: ; Include the appropriate register definition file.
Program Sections
A program consists of:
- A Data Segment.
- Refers to SRAM.
- Specified with an assembler directive: .dseg.
- The .org directive specifies the originating location.
- Typically we'll use .org 0x60 since that is the beginning of SRAM
- Note: We actually don't need to do this because 0x60 will be used by default.
- The .byte 1 directive is used to reserve 1 bytes of SRAM, where 1 may be replaced by a different non-negative integer.
- A Code Segment.
- Refers to Flash.
- Specified with an assembler directive: .cseg.
- As with the Data Segement, we can use .org to specify the starting location of our code (default is 0x0).
- We begin our programs with a jump directive, e.g.,
- RJMP start
- This jumps us to the location specified by the start label.
- The beginning part of Flash memory (0x00 - 0x29) is reserved for the interrupt jump table (more on this later this quarter).
- 0x00 is the location of the reset vector which stores the memory location where the program counter should start.
Listing File
The listing file for the simple program is shown below:
AVRASM ver. 2.1.0 C:\Atmel\Projects\wk2lec3a\wk2lec3a.asm Wed Mar 14 14:57:38 2007 C:\Atmel\Projects\wk2lec3a\wk2lec3a.asm(5): Including file 'C:\Atmel\AVRTools\AvrAssembler2\Appnotes\m32def.inc' ; t a y l o r@msoe.edu, 3-14-2007 .list .dseg ; DATA SEGMENT .org 0x60 ; Set SRAM address to hex 60, this is right after I/O result: 000060 .byte 1 ; Reserve 1 byte in SRAM to store the resulting sum .cseg ; CODE SEGMENT .org 0 ; Set the RESET vector to 000000 c029 rjmp start ; The beginning of our code .org 0x2A ; Set Program Counter to hex 2A, end of Interrupt Jump Table start: 00002a e147 ldi r20, 23 ; Initialize r20 with first value 00002b e354 ldi r21, 52 ; Initialize r21 with second value 00002c 0f45 add r20, r21 ; Add two numbers 00002d 9340 0060 sts result, r20 ; Store the result in SRAM stop: 00002f cfff rjmp stop ; Loop forever here (so that it doesn't continue ; executing whatever is stored in program memory ; after this. RESOURCE USE INFORMATION ------------------------ Notice: The register and instruction counts are symbol table hit counts, and hence implicitly used resources are not counted, eg, the 'lpm' instruction without operands implicitly uses r0 and z, none of which are counted. x,y,z are separate entities in the symbol table and are counted separately from r26..r31 here. .dseg memory usage only counts static data declared with .byte ATmega32 register use summary: r0 : 0 r1 : 0 r2 : 0 r3 : 0 r4 : 0 r5 : 0 r6 : 0 r7 : 0 r8 : 0 r9 : 0 r10: 0 r11: 0 r12: 0 r13: 0 r14: 0 r15: 0 r16: 0 r17: 0 r18: 0 r19: 0 r20: 3 r21: 2 r22: 0 r23: 0 r24: 0 r25: 0 r26: 0 r27: 0 r28: 0 r29: 0 r30: 0 r31: 0 x : 0 y : 0 z : 0 Registers used: 2 out of 35 (5.7%) ATmega32 instruction use summary: adc : 0 add : 1 adiw : 0 and : 0 andi : 0 asr : 0 bclr : 0 bld : 0 brbc : 0 brbs : 0 brcc : 0 brcs : 0 break : 0 breq : 0 brge : 0 brhc : 0 brhs : 0 brid : 0 brie : 0 brlo : 0 brlt : 0 brmi : 0 brne : 0 brpl : 0 brsh : 0 brtc : 0 brts : 0 brvc : 0 brvs : 0 bset : 0 bst : 0 call : 0 cbi : 0 cbr : 0 clc : 0 clh : 0 cli : 0 cln : 0 clr : 0 cls : 0 clt : 0 clv : 0 clz : 0 com : 0 cp : 0 cpc : 0 cpi : 0 cpse : 0 dec : 0 eor : 0 fmul : 0 fmuls : 0 fmulsu: 0 icall : 0 ijmp : 0 in : 0 inc : 0 jmp : 0 ld : 0 ldd : 0 ldi : 2 lds : 0 lpm : 0 lsl : 0 lsr : 0 mov : 0 movw : 0 mul : 0 muls : 0 mulsu : 0 neg : 0 nop : 0 or : 0 ori : 0 out : 0 pop : 0 push : 0 rcall : 0 ret : 0 reti : 0 rjmp : 2 rol : 0 ror : 0 sbc : 0 sbci : 0 sbi : 0 sbic : 0 sbis : 0 sbiw : 0 sbr : 0 sbrc : 0 sbrs : 0 sec : 0 seh : 0 sei : 0 sen : 0 ser : 0 ses : 0 set : 0 sev : 0 sez : 0 sleep : 0 spm : 0 st : 0 std : 0 sts : 1 sub : 0 subi : 0 swap : 0 tst : 0 wdr : 0 Instructions used: 4 out of 111 (3.6%) ATmega32 memory use summary [bytes]: Segment Begin End Code Data Used Size Use% --------------------------------------------------------------- [.cseg] 0x000000 0x000060 14 0 14 32768 0.0% [.dseg] 0x000060 0x000061 0 1 1 2048 0.0% [.eseg] 0x000000 0x000000 0 0 0 1024 0.0% Assembly complete, 0 errors, 0 warnings
- The assembler doesn't generate a listing file by default.
- To generate a listing file:
- Select Assembler Options from the Program menu in AVR Studio.
- Check the Create List File checkbox.
- Select OK to close the dialog box.
- A list file will now be generated whenever the program is assembled.
- The list file contains all of the original program shifted to the right.
- Some lines contain additional numbers to the left of the code.
- The 000060 at the beginning of .byte 1 indicates that the reserved byte is at memory location 0x000060. This also tells us the value represented by result.
- The 00002a at the beginning of ldi r20, 23 indicates that this program instruction is stored in memory location 0x00002A in Flash.
- The e147 after the 00002a is the hexidecimal code for the instruction on that line.
- Most instructions can be represented with two bytes; however, the STS result, r20 instruction requires four bytes.
- Notice that the next program address used is 00002f instead of 00002e because four bytes were required.
- The Resource Use Information section provides additional details on resources used by the program.
- It indicates that R20 was used three times and R21 was used twice.
- It indicates that four instructions (ADD, LDI, RJMP and STS) were used, and how frequently.
- It indicates that the program required 14 bytes of program memory and one byte of SRAM.
Sample Programs
Sum of Two 16-Bit Numbers
We could modify the sample program above to add two 16-bit numbers as follows:
; Sample program that adds two 16-bit numbers. ; 313 + 8000 = 8313 ; t a y l o r@msoe.edu, 3-14-2007 .nolist .include "m32def.inc" ; Include the appropriate register definition file .list .dseg ; DATA SEGMENT .org 0x60 ; Set SRAM address to hex 60, this is right after I/O result: .byte 2 ; Reserve 2 bytes in SRAM to store the resulting sum .cseg ; CODE SEGMENT .org 0 ; Set the RESET vector to rjmp start ; The beginning of our code .org 0x2A ; Set Program Counter to hex 2A, end of IJT start: ldi r21, 0x01 ; Initialize r21 with high byte of first value ldi r20, 0x39 ; Initialize r20 with low byte of first value ldi r23, 0x1F ; Initialize r23 with high byte of second value ldi r22, 0x40 ; Initialize r22 with low byte of second value add r20, r22 ; Add low byte of the two numbers adc r21, r23 ; Add high byte of the two numbers sts result+1, r21 ; Store high byte of the result in SRAM sts result, r20 ; Store low byte of the result in SRAM stop: rjmp stop ; Loop forever here (so that it doesn't continue ; executing whatever is stored in program memory ; after this.
Note:
- 31310 = 00000001001110012 = 013916.
- 800010 = 00011111010000002 = 1F4016.
- 831310 = 00100000011110012 = 207916.
- If we do 192 + 64 = 256 we can see the carry bit in action.
- 19210 = 00000000110000002 = 00C016.
- 6410 = 00000000010000002 = 004016.
- 25610 = 00000001000000002 = 010016.
Sum of Five Numbers Part I
This example uses direct addressing mode to calculate the sum of five 8-bit numbers.
; Sample program that calculates the sum of five numbers. ; The sum of the five numbers must be less than 256. ; This program uses direct addressing, which is NOT the best ; way to do this. ; t a y l o r@msoe.edu, 3-14-2007 .nolist ; Ignore what follows when generating the list file .include "m32def.inc" ; Include the appropriate register definition file .list ; Include what follows when generating the list file .equ n1 = 0x01 .equ n2 = 0x02 .equ n3 = 0x03 .equ n4 = 0x04 .equ n5 = 0x05 .def temp = r16 ; Use r16 as a temporary register .def sum = r20 ; Use r20 to store the sum of the five numbers .def addend = r21 ; Use r21 to store the value to be added to the sum .dseg ; DATA SEGMENT .org 0x60 ; Set SRAM address to hex 60, this is right after I/O nums : .byte 5 ; Reserve 5 bytes in SRAM for the five numbers result: .byte 1 ; Reserve 1 byte in SRAM to store the resulting sum .cseg ; CODE SEGMENT .org 0 ; Set the RESET vector to rjmp start ; The beginning of our code .org 0x2A ; Set Program Counter to hex 2A, end of Interrupt Jump Table start: ldi temp, n1 ; Initialize data memory with values to be summed sts nums, temp ldi temp, n2 sts nums+1, temp ldi temp, n3 sts nums+2, temp ldi temp, n4 sts nums+3, temp ldi temp, n5 sts nums+4, temp lds sum, nums ; Load first number to sum register lds addend, nums+1 ; Load second number to addend register add sum, addend ; Add addend to cummulative sum lds addend, nums+2 ; Load third number to addend register add sum, addend ; Add addend to cummulative sum lds addend, nums+3 ; Load third number to addend register add sum, addend ; Add addend to cummulative sum lds addend, nums+4 ; Load third number to addend register add sum, addend ; Add addend to cummulative sum sts result, sum ; Store sum in result memory location stop: rjmp stop
Sum of Five Numbers Part II
- This example uses indirect addressing mode to calculate the sum of five 8-bit numbers.
- By using indirect addressing we can use a loop to do the repetitive summing.
- This would be noticably superior to the previous method if we need to sum an even larger quatity (e.g., 100) of numbers.
; Sample program that calculates the sum of five (or whatever) numbers. ; The sum of the numbers must be less than 256. ; This program uses indirect addressing ; t a y l o r@msoe.edu, 3-14-2007 .nolist ; Ignore what follows when generating the list file .include "m32def.inc" ; Include the appropriate register definition file .list ; Include what follows when generating the list file .equ bvalue = 0x01 ; Starting value for numbers to sum .equ num = 5 ; Number of values to sum .def temp = r16 ; Use r16 as a temporary register .def sum = r20 ; Use r20 to store the sum of the five numbers .def addend = r21 ; Use r21 to store the value to be added to the sum .def counter = r22 ; Use r22 as a counter .dseg ; DATA SEGMENT .org 0x60 ; Set SRAM address to hex 60, this is right after I/O nums: .byte num ; Reserve 5 bytes in SRAM for the five numbers result: .byte 1 ; Reserve 1 byte in SRAM to store the resulting sum .cseg ; CODE SEGMENT .org 0 ; Set the RESET vector to rjmp start ; The beginning of our code .org 0x2A ; Set Program Counter to hex 2A, end of IJT start: ; Initialize X register with 0x0060 ldi r27, 0x0 ; Place 0x00 in high byte of X register ldi r26, nums ; Place 0x60 in low byte of X register ldi temp, bvalue ; Initialize data memory with beginning value ; of the numbers to be summed ldi counter, num ; Initialize counter to repeat loop 5 times iloop: ; Start of initialization loop st X+, temp ; Store value in data memory inc temp ; Increments temp register by one dec counter ; Decrement counter brne iloop ; Repeat loop if counter not zero ; Initialize X register with 0x0060 ldi r27, 0x0 ; Place 0x00 in high byte of X register ldi r26, nums ; Place 0x60 in low byte of X register ld sum, X+ ; Load first number to sum and advance X to next number ldi counter, num-1 ; Initialize counter to repeat loop 4 times sloop: ld addend, X+ ; Load second number to addend register and inc X add sum, addend ; Add addend to cummulative sum dec counter ; Decrement counter brne sloop ; Repeat loop if counter not zero sts result, sum ; Store sum in result memory location stop: rjmp stop
Instead of
ldi r27, 0x0 ; Place 0x00 in high byte of X register ldi r26, nums ; Place 0x60 in low byte of X register
we could write the more readable:
ldi XH, HIGH(nums) ; Place 0x00 in high byte of X register ldi XL, LOW(nums) ; Place 0x60 in low byte of X register