📄 chapter 12 assembly language programming -- valvano.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0058)http://www.ece.utexas.edu/~valvano/embed/chap12/chap12.htm -->
<HTML><HEAD><TITLE>Chapter 12: Assembly Language Programming -- Valvano</TITLE>
<META http-equiv=content-type content=text/html;charset=iso-8859-1>
<META content="MSHTML 5.50.3825.1300" name=GENERATOR>
<META
content="StarMax HD:Microsoft Office 98:Templates:Web Pages:Blank Web Page"
name=Template></HEAD>
<BODY vLink=#800080 link=#0000ff>
<P><!--Developing Embedded Software in C using ICC11/ICC12/Hiware by Jonathan W. Valvano--><B><FONT
face="Times New Roman,Times" size=4>Chapter 12: Assembly Language
Programming</FONT></B></P>
<P><B><I><FONT face=Helvetica,Arial>What's in Chapter 12?</FONT></I></B></P>
<DIR>
<P><A
href="http://www.ece.utexas.edu/~valvano/embed/chap12/chap12.htm#INSERT">How to
insert single assembly instructions</A><FONT face=Monaco><BR></FONT><A
href="http://www.ece.utexas.edu/~valvano/embed/chap12/chap12.htm#MIXTURE">How to
compile with a mixture of assembly and C files</A><FONT
face=Monaco><BR></FONT><A
href="http://www.ece.utexas.edu/~valvano/embed/chap12/chap12.htm#DIRECTIVES">Assembler
Directives</A><A
href="http://www.ece.utexas.edu/~valvano/embed/chap12/chap12.htm#OPTIMIZE"><BR>How
to use assembly to optimize a C function</A></P></DIR>
<P><FONT face="Times New Roman,Times">One of the main reasons for using the C
language is to achieve portability. But there are occasional situations in which
it is necessary to sacrifice portability in order to gain full access to the
operating system or to the hardware in order to perform some interface
requirement. If these instances are kept to a minimum and are not replicated in
many different programs, the negative effect on portability may be acceptable.
There are two approaches to writing assembly language with ICC11 and ICC12. The
first method inserts a single assembly instruction directly into a C function
using the <B>asm("string");</B> feature. Everything within the <B>"string"</B>
statement is assumed to be assembly language code and is sent straight to the
output of the compiler exactly as it appears in the input. The second approach
is to write an entire file in assembly language, which may include global
variables and functions. Entire assembly files can be inserted into our C
programs using the <B>asm(".include 'filename' ");</B> feature. Entire assembly
files can also be assembled separately then linked at a later time to the rest
of the programs. The simple insertion method is discussed in this
chapter.</FONT></P>
<P><B><I><FONT face=Helvetica,Arial><A name=INSERT></A>How to insert single
assembly instructions.</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">To support this capability, C provides for
assembly language instructions to be written into C programs anywhere a
statement is valid. Since the compiler generates assembly language as output,
when it encounters assembly language instructions in the input, it simply copies
them directly to the output. </FONT></P>
<P><FONT face="Times New Roman,Times">A special directive delimits assembly
language code. The following example inserts the assembly language instruction
<B>cli</B> (enable interrupts) into the program at that point.</FONT></P>
<DIR>
<P><CODE>asm(" cli"); </CODE></P></DIR>
<P><FONT face="Times New Roman,Times">Some of the older versions of ICC11
require a space before the op code as shown in the examples in this chapter.
ICC12 version 5.1 does not need the space before the op code. The extra space is
ignored by these newer compiler versions, so experiment with your particular
compiler to see whether or not the space is required. Macro substitution is not
performed, but you can define macros that insert assembly. The following macros
are defined in the HC11.H and HC12.H header files.</FONT></P>
<DIR>
<P><CODE>#define INTR_ON() asm(" cli")<BR>#define INTR_OFF() asm("
sei")</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">The following function runs with
interrupts disabled.</FONT></P>
<DIR>
<P><CODE>void InitFifo(void){<BR> INTR_OFF(); /*
make atomic, entering critical section
*/<BR> PutI=GetI=Size=0; /* Empty when Size==0
*/<BR> INTR_ON(); /*
end critical section */<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-1: Example of an assembly language macro</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">Of course, to make use of this feature, we
must know how the compiler uses the CPU registers, how functions are called, and
how the operating system and hardware works. It will certainly cause a
programming error if your embedded assembly modifies the stack pointer, SP, or
the stack frame pointer, X. On the other hand, in most situations you should be
able to modify the CCR, A, B, or Y without causing a program error. It is good
practice to observe the resulting assembly output of the entire function to
guarantee that the embedded assembly has not affected the surrounding C code.
Unfortunately, this verification must be repeated when you upgrade the
compiler.</FONT></P>
<P><FONT face="Times New Roman,Times">You can assess global variables directly
using its equivalent assembly name (starts with an underscore). The following
function adds one to the 16-bit global time.</FONT></P>
<DIR>
<P><CODE>short time;<BR>void Add1time(void){<BR> asm(" ldy
_time");<BR> asm(" iny");<BR> asm(" sty
_time");<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-2: Example of an assembly language access to a global
variable</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">You can assess local variables directly
using a <B>%</B>before its name. </FONT></P>
<DIR>
<P><CODE>void InitFifo(void){ unsigned char SaveSP;<BR> asm("
tpa"); /* Reg A
contains previous CCR */<BR> asm(" staa %SaveSP"); /* Save
previous CCR value */<BR> asm("
sei"); /* make
atomic, entering critical
section */<BR> PutI=GetI=Size=0; /* Empty
when Size==0 */<BR> asm(" ldaa %SaveSP"); /* Reg A
contains previous CCR */<BR> asm("
tap"); /* end
critical section */<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-3: Example of an assembly language access to a local
variable</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">The above method of disabling interrupts
is a good way to execute critical code. This is an appropriate way to execute
critical code because once the critical code is started it will finish (i.e.,
atomic). The code becomes atomic because interrupts are disabled. At the end of
the critical code, the interrupt status is restored to its previous value. This
save/restore interrupt status procedure allows you to nest one critical code
inside another critical code. If you disable interrupts before the critical code
and enable interrupts after the critical code, you are presuming that interrupts
were enabled when the critical code was started. The disable/enable method of
executing critical code does not allow for one critical code to call another
critical code. In the following example, <B>InitFifo</B> properly returns with
interrupts still disabled.</FONT></P>
<DIR>
<P><CODE>void InitSystem(void){ unsigned char SaveSP;<BR> asm("
tpa"); /* Reg A
contains previous CCR */<BR> asm(" staa %SaveSP"); /* Save
previous CCR value */<BR> asm("
sei"); /* make
atomic, entering critical section
*/<BR> InitFifo();<BR> InitPort();<BR> InitTimer();<BR> asm("
ldaa %SaveSP"); /* Reg A contains previous CCR
*/<BR> asm("
tap"); /* end critical section */<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-4: Example of a multiple line assembly language
insertion</ADDRESS>
<DIR>
<DIR>
<P> </P></DIR></DIR>
<P><FONT face="Times New Roman,Times">If you don't like the above style of
writing each line separately, there is a shorthand for multiple-line assembly as
shown in the following implementation.</FONT></P>
<DIR>
<P><CODE>void InitFifo(void){ unsigned char SaveSP;<BR> asm("
tpa\n" /* Reg A
contains previous CCR */<BR> " staa
%SaveSP\n" /* Save previous CCR value
*/<BR> "
sei"); /* make atomic,
entering critical section
*/<BR> PutI=GetI=Size=0; /* Empty when Size==0 */<BR> asm("
ldaa %SaveSP\n" /* Reg A contains previous CCR
*/<BR> "
tap"); /* end critical section */<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-5: A second example of a multiple line assembly language
insertion</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">There is yet another style of writing
multiple-line assembly, but I don't recommend it because it is harder to
read.</FONT></P>
<DIR>
<P><CODE>void InitFifo(void){ unsigned char SaveSP;<BR> asm("
tpa\n staa %SaveSP\n sei"); /* make atomic, entering
critical section
*/<BR> PutI=GetI=Size=0; /* Empty when Size==0 */<BR> asm("
ldaa %SaveSP\n
tap"); /* end critical section */<BR>}</CODE></P></DIR>
<ADDRESS>Listing 12-6: A third example of a multiple line assembly language
insertion</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">This last example suggests the macro
definitions:</FONT></P>
<DIR>
<P><CODE>#define START_CRITICAL() asm(" tpa\n staa %SaveSP\n sei")<BR>#define
END_CRITICAL() asm( ldaa %SaveSP\n tap")</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">The use of these two macros requires the
definition of an 8-bit local variable called <B>SaveSP</B>.</FONT></P>
<P> </P>
<P><B><I><FONT face=Helvetica,Arial><A name=MIXTURE></A>How to compile with a
mixture of assembly and C files</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">The following C program embeds an assembly
language file (programs and data). In this example the C program accesses a
global variable (<B>lowGlobal</B>) and calls a function (<B>lowSub</B>) defined
in the assembly file, and the assembly function assesses a global variable
(<B>highGlobal</B>) and calls a function (<B>highSub</B>) defined in the C file.
To access an assembly function, the C program simply calls it, with the standard
ICC11/ICC12 parameter passing rules. To access an assembly level global
variable, the C program types it with the <B>extern</B>. Notice however that the
assembly function (<B>lowSub</B>) does not need a prototype in the high level C
program. </FONT></P>
<DIR>
<P><CODE>/* C level program file="high.C" */<BR>int
highGlobal;<BR>extern int lowGlobal; //
typed here but defined in low.s<BR>asm(".include 'low.s' "); //
insert assembly here<BR>void main(void){ <BR> lowSub(5);
// call to assemble
routine<BR> lowGlobal=6; // access of assembly
global<BR>};<BR>int highSub(int input){return(input++);}</CODE></P></DIR>
<ADDRESS>Listing 12-7: A high-level C program that calls a low-level assembly
function</ADDRESS>
<DIR>
<DIR>
<P> </P></DIR></DIR>
<P><FONT face="Times New Roman,Times">The following assembly program is embedded
into the above high level C program. The double colon, <B>::</B>, specifies the
label as external and will be available in the *.map file. The <B>.area text</B>
is the standard place for programs (in ROM), and the <B>.area bss</B> is the
standard area for globals (in RAM). Assembly level functions (e.g.,
<B>_lowSub</B>) and variables (e.g., <B>_lowGlobal</B>) are defined beginning
with an underscore, "_". Notice that in the assembly file the names have the
underscore, but the same name in the C file do not. To access a C function, the
assembly program simply calls it (the name begins with an underscore.) The
assembly program has full access to high level global variables (the name begins
with an underscore.)</FONT></P>
<P> </P>
<DIR>
<P><CODE>; assembly language program file="low.s"
<BR> .area
text<BR>_lowSub:: ;
definition of low level subroutine<BR> jsr
_highSub ; call to high level
function<BR> std _highGlobal ;
access to high level
global<BR> rts<BR> .area
bss<BR>_lowGlobal:: ; definition
of low level global<BR> .blkb 2</CODE></P></DIR>
<ADDRESS>Listing 12-8: A low-level assembly program that calls a high-level C
function</ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">Again, parameter passing with both
functions (the assembly calls to the C and the C calls to the assembly) must
adhere to the standard ICC11/ICC12 parameter passing rules: </FONT></P>
<DIR>
<P><FONT face="Times New Roman,Times">The output parameter, if it exists, is
passed in Register D,</FONT><CODE><BR></CODE><FONT
face="Times New Roman,Times">The first input parameter is passed in Register
D,</FONT><CODE><BR></CODE><FONT face="Times New Roman,Times">The remaining input
parameters are passed on the stack,</FONT><CODE><BR></CODE><FONT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -