Week 13-14 PC Stack & Subroutines
Week 13-14 PC Stack & Subroutines
Subroutines
Week 13-14
EE- 354 Embedded Systems
Spring, 23
1
Program Counter
2
Program Counter
● Program Counter (PC) is a register that holds address of the next
instruction to be executed.
● Normally, for sequential execution of instructions, PC gets
incremented by +1 to get the next instruction.
PC = PC+1
● The contents of the program counter are placed on the address
bus to find and fetch the desired instruction.
● The instructions that break sequential execution like (Branch
instructions and Jump Instructions etc.) affect PC.
● Like in JMP, PC becomes equal to the address of the target
specified in JMP instruction. So after execution of the JMP
instruction, processor knows that the next instruction is the
instruction pointed by JMP.
3
Program Counter
The ATmega328P program counter (PC) is 14 bits
wide, thus addressing the 16K program memory
locations.
The wider the program counter, the more
memory locations a CPU can access. That means
that a 14-bit program counter can access a
maximum of 16K (214 = 16K) program memory
locations.
4
Program Counter
Consider the code
LDI R16,0
LDI R17,20
HERE: ADD R16, R17
JMP HERE
5
Branch Instruction Decoding
The Branch instructions also affect PC (as they break sequential execution). But unlike the
JMP instruction, the PC doesn’t become equal to the label (address pointing to the target).
Instead, the branch instructions only save an offset (that is added to the current program
counter to find the address of target) and not the complete address.
The offset (k) saved in the branch instruction is related as:
PC next = PC current + Offset
Where, PC current = Address of Branch Instruction + 1 (This +1 is because when branch is
being executed, PC is incremented to point to the next instruction after branch). But after
execution of branch, it is known whether the processor has to go to the target or the not
(i.e., branch is true or false).
PC next is the address of target (or address of the instruction being pointed by the branch
instruction).
Storing offset in branch instruction instead of the complete address of the target requires
less no. of bits.
6
Branch Instruction Decoding
Let’s take a look at BREQ instruction format:
The 16 bit opcode shows 7-bits for ‘k’. 7-bits can store -64 to +63 (range of
signed nos.). Note that for forward branch, k is positive and for a backward
branch it is -ve. All branches are short jumps, i.e., they can jump 64 locations
ahead or back.
ALL BRANCH instructions are therefore SHORT jumps. Encoding of other branches is same, only the
opcodes are different. Refer to the machine format of other studied branches from the AVR
instruction manual.
7
Branch Instruction Decoding
Example In this code: BREQ HERE
Is decoded using the machine format as:
1111001111011001
k= 1111011 = -5 (in 2s Complement)
This is correct as the address of 3rd PROM Address
(location of
instruction is $02. (Next PC = $02) instructions)
ANSWER:
1111 0000 0001 0001
10
Branch Instruction Decoding
Practice Problem #2: Using the machine format of BRNE
instruction, write the HEX equivalent of it for the following code.
11
Branch Instruction Decoding
Practice Problem #3: Using the machine format of BRGE
instruction, write the HEX equivalent of it for the following code.
12
Branch Instruction Decoding
Practice Problem #4: Using the machine format of BRNE
instruction, write the HEX equivalent of it for the following code.
13
STACK and STACK POINTER
14
STACK & SUBROUTINES
● Another control transfer instruction is the CALL
instruction, which is used to call a subroutine (like
functions / subroutines in any other language).
● Subroutines are often used to perform tasks that need
to be performed frequently. This makes a program more
structured in addition to saving memory space.
● Call and Return instructions are used to call, implement
and execute subroutines in AVR assembly.
● Before we study these in detail, we need to understand
working of stack.
15
STACK AND STACK POINTER
● The stack is a section of RAM used by the CPU to store information
temporarily.
● This information could be data or an address.
● The CPU needs this storage area because there are only a limited number
of registers.
● Stack is LIFO (Last In First Out).
If the stack is a section of RAM, there must be a register inside the CPU to point
to it. The register used to access the stack is called the SP (stack pointer)
register.
In I/O memory space, there are two registers named SPL (the low byte of the
SP) and SPH (the high byte of the SP). The SP is implemented as two registers.
The SPH register presents the high byte of the SP while the SPL register
presents the lower byte.
16
STACK AND STACK POINTER
17
STACK AND STACK POINTER
● The stack is mainly used for storing temporary data, local variables, and
return addresses after interrupts and subroutine calls.
● The stack is implemented as growing from higher to lower memory
locations. Grows downward (higher memory address to lower).
● The Stack Pointer register always points to the top of the stack.
● The stack in the data SRAM must be defined by the program before
any subroutine calls are executed or interrupts are enabled.
● Initial stack pointer value equals the last address of the internal SRAM
and the stack pointer must be set to point above start of the SRAM.
18
STACK AND STACK POINTER
In AVR, the stack grows from higher memory location to lower memory
location (when we push onto the stack, the SP decrements). So, it is
common to initialize the SP to the uppermost memory location. Different
AVRs have different amounts of RAM.
In the AVR assembler RAMEND represents the address of the last RAM
location. So, if we want to initialize the SP so that it points to the last
memory location, we can simply load RAMEND into the SP. Notice that SP is
made of two registers, SPH and SPL. So, we load the high byte of RAMEND
into SPH, and the low byte of RAMEND into the SPL.
19
STACK AND STACK POINTER
STACK POINTER = SP
$08FF
Points to TOS (top of stack)
STACK To initialize SP with 0x08FF,
If the highest We need to load 08 in SPH and
address is $08FF, FF in SPL.
Stack will start from This can be done as:
$08FF and it will
grow downward. LDI R16, 0x08
OUT SPH, R16
Here, Internal SRAM LDI R16, 0xFF
RAMEND=$08FF OUT SPL, R16
Or,
POP Rr; (The last entered value in stack is copied back to the
register Rr. And then SP is incremented by 1). Stack is LIFO memory.
21
STACK AND STACK POINTER
● A stack PUSH command will decrease the stack pointer.
● POP will automatically increment it by 1.
22
PUSH & POP
Stack
Stack
Rr [Rr] will be copied SP
to location Rd The last filled SP=SP+1
pointed by SP location will be
copied to Rd.
SP=SP-1
SP
PUSH Rr POP Rd
Rr will be copied to Stack @TOS SP will be incremented by 1. The
(pointed by SP). last filled location of stack will be
SP will be updated (decremented copied to Rd. The location will
by 1) to point to the next location now be treated as the TOS.
as the previous TOS has been
filled. 23
Example 1: Working of Stack with PUSH and POP
The example code shows here stack INCLUDE "M32DEF.INC"
.ORG 0
locations with PUSH and POP
commands. ;initialize the SP to point to the last location
of RAM (RAMEND)
The stack pointer is first initialized LDI R16, HIGH(RAMEND) ;load SPH
with the highest RAM address OUT SPH, R16
LDI R16, LOW(RAMEND) ;load SPL
(denoted by RAMEND). OUT SPL, R16
HIGH(RAMEND) returns higher byte LDI R31, 0
LDI R20, 0x21
of the address. LDI R22, 0x66
LOW(RAMEND) returns its lower byte. PUSH R20
Note, OUT is used to store them in PUSH R22
LDI R20, 0
SPH and SPL as these are I/O LDI R22, 0
registers, not GPR. POP R22
POP R31
24
Show the contents of registers and Stack before and after each instruction of the last
program.
Solution With each PUSH, SP is decremented. And with each POP, SP is incremented.
25
Practice Problem
Verify that the code below swaps the
contents of R20 and R21 (without using any
third register). Show the contents of
registers and stack after each
instruction.
Stack is LIFO.
R20 is pushed first.
And then R21.
First Pop: When Stack contents are popped
in R20, following the LIFO sequence, R20
gets the contents of R21 (which was pushed
later). 26
SUBROUTINES (CALL and RET Instructions)
Creating and Calling Subroutines. Effect of
Subtroutines on PC and Stack.
27
CALL Instruction
Subroutines are made up of a sequence of instructions that can receive data, process it and produce
some result.
CALL is used to call a subroutine defined anywhere in the program memory.
CALL is a 4-byte (32-bit) instruction, 10 bits are used for the opcode and the other 22 bits, k21–k0, are used
for the address of the target subroutine, just as in the JMP instruction.
28
CALL (Usage for subroutine) MAIN:
Let’s assume a subroutine named ADD_TWO is defined at program
:
memory location 0x300.
:
To call this subroutine in the main program, CALL instruction is used.
LDI R16, 10
LDI R17,20
CALL 0x300
CALL ADD_TWO
Should be used in the main program to call the subroutine.
CLR R20
Instead of using the address, we can use a label
:
As used ADD_TWO here.
29
CALL
STACK POINTER Before execution of Call instruction.
30
CALL
STACK POINTER After execution of Call instruction.
PC => 300, SP is decremented by 2.
31
CALL & RET
● To make sure that the AVR knows where to come back to after execution of the
called subroutine, the microcontroller automatically saves on the stack the
address of the instruction immediately below the CALL.
● When a subroutine is called, control is transferred to that subroutine, and the
processor saves the PC (program counter) of the next instruction on the stack
and begins to fetch instructions from the new location.
● After finishing execution of the subroutine, the RET instruction transfers
control back to the caller using PC stored on Stack.
● Every subroutine needs RET as the last instruction.
● ALL CODES THAT USE SUBROUTINES, MUST HAVE INITIALIZE THE STACK AT
THE START (i.e, save RAMEND in SPH and SP)
32
CALL INSTRUCTION & ROLE OF STACK
● When a subroutine is called, the processor first saves the address of the instruction just
below the CALL instruction on the stack, and then transfers control to that subroutine.
This is how the CPU knows where to resume when it returns from the called subroutine.
● The value of the program counter is broken into 2 bytes. The higher byte is pushed onto
the stack first, and then the lower byte is pushed.
● After CALL instruction, the stack pointer is decremented by 2.
37
Example # 1 (b)
Initially, the SP is 0x85F in this example.
38
Calling multiple subroutines
The main program may call
multiple subroutines. The
structure of code is shown
here.
39
Calling Subroutine Inside a Subroutine
A subroutine may call another subroutine in its body. In that case, the stack LIFO
comes handy. See the example below and analyze the contents of stack. Observe
how control transfer takes place from main program to subroutine 1 and then
subroutine 2. After 2nd subroutine, the control is transferred back to subroutine 1
and upon its completion, it’s finally transferred to the main program.
40
41
42
Practice Problem LDI R16, HIGH(RAMEND)
OUT SPH, R16
For the code given here, complete the following table:
LDI R16, LOW(RAMEND)
RAMEND= 0x08FF
Show contents after the execution of each instruction. OUT SPL, R16
Note CALL, RET and STS are 4B instructions, Take 2
program mem locations.
LDI R17, 10
Instruction R17 Memory Memory SP PC ADD R17, R17
(In Location Location
CALL MEM_SAVE
Sequence 0x100 0x200
of CLR R17
execution)