Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Introduction to Microcontrollers. Architecture, Programming, and Interfacing of the Motorola 68HC12 (G.J. Lipovski, 1999).pdf
Скачиваний:
191
Добавлен:
12.08.2013
Размер:
29.57 Mб
Скачать

9.2 Expressions and Assignment Statements

257

The input and output statements use page-zero addressing, which provides improved static and dynamic efficiency over direct adddressing. Note that the MOVB instruction is not useful for accessing these I/O ports, because there is no page-zero address option in MOVB. The LDAB and STAB instructions above are more efficient than a MOVB instruction.

The assignment of I/O ports to global variable names should be written and executed before true global variables are assigned, because the origin will be set to the beginning of RAM (at $800) to assign true global variables. The declaration of globally defined I/O ports is often put in an #include file, which is inserted in a program before globals are defined in the program.

9.2 Expressions and Assignment Statements

In this section, we illustrate how operators are used in expressions. We will look at addition and subtraction statements that use same-width and different-width operands in a discussion of upcasting and downcasting. We will then study statements that use logical and arithmetic operators. We will carefully consider the increment and decrement operators and then look at expressions that save temporary results on the hardware stack.

The program in Figure 9.2a has several local and global variables, some of which are signed and others of which are unsigned, and some of which are 8-bit and others of which are 16-bit. Figure 9.2b shows assembly language developed from this program. Observe that each variable's name is an abbreviation of its characteristics; gsi is a global signed integer.

Many C statements are easily and efficiently translated into assembly language. This

is especially true when all the variables

in a statement are 8-bit char or unsigned

char

variables or when all the variables in a statement are 16-bit int or unsigned

int

variables. Assume the following statements

are written in Figure 9.2a's main.

Figure 9,2's statement

gsi

= lui + 12;

is easily encoded as

 

 

LDX

0, SP

; get 16-bit local variable

lui

 

 

LEAX

12, X

