Some Samples of MIPS Assembly Language

advertisement
Some Samples of
MIPS Assembly Language
Lecture for CPSC 5155
Edward Bosworth, Ph.D.
Computer Science Department
Columbus State University
Structure of This Lecture
• This lecture will be built around a number of
sample programs, written in assembly
language and run under both SPIM and MARS.
• We begin with some of the syntax for writing
the programs and then illustrate.
System Calls
• Almost all programs, user and system, are
written to be run on a machine with a fully
functional operating system.
• The operating system provides a number of
services to other programs.
• We shall use a number of SPIM system calls to
facilitate input and output.
Example of System Calls
•
.data
str: asciiz “The answer is ”
.text
li $v0, 4
# Code for print string
la $a0, str # Address of string
syscall
# Print the string
li $v0, 1
# Code for print integer
li $a0, 5
# Value to print
syscall
li $v0, 10 # Code for exit
syscall
The SPIM System Services
SPIM Data Directives
• Here are a number of directives used to set
aside memory and initialize it.
• .asciiz str stores the string in memory
and null terminates it in the style of C or C++.
• .space N allocates N bytes of storage
for structures such as arrays, etc.
• .word w1 … wn
allocates and initializes n 32-bit words.
Sample of Space Allocation
• S1:
.asciiz “A null-terminated string”
This associates label S1 with the string.
• C1:
.space 80
This allocates 80 bytes, possibly for an array
to hold 80 characters or 20 32-bit integers.
• W1:
.word 1, 2, 3
This initializes three integer values. Same as
W1:
.word 1
.word 2
.word 3
# At address W1 + 4
# At address W1 + 8
Conventions for Strings
• Strings should be null terminated, as in the
style of C and C++.
• String constants are enclosed in double quotes
“This is a string”
• Special characters follow the C/C++ style
newline
\n
tab
\t
quote
\”
Data Alignment
• The assembler will normally align data as
required by the data type.
• The .align N directive aligns the next entry
on an address that is a multiple of 2N.
• Character data can be stored anywhere.
• Byte data must be stored at an address that
is a multiple of 2. Use .align 1
• Word data must be stored at an address that
is a multiple of 4. Use .align 2
Kernel and User Mode
• All modern computer systems restrict certain
operations to the operating system, when it is
operating in what is called “kernel mode”.
• Example restricted operations: direct access to
I/O devices, memory management, etc.
• SPIM allows programs to be run in either user
mode or kernel mode, as both modes are
emulated on the host machine.
SPIM Text & Data
• .data <address> This stores subsequent
items in the user data segment.
• .kdata <address>
This stores
subsequent items in the kernel data segment.
• .ktext <address>
This stores
subsequent items in the kernel text area, which
holds instructions for kernel code.
• .text <address>
This stores
subsequent items in the user text area, also for
program instructions.
The Optional Address
• Each of these directives has an optional address,
commonly not used.
• One exception will be for an interrupt handler,
which must be in the kernel at a fixed address.
•
savea0
savea1
.ktext 0x80000180
sw $a0, savea0
sw $a1, savea1
More code goes here.
.kdata
.word 0
.word 0
Compute Fibonacci Numbers
• The Fibonacci sequence was introduced in
1202 by the Italian mathematician Leonardo
of Pisa, known as Fibonacci.
• The sequence is defined for N  0 as follows:
F0 = 1, F1 = 1, and FN = FN-1 + FN-2 for N  2.
• This is often used as an example of recursion.
• We shall implement a non-recursive solution
in the MIPS assembly language.
The Basic Algorithm
• The basic non-recursive algorithm for computing
Fibonacci numbers uses a loop.
• To compute F(N), do the following
F1 = 1
F2 = 1
For (J = 2; J <= N; J++)
F0 = F1
F1 = F2
F2 = F1 + F0
End For
The Program (Page 1)
• Here is the standard program header.
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
Fibonacci
This is a non-recursive program to calculate Fibonacci
numbers, defined as follows: F(0) = 1, F(1) = 1,
and F(N) = F(N - 1) + F(N - 2), for N >= 2.
This runs under both MARS and SPIM.
Written by Edward Bosworth, Ph.D.
Associate Professor of Computer Science
Columbus State University
Columbus, GA 31907-5645
E-Mail
bosworth_edward@ColumbusState.edu
Date first written: July
Date last revised: July
4, 2012
4, 2012.
The Program (Page 2)
• Here is the start of the code. Note that the program must
have a globally visible label “main” at its start.
main:
#
getN:
#
.text
.globl main
# Make this global
li $v0, 4
# Print string
la $a0, str0 # Address of title string
syscall
# Print the title
li $v0, 4
# Print string
la $a0, str1 # Address of input prompt
syscall
# Print the prompt.
li $v0, 5
syscall
# Read an integer
# Return the value in $v0
The Program (Page 3)
• The program is designed to loop: read user input and then
to produce the result. The user input is found in $v0.
• Non-positive input is a signal to terminate the program.
A value of 1 disrupts the loop logic, so treat as special.
#
#
blez $v0, done
li
$v1, 1
bgt $v0, $v1, doit
# Do we stop?
# F(1) is trivial.
# Is N > 1?
li $v0, 4
la $a0, str2
syscall
j
getN
#
#
#
#
F(1) will disrupt
the loop logic;
just print answer
Get more input.
The Program (Page 4)
• Here is the main computational loop.
doit: li
li
#
loop: addi
move
move
addu
blt
#
$t1, 1
$t2, 1
# Initialization
# code for loop.
$v1,
$t0,
$t1,
$t2,
#
#
#
#
#
#
$v1, 1
$t1
$t2
$t0, $t1
$v1, $v0, loop
Bump $v1
New F(N - 2)
New F(N - 1)
New F(N), where
$v1 contains N
Are we done?
The Program (Page 5)
•
Print out the result and get more input.
move
$a1, $v0
# Set aside the value of N
li
$v0, 4
la
$a0, str3 # Print part of output string
syscall
#
li
$v0, 1
move
$a0, $a1
# Get the value of N back
syscall
# Print N
#
li
$v0, 4
la
$a0, str4 # Print more of the string
syscall
#
li
$v0, 1
# F(N) is found in $t2
move
$a0, $t2
# Print the result
syscall
#
j
getN
# Get more input.
The Program (Page 6)
•
Here is the closing code and data section.
#
Set up for a proper exit
#
done:
li
$v0, 4
# Print closing remark
la
$a0, finis # Address of closing remark
syscall
#
li
$v0, 10
# Call exit
syscall
#
.data
str0: .asciiz "Program to calculate a Fibonacci number“
str1: .asciiz "\nInput an integer: “
str2: .asciiz "\nF(1) is equal to 1.“
str3: .asciiz "\nThe Fibonacci number F(“
str4: .asciiz ") is equal to “
finis: .asciiz "\nAll done. \n"
# \n is New line
Comments on the Text
• Figure B.1.4 on page B-7 contains the
following. It has a problem.
.text
.align 2
.globl main
main:
• The MARS emulator does not allow the .align
directive within the text area.
When to Use Assembly Language
• When should one prefer assembly language
for writing programs?
• Your instructor’s opinion is “almost never”.
Compiler technology has advanced to a point
that it is almost impossible to write code
better or faster than that emitted by a modern
compiler.
• The only real use for assembly language is as a
part of teaching computer science.
Ancient History (PDP-9 FORTRAN)
• The PDP-9 computer was fairly advanced for
the early 1970’s. Your instructor programmed
such a machine from 1971 to 1973.
• The PDP-9 supported programs written in the
FORTRAN programming language. The code
produced was very slow.
• The preferable method was to have the
FORTRAN compiler emit assembly language
code, edit that code, and assembly it.
Labels: Local and Global
• A label is called “global” or “external” if it can be
referenced from another module.
• The label may refer to a memory storage location
or to a function or procedure.
• The linker will resolve global references as a part
of creating the executable image. If module A
references a global in module B, the linker will
make the correct connection.
• Any label not declared as global is local, not
available for reference by other modules.
Rdata & Sdata
• The sample code on page B-28 includes a data
directive “.rdata”.
• There is another directive, “.sdata”.
• The MARS emulator does not recognize either
directive. Use “.data” for user data and
“.kdata” for kernel data.
Various Jump Commands
• The code near the bottom of page B-28
contains an error: 2 commands are confused.
• j jump to the instruction at the target
address
• jr jump to the instruction at the address
stored in the register.
• The instruction should be j L1.
• Also, the label should be L1, not $L1.
The Assembly Temporary
($at) Register
• Register $1 (called “$at”) is reserved for use
by the assembler.
• The SPIM emulator will raise an error if the code
references the $at register.
• To avoid this problem, when it is necessary to
save the $at register, use the following.
• .set noat
# Allow use of $at
move $k1, $at # Save it
.set at
# Assembler can now
# use $at again.
Exception Handler Code
• The sample code on page B-36 contains the
following code, which should be corrected
.ktext 0x80000180
mov $k1, $at # Save the register $at
• It should read as follows
.ktext 0x80000180
.set noat
move $k1, $at
.set at
Exceptions & Interrupts
• Exceptions are events that disrupt the normal
flow of program control and cause exception
code to be executed.
• Almost always, this is kernel code managed by
the operating system.
• Interrupts are exceptions from outside sources
such as I/O devices.
• The terminology is not uniformly applied.
Examples of Exceptions
• External interrupts include:
Input the device has data ready to transfer
Output the device is ready to receive data
Timer the CPU timer raises an interrupt,
used to run the CPU clock.
• Exceptions include
Arithmetic overflow – an arithmetic error
Page fault – a reference has been made to an
invalid virtual memory address.
Exceptions: Control Unit Implications
• For most external interrupts, the implications
for the control unit are rather simple.
• As the control unit begins the execution of
each instruction, it tests a signal (often called
“INT”) that indicates that there is an interrupt
pending.
• If there is a pending interrupt, the control unit
branches unconditionally to kernel code.
Handling Exceptions
• Depending on the exception type, the control unit will
begin execution of kernel code at
one of two locations.
0x80000000
for undefined instructions
0x80000180
for other exceptions
• For that reason, the standard exception handler begins
as follows:
.ktext 0x80000180
.set noat
move $k1, $at # This at 0x80000180
.set at
More Control Unit Implications
• The handling of page fault exceptions shows
one of the strengths of a load/store RISC.
• Only register load and register store
instructions can reference memory.
• Neither load nor store change the computer
state prior to referencing memory, so that any
instruction can be restarted after a page fault.
The Coprocessors
CP0 for exceptions; CP1 for floating point
Coprocessor Registers
• Coprocessor 0 has a number of registers to
control exceptions and manage memory.
• Here are some of the registers used by SPIM
$12
the interrupt mask and enable bits
$13
the exception type and pending
interrupt bits
$14
EPC: address of the instruction
that caused the exception.
Accessing CP0 Registers
• There are two instructions for accessing the
registers in coprocessor 0: mfc0 and mtc0.
• mfc0 $k0, $13
Copy CP0 cause register ($13) into
CPU register $k0 ($26).
• mtc0 $k1, $12
Load CP0 status register ($12) from
CPU register $k1 ($27).
Structure of Two Registers
Sample Exception Handler Code
•
.ktext 0x80000180
sw
$a0, savea0
sw
$a1, savea1
sw
$v0, savev0
#
# Now determine the
#
mfc0
$t0, $13
srl
$t0, $t0,
andi
$t0, $t0,
# More code here to
# Use static storage
# It uses $a0 and $a1, so save
# It also uses $v0
cause of the exception or interrupt
# Move cause into $t0
2
# Shift to get exception code
0xF
# Put the code into $t0
handle exception
Returning from Exception
•
la
$a0, L4
mtc0
#
mtc0
mfc0
andi
ori
mtc0
#
lw
lw
lw
#
eret
$a0, $14
# L4 is the return address,
# defined elsewhere in code
# Put it into the EPC
$0,
$a1,
$a1,
$a1,
$a1,
#
#
#
#
#
$13
$12
0xFFFD
0x1
$12
Clear the cause register
Get the status register
Clear the EXL bit
Enable the interrupt and
reset the status register
$v0, savev0
$a1, savea1
$a0, savea0
# Return to new spot
# Not a subroutine return.
Download