Transcript Lecture 1
Instruction Set Architecture Classification
According to the type of internal storage in a
processor the basic types are
• Stack
• Accumulator
• General Purpose register
• Register – Memory
• Register – Register/ Load – Store
• Memory – Memory (obsolete)
• Extended accumulator/extended general purpose
register
Processor
Stack
• A Top-of-Stack (TOS)
register points to the top
input operand, which is
combined with the operand
below
• The first operand is removed
from the stack, and the
result is stored in the place
of the second operand, while
TOS is updated
TOS
...
ALU
Memory
...
...
Accumulator
One operand implicitly in
accumulator, the other in
memory and result in
accumulator
ALU
...
...
...
Register - Memory
One operand is in a
register the other in
memory and the result is
stored in a register
...
ALU
...
...
...
Register – Register/ Load – Store
...
Both operands and result are
stored in registers
ALU
...
...
Addressing Modes
•
•
•
•
•
•
•
•
•
•
Register
• ADD R4, R3 ; Regs[R4] ←Regs[R4] + Regs[R3]
Immediate
• ADD R4, #3 ; Regs[R4] ←Regs[R4] + 3
Displacement
• ADD R4, 100(R1) ; Regs[R4] ←Regs[R4] + Mem[100+Regs[R1]]
Register Indirect
• ADD R4, (R1) ; Regs[R4] ←Regs[R4] + Mem[Regs[R1]]
Indexed
• ADD R3, (R1+R2) ; Regs[R3] ←Regs[R3] + Mem[Regs[R1]+ Regs[R2]]
Direct or absolute
• ADD R1, (1001) ; Regs[R1] ←Regs[R1] + Mem[1001]
Memory indirect
• ADD R1, @(R3) ; Regs[R1] ←Regs[R1] + Mem[Mem[Regs[R3]]]
Autoincrement
• ADD R1, (R2)+ ; Regs[R1] ←Regs[R1] + Mem[Regs[R2]]
Regs[R2] ← Regs[R2] + d
Autodecrement
• ADD R1, -(R2) ; Regs[R2] ← Regs[R2] - d
Regs[R1] ←Regs[R1] + Mem[Regs[R2]]
Scaled
• ADD R1, 100(R2)[R3] ; Regs[R1] ←Regs[R1] + Mem[100 + Regs[R2] + Regs[R3]*d]
Instruction encoding
• Variable length (x86)
• Fixed length (ARM, MIPS, PowerPC)
• Hybrid (MIPS16, Thumb, TI TMS320C54x)
Taking orders
• A computer does what you tell it to do
• Not necessarily what you want it to do...
• We give computers orders by means of instructions
• Instructions tell the computer what it should be doing,
right now
• Arithmetic
• Logic
• Data movement
• Control
3.1
Binary review
Binary representations of numbers consist of only 1’s and 0’s
01012 = 510
10002 = 810
11111112 = 12710
Unsigned (always positive)
binary numbers
Binary Facts:
210 = 1024 = 1K 1,000
220 = 1,048,576 = 1M 1,000,000
230 = 1,073,741,824 = 1G 1,000,000,000
Converting between binary and hex
Binary
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Hexadecimal
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
Group bits together in groups of 4
10001100101100100001112
--> 10 0011 0010 1100 1000 01112
Assign the appropriate hex digit to each group
10 0011 0010 1100 1000 01112
--> 2 3
2
C
8
7
Done
= 232C8716
The Translation Process
Computers speak in binary. We don’t.
High-level language
A=B+C
Assembly language
Compiler
add
$1, $2, $3
Compilers and Assemblers
translate from one language
to another.
Assembler
Machine language
000000 00010 00011 00001 00000 100000
3.2
MIPS Instructions
Operation
add
Destination
A,
B,
Sources
C
A=B+C
sub
D,
A,
D =A-B
B
In MIPS,
All register-to-register
arithmetic instructions
have three operands.
3.2
Operands
add
A, B, C
What are A, B, and C?
The operands of arithmetic instructions are always registers
add
$17, $18, $19
Add contents of registers 18 and 19 and put result in register 17
sub
$19, $19, $18
Subtract $19 - $18 and put the result back in $19
3.3
Registering
47
$2
• MIPS has 32 general-purpose registers
• $0 through $31
• Each register holds 32 bits
• 0 to 232 -1 (4 billion) if unsigned
• -231 to +231-1 (-2 billion to +2 billion) if signed
• Most registers can hold any value, for any purpose
• Exception: $0 is always zero!
3.3
Register Naming and Conventions
• In MIPS, all registers (except $0) can be used for any purpose
desired
• However, there are standard use conventions that make it
easier to write software
#
$0
$1
$2
$3
$4
$5
$6
$7
$8
$9
$10
$11
$12
$13
$14
$15
Name
$zero
$at
$v0
$v1
$a0
$a1
$a2
$a3
$t0
$t1
$t2
$t3
$t4
$t5
$t6
$t7
Purpose
Constant zero
Reserved for assembler
Function return value
Function parameter
Temporary – Caller-saved
#
$16
$17
$18
$19
$20
$21
$22
$23
$24
$25
$26
$27
$28
$29
$30
$31
Name
$s0
$s1
$s2
$s3
$s4
$s5
$s6
$s7
$t8
$t9
$k0
$k1
$gp
$sp
$fp
$ra
Purpose
Temporary – Callee-saved
Temporary – Caller-saved
Reserved for OS
Global pointer
Stack pointer
Frame pointer
Function return address
Reflections on Registers
• Registers are just “special” memory locations
• A small number of registers, as opposed to a huge
number of memory locations
• Because there are a small number of registers,
accessing them is fast
• Principle: Smaller is usually faster.
• Trade-offs
• More registers --> More data in fast memory -->
Faster execution
• Fewer registers --> Registers are faster --> Faster
execution
• Compromise: 16 to 32 registers works well
3.3
Complicated arithmetic
F = (A + B) - (C + D)
Assume:
A is in $8
B is in $9
C is in $10
D is in $11
F is in $12
add
add
sub
$12 = ($8 + $9) - ($10 + $11)
Note:
Typically, the compiler
assigns variables to
registers
$13, $8, $9
$14, $10, $11
$12, $13, $14
We don’t have a 5-operand
add/subtract instruction!
Use temporary variables to
solve the problem.
# $13 <-- A + B
# $14 <-- C + D
# F <-- (A+B) - (C+D)
$13 and $14 are
temporary variables
3.3
Getting to the bits of it all
We’ve looked at assembly language (briefly)
The CPU wants bits.
R-Type Instruction
add
$13, $8, $9
Assembler
000000 01000 01001 01101 00000 100000
0
Opcode
32 bits, total
8
9
RS
RT
13
0
32
RD ShAmt Function
6 bits
5 bits
5 bits
5 bits
5 bits
6 bits
0 = Add
$8
$9
$13
0
32=Add
3.4
Staying Regular
R-Type instructions all have the same format:
Opcode
6 bits
RS
5 bits
RT
5 bits
RD ShAmt Function
5 bits
5 bits
6 bits
Add has an opcode of ‘0’, a function of ‘32’
add $13,$8,$9: 000000 01000 01001 01101 00000 100000
Subtract has an opcode of ‘0’, a function of ‘34’
sub $13,$8,$9: 000000 01000 01001 01101 00000 100010
The instructions differ only in one bit!
Regularity:
Similar functions should be similar in format.
Regularity is a key
to high-performance
3.4
Constants
Many times, an instruction needs to use a constant value
• Multiply by 4
• Add 3
Instructions with constant data in them are called immediate instructions
• addi $12, $10, 4
# Reg. 12 <-- Reg. 10 + 4
add
immediate
I-Type instructions all have the same format:
Opcode
RS
RT
6 bits
5 bits
5 bits
8
10
12
001000 01010 01100
I-Type Instruction
Immediate Data
16 bits
4
0000 0000 0000 0100
3.8
Doing Double Duty
• You desire to copy the value in register $8 to $10
• Called a “move” in computer terms
• move $10, $8
#copy register $8 to $10
• Doesn’t exist in MIPS assembly language!
• add $10, $8, $0
# adds zero and $8, result in $10
• Does the same thing as a move
• Allows the add instruction to serve double duty!
• Many instructions have double/triple functions
• sub $8, $0, $8 # negate $8
• addi $12, $0, 4 # load register $12 with value 4
3.4
Thanks for all the Memory!
When 32 registers just won’t do.
Many times (almost all the time, actually), you can’t fit all of your
data into 32 registers.
What do you do? Put some (most) of the data in main memory.
Remember: Smaller is faster.
Registers: Small and Fast
Memory: Big and Slow
In MIPS, all operations (i.e. arithmetic)
are done on registers, only.
Memory is used only for storing what
won’t fit in registers.
3.3
Loading and Storing
So you’ve got some data in memory.
Big deal. You need it in a register
to do anything useful.
3288
44 43
234
0996
1000
1004
You need to load a register with a value from memory.
lw
$10, 1000($0)
# copy memory location 1000 to $10
Afterwards, $10 has the value 43
Load Word Loads a whole 32-bit word
This value is added to 1000 - for now, it is zero
Say you’ve added 1 to register $10 (now it has the value 44).
Now you want to put it back in memory again.
You need to store the register’s value back to memory.
sw
$10, 1000($0)
# copy $10 to memory location 1000
3.3
Aside: Load and Store Architectures
• The only way to communicate with memory is
through a LW or SW instruction
• If you want to operate on memory, you have to use at
least three instructions (usually)
lw $15, 4500($0)
add $15, $15, $3
sw $15, 4500($0)
# load M[4500] into $15
# add $3 to $15
# store $15 back into M[4500]
• It doesn’t have to be this way
• Contrast this with the Motorola 68000
• ADD D3, 4500
; add register D3 to M[4500]
• Is the grass greener on the other side?
• MIPS: Takes more, simpler instructions...
RISC
• MC68000: Takes fewer, complex instructions... CISC
3.3
Data Structures - Arrays
A single-dimensional array (vector) is a simple linear data structure
int A[5]; /* integers are 4 bytes each */
2000
2004
2008
2012
2016
2020
2024
2028
A[0]
A[1]
A[2]
A[3]
A[4]
start of array (2004 in this example)
For 4-byte integers:
Location of A[n] = Start + n*4;
For data items of size s bytes:
Location of A[n] = Start + n*s;
Accessing data in memory
Assume that the variable List points to the beginning of an array
of 32-bit integers.
...
List=6000
6000
123 List[0]
3288 List[1]
6004
Move List[0] into $3:
43 List[2]
6008
lw $3, List($0) # $3 <-- List[0]
1 List[3]
6012
6016
45 List[4]
Move List[1] into $4:
...
addi $8, $0, 4
# $8 <-- 4
Note: Memory addresses
lw $4, List($8) # $4 <-- List[1]
refer to 8-bit bytes! We
List and contents of $8 are
added together to form address
Move List[4] into $5:
addi $8, $0, 16
# $8 <-- 16
lw $5, List($8) # $5 <-- List[4]
usually reference 32-bit
words.
All lw/sw instructions must
use an address that is a
multiple of 4!
To get proper index, have to
multiply by 4.
3.3
Load/Store Format
•
What instruction format do LW and SW have?
• lw $5, 240($9)
# load M[240+$9] into $5
• Needs
• Opcode
• Source register ($9)
• Immediate Operand (240)
• Destination register ($5)
• Hmmm, we’ve seen this before....
Opcode
for LW: 35
Opcode
6 bits
Opcode
for SW: 43
35
RS
5 bits
9
RT
5 bits
5
100011 01001 00101
I-Type Instruction
Immediate Data
16 bits
240
0000 0000 1111 0000
Think
Regularity!
3.4
Assembler directives
• Somehow, we’ve got to get data into memory
• User input
• Involves system calls (we’ll get to that later)
• Constant data
• Constant data is data that is in memory before our
program starts executing
• Machine-language instructions don’t give much help
• The only way is to use Immediate instructions
• The assembler helps us here!
• Assembler directives are special commands to the
assembler. The most common directives put data
into memory.
A.10
.word Assembler Directive
Buffer: .word
Label: A name for this
memory to go by.
Acts as a variable name.
Buffer:
Buffer+ 4:
01, 02
Data to be stored.
.word: Directive to store
words in memory here.
Remember:
00
00
00
01
Words are 4 bytes each!
00
00
00
02
Loads from Buffer+0 Loads from Buffer+4
lw $12, Buffer($0)
addi $10, $0, 4
lw $13, Buffer($10)
# $12 <-- 00 00 00 01
# $10 <-- 4
# $13 <-- 00 00 00 02
A.10
The Assembler Location Counter
The assembler keeps track of where to put things by using a
location counter. The location counter just points to the memory
location to put the “next” item.
For this example, assume the location counter starts at 4000
Loc. Ctr.
4004
4008
Label Table
buffer1:
.word
12
4000:
4004: buffer2: .word 3, 4, 0x20, 0x5
buffer1 = 4000
buffer2 = 4004
firstld = 4024
secld = 4032
4020:
4024: firstld:
4028:
4032: secld:
add
lw
addi
lw
Hex Constants
a denoted by
the “0x” prefix
4012
$9, $0, $0
$8, buffer1($9)
$9, $9, 4
$10, buffer2($9)
4016
Data Structures? No, thanks
• Assembly has no concept of “data structures”
• You can access a “variable” using another
“variable”
.data
Tonto: .word
Tonto2: .word
0x44, 0x22
0x32
.text
main:
add
lw
addi
lw
addi
lw
addi
syscall
$9, $0, $0
$8, Tonto($9)
$9, $9, 4
$10, Tonto($9)
$9, $9, 4
$10, Tonto($9)
$v0,$0,10
# clear $9
# put Tonto[0] in $8
# increment $9
# put Tonto[1] in $10
# increment $9
# put Tonto[2] ???? in $10
Other Memory Assembler Directives
borg:
.byte
borg:
10
?
greeting:
greeting:
greeting2:
greeting2:
.byte - reserves bytes in memory
33, 22, 12, 10, 8, 1
12
?
22
1
33
8
.asciiz “Resistance is small.”
52
65
73
69
6C
65
2E
0
.ascii
...
“You will be informed.”
59
6F
75
65
64
2E
...
.asciiz - reserves Nullterminated ASCII chars
Null-terminated
.ascii - reserves ASCII
characters (no NULL)
20
--
A.10
Meeting all your needs for space
Sometimes, we need to allocate (empty) space to be used later.
inputbuffer:
.space 100
Allocates 100 bytes of space for an input buffer.
Space allocated this way is just reserved by the assembler.
You have to make your own use of it.
addi
sw
$12, $0, 6
$12, inputbuffer($0)
# stores 6 in buffer
A.10
Our first program!
# This is our first program! Yeah!
.data
Tonto: .word
.text
.data means that data follows
0x44, 0x22
.text means that code follows
main: tells SPIM where to start
main:
add
lw
addi
lw
$9, $0, $0
$8, Tonto($9)
$9, $9, 4
$10, Tonto($9)
addi
$v0,$0,10
syscall
# clear $9
# put Tonto[0] in $8
# increment $9
# put Tonto[1] in $10
these two instructions end the program
A.10
Instruction
1
add $6, $0, $0
2
add $7, $0, $0
3
lw $5, ARRAY($7)
4
add $6, $6, $5
5
addi $7, $7, 4
6
lw $5, ARRAY($7)
7
add $6, $6, $5
8
addi $7, $7, 4
9
lw $5, ARRAY($7)
10
add $6, $6, $5
11
addi $7, $7, 4
12
lw $5, ARRAY($7)
13
add $6, $6, $5
14
addi $7, $7, 4
15
lw $5, ARRAY($7)
16
add $6, $6, $5
17
sw $6, SUM($0)
18
addi $v0, $0, 10
PC
R5
R6
R7
Logic Instructions
• and $10, $8, $6 # bitwise and between $8 and $6, result in $10
• Example:
•
•
•
•
•
•
•
• $8 = 0010 0001 1100 0001 0011 1100 1010 0000
• $6 = 1101 1110 0011 0001 1111 0000 1100 0001
• $10=0000 0000 0000 0001 0011 0000 1000 0000
or $10, $8, $6 # bitwise or between $8 and $6, result in $10
xor $10, $8, $6 bitwise xor between $8 and $6, result in $10
The above are R-Type instructions
andi $10, $8, 6 # bitwise and between $8 and 6, result in $10
• Example:
• $8 = 0010 0001 1100 0001 0011 1100 1010 0000
• 6 = 0000 0000 0000 0000 0000 0000 0000 0110
• $10=0000 0000 0000 0000 0000 0000 0000 0000
ori $10, $8, 6 # bitwise or between $8 and 6, result in $10
xori $10, $8, 6 bitwise xor between $8 and 6, result in $10
The above are I-Type instructions
Example
• Write at least 5 ways of clearing a register
• Write at least 4 ways of copying the contents of a
register to another register
Pseudoinstructions
• Some “missing” instructions are commonly composed of
others
• The assembler “implements” these by allowing the “missing”
instructions to be entered in assembly code.
• When machine code is generated, the pseudoinstructions are
converted to real instructions.
• Pseudoinstructions are assembler-dependent
• They can be turned-off in SPIM
move
$5, $3
add
$5, $3, $0
neg
$8, $9
sub
$8, $0, $9
li
$8, 44
addi
$8, $0, 44
or
ori
$8, $0, 44
A.10
SPIM I/O
• SPIM I/O uses the SYSCALL pseudoinstruction
• Set up parameters
• Place correct code in $v0
• Execute SYSCALL
Action
Print an Integer
Print a String
Input an Integer
Input a String
Exit program
Code (in $v0)
1
4
5
8
10
To print the value in $t3:
move $a0, $t3
li
$v0, 1
syscall
Parameters
$a0 = value to print
$a0 = location of string
(after syscall) $v0 contains integer
$a0 = location of buffer, $a1 = length
To display a string
prompt: .asciiz “hello world”
la $a0,prompt
li $v0, 4
syscall
Boring
• Straight-line code is nice,
but boring
• Just arithmetic and
loads/stores based on a
predetermined sequence
• Decision-making elements
add some spice to the
equation
• Control allows programs to
make decisions based on
their current state
• The most common control
structure is the branch
A = B+C
D = B+F
M[18]=D
D = B+F
D>23?
Y
N
M[22] = D
C = B+A
3.5
Going places
Consider the GoTo
if (x == y) q = 13;
Next:
if (x != y) GoTo Next;
q = 13;
...
if (p > q) r = 3; else r=2;
while (y < 2) y = y+1;
Loop:
End:
if (y >=2) GoTo End;
y = y+1;
GoTo Loop;
...
R3:
Next:
if (p>q) GoTo R3;
r = 2;
GoTo Next;
r = 3;
...
if (condition) GoTo location and
GoTo location are all we need
3.5
Branching out
if ($9 == $10) GoTo Label;
beq
$9, $10, Label
if ($7 != $13) GoTo Next;
bne
beq - Branch if EQual
bne - Branch if Not Equal
$7, $13, Next
Branches use I-Type Instruction Format
(need two registers and 16-bit data)
GoTo Exit;
j
Exit
j - Jump (unconditionally)
Jumps need only an opcode and data There is a lot more room for the data...
Opcode
6 bits
Immediate Data
26 bits
J-Type Instruction
3.5
IF-Then Structures
if $x == $y then S1
S2
S1 should be executed if $x == $y is True
If $x != $y, or after S1 is executed, S2 is executed
False:
bne
S1
S2
$x, $y, False
# if $x != $y, skip S1
# $x == $y, execute S1
# either way we get here, execute S2
If you can’t express the condition as a negative, try this:
True:
False:
beq
j
S1
S2
$x, $y, True
False
# if $x == $y, then execute S1
# $x != $y, so exit
# $x == $y, execute S1
# either way we get here, execute S2
3.5
IF-Then-Else Structures
if $x == $y then S1 else S2
S3
S1 should be executed if $x == $y
S2 should be executed if $x != $y
After executing S1 or S2, execute S3
IF:
Finish:
beq
S2
j
S1
S3
$x, $y, IF
Finish
# if $x == $y, goto S1, skip S2
# $x != $y, execute S2
# now execute S3
# $x == $y, so execute S1
# either way, we do S3 afterwards
3.5
More Complicated If-Then-Else structures
if $x == $y and $z == $w then S1 else S2
S3
S1 should be executed if both $x == $y and $z == $w
S2 should be executed if either $x != $y or $z != $w
After executing S1 or S2, execute S3
The simplest way to figure out complex if-then-else
structures is to first write the conditions, then all the
statements and finally figure out the branches and jumps
STEP 1: conditions STEP 2: statements
STEP 3: branches
bne $x, $y, ____
bne $x, $y, ____
bne $x, $y, false
bne $z, $w, false
bne $z, $w, ____
bne $z, $w, ____
S1
j skip
S1
false: S2
S2
skip: S3
S3
Example
if $x == $y or $z == $w then S1 else
if $x == $z or $y == $w then S2 else
S3
STEP 1: conditions
bne $x, $y, ____
beq
STEP 2: statements
beq $x, $y, ____
bne $z, $w, ____
beq
beq $z, $w, ____
beq $x, $z, ____
beq $x, $z, ____
beq $y, $w, ____
beq $y, $w, ____
STEP 3: branches
beq $x, $y, then1
beq $z, $w, then1
beq $x, $z, then2
beq $y, $w, then2
j skip
then1: S1
j skip
then2: S2
S1
S2
S3
skip: S3
Interlude: Comments on Comments
• Code should be thoroughly commented
• Code may be modified by different programmers
• Code may be reused a long time after writing it
• There are two types of commenting style depending on the reader of
the code the comments are intended for
• Comments that explain what the instruction does
• Typical for programming language books and lecture notes
• The purpose is to learn the language
• Worthless if used in a real program
• Comments that explain the logic behind the instruction
• Typical for real programs, assumes reader knows language
• The purpose is to understand the program
• Not helpful for learning the language
• Examples:
• addi $7, $7, 4
#add 4 to R7, R7<-R7+4 #incrementing address
• lw $5, ARRAY($7) #R5 <- [ARRAY+4]
#fetching next ARRAY
#element
While Loops
while $x == $y do S1
Execute S1 repeatedly as long as $x == $y is true
Repeat: bne
S1
j
Exit:
$x,$y, Exit
Repeat
# exit if $x != $y is False
# execute body of loop
# do it all over again
# end of the loop
Warning: The following loop always executes at least once,
no matter what $x and $y are:
Repeat: S1
beq
Exit:
$x,$y, Repeat
# execute body of loop
# do it again if $x == $y
# end of the loop
3.5
For Loops
for i = $start to $finish {S1}
S2
Use temporary, $t0 to hold i
Execute S1 for all values from $start to $finish (step of 1)
move
Loop: bgt
S1
addi
j
done: S2
$t0, $start
# copy start to i ($t0)
$t0, $finish, done # if i > finish, then we’re done - do S2
# execute S1
$t0, $t0, 1
# increment count
Loop
# go again
Note: bgt doesn’t really exist - more on that later...
3.5
Other conditions
slt
$4, $10, $11
Set on Less Than
Set $4 = 1 if ($10 < $11), otherwise $4 = 0
if ($7 < $8) then $15 = 3;
slt
beq
addi
$1, $7, $8
$1, $0, GoOn
$15, $0, 3
Example: $7=4, $8=9
$1 = 1 ( $7 < $8)
$1 0, Don’t branch
Set $15 to 3
Example: $7=4, $8=2
$1 = 0 ( $7 > $8)
$1 == 0, Branch
GoOn ($15 not changed)
# $1 <-- ($7 < $8)
# If not less than, go on
# ($7 < $8), so $15 <-- 3
GoOn:
if ($12 >= $3) then $4 = $2;
slt
bne
add
$1, $12, $3
$1, $0, GoOn
$4, $2, $0
Example: $12=4, $3=2
$1 = 0 ( $12 > $3)
# $1 <-- ($12 < $3)
$1 == 0, Don’t branch
# If less than, go on
# ($12 >= $13), so $4 = $2 Set $4 to 2
GoOn:
3.5
Pseudoinstructions for branches
• Branches can be nasty to figure out
• SPIM provides several pseudoinstructions for branches
blt
$3, $4, dest
slt
bne
$1, $3, $4
$1, $0, dest
bge
$3, $4, dest
slt
beq
$1, $3, $4
$1, $0, dest
$3 >= $4 is the
opposite of $3 < $4
bgt
$3, $4, dest
slt
bne
$1, $4, $3
$1, $0, dest
$3 > $4 same as
$4 < $3
ble
$3, $4, dest
slt
beq
$1, $4, $3
$1, $0, dest
$3 <= $4 is the
opposite of $3 > $4
A.10
Branch limitations
• A conditional branch (BEQ, BNE) uses an I-type
Instruction
• Allows a 16-bit immediate operand
• 216 = 64K Locations is too small
• Notice that most branches don’t go very far away
(back to the beginning of a loop, etc.)
• Use PC-relative addresses for branches
• Immediate operand is a displacement in 4-byte
words from the next instruction
• May be positive (forward branches) or negative
(backwards branches)
3.8
Branch example
loop:
bgt
lw
addi
beq
bigger: move
Branches: offset is in instructions from
the instruction following the branch
8000
8004
8008
8012
8016
8020
$t0, $t1, bigger
$s0, 0($t0)
$t0, $t0, 1
$s0, $s1, loop
$s2, $t0
loop: -5 instructions
loop: slt
$1, $8, $9
+3
bne
$1, $0, bigger
lw
$16, 0($8)
addi
$8, $8, 1
-5
beq
$16, $17, loop
bigger: add
$18, $8, $0
bigger: + 3 instructions
8000
8004
8008
8012
8016
8020
0
5
35
8
4
0
8
1
8
8
16
8
9
0
16
8
17
0
1
18
0
+3
0
1
-5
0
42
32
Note: Negative
numbers require
2’s complement
3.8
Jump Addressing
• Jumps use a J-type instruction and have a 26-bit offset
• A lot more range than 16-bit branches
• Allows a range of 226=64M possibilites
• Because the range is so much larger, jumps use absolute
addressing
• Absolute addressing just specifies the address of the jump target
• Since all instructions have addresses that are multiples of 4, we
only need to put the address divided by 4 in the instruction field
• Actual byte address is obtained by multiplying by 4
• Allows a range of 64M instructions = 256M bytes
Example:
2000
2004
2000:
2004: target:
2
0
2
j
add
4
target 501 = 2004/4
$1, $2, $4
501
1
0
32
3.8
Jumping based on Registers
• Jumps change the PC to a fixed location
• j OverThere
• Always goes to the same place
• Is there a way to jump to a place to be determined by
the program?
• Put the address to go to in a register
• addi $14, $0, 10000
• Jump to the address contained in that register
• jr
$14
JR - Jump Register
3.5
LUI
• Registers can hold 32 bits, but we can only load in 16-bit
immediate data
• LUI - Load Upper Immediate
• Loads constant into bits 31-16 of register
• Bits 15-0 become zero
Put the constant 0x1A2B3C4D in register $8
lui
li
$8, 0x1A2B
$8, 0x3C4D
Warning: Don’t use addi for the second
instruction; use LI or ORI. (Sign Extension)
---- 1A2B
$8:
31
We can let the assembler do the work:
li $8, 0x1A2B3C4D will be converted to
these two instructions
---- 0000 3C4D
16 15
0
3.8
Getting around branch limitations
Branches have a limit of +/- 215 instructions - How can we branch further?
1000:
beq $s0,$t1,far
1004:
sub $s2, $v0, $a0
…
500000: far: add $t1, $t2, $t3
Can’t branch that far...
1000:
bne
1004:
j
1008:
stay: sub
…
500000: far: add
$s0,$t1,stay
far
$s2, $v0, $a0
$t1, $t2, $t3
Use the larger range of the jump instruction:
3.8
Example
Instruction
R5
R6
R7
Addr:Data
1
add $6, $0, $0
8000: 0x3
2
addi $7, $0, 8
8004: 0x4
3
lw $5, ARRAY($7)
8008: 0x5
4
add $6, $6, $5
800C
5
addi $5, $0, 0
8010
6
lui $5, 0x5
8014
7
be $5, $0, EXIT
8018
8
slt $5, $0, $6
801C
9
li $7, 0x8000
8020
10
lw $5, 0($7)
11
and $5, $5, $7
12
bgt $5, $6, EXIT
13
li $7, 0xC
14
sw $5, 8000($0)
15
sw $6, 8000($4)
16
j EXIT
17
sw $7, 8014($0)
18
EXIT:
The Stack
•
•
•
•
•
•
•
•
A stack is a one-dimensional data structure
The stack segment of a program is used for temporary storage of data
and addresses
Items are added to and removed from one end of the structure using a
"Last In - First Out" technique (LIFO)
The top of the stack is the last addition to the stack
Every program has three segments of memory assigned to it by the
operating system
• the “text” segment where the machine language code is stored,
• the “data” segment where space is allocated for global constants
and variables,
• the stack segment.
The stack segment is provided as an area where
• parameters can be passed,
• local variables for functions are allocated space,
• return addresses for nested function calls and recursive functions
are stored
The operating system initializes register 29 ($sp) in the register file to
the base address of the stack area in memory
The stack grows toward lower addresses
The Stack
• MIPS has no special push and pop instructions
• However the following instructions are equivalent
• PUSH
addi $sp, $sp, -4
sw $5, 0($sp)
#decrement stack pointer
#save $5 to stack
• POP
lw $5, 0($sp)
#load from stack to $5
addi $sp, $sp, 4 #increment stack pointer
Subroutines
• Subroutines allow common program portions to be
reused
• int CalcInterest(int principle, int time) { ... }
• y = CalcInterest(1000, 10)
• z = CalcInterest(1000, 15)
• When calling a subroutine, you must:
• Set up any parameters
• Save the current position so the program will know
where to return to
• Jump to the location of the subroutine
3.6
Jumpin’ and Linkin’
• JAL - Jump and Link
• Saves the return address
• Write address of next instruction in $31 ($ra)
• Jumps to the address specified and keeps going
100:
104:
342:
346:
368:
jal
sub
...
CALC: add
mult
...
jr
CALC
$4, $4, $2
$14,$15,$2
$14, $2
$ra
Call the Calc subroutine
Save addr. of next instr. in $ra ($31)
104
$ra
Start of Subroutine
End of Subroutine.
Return to Return Address in $ra
3.6
Instruction
R5
R6
R7
Addr:Data
1
add $6, $0, $0
8000: 0x3
2
addi $7, $0, 8
8004: 0x4
3
lw $5, ARRAY($7)
8008: 0x5
4
add $6, $6, $5
800C
5
addi $5, $0, 0
8010
6
jl CALC
8014
7
be $5, $0, EXIT
8018
8
slt $5, $0, $6
801C
9
li $7, 0x8000
8020
10
j EXIT
11
CALC: and $5, $5, $7
12
li $7, 0xC
13
sw $5, 8000($0)
14
sw $6, 8000($4)
15
sw $7, 8008($0)
16
jr $ra
17
sw $7, 8014($0)
18
EXIT:
Passing Parameters
• Most subroutines have parameters to make them
more interesting...
• Z = Addemup(A,B,C)
• In order to pass parameters, we must place the
parameters in registers before calling the subroutine
• $a0, $a1, $a2, $a3 used for these ($4 - $7)
• $a0 <-- A, $a1 <--B, $a2 <--C
• Before calling a routine, copy all parameters to the
appropriate registers
• Return values are put in $v0, $v1 ($2, $3)
• $v0 <-- Z
• After subroutine finished, copy return values back
3.6
Thoughts about MIPS programming
• Write the program in C/C++ first
• Break it into procedures as appropriate
• Convert the program to assembly language
• Start out simple
• Get basic parts working before adding error checking,
etc.
• Don’t forget: Words are 4 bytes
• Use pseudoinstructions when applicable
Example
•
Write a MIPS assembly program that finds the sum of 5 numbers
found in consecutive memory locations starting at array and stores it
in memory location sum.
.data
ARRAY: .word 3, 5, 7, 9, 2 #random values
SUM: .word 0
#initialize sum to zero
.text
main:
addi $6, $0, 0
#set loop counter to 0
addi $9, $0, 5 #cannot compare with 5 directly
addi $7, $0, 0
#set pointer to zero
addi $8, $0, 0
#set $8 (sum temp) to zero
REPEAT:
lw $5, ARRAY($7)
add $8, $8, $5
addi $7, $7, 4
#increment pointer
addi $6, $6, 1
#increment loop counter
bne $6, $9, REPEAT
sw $8, SUM($0) #copy sum to memory
addi $v0, $0, 10 #exit program
syscall
Example (improved version)
•
We can improve the previous program if we consider that comparing with zero is free in
MIPS, so we can count down to zero instead of up to five. This saves one instruction and
one register
.data
ARRAY: .word 3, 5, 7, 9, 2 #random values
SUM: .word 0
#initialize sum to zero
.text
main:
addi $6, $0, 5
#initialize loop counter to 5
addi $7, $0, 0
#initialize array index to zero
addi $8, $0, 0
#set $8 (sum temp) to zero
REPEAT:
lw $5, ARRAY($7) #R5 = ARRAY[i]
add $8, $8, $5
#SUM+= ARRAY[I]
addi $7, $7, 4
#increment index (i++)
addi $6, $6, -1 #decrement loop counter
bne $6, $0, REPEAT #check if 5 repetitions
sw $8, SUM($0) #copy sum to memory
addi $v0, $0, 10 #exit program
syscall
Example (improved v2)
•
We can eliminate the loop counter and use the index to the array as
counter if we consider the end value 4*5=20.This saves one more
instruction
.data
ARRAY: .word 3, 5, 7, 9, 2 #random values
SUM: .word 0
#initialize sum to zero
.text
main:
addi $6, $0, 20 #set loop counter to 20
addi $7, $0, 0
#set pointer to zero
addi $8, $0, 0
#set $8 (sum temp) to zero
REPEAT:
lw $5, ARRAY($7)
add $8, $8, $5
addi $7, $7, 4
#increment pointer
bne $6, $7, REPEAT
sw $8, SUM($0) #copy sum to memory
addi $v0, $0, 10 #exit program
syscall
Example 2
•
Modify the program to read five numbers from the keyboard and then
move them to location ARRAY
.data
ARRAY: .space 20
#reserving space for 5 numbers
SUM: .word 0
#initialize sum to zero
PROMPT: .asciiz "Please enter five numbers"
RESULT: .asciiz "The sum of the numbers you entered is:"
.text
main:
addi $6, $0, 5
#set loop counter to 5
addi $7, $0, 0
#set pointer to zero
addi $8, $0, 0
#set $8 (sum temp) to zero
la $a0,PROMPT #print prompt
li $v0, 4
syscall
INPUT:
li
$v0, 5
syscall
sw $v0, ARRAY($7) #moving input to array
addi $7, $7, 4
#increment pointer
addi $6, $6, -1 #decrement loop counter
bne $6, $0, INPUT
•
Example 3 (1/3)
Write a MIPS assembly program that finds the maximum of 5 positive
numbers read from the keyboard, stores it to memory location max
and prints the result on the screen. Use functions.
main:
.data
ARRAY: .space 20
#20 bytes for the 5 numbers
MAX: .word 0
#initialize sum to zero
PROMPT: .asciiz "Please enter five numbers"
RESULT: .asciiz "The maximum of the numbers you entered is:"
.text
la $a0,PROMPT #setup call to print prompt
jal PRINT
#call to print message
jal READ
#call to input function, reads from keyboard
jal FINDMAX
#call to findmax function
la $a0,RESULT #setup call to print result
jal PRINT
move $a0, $8 #setup value to print
jal OUTPUT
#call to output function, prints to screen
addi $v0, $0, 10 #exit program
syscall
Example 3 (2/3)
PRINT:
li $v0, 4 #print prompt
syscall
jr $ra
READ: addi $6, $0, 5 #set loop counter to 5, setup input function
addi $7, $0, 0 #initialize pointer
REPEAT:
li $v0, 5
syscall
sw $v0, ARRAY($7) #moving input to array
addi $7, $7, 4
#increment pointer
addi $6, $6, -1 #decrement loop counter
bne $6, $0, REPEAT
jr $ra
Example 3(3/3)
FINDMAX:
REPEAT:
SKIP:
OUTPUT:
addi $6, $0, 5 #set loop counter to 5
addi $7, $0, 0 #set pointer to zero
addi $8,$0, 0 #initial maximum
lw $5, ARRAY($7)
bge $8, $5, SKIP #if $8 > $5, keep current maximum
move $8, $5 #else new maximum
addi $7, $7, 4 #increment pointer
addi $6, $6, -1 #decrement loop counter
bne $6, $0, REPEAT
sw $8, MAX($0)
#copy MAX to memory
jr $ra
li
$v0, 1
syscall
jr $ra
Example 4
Write a function to scan an array “X” of 10 bytes
counting how many bytes are ASCII codes for:
• a. upper case letters - U
• b. lower case letters - L
• c. decimal digits - D
.data
ARRAY: .asciiz “df12o@pZ4X” #data for test
U: .word 0
#initialize sum to zero
L: .word 0
D: .word 0
ASCII Table
.text
main: addi $5, $0, 10
addi $6, $0, 0
add $7, $0, $0
add $8, $0, $0
add $9, $0, $0
li $10, 48
li $11, 57
li $12, 65
li $13, 90
li $14, 97
li $15, 122
#set loop counter to 5
#set pointer to zero
#U
#L
#D
#0
#9
#A
#Z
#a
#z
REPEAT: lb $16, ARRAY($6)
blt $16, $10, SKIP
bgt $16, $11, LETTER
addi $9, $9, 1
j SKIP
LETTER: blt $16, $12, SKIP
bgt $16, $13, LOWER
addi $7, $7, 1
j SKIP
LOWER: blt $16, $14, SKIP
bgt $16, $15, SKIP
addi $8, $8, 1
j SKIP
SKIP: addi $6, $6, 1
bne $5, $6, REPEAT
# if ASCII<’0’, neither
#else if ASCII>’9’, not a number
#else ‘0’<ASCII<‘9’, it’s a number
#if 9<ASCII<‘A’, neither
#else if ASCII>’Z’, not uppercase
#else 9<ASCII<‘A’, uppercase
# if ‘Z’<ASCII<’a’, neither
#else if ASCII>’z’, neither
#else ‘a’<ASCII<’z’,
sw $7, U($0)
sw $8, L($0)
sw $9, D($0)
addi $v0, $0, 10
syscall
#exit program
Saving registers and passing parameters through
the stack
• Subprograms are typically written by different
programmers
• Each programmer does not know which registers the
others are using
• Could overwrite each others data!
• Don’t know where to find arguments and return
results
Example of overwriting data by mistake
main: addi $t0, $0, 5 #main program needs 5 in $t0
jal FUNC1
add $t0,$t0, $t1 #now $t0 has wrong value
FUNC1: addi $t0, $0, 10 #FUNC overwrites $t0
…
jr $ra
Solution: save data you need on the stack
main: addi $t0, $0, 5 #main program needs 5 in $t0
addi $sp, $sp, -4 #decrement stack pointer
sw $t0, 0($sp)
#save $t0 to stack
jal FUNC1
#before calling FUNC1
lw $t0, 0($sp)
#load from stack to $t0
addi $sp, $sp, 4 #increment stack pointer
add $t0,$t0, $t1 #now $t0 has correct value
FUNC1: addi $t0, $0, 10 #FUNC can now use $t0
…
jr $ra
Passing parameters
• Let’s create a function that adds two numbers
• In high-level languages this would be x=SUM(a,b)
• Where can a, b and x be found in assembly?
main:
jal SUM
SUM: add $??, $??, $?? #SUM must know the registers
…
jr $ra
Solution: Pass a, b and x through the stack
main: addi $sp, $sp, -4 #decrement stack pointer
sw $t0, 0($sp)
#push a=$t0 to stack
addi $sp, $sp, -4 #decrement stack pointer
sw $t0, 0($sp)
#push b=$t1 to stack
jal SUM
lw $t0, 0($sp)
#load from stack to x=$t0
addi $sp, $sp, 4 #increment stack pointer
SUM: lw $t0, 0($sp)
#load from stack to $t0=a
addi $sp, $sp, 4 #increment stack pointer
lw $t1, 0($sp)
#load from stack to $t1=b
addi $sp, $sp, 4 #increment stack pointer
add $t1, $t0, $t1 #no need to know the registers
addi $sp, $sp, -4
sw $t1, 0($sp)
jr $ra
#decrement stack pointer
#push x=$t1 to stack
Example 5
• Write a program that loads a 20-byte string from
memory stored in memory location MSG, converts
lowercase letters to uppercase and vice versa,
stores the modified string in memory location MSG2
and prints it on the screen.
.data
MSG: .asciiz “#8puIth45FaSdf12o@pZ” #data for test
MSG2: .space 20
#reserve 20 bytes
.text
main:
addi $5, $0, 20
#set loop counter to 20
addi $6, $0, 0 #set pointer to zero
li $12, 65
#ASCII value of A
li $13, 90
#ASCII value of Z
li $14, 97
#ASCII value of a
li $15, 122
#ASCII value of z
loop: lb $16, MSG($6)
blt $16, $12, SKIP
#ASCII<‘A’, do nothing
bgt $16, $13, LOWER
#else if ASCII>’Z’, not uppercase
jal TO_LOWER
#else uppercase
j SKIP
LOWER: blt $16, $14, SKIP
# if ‘Z’<ASCII<’a’, neither
bgt $16, $15, SKIP
#else if ASCII>’z’, neither
jal TO_UPPER
#else ‘a’<ASCII<’z’,
SKIP: jal STORE
addi $6, $6, 1 #increment pointer
bne $5, $6, loop
jal PRINT
addi $v0, $0, 10
#exit program
syscall
TO_LOWER: addi $16, $16, 32
jr $ra
#add offset between upper and lower
TO_UPPER: addi $16, $16, -32
jr $ra
#subtract offset between upper and lower
STORE: sw $16, MSG2($6)
jr $ra
#storing converted number to MSG2
PRINT: la $a0, MSG2
li $v0, 4
syscall
jr $ra
#putting address of MSG2 to a0 to print
#print string system call