Файл: 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