Файл: Introduction to Microcontrollers. Architecture, Programming, and Interfacing of the Motorola 68HC12 (G.J. Lipovski, 1999).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 14.06.2025
Просмотров: 1414
Скачиваний: 0
6,4 Calling And Returning Mechanisms |
165 |
The extended local access of stacked local variables can be used with this technique. Consider the body of the subroutine after the PSHC instruction and before the PULC instruction as a program segment. The local variables are allocated just after the PSHC instruction that saves registers and are deallocated just before the PULC instruction that returns to the calling routine. You now look at the saved register values as stacked local variables of an outer program segment that includes the PSHD, PSHC, PULC, and PULD instruction. Using extended local access, you can read these registers and write into them, too. This allows you to output data in a register, even if the data are saved.
REGCC: |
EQU |
0 |
||
REGD: |
EQU |
1 |
||
REGX: |
EQU |
3 |
||
REGY: |
EQU |
5 |
||
* |
||||
SUB: |
PSHY |
; Save Y |
||
PSHX |
; Save X |
|||
PSHD |
; Save D |
|||
PSHC |
; Save CC |
|||
LDD |
REGX, SP |
; Get to caller's X value |
||
ADDD |
REGY, SP |
; Add to caller's Y value |
||
STD |
REGY, SP |
; Result to caller's Y value |
||
PULC |
; Restore CC |
|||
PULD |
; Restore |
D |
||
PULX |
; Restore |
X |
||
PULY |
; Restore |
Y |
||
RTS |
;Return |
|||
Figure 636. Saving and Restoring All the Registers |
||||
SUB |
LBRA |
SUBO |
||
LBRA |
SUB1 |
|||
LBRA SUB2 |
||||
SUBO: |
; performinitialization |
|||
RTS |
||||
SUB1: |
; perform output |
|||
RTS |
||||
SUB2: |
; performtermination |
|||
RTS |
||||
Figure 637. A Subroutine with Multiple Entry Points
As an example of this, look at the preceding example again, now using saved registers as stacked local variables of an outer program segment. See Figure 6.36. This idea was expanded earlier to cover the passing of arguments on the stack. The basic idea is that you just have to know where the data are, relative to the current stack pointer SP, in order to access the data. Thus, access to the saved registers, the caller's stacked local
6.4 Calling And Returning Mechanisms |
169 |
* original variables |
|
RESULT; DS.W |
1 |
*
*SUBROUTINE DOTPRD
*LOCALVARIABLES
*
TERM: |
EQU |
0 |
|
MBYTES: EQU |
2 |
||
* Saved registers |
|||
* |
|||
REGCC: |
EQU |
0+NBYTES |
; saved condition code register |
REGB: |
EQU |
1+NBYTES |
; saved accumulator B ~ note "backwards" |
REGA: |
EQU |
2+NBYTES |
; saved accumulator A —note "backwards" |
REGX: |
EQU |
3+NBYTES |
; saved index register X |
REGY: |
EQU |
5+NBYTES |
; saved index register Y |
* |
|||
DOTPRD: LEAS |
-NBYTES,SP |
||
LDAA |
REGA,SP |
||
LDAB |
REGB,SP |
||
MUL |
|||
STD |
TERM, SP |
; First term to local variables |
|
LDAA |
REGX+lr SP |
||
LDAB |
REGY+1,SP |
||
MUL |
|||
ADDD |
TERM, SP |
; Dot product into D |
|
STAA |
REGA, SP |
; Dot product high byte to output parameter |
|
STAB |
REGB, SP |
; Dot product low byte to output parameter |
|
LEAS |
NBYTES, SP |
; Deallocate local variables |
|
RTI |
|||
Figure 6.43. An SWI Handler |
|||
entry: MOVW |
#DOTPRD,$FFP6 |
a. Initialization (done just once) |
|
LDAA |
#1 |
LDAB |
#2 |
LDX |
#3 |
LDY |
#4 |
SWI |
|
STD |
RESULT ; Put in global location |
BRA |
* |
b. Calling sequence (done each time the operation is to be performed).
Figure 6.44. Calling an SWI Handler
7
Arithmetic Operations
This chapter deals with how one number crunches, using algebraic formulas, and how one writes subroutines for conversion between different bases, multiple-precision integer arithmetic, floating-point arithmetic, and fuzzy logic.
The first section describes unsigned and signed multiplication and division. Although the subroutines developed herein are in fact equivalent to 6812 instructions, they clearly illustrate the algorithms used to execute these instructions in a typical controller, and easily developed variants of these subroutines are usable on other microcontrollers that do not have these instructions.
In the next section, we develop ways to convert integers between number systems, such as binary and decimal. These techniques are needed when you input numbers from a terminal keyboard and output numbers to a terminal display. A full comparison of these techniques is made, examining all known possibilities and selecting the best, something that you should try to do in writing any of your own subroutines for any purpose.
The third section presents a technique to write program segments that evaluate algebraic formulas. The operations in the formulas are implemented with macros. Formula evaluation becomes a sequence of macro calls. You can hand assemble these macros. The actual variables used in the formula could be 32-bit integers, floating-point numbers, or any other type of variable that the subroutines have been written to handle.
Some C compilers do not support long and float data types. Section 7.4 shows how to perform 32-bit signed and unsigned integer arithmetic, which is useful to one who uses a microprocessor in a numerical control application. The fifth section deals with floating-point arithmetic. These sections will provide subroutines that enable you to perform arithmetic using these numbersystems.
Section 7.6 deals with fuzzy logic, for which the 6812 has special instructions. This section will give you some background so that you can describe a fuzzy logic system, and you can write assembly language subroutines to execute fuzzy logic.
After reading this chapter, you should be able to convert integers from one base to another. You should be able to write a sequence of subroutine calls to evaluate any algebraic formula and write subroutines to work out any multiprecision arithmetic operation, especially 32-bit long arithmetic. You should understand the principles of floating point arithmetic and fuzzy logic to the point that you could write subroutines for the usual floating-point and fuzzy logic operations.
179
7,1 Multiplicationand Division |
181 |
0010
0110 ) 0001101
0011
0000
0110
0001
0000
0001
Another way of doing the bookkeeping of this last version is to first put all zeros in the nibble A and put the dividend in nibble B so that the contents of A:B look like
which we will think of as our initial 8-bit state. Next, shift the bits of A:B left, putting 1 in the rightmost bit of B if the divisor can be subtracted from A without a carry, putting in 0 otherwise. If the subtraction can be done without a carry, put the result of the subtraction in A. Repeat this shift-subtract process three more times to get the remainder in A and the quotient in B.
*
*DIVIDE divides the 1-byte unsigned number in B (dividend) by the
*1-byte unsigned number in A (divisor), putting the quotient in B and
*the remainder in A. Register Y is unchanged.
*
DIVIDE: |
PSHA |
; Save divisor |
|
CLRA |
; Expand dividend, fill with zeros |
||
* |
LDX |
#8 |
; Initialize counter |
LOOP: |
ASLD |
; Shift dividend and quotient left |
|
* |
|||
CMPA |
0, SP |
; Check if subtraction will leave positive rslt |
|
* |
BLO |
JUMP |
; If so |
SUBA |
0, SP |
; Subtract divisor |
|
* |
INCB |
; Insert 1 in quotient |
|
JUMP: |
DBNE |
X,LOOP |
; Decrement counter |
* |
|||
LEAS |
1, SP |
; Balance stack |
|
RTS |
; Return with quotient in B, remainder in A |
Figure 72.8-Bit Unsigned Divide Subroutine