4.4 Subroutine and Stack
Subroutine
• A subroutine is a sequence of instructions that can be called from different places in a program.
Copyright By PowCoder代写 加微信 powcoder
• Two reasons for creating subroutines:
– The problem is too big: Easier to divide the problem into smaller sub-problems
– There are several places in a program that need to perform the same operation.
Calling subroutine: Is it just branching?
• Calling subroutine involves the “jumping” part, which is the same as branching.
• But we need to get back to the main program after the subroutine returns.
• Thus, we need a location in which the return address can be stored.
Image courtesy of S. Katzen, The essential PIC18 Microcontroller, Springer
Return Address Stack
• The program counter is pushed to the top of the return address stack when calling a subroutine.
• 31-word-by-21-bit memory
• 5-bit stack pointer (STKPTR) pointing to the top of stack (TOS)
Return Address Stack Pointer (STKPTR)
• STKPTR is 0 when powered up
• STKPTR is 1 upon the first subroutine call.
• Thus, the stack has 31 spaces for address storage.
– Useful for nested subroutine calls.
• The TOS address is readable and writable through three registers: TOSU, TOSH, TOSL.
Demonstration: SubroutineDemo.asm
• You can run this demonstration yourself at home by following these instructions:
– Download the SubroutineDemo.asm file available at Canvas.
– Create a new project in MPLAB. (For instructions on how to do this, refer to Tutorial Week 3).
– Step through the program and stop when the green arrow is pointing to the call instruction.
– Open the Hardware Stack window by selecting View→Hardware Stack.
– In the Watch window, type STKPTR and TOS in the Symbol column.
– Continue stepping through the program and see what happens.
What happens when calling and returning from a subroutine?
(a) Initial state
Image courtesy of S. Katzen, The essential PIC18 Microcontroller, Springer
What happens when calling and returning from a subroutine?
Calling: [Figure (b)]
1. Increment Stack Pointer (STKPTR).
2. Copy the 21-bit contents of the Program Counter (PC) into the stack at the location pointed to by the STKPTR (i.e., this stored item is the address of the instruction following the call instruction)
3. The address of the instruction with label UseBSR (entry point of the subroutine) overwrites the original state of the PC (i.e., program jumps to subroutine).
Returning: [Figure (c)]
1. Copy the 21-bit address in the stack pointed to by the STKPTR into the PC.
2. Decrement the STKPTR.
call instruction
• Encodessubroutine address by absolute address (similar to goto).
• Increment stack pointer (STKPTR)
• Top of Return Address Stack (TOS) = address of the instruction following the call instruction.
return instruction
• PutTopofReturn Address Stack (TOS) to Program Counter (PC).
• Decrement stack pointer (STKPTR)
rcall instruction
• Encodessubroutineaddress by relative address (similar to bra).
• 11 bits are used to store the relative address of the
targeting instruction→ rcall can jump forward for
a max. of 1023 instructions and backward for a max. of 1024 instructions.
• Store address in stack and increment STKPTR the same way as the call instruction.
Nested subroutines
What happens if I call another subroutine (SR2) within a subroutine (SR1)?
TOS = PC1 TOS = PC2 PC = PC2 PC = PC1
STKPTR = 1 STKPTR = 2 TOS = PC1 STKPTR = 0 STKPTR = 1
Image courtesy of S. Katzen, The essential PIC18 Microcontroller, Springer
A demonstration on nested subroutines
• Write a program to calculate the value of f(0x07) where
– f(x) = g(x+0x18) + 0x05 – g(x) = x+0x12
• Referring to the NestedSubroutine.asm file uploaded
to Canvas, determine the status of the stack and the values of TOS, and STKPTR at Points 1-4.
Memory Machine LINE SOURCE
Address Code
000000 EF?? F???
000004 0E07 000006 6E00 000008 EC?? F??? 00000C 5002 00000E D7FF
000010 5000 000012 0F18 000014 6E01 000016 D??? 000018 5003 00001A 0F05 00001C 6E02 00001E 0012
000020 5001
000022 0F12
000024 6E03
000026 0012
00008 CBLOCK 0X00
00009 finput
00010 ginput
00011 foutput
00012 goutput
00013 endc
00014 ;———————————————————————
00016 ORG 0x0000
00017 goto Main ;go to start of main code
00018 ;———————————————————————
00019 Main: movlw 0x07
movwf finput, A
movf foutput, W, A
movf finput, W, A
addlw 0x18
movwf ginput, A
movf goutput, W, A
addlw 0x05
movwf foutput, A
;[WREG] = [finput]
;[WREG] = [WREG] + 0x18
;[ginput] = [WREG]
;[WREG] = [goutput]
;[WREG] = [WREG] + 0x05
;[foutput] = [WREG]
movf ginput, W, A; [WREG] = [ginput] addlw 0x12; [WREG] = [WREG] + 0x12 movwf goutput, A; [goutput] = [WREG] return ; Point 4
Flow Diagram of the Program
You should be able to ….
• Code PIC subroutine.
• Describe the stack and its use in subroutine.
• Discuss how branching and subroutine calling affect the pipelining mechanism.
• Describe the difference of the call and rcall instructions.
4.5 Register Indirect Addressing Mode in PIC18
Dealt with in Chapter 2:
• Immediate addressing mode • Direct addressing mode
• Register Indirect addressing mode
Immediate Addressing Mode
• The operand is a literal constant
• The instruction has a ‘L’ (literal)
• Can be used in loading information and performing arithmetic and logic operations ONLY in the WREG register
• Examples:
– movlw 0x25; load 0x25 into [WREG]
– sublw D’62’; subtract [WREG] from 62 – addlw 0x40; add WREG with 0x40
Register Direct Addressing Mode
• The operand data is in a file register in data memory.
• The address of the file register is provided as a part of the instruction.
• Example:
– movwf 0x40, A; copy [WREG] into file register location 0x040
Destination Option in Direct Addressing Mode
• Provides an option to store the result either in WREG or in file register.
• Example:
movwf 0x20, A incf 0x20, W, A incf 0x20, W, A incf 0x20, F, A incf 0x20, F, A
;[WREG] = 0
;[0x20] = 0, [WREG] = 0 ;[0x20] = 0, [WREG] = 1 ;[0x20] = 0, [WREG] = 1 ;[0x20] = 1, [WREG] = 1 ;[0x20] = 2, [WREG] = 1
Register Indirect Addressing Mode
• Suppose you want to copy value 0x55 to location 0x040 to 0x044.
• A fixed address must be specified in direct addressing mode as an operand.
• Thus, using direct addressing mode, one instruction copies to one register:
movlw 0x55 movwf 0x40, A movwf 0x41, A movwf 0x42, A movwf 0x43, A movwf 0x44, A
• How about if you want to copy 0x55 to 1000 consecutive memory locations?
Register Indirect Addressing Mode
• Three registers known as file select registers (FSRx, where x = 0, 1, 2) store addresses of the data memory location (i.e., pointers).
• A FSR is a 12-bit register which is split into two 8-bit registers, known as FSRxL and FSRxH.
• To load a data memory address into a FSR, use LFSR (Load FSR):
– LFSR 0, 0x030; load FSR0 with 0x030 – LFSR 1, 0x040; load FSR1 with 0x040 – LFSR 2, 0x06F; load FSR2 with 0x06F
Register Indirect Addressing Mode
• FSRx is associated with a INDFx register (where x = 0, 1, 2).
• When reading from (writing to) the INDFx register, we are reading from (writing to) the file register pointed to by the FSR
• Example:
LFSR 0, 0x030
movwf INDF0
;FSR0 points to data memory
address 0x030
;copy the content of WREG into
data memory address 0x030
e.g., Write a program to copy the value 0x55 to location 0x40 to 0x44
Direct Addressing Mode
movlw 0x55 movwf 0x40, A movwf 0x41, A movwf 0x42, A movwf 0x43, A movwf 0x44, A
Indirect Addressing Mode
COUNT equ 0x00
movlw 0x05
movwf COUNT, A
movlw 0x55
LFSR 0, 0x040
Loop: movwf INDF0
incf FSR0L, F decfsz COUNT, F, A bra Loop
Register Indirect Addressing Mode
• Indirect addressing mode allows looping
• However, we incremented only [FSRxL]
• To deal with FSRxH, we need to use branching instructions conditioned on the Carry Bit (e.g., for copying contents to addresses from 0x090 to 0x110)
• Solution: Auto-increment option
Auto-increment option for FSR
• POSTDECx
– movwf POSTDEC0 does what movwf INDF0 did, but in addition, [FSR0] will be decremented by 1 after the execution
• POSTINCx
– movwf POSTINC0 increments [FSR0] by 1 after the move operation.
– movwf PREINC0 increments [FSR0] by 1 before the move operation.
– movwf PLUSW0 adds an offset to [FSR0] that equals to the content of WREG before the move operation. However, the content of FSR0 will not be modified after operation (different from previous three SFRs)
• Try to compile and run FSRAutoIncOptions.asm to verify what I describe here.
• Before operation:
[FSR0] = 0x020, [WREG] = 0x05
• Afteroperation:
– movwf POSTDEC0:
[FSR0] = 0x01F, [020] = 0x05
– movwf POSTINC0
[FSR0] = 0x021, [020] = 0x05
– movwf PREINC0
[FSR0] = 0x021, [021] = 0x05
– movwf PLUSW0
[FSR0] = 0x020 (unchanged), [025] = 0x05
Previous example revisited
e.g., Write a program to copy the value 0x55 to location 0x040 to 0x044
COUNT equ 0x00 movlw 0x05
movwf COUNT, A movlw 0x55
LFSR 0, 0x040
Loop: movwf POSTINC0
decfsz COUNT, F, A
Introduce movff before next example…
• Copy a block of 5 bytes of data from data memory locations starting from 0x030 to data memory locations starting from 0x060
COUNT equ 0x00 movlw 0x05 movwf COUNT, A lfsr 0, 0x030 lfsr 1, 0X060
Loop: movff POSTINC0, POSTINC1 decfsz COUNT, F, A
Add the contents in data memory locations
0x040-043 together and place the result in locations 0x006 and 0x007
COUNT equ 0x00
L_BYTE equ 0x06
H_BYTE equ 0x07
Loop: Next:
LFSR 0, 0X040
movlw 0x04
movwf COUNT, A
clrf H_BYTE, A
clrf L_BYTE, A
movf POSTINC0, W; addwf L_BYTE, F, A; bnc Next
incf H_BYTE, F, A; decfsz COUNT, F, A bra Loop
You should be able to …..
• List all the addressing modes of the PIC18 microcontroller.
• Contrast and compare addressing modes.
• Code PIC instructions using each addressing mode.
• Access the data memory file register using various addressing modes.
4.6 Lookup Table
Why Lookup Table?
• Suppose you want to compute the value of the function f at x.
– Computation may be complicated, thereby taking long time to get the result.
– The function cannot be represented analytically.
• You may represent the results in an array or lookup table and retrieve the suitable answer as needed without going through the computation once again. This is much more efficient.
• There are two methods of implementing lookup table in PIC18:
– Computed goto
– Using table read operations
Applications: Mapping number to digit pattern to be displayed in LED
Use lookup table to implement a subroutine with the following input/output:
– Input: A number N ranging from 0 to 9 stored in WREG.
– Output: The 7-segment LED digit pattern corresponding to the input number.
Image courtesy of S. Katzen, The essential PIC18 Microcontroller, Springer
Computed Goto
• Add an offset to PCL to access the appropriate item in the table
• retlw will load the desired item to WREG
• e.g., Implement a look-up table in program memory, and write a program to find y where y(x) = x2+5, and x is between 0 and 4.
Computed Goto
movf x, W, A
addwf WREG, W addwf PCL, F
retlw d‘5’; f(0) retlw d‘6’; f(1) retlw d‘9’; f(2) retlw d‘14’; f(3) retlw d‘21’; f(4)
Disadvantage of computed goto
• 16-bit instruction is used to store each 8- bit value. In each instruction,
– retlw takes 8-bit
– the value stored takes 8-bit
• For a more efficient use of program memory space, use table read operation.
Using Table Read Operations
• We can use program memory to store fixed data.
• Use the db (define byte) directive to define fixed data in program memory.
• Example:
org 0x000500
array db d’5’, d’6’, d’9’, d’14’, d’21’
Program Memory Address
Value in decimal
Reading Data Using TBLPTR and TABLAT
• To access data in a location in program memory, we need a register specifying which location we want to access→TBLPTR
• TBLPTR must have 21 bits to address the whole range of program memory.
• TBLPTR is divided into three 8-bit parts: TBLPTRL (low), TBLPTRH (high), TBLPTRU (upper).
• We need a register to store the data fetched by a table read operation→TABLAT
Table Read Operations
– After read, TBLPTR stays the same
– Reads then increments TBLPTR
– Reads then decrements TBLPTR
– Increments TBLPTR then reads
org 0x000500
array db d’5′, d’6′, d’9′,…
Before operation:
[TBLPTR] = 000500
After operation: • tblrd*
[TABLAT] = 05; [TBLPTR] = 000500
[TABLAT] = 05; [TBLPTR] = 000501
[TABLAT] = 05; [TBLPTR] = 0004FF
[TABLAT] = 06; [TBLPTR] = 000501
Steps for Table Read from Program Memory
1. Write an array to program memory by using the db directive.
2. Specify the table pointer (TBLPTR) from which data is read.
3. Perform a tblrd instruction.
4. The data read is stored in the table latch (TABLAT).
Implement a look-up table in program memory, and write a program to find y where y(x) = x2+5, and x is between 0 and 4.
(implemented using computed goto previously)
Steps to implement this lookup table using tblrd operation:
1. In the .asm file, declare array:
org 0x000500
array db d’5′, d’6′, d’9′, d’14’, d’21’
2. Put starting address of array into TBLPTR: movlw upper array
movwf TBLPTRU
movlw high array movwf TBLPTRH movlw low array movwf TBLPTRL
array TBLPTR
TBLPTRUTBLPTRHTBLPTRL 3. Perform tblrd*+ x+1 times (note: x is the argument in y(x))
4. Read the result from TABLAT.
Demonstration
• We will look at the program LookupTable.asm together.
Applications: Mapping number to digit pattern to be displayed in LED
Use lookup table to implement a subroutine with the following input/output:
– Input: A number N ranging from 0 to 9 stored in WREG.
– Output: The 7-segment LED digit pattern corresponding to the input number.
Image courtesy of S. Katzen, The essential PIC18 Microcontroller, Springer
You should be able to …..
• Useretlwandtblrdtobuildalookup table.
• Read contents from a lookup table.
• Describe the disadvantage of the computed
goto (retlw) method for implementing a lookup table.
• Build lookup tables for LED display.
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com