; add 12 (note that this is shorter than addd #12)

 

STX

$0801

; put into 16-bit global variable gsi

 

and similarly the statement

guc

= Isc

- 33;

is simply encoded as

 

 

LDAB

2, SP

; get 8-bit local variable Isc

 

 

SUBB

#33

; subtract 33

 

 

 

 

STAB

$0800

; put into 8-bit global variable guc

 

If a statement gets an int

variable and writes a char variable, the source is truncated

when it is read. Figure 9.2's statement guc

= lui

+ 9;

is encoded as

 

 

LDAB

1, SP

; get low byte of 16-bit local variable lui

 

ADDB

#9

 

; add 9

 

 

 

 

 

STAB $0800

; put into 8-bit global variable guc

 

An optimizing compiler can change the instruction ADDD #9

to ADDB #9

because the result will not be altered (reducing the precision is called

downcasting).

9.2

Expressions and Assignment Statements

 

 

259

 

If a statement gets a char variable and writes an int or unsigned

int

variable,

the result is sign extended when it is read. Figure 9.2's statement gsi =

gsi

+ Isc;

or equivalently gsi

 

+= isc ,•is simply encoded as

 

 

 

 

LDAA

2, SP

; get 8-bit global variable Isc

 

 

 

 

SEX

 

A, D

; upcast from char to int or unsigned

int

 

 

ADDD

$08 01

; add in 16-bit global variable gsi

 

 

 

STD

 

$0801

; put into 16-bit global variable

gsi

 

 

But if a statement gets an unsigned char variable and writes an int

or unsigned

int

variable, the high byte is cleared before the unsigned

char variable is read.

Figure 9.2's statement lui =

guc - 17; is encoded as

 

 

 

 

LDAB $0800

; get 8-bit global variable guc saved earlier

 

 

 

CLRA

 

 

; upcast from unsigned char to int

or unsigned

int

 

SUED

#17

; subtract 17

 

 

 

 

STD

0, SP

; put into 16-bit global variable lui

 

 

 

You should observe that the declaration char or int affects the instruction data length, and char and unsigned char determine whether, on upcasting, the 8-bit data is sign extended with an SEX instruction or filled with zeros using a CLRA instruction.

The previous examples should indicate to the C programmer how to decide how a

variable is

to be type cast. If its range of values is 0 to 127, declare it to

be an

unsigned

char, because upcasting is done with a short CLRA instruction rather than a

longer SEX

instruction. If its range is 0 to 256, declare it to be an unsigned

char,

but if the range is -128 to 127, declare it a char, to save space and time. Otherwise declare it to be int.

To discuss how common operators are handled, we use the following main as an example; it merely ANDs, ORs, multiplies, and divides some variables. Figure 9.3a's program is compiled into the assembly-language program in Figure 9.3b.

Logical bit-by-bit ANDing is illustrated in Figure 9.3 by the expression Isc = lsc& guc; or equivalentlyby Isc &= guc;, which is realized by

LDAA

2, SP

; get local variable Isc

ANDA $0800

; AND with global variable guc

STAA

2, SP

; put into local variable Isc

However, if one of the operands is constant, the BCLR instruction can be used. The expression in Figure 9.3, Isc = lsc& 0x12;,or equivalently Isc &= 0x12; is realized by

BCLR 2, SP, #23 7 ; ANDlocal variable Isc with inverted constant 0x12

Note that the complement of the constant is used in the operand of BCLR. Logical bit-

by-bit ORing is illustrated

in Figure 9.3 by the expression gsi - gsi | lui; or

equivalently bygsi |= lui;, which isrealizedby

 

LDD

$0801

; get global variable gsi

 

ORAA

1, SP

; OR with high byte of local variable

lui

ORAB

0, SP

; OR with low byte of local variable

lui

STD

$0801

; put into global variable gsi

 

260

 

 

 

 

Chapter 9

Implementation of C Procedures

unsigned

char

guc;

int

gsi;

 

 

 

main(){

char

Isc;

unsigned

int lui;

 

 

Isc

= Isc

&guc;

Isc &= 0x12;

gsi = gsi

| lui;

gsi

= gsi

& 0x1234; lui

= Isc * guc; lui

= lui / guc;

}

a.A C program

4:main(){ char Isc; unsigned int lui;

0000095B 1B9D

LEAS -3,SP

5:Isc = Isc & guc; Isc &= 0x12;

0000095D

A682

LDAA

2, SP

0000095F B40800

ANDA

$0800

00000962

6A82

STAA

2,SP

00000964

OD82ED

BCLR

2,SPf#237

6:gsi = gsi|lui; gsi = gsi|0x1234;

00000967

FC0801

LDD

$0801

0000096A

EA81

GRAB

1,SP

0000096C AA80

ORAA

0,SP

0000096E

7C0801

STD

$0801

00000971

1C080112

BSET

$0801,#18

00000975

1C080234

BSET

$0802,#52

7:lui = Isc *guc;

00000979

A682

LDAA

2,SP

0000097B B706

SEX

ArY

0000097D

F60800

LDAB

$0800

00000980

87

CLRA

 

00000981

13

EMUL

 

00000982

6C80

STD

0,SP

7:lui = lui / guc;

00000984 F60800

LDAB

$0800

00000987

87

CLRA

 

00000988

B745

TFR

D,X

0000098A ECB1

LDD

0,SP

0000098C

1810

IDIV

 

0000098E

6E80

STX

0,SP

8: }

 

 

 

00000990

1B83

LEAS

3,SP

00000992

3D

RTS

 

b. Assembly Language Generated by Part (a)

Figure 93. A C Program with SomeOperators

However, if one of the operands is constant, BSET can be used. The expression gsi =

gsi | 0x1234; orequivalently gsi

|= 0x1234; isrealizedby

BSET

$0801,#18

;OR high byte of global variable gsi with Ox 12

BSET

$0802, #52

; OR global variable low byte gsi with 0x34

262

 

Chapter 9 Implementation of C Procedures

LDX

$0801

;getgsi

INX

 

; add 1

STX

$0801

; put it back

and the statement lui—; in Figure 9.4 is implemented

LDX

1, SP

; get lui

DEX

 

; subtract 1

STX

1, SP

; put it back

When the increment or decrement operator appears in a larger expression, the initial or final value of the variable used in the outer expression depends on whether the pair of "+" or "-" signs appearsbefore or after the variable. Isc = ++ guc; is implemented

unsigned char guc; int gsi; main{){ char Isc; unsigned int lui;

guc++; Isc—; gsi++; lui—; Isc = ++guc; Isc = guc++;

}

a.A C Program

4:main(){ char Isc; unsigned int lui;

0000095B 1B9D

LEAS -3,SP

5:guc++;

0000095D

720800

INC

$0800

6:

Isc—;

 

 

00000960

6380

DEC

0,SP

7:gsi++;

00000962

FE0801

LDX

$0801

00000965

08

INX

 

00000966

7E0801

STX

$0801

8:lui—;

00000969

EE81

LDX

1,SP

0000096B 09

DEX

 

0000096C

6E81

STX

1,SP

9:Isc = ++guc;

0000096E

720800

INC

$0800

00000971

B60800

LDAA

$0800

00000974

6A80

STAA

0,SP

10:Isc = guc++;

00000976

A680

LDAA

0,SP

00000978

720800

INC

$0800

0000097B

6A80

STAA

OrSP

0000097D

1B83

LEAS

3,SP

0000097F

3D

RTS

 

b. Assembly Language Generatedby Part (a)

Figure 9.4. A C Program with Incrementing andDecrementing

264

Chapter 9 Implementation of C Procedures

unsigned char guc; int gsi;

main(){ char Isc; unsigned

int lui;

lui

-= Isc; lui = (lui

& Oxfc7f) j ((Isc « 7) & 0x380);

lui

= (lui « 3) + (lui

« 1) + Isc - '0' ;

}

a.C Program

4:main(){ char Isc; unsigned int lui; lui -= Isc;

0000095B

1B9D

LEAS

-3,SP

0000095D A682

LDAA

2,SP

0000095F B706

SEX

A,Y

00000961 EC80

LDD

0,SP

00000963

35

PSHY

 

00000964

A3B1

SUBD

2,SP+

00000966

6C80

STD

0,SP

6:

lui = (lui

& Oxfc7f)|

((Isc « 7) & 0x380);

00000968

3B

PSHD

 

00000969 C680

LDAB

#128

0000096B

87

CLRA

 

0000096C

35

PSHY

 

0000096D

13

EMUL

 

0000096E C480

ANDB

#128

00000970

8403

ANDA

#3

00000972

3B

PSHD

 

00000973

EC84

LDD

4,SP

00000975

C47F

ANDB

#127

00000977

84FC

ANDA

#252

00000979

AA81

ORAA

1,SP+

0000097B

EA81

GRAB

0,SP+

0000097D

6C82

STD

2,SP

7:lui = (lui « 3) + (lui « 1) + Isc -'0 ' ;

0000097F

59

ASLD

 

00000980

59

ASLD

 

00000981

59

ASLD

 

00000982

B745

TFR

D,X

00000984

EC82

LDD

2,SP

00000986

59

ASLD

 

00000987

1AE6

LEAX

D,X

00000989

B754

TFR

X,D

0000098B

E380

ADDD

0,SP

0000098D

830030

SUBD

#48

00000990

6C84

STD

4,SP

00000992

1B87

LEAS

7,SP

00000994

3D

RTS

 

b. Assembly Language Generatedby Part (a)

Figure 9.5. A C Program with ORing, ANDing and Shifting

266

Chapter 9 Implementation of C Procedures

unsigned char guc; int gsi;

 

 

main{){

char

Isc; unsigned int lui;

 

 

guc

= Isc

> -3;

Isc = lui > 5; lui

= gsi

>= 0;

gsi

= lui

>= 0;

gsi = Isc — 0;

Isc =

(gsi & 4) == 0;

1

a.A C Program

5:guc = Isc > -3; Isc = lui > 5;

0000095B A6AD

LDAA

3,-SP

 

0000095D

81FD

CMPA

#253

 

0000095F

2E02

BGT

*+4

;abs = 0963

00000961

87

CLRA

 

 

00000962

8F8601

CPS

#34305

 

00000965

7A0800

STAA

$0800

 

00000968

EC81

LDD

1,SP

 

0000096A

8C0005

CPD

#5

 

0000096D

2202

BHI

*+4

;abs = 0971

0000096F

87

CLRA

 

 

00000970

8F8601

CPS

#34305

 

00000973

6A80

STAA

0,SP

 

7:lui = gsi >= 0;

00000975

FC0801

LDD

$0801

 

00000978 2A02

BPL

*+4

;abs = 097C

0000097A

C7

CLRB

 

 

0000097B

8FC601

CPS

#50689

 

0000097E

87

CLRA

 

 

0000097F

6C81

STD

1,SP

 

8s

gsi = lui >= 0;

 

 

00000981

C601

LDAB

#1

 

00000983

87

CLRA

 

 

00000984

7C0801

STD

$0801

 

9:gsi = Isc == 0;

00000987 A680

LDAA

0,SP

 

00000989

2702

BEQ

*+4

,-abs = 098D

0000098B

C7

CLRB

 

 

0000098C

8FC601

CPS

#50689

 

0000098F

87

CLRA

 

 

00000990

7C0801

STD

$0801

 

10:Isc = (gsi& 4) == 0;

00000993

1F08020402

BRCLR

$0802,#4,*+7

;abs = 099A

00000998

87

CLRA

 

 

00000999

8F8601

CPS

#34305

 

0000099C 6AB2

STAA

3,SP+

 

b. Assembly Language Generated by the body of Part (a)

Figure 9.6. A Program with Boolean Operators

268

 

 

Chapter 9 Implementation of C Procedures

Certain bit tests can often use BRSET

or BRCLR branches. In Figure 9.6, the

expression Isc = (gsi & 4)

== 0; results in the following code:

BRCLR

$0802, #4 , *+2

;if bit 4 is not zero then

CLRA

 

; clear result

GPS

#34305

; skip, or set result to 1

STAA

3, SP+

; put result in lui and deallocate local variables

The Boolean result of the test, a value of 1 (T) or a 0 (F), is actually not usually generated but may be used to branch to a different location. For instance if {lui > 5) results in the following code:

LDD

1, SP

; get 16-bit variable lui

CPD

#5

; if less than 5 as an unsigned number

BLS

L

; branch around the expression if lui is higher than 5

Simple conditional expressions of the form if then, full conditionals of the form if then else, and extended conditionals of the form if then else if then else if then , . . else, use conditional expression operators. In the last expression, the else if part can be repeated as many times as needed, and the last part can be an optional else. Variables are compared using relational operators ( > and < ), and these are combined using logical operators (&&). We give examples of common simple conditionals first.

The C program in Figure 9.7a is compiled into the assembly language program shown in Figure 9.7b. A statement if (! Isc) guc = 0; or equivalently if (Isc ==

0) guc = 0; is encoded as

 

LDAA

3, -SP

; allocate and set condition codes for variable Isc

BNE

*+5

; if nonzero, skip over next instruction

CLR

$0800

;otherwise, if zero, clear variable guc

Where the condition applies to a complex expression of many statements, the branch instructions can be converted to long branch instructions. For instance,

 

 

if (gsi

< 5) { ... /* many instructions */}

can be implemented

 

 

 

LDD

$0801

;get variable gsi

 

CPD

#5

; if greater than or equal to 5 as an unsigned number

 

LBGE

LI

; then skip over next several instructions

 

 

 

; many instructions generated between { } appear here

LI:

EQU

*

; located after the latter} matching the if statement's {

A simple C compiler can always implement the conditional operation using the long branch instructions like LBHS, but an optimizing C compiler will get the size of the branch offset. It uses a long branch instruction when the label cannot be reached by the corresponding shorter branch instruction.

9.3 Conditional Statements

269

unsigned char guc; int gsi; main(){ char Isc; unsigned int lui;

if(lsc == 0) guc = 0;

if(gsi < 5) { ... /* many instructions */ } if(Isc + guc) gsi = 0;

if(guc < 5) Isc = 0; else Isc = 9;

}

a.A C Program

4: main(){ char Isc; unsigned int lui;if(Isc == 0) guc = 0;

0000095B A6AD

LDAA

3,-SP

 

0000095D

2603

BNE

*+5

;abs = 0962

0000095F

790800

CLR

$0800

 

6:

if(gsi < 5) { /* many instructions */ lui =0; }

00000962

FC0801

LDD

$0801

 

00000965

8C0005

CPD

#5

 

00000968

2C04

BGE

*+6

;abs = 096E

0000096A

C7

CLRB

 

 

0000096B

87

CLRA

 

 

0000096C

6C81

STD

1,SP

 

7:if(Isc + guc)gsi = 0;

0000096E

A680

LDAA

0,SP

00000970

B704

SEX

A,D

00000972

B745

TFR

D,X

00000974

F60800

LDAB

$0800

00000977

87

CLRA

 

00000978

1AE6

LEAK

D,X

0000097A

044504

TBEQ

X,*+7 ,-abs = 0981

0000097D

C7

CLRB

 

0000097E

7C0801

STD

$0801

8:if(guc < 5) Isc = 0; else Isc = 9;

00000981

B60800

LDAA

$0800

 

00000984

8105

CMPA

#5

 

00000986

2404

BCC

*+6

;abs = 098C

00000988

6980

CLR

0,SP

 

0000098A

2004

BRA

*+6

;abs = 0990

0000098C

C609

LDAB

#9

 

0000098E

6B80

STAB

0,SP

 

9: }

 

 

 

 

00000990

1B83

LEAS

3,SP

 

00000992

3D

RTS

 

 

b. Assembly Language Generated by Part (a)

Figure 9.7. A Program with If-Then Expressions

270

Chapter 9 Implementation of C Procedures

unsigned char alpha, beta , gamma, delta, epsilon, zeta;

main ( ) {

 

 

 

 

if((alpha

< 5)&&(beta = = 0 ) )

gamma

=

0;

if((alpha

< 5)||(beta = = 0 ) )

gamma

=

0;

if(alpha

!= 0) beta = 10; else if(gamma — 0) delta++;

else if((epsilon != 0)&&(zeta==l))

beta=beta « 3; else beta=0;

}

a.A C Program

6:if((alpha < 5)&&(beta == 0)) gamma = 0;

0000095B

B60800

LDAA

$0800

 

0000095E

8105

CMPA

#5

 

00000960

2C08

BGE

*-t-10

;abs = 096A

00000962

B60801

LDAA

$0801

 

00000965

2603

BNE

*+5

;abs = 096A

00000967

790802

CLR

$0802

 

7:if((alpha < 5)|[(beta == 0)) gamma = 0;

0000096A

B60800

LDAA

$0800

 

0000096D

8105

CMPA

#5

 

0000096F

2D05

BLT

*+7

;abs= 0976

00000971

B60801

LDAA

$0801

 

00000974

2603

BNE

*+5

;abs = 0979

00000976

790802

CLR

$0802

 

8:if(alpha 1= 0) beta = 10;

00000979

B60800

LDAA

$0800

 

0000097C

2707

BEQ

*+9

;abs = 0985

0000097E

C60A

LDAB

#10

 

00000980

7B0801

STAB

$0801

 

00000983

201C

BRA

*+30

;abs = 09A1

9:else if(gamma == 0) delta++;

00000985

B60802

LDAA

$0802

 

 

00000988

2605

BNE

*+7

;abs =

098F

0000098A

720803

INC

$0803

 

 

0000098D

2012

BRA

*+20

;abs

=09A1

10:else if((epsilon!=0)&&(zeta==l)) beta=beta«3; else beta=0;

0000098F

B60804

LDAA

$0804

 

00000992

270A

BEQ

*+12

;abs = 099E

00000994

B60805

LDAA

$0805

 

00000997

042004

DBNE

A,*+7

;abs = 099E

0000099A

0764

BSR

*+102

;abs = OAOO

0000099C

2003

BRA

*+5

;abs = 09A1

0000099E

790801

CLR

$0801

 

b. Assembly Language Generated by Part (a)

Figure 9.8. Assembly Language for a Decision Tree

9.3 Conditional Statements

271

An operation result may be in accumulator B or D. It can be tested by the TBEQ or

TBNE instructions.In Figure 9.7, the statement if(lsc + guc) gsi = 0; similarly

encodes as

 

 

LDAA

0, SP

; get value of Isc

SEX

A,D

; upcast to 16 bits

TFR

Df X

; use X as accumulator

LDAB

$08 00

; get value of guc

CLRA

 

; upcast to 16 bits

LEAX

D, X

; add values

TBEQ

X, *+7

; check value of sum. If zero

CLRB

 

; generate a 16-bit zero (A is already clear)

STD

$0801

; store to clear variable gsi

In Figure 9.7, the else part of a conditional expression is easily implemented by a

BRA instruction. The statement

if (guc < 5) Isc = 0; else Isc = 9; encodes as

LDAA

$08 00

; get variable guc

CMPA

#5

; if greater than or equal to 5 as an unsigned number

BBS

*+6

; then skip over next instruction (this isBCC)

CLR

0, SP

; otherwise, if zero, clear variable Isc

BRA

*+6

; now skip over next two instructions

LDAB

#9

; write 9 into variable Isc

STAB

0,SP

 

A conditional expression can be a logical OR or a logical AND of tests described above. The logical OR test will check each case, from left to right, for a true result, and will execute the statement when it finds the first true result. The logical AND checks each case, from left to right, for a false, and bypasses the statement the first time it finds

a false test. If alpha,

beta,

and gamma are signed global char variables, the

statement in Figure 9.8 if ((alpha

< 5)

&&(beta = = 0 ) ) gamma = 0; encodes as

LDAA $0800

; get variable alpha

CMPA

#5

 

; if less than 5 as a signed number

BGE

*+10

; then skip to CLR instruction

LDAA

$0801

; if beta is nonzero

BNE

*+5

 

; then skip over next instruction

CLR

$0802

;if you get here, clear variable gamma

and if ((alpha < 5) | |

(beta

= = 0 ) )

gamma = 0; is encodedas

LDAA $0800

; get variable alpha

CMPA

#5

 

; if less than 5 as a signed number

BLT

*+7

 

; then skip to CLR instruction

LDAA

$08 01

; if beta is nonzero

BNE

*+5

 

; then skip over next instruction

CLR

$0802

; if you get here, clear variable gamma.

As seen in the previous examples, the ANDing of conditions is affected by branching around the "then" code if either condition is false, and the ORing of conditions is affected by branching to the "then" code if either condition is true.

272

Chapter 9 Implementation of C Procedures

Many else if expressions can

be inserted between an if expression and the final

else expression. The branch instructions jump out of a statement that is executed to the statement beyond the final else statement. Moreover, the final else expression may be omitted. Obviously, one can have more than two OR or AND tests, and one can nest OR tests within AND tests, or one can nest AND tests within OR tests, and so on.

One of the common errors in C is to confuse bit-wise logical OR with the OR test

discussed above. Theexpression if ((alpha < 5) | (beta == 0 ) ) gamma = 0;

encodes as

 

 

 

 

LDAA

alpha

; get variable alpha

 

CMPA

#5

 

 

BLT

LO

; if greater or equal to 5

 

LDX

#0

; generate zero

 

BRA

LI

; and skip

LO:

LDX

#1

; otherwise generate one

LI:

LDAA

beta

; test variable beta

 

BEQ

*+4

; if nonzero, branch to middle of CPS

 

CLRB

 

; otherwise clear B

 

CPS

#50689 ; address mode is actually LDAB #1

 

CLRA

 

; high-order byte is always zero

 

PSHX

 

; OR X into D

 

GRAB

1, SP

; by pushing X

 

ORAA

2,SP+

; then pulling it and ORing it into D

 

TBEQ

D, *+6

; if the result is nonzero

 

CLR

gamma

; clear variable gamma

What a difference a single character makes! Although the same answer is obtained with

the statement if ((alpha < 5)

| j

(beta = = 0 ) ) gamma = 0; as with if ((alpha

< 5) | (beta ==

0 ) ) gamma =

0;, the assembly language generated by the latter is

significantly less efficient than that generated by the former statement.

Another of the common errors in C is to confuse assignment with equality test. The

expression if (beta

== 0)

gamma

= 0; encodes as

TST

beta

 

; test variable beta

BNE

*+5

 

; if the result is nonzero then

CLR

gamma

 

; clear variable gamma

The expression if (beta =

0)

gamma = 0; encodes as

CLR

beta

 

; clear variable beta (note: this is an assignment statement)

BNE

*+5

 

; if the result is nonzero (it isn't) then

CLR

gamma

; clear variable gamma

From the rest of Figure 9.8, note how a string of else if ( . . . ) . . . else . . . ; statements cause the tests we have already discussed to be done, and when one is successful, so its following statement is executed, a branch is made to the end of the

series of else i f ( . . .

) . . . else . . .; statements. Incidentally, the subroutine branched

tobyBSR * +10 2

shifts the byte in beta left three places.