📄 chapter 12 assembly language programming -- valvano.htm
字号:
face="Times New Roman,Times">8-bit parameters are promoted to 16
bits.</FONT></P></DIR>
<P> </P>
<P><FONT face="Times New Roman,Times">Chapter 10 presented </FONT><A
href="http://www.ece.utexas.edu/~valvano/embed/chap10/chap10.htm#STACK">some
examples</A><FONT face="Times New Roman,Times"> of the assembly code generated
by the compiler when calling a function with parameters. If you are writing an
assembly language function that is to be called from C, one method to get the
parameter passing correct is to write a simple C function that simply passes the
parameters. Compile this simple C function with your other C code, and observe
the assembly language created by the compiler for the simple C function. Next
draw a stack picture that exists at the start of the function. The C compiler
will do some weird things within the function (like pushing register D on the
stack, and shifting some 8 bit parameters around), which you do not have to
duplicate. One difficulty with mixing the assembly with C is that when the
compiler is upgraded, this compatibility matching must be redone.</FONT></P>
<P><B><I><FONT face=Helvetica,Arial><A name=DIRECTIVES></A>Assembler
Directives</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">An assembler directive (or pseudo-op) is
not executed by the 6811/6812, but rather affect the assembler in certain ways.
The assembly pseudo-ops supported by the ICC11 and ICC12 assembler are described
in this section.</FONT></P>
<P><FONT face="Times New Roman,Times">The first set of directives affect where
in memory the subsequent assembly lines will be stored. The <B>.org</B>
pseudo-op takes an expression, and changes the memory storage location to the
value of the expression. This directive can only be used within an absolute
area. Example</FONT></P>
<P><FONT face="Times New Roman,Times">.org 0xF000 ; put subsequent object code
at $F000</FONT></P>
<P><FONT face="Times New Roman,Times">The <B>.area</B> pseudo-op specifies into
which segment the subsequent code will be loaded. </FONT></P>
<DIR>
<P><CODE> .area text ; code in the ROM
segment<BR> .area data ; code in the initialized RAM
segment<BR> .area idata ; code in ROM used to initialize
the data segment<BR> .area bss ; code in the
uninitialized RAM
segment<BR> .text ;
same as .area
text<BR> .data ; same
as .area data</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">When writing assembly language programs, I
suggest allocating variables in the <B>.area bss</B> segment and fixed
constants/programs in the <B>.area text</B>. In other words, I suggest that you
not use <B>.area data</B> and <B>.area idata</B> in your assembly programs.
Other names can be used for segments. If the <B>(abs)</B> follows the name, the
segment is considered absolute and can contain <B>.org</B> pseudo-ops. For
example to set the reset vector in an assembly file, you could write</FONT></P>
<DIR>
<P><CODE> .area
VectorSegment(abs) <BR> .org 0xFFFE ; reset
vector address<BR> .word Start ; place to
begin</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">The next set of directives allocate space
in memory. The <B>.blkb</B> pseudo-op will set aside a fixed number of 8-bit
bytes without initialization. Similarly, the <B>.blkw</B> pseudo-op will set
aside a fixed number of 16-bit words without initialization.</FONT></P>
<DIR>
<P><CODE> .blkb 10 ; reserve 10 bytes<BR> .blkw
20 ; reserve 20 words</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">The next three directives load specific
data into memory. The <B>.byte</B> pseudo-op will set aside a fixed number of
8-bit bytes and initialize the memory with the list of 8-bit bytes. The size of
the allocated storage is determined by the number of data values in the list.
The <B>.word</B> and <B>.ascii</B> pseudo-ops work in a similar way for 16-bit
words and ASCII strings. The .asciz pseudo-op is similar to .ascii except that
an extra byte is allocated and set to null (0). Examples include:</FONT></P>
<DIR>
<P><CODE> .byte 10 ; reserve 1
byte initialized to 10<BR> .byte 1,2,3 ; reserve 3
bytes initialized to 1,2,3<BR> .word
20 ; reserve 1 word initialized to
20<BR> .word 10,200 ; reserve 2 words initialized to
10,200<BR> .ascii "JWV" ; reserve 3 bytes initialized to
"J" "W" "V"<BR> .asciz "JWV" ; reserve 4 bytes initialized
to "J" "W" "V" 0</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">Because the 6812 is more efficient when
accessing 16 bit data from even addresses, sometimes we wish to skip a memory
byte to force the subsequent code to loaded into an even or odd address. To do
this we can use:</FONT></P>
<DIR>
<P><CODE> .even ; force next code to be at an even
address<BR> .odd ; force next code to be at an odd
address</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">There are two ways to make an assembly
language label global (accessible outside the file). The first way is to use
double colons as in Listing 12-8. The second way is to use the .global
pseudo-op:</FONT></P>
<DIR>
<P><CODE> .global Start ; make this label
global</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">We can create assembly constants using the
= pseudo-op. One application of this directive is defining symbolic names for
the I/O ports. Instead of writing code list this:</FONT></P>
<DIR>
<P><CODE>; read a byte from the SCI port<BR>getchar:: ldaa 0x00C4
; wait for new character
available<BR> bita
#$20<BR> beq getchar<BR> clra<BR> ldab
0x00C7 ; new character from
SCI<BR> rts</CODE></P></DIR>
<ADDRESS>Listing 12-9: A subroutine that reads a character from the 6812 SCI0
port</ADDRESS>
<P><FONT face="Times New Roman,Times">we can add symbols to make it more
readable:</FONT></P>
<DIR>
<P><CODE>; read a byte from the SCI
port<BR>SC0SR1=0x00C4<BR>SC0DRL=0x00C7<BR>RDRF=0x20<BR>getchar:: ldaa
SC0SR1 ; wait for new character
available<BR> bita
#RDRF<BR> beq getchar<BR> clra<BR> ldab
SC0DRL ; new character from
SCI<BR> rts</CODE></P></DIR>
<ADDRESS>Listing 12-10: A better subroutine that reads a character from the 6812
SCI0 port</ADDRESS>
<P><FONT face="Times New Roman,Times">NOTE: the assembly directive <B>=</B>is
not a macro substitute. Rather the expression is evaluated once, and the number
value is used in place of the symbol.</FONT></P>
<P><FONT face="Times New Roman,Times">Conditional assembly can be implemented
using the<B> .if <exp> .else .endif </B>construction. If the <exp>
is true (not zero) then the assembly code up to the <B>.else</B> is included. If
the <exp> is false (0) then the assembly code between the<B> .else </B>and
<B>.endif </B>will be included. For example</FONT></P>
<DIR>
<P><CODE>IS6812=1 ; means it is a 6812<BR>.if
IS6812<BR>SCSR=0x00C4<BR>SCDR=0x00C7<BR>.else<BR>SCSR=0x102E<BR>SCDR=0x102F<BR>.endif<BR>RDRF=0x20<BR>getchar:: ldaa
SCSR ; wait for new character
available<BR> bita
#RDRF<BR> beq getchar<BR> clra<BR> ldab
SCDR ; new character from
SCI<BR> rts</CODE></P></DIR>
<ADDRESS>Listing 12-11: A flexible subroutine that reads a character from the
6811 or 6812 SCI port</ADDRESS>
<P><FONT face="Times New Roman,Times">The last pseudo-op is used to include
other assembly files. For example</FONT></P>
<DIR>
<P><CODE>; read a byte from the SCI port<BR>.include
"HC12.S"<BR>getchar:: ldaa SC0SR1 ; wait for new character
available<BR> bita
#RDRF<BR> beq getchar<BR> clra<BR> ldab
SC0DRL ; new character from
SCI<BR> rts</CODE></P></DIR>
<ADDRESS>Listing 12-12: The .include pseudo-op allows you to divide software
into separate files</ADDRESS>
<P> </P>
<P><B><I><FONT face=Helvetica,Arial><A name=OPTIMIZE></A>How to use assembly to
optimize a C function</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">In almost all situations when faced with a
time-critical constraint it would be better to solve the problem other ways than
to convert C code to assembly. Those alternative ways include using a faster CPU
clock speed, upgrading to a more efficient compiler, and upgrading to a more
powerful processor. On the other hand, some times we need to write and link
assembly functions. One good reason to code in assembly is to take advantage of
computer-specific operations. The enabling and disabling of interrupts is an
example of an important operation that can not be performed in standard C.
Another example is the use of specialize functions on the 6812 like fuzzy logic
and table look-up. Although you could develop fuzzy logic control system in
standard C, there are compelling speed advantages to implementing the core fuzzy
logic controller in assembly. </FONT></P>
<P><FONT face="Times New Roman,Times">In this example we will optimize the<B>
add3()</B> function presented previously in Chapter 10. The assembly generated
by ICC11 and ICC12 for this example was discussed <A
href="http://www.ece.utexas.edu/~valvano/embed/chap10/chap10.htm#STACK">back in
Chapter 10</A>. The C code from Listing 10-8 is repeated:</FONT></P>
<DIR>
<P><CODE>int x1;<BR>static int x2;<BR>const int x3=1000;<BR>int add3(int z1, int
z2, int z3){ int
y;<BR> y=z1+z2+z3;<BR> return(y);}<BR>void
main(void){ int
y;<BR> x1=1000;<BR> x2=1000;<BR> y=add3(x1,x2,x3);</CODE></P></DIR>
<ADDRESS>Listing 10-8: Example function call with local variables</ADDRESS>
<P><FONT face="Times New Roman,Times">The assembly output (Listing 10-10)
generated by the ImageCraft ICC12 version 5.1 is also repeated.</FONT></P>
<DIR>
<P><CODE> .area text<BR>_x3:: .word
1000<BR> .area text<BR>; y -> -2,x<BR>; z3 ->
8,x<BR>; z2 -> 6,x<BR>; z1 -> 2,x<BR>_add3::
pshd<BR> pshx<BR> tfr
s,x<BR> leas -2,sp<BR> ldd
2,x<BR> addd 6,x<BR> addd
8,x<BR> std -2,x<BR> ldd
-2,x<BR> tfr
x,s<BR> pulx<BR> leas
2,sp<BR> rts<BR>; y -> -2,x<BR>_main::
pshx<BR> tfr s,x<BR> leas
-8,sp<BR> movw #1000,_x1<BR> movw
#1000,_x2<BR> movw
_x3,2,sp<BR> movw _x2,0,sp<BR> ldd
_x1<BR> jsr _add3<BR> std
-4,x<BR> tfr d,y<BR> sty
-2,x<BR> tfr
x,s<BR> pulx<BR> rts<BR>.area
bss<BR>_x2: .blkb 2<BR>_x1:: .blkb
2</CODE></P></DIR>
<ADDRESS>Listing 10-10: ICC12 assembly of function call with local
variables</ADDRESS>
<P><FONT face="Times New Roman,Times">Next we draw a stack picture at the point
of the first instruction of the function<B> add3()</B>.</FONT></P>
<P><FONT face="Times New Roman,Times"><IMG height=187
src="Chapter 12 Assembly Language Programming -- Valvano.files/add3stk.gif"
width=250></FONT></P>
<ADDRESS>Figure 12-1 Stack frame at the start of add3()</ADDRESS>
<P><FONT face="Times New Roman,Times">The next step in optimization is to copy
and paste the ICC11/ICC12 compiler code from the *.s file into a new assembly
file. We will name the file add3.s. Using the stack frame picture as our guide,
we optimize the function. One possible optimization is shown below. Notice that
I created a new local variable stack binding based on SP instead of Reg X.
</FONT></P>
<DIR>
<P><CODE>; ****filename is add3.s *******<BR>; z3 -> 4,sp<BR>; z2 ->
2,sp<BR>; z1 in Reg D<BR>_add3:: addd 2,sp ;
z1+z2<BR> addd
4,sp ;
z1+z2+z3<BR> rts</CODE></P></DIR>
<ADDRESS>Listing 12-13 Optimized add3 function</ADDRESS>
<P><FONT face="Times New Roman,Times">Now this new function is linked into the
original program.</FONT></P>
<DIR>
<P><CODE>int x1;<BR>static int x2;<BR>const int x3=1000;<BR>asm(".include
'add3.s' ");<BR>int add3(int, int, int);<BR>void main(void){ int
y;<BR> x1=1000;<BR> x2=1000;<BR> y=add3(x1,x2,x3);</CODE></P></DIR>
<ADDRESS>Listing 12-14: Use of the new optimized function</ADDRESS>
<P><FONT face="Times New Roman,Times">Embedding the assembly function
(<B>add3</B>) into C seems to work with or without the<B> int
add3(int,int,int);</B> prototype.</FONT></P>
<P><FONT face="Times New Roman,Times">For more information about assembly
language programming see the Motorola Microcomputer Manuals and the help system
of the application <B>TExaS</B> that is included with the book <U>Embedded
Microcomputer Systems: Real Time Interfacing</U> by Jonathan W. Valvano
published by Brooks-Cole.</FONT></P>
<P><FONT face="Times New Roman,Times">Go to <A
href="http://www.ece.utexas.edu/~valvano/embed/app1/app1.htm">Appendix 1 on
Adapt812 board</A> Return to <A
href="http://www.ece.utexas.edu/~valvano/embed/toc1.htm">Table of
Contents</A></FONT></P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -