0% found this document useful (0 votes)
51 views45 pages

Week 13-14 PC Stack & Subroutines

The document discusses the program counter, stack pointer, and stack in embedded systems. It explains how the program counter tracks the next instruction and can be affected by branch instructions. It also describes how the stack pointer points to the top of the stack in memory and how push and pop operations modify the stack pointer during function calls.

Uploaded by

Muhammad Subhan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
51 views45 pages

Week 13-14 PC Stack & Subroutines

The document discusses the program counter, stack pointer, and stack in embedded systems. It explains how the program counter tracks the next instruction and can be affected by branch instructions. It also describes how the stack pointer points to the top of the stack in memory and how push and pop operations modify the stack pointer during function calls.

Uploaded by

Muhammad Subhan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 45

Program Counter, Stack and

Subroutines
Week 13-14
EE- 354 Embedded Systems
Spring, 23

1
Program Counter

Concept of Program Counter and Effect of Branch


Instructions on PC

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.

Since all AVR instructions are 16 or 32 bits wide, the


flash is organized as 16K x 2B = 32 KB.

When the AVR is powered up, the PC (program


counter) has the value of 00000 in it. This means
that it expects the first opcode to be stored at ROM
address $00000.

4
Program Counter
Consider the code
LDI R16,0
LDI R17,20
HERE: ADD R16, R17
JMP HERE

In this code, when JMP


instruction is executed, PC is
not incremented. Rather, it
becomes equal to the address
of ADD instruction.

The image at RHS shows that


after execution of 4
instructions, PC =2 again.

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)

Current PC = Address of BEQ + 1 = 7


02 = 7 + Offset ⇒ Offset = -5
Current PC - Offset (7-5) is required to
reach the label HERE (that points to $02).

00007 (Address of next location after branch)


Remember, each location of Prog Mem is 2B wide. 8
9
Branch Instruction Decoding
Practice Problem #1: Using the machine format of BREQ instruction,
write the HEX equivalent of it for the following code.

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.

BRNE Machine Format

ANSWER: F411 BRNE GO

11
Branch Instruction Decoding
Practice Problem #3: Using the machine format of BRGE
instruction, write the HEX equivalent of it for the following code.

BRGE Machine Format

ANSWER: F41C BRGE GO

12
Branch Instruction Decoding
Practice Problem #4: Using the machine format of BRNE
instruction, write the HEX equivalent of it for the following code.

ANSWER: F7E9 BRNE GO

13
STACK and STACK POINTER

Concept of Stack, Stack Pointer, Push and Pop

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,

64 I/O Reg & 160 Extended I/O LDI R16, HIGH(RAMEND)


OUT SPH, R16
LDI R16, LOW (RAMEND)
32-GPRs (R0-R31) OUT SPL, R16
$0000
Data Memory addresses and structure. Stack is implemented at the top. 20
STACK AND STACK POINTER
PUSH & POP
The storing of CPU information to stack is PUSH, and the loading of
stack contents back into a CPU register is called a POP.
In other words, a register is pushed onto the stack to save it and
popped off the stack to retrieve it.
The two commands (Push and Pop) are:

PUSH Rd; (Rd is copied to top of the stack and then SP is


decremented to point to next location which is empty- i.e. updated
top).

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 Pointer is initialized.


SPH= $08
SPL= $FF

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.

K in 22 bits: 00 0000 0000 0011 0000 0000 -0x300


.ORG 0x300 ; .ORG directive is used
(the address of location where subroutine is stored in memory). to organize memory(the code below will
be saved at address 0x300)
The machine code of CALL ADD_TWO will be ADD_TWO:
1001 0100 0000 1110 LDI R20,2
0000 0011 0000 0000 ADD R16,2
= 940E 0300 RET

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.

For the previous example, the


instruction below CALL is
saved at address 0x0008.
After execution of CALL, this
is saved at TOS
(Stack-memory location
0x08FF). And then SP is
decremented by 2.
33
Return Instruction & Role of Stack
● When the RET instruction at the end of the subroutine is executed, the top location of the
stack (which has address of the instruction below the CALL) is copied back to the program
counter and the stack pointer is incremented. So the instruction below the CALL
instruction is executed subroutine.
● After RET, SP is incremented by 2.

Before execution of RET After execution of RET

PC is updated with contents of STACK (0x0008)


saved in SRAM And then, SP is incremented by 2.
34
Example # 1
● SOLUTION

Toggle all the bits of Port B by sending to it


the values $55 and $AA continuously. Put a
time delay between each issuing of data to
Port B.
● The code first initializes SP
● A While loop is added to toggle portB
continuously.
● The DELAY subroutine is called each
time when portB is toggled.
● The subroutine produces a time delay
by NOP (No Operation) Instructions.
● NOP simply wastes processor time in
execution without affecting or writing
any of the registers/ memory.
● A loop runs in DELAY 255 times. The
loop body contains 2 NOPs. Repeated
execution of NOPs introduces certain
time delay whenever the DELAY is
35
called.
Example # 1 ● SOLUTION

To understand the role of the stack in


call instruction and returning, ine the
contents of the stack and stack pointer.
1. Notice the DELAY subroutine. After
the first “CALL DELAY” is executed,
the address of the instruction right
below it, “LDI R16,0xAA”, is pushed
onto the stack, and the AVR starts
to execute instructions at address
0x300.
2. In the DELAY subroutine, the
counter R20 is set to 255 (R20 =
0xFF); therefore, the loop is
repeated 255 times. When R20
becomes 0, control falls to the RET
instruction, which pops the
address from the top of the stack
into the program counter and
resumes executing the instructions
after the CALL.
36
Example # 1(b)
Analyze the stack for
Example 1.

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.

Each time a subroutine is


called, stack saves address
of the next instruction after
that CALL. And returning
from that subroutine
updates PC with stack
contents.

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.

Example: Calling Subroutine Inside a Subroutine


Write a program to count up from 00 to $FF and send the count to Port B.
Use one CALL subroutine for sending the data to Port B and another one
for time delay. Put a time delay between each issuing of data to Port B.

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)

- - - - - 0000 .ORG 0x200


(Initially)
MEM_SAVE:
STS 0x100, R17
STS 0x101, R17
RET
43
Solution LDI R16, HIGH(RAMEND)
OUT SPH, R16
Instruction (In R16 R17 Data Data Mem SPH SPL PC STACK
Sequence of Memory 0x200 LDI R16, LOW(RAMEND)
execution) 0x100
- - - - - 0000 - OUT SPL, R16
LDI R16,... $08 - - - - - 0001 -

OUT SPH,... $08 - - - $08 - 0002 - LDI R17, 10


LDI R16,.. $FF - - - $08 - 0003 - ADD R17, R17
OUT SPL,.. $FF - - - $08 $FF 0004 - CALL MEM_SAVE
LDI R17,10 $FF 10 - - $08 $FF 0005 -
CLR R17
ADD R17,.. $FF 20 - - $08 $FD 0006 -

CALL $FF 20 - $08 $FD 0x200 0008 .ORG 0x200


(Add of CLR)
STS 0x100,.. $FF 20 20 - $08 $FD 0x202 0008 MEM_SAVE:
STS 0x101 $FF 20 20 - $08 $FD 0x204 0008
STS 0x100, R17
RET $FF 20 20 - $08 $FF 0008 0008
STS 0x101, R17
CLR R17 $FF 0 20 - $08 $FF 0008 0008 RET
44
Solution Note that Data memory
Location 0x200 is
Instruction (In R16 R17 Data Data Mem SPH SPL PC STACK
Sequence of Memory 0x200 unchanged / not affected.
execution) 0x100
- - - - - 0000 - This is because the code
LDI R16,... $08 - - - - - 0001 - doesn’t write to DM 0x200.
OUT SPH,... $08 - - - $08 - 0002 -

LDI R16,.. $FF - - - $08 - 0003 - However, the code


OUT SPL,.. $FF - - - $08 $FF 0004 - (subroutine) is saved at
LDI R17,10 $FF 10 - - $08 $FF 0005 -
0x200 (which is the
ADD R17,.. $FF 20 - - $08 $FD 0006 - location of Program
CALL $FF 20 - $08 $FD 0x200 0008 Memory not the DM.
(Add of CLR)
STS 0x100,.. $FF 20 20 - $08 $FD 0x202 0008
STS 0x101 $FF 20 20 - $08 $FD 0x204 0008

RET $FF 20 20 - $08 $FF 0008 0008

CLR R17 $FF 0 20 - $08 $FF 0008 0008


45

You might also like