lmips.s
## LSU EE 4720 -- Spring 2022 -- Computer Architecture
#
## MIPS Overview
## Contents
#
# MIPS Background
# Machine Language Basics
# Machine Languages Covered in ECE Courses
# Instructions, Registers, Immediates, and Memory
# Basic Three-Register Instructions
# Other Basic Instructions
# Instruction Coding
# Miscellaneous Integer Arithmetic Instructions
# Pseudo Instructions
#
# Types of Control-Transfer Instructions
# A Simple Jump Instruction
# A Branch Instruction
# More Branch Instructions
# More Jump Instructions
# Procedure Call Example
# Typical CTI Uses
#
# Load Byte (Unsigned)
# Store Byte
# Load Byte
# Load Word, Store Word
# Load and Store Half
# Array Access Examples
# Histogram Program
## References
#
# :PH: Patterson & Hennessy, "Computer Organization & Design"
# :Mv1: MIPS Technologies, "MIPS32 Architecture for Programmers Vol I: Intro"
# :Mv2: MIPS Technologies, "MIPS32 Architecture for Programmers Vol II: Instr"
## Objectives
#
# Understand MIPS Register and Memory Organization
# Understand MIPS Instructions
# Read programs using instructions, write program using instructions.
# Understand MIPS Instruction Coding and Formats
# Determine binary coding from assembly, and vice versa.
# Ability to Learn New Instructions from MIPS Documentation
# Write Simple Assembly Language Programs
################################################################################
## MIPS Background
## History
#
# Developed in early 1980's by MIPS Computer Systems.
#
# An early and good example of RISC style of ISA.
#
# Intended for general-purpose computation.
#
# First implementations were for what were called /engineering
# workstations/ (would be called a high-end personal computer today)
# and servers.
#
# MIPS (the company) promoted MIPS implementations for personal
# computers. That didn't work out.
#
# In 80s and early 90s MIPS implementations were successful for
# workstations and servers.
#
# Used in the cool (for their time) Silicon Graphics workstations.
#
# In 90s popularity for servers and workstations faded but ...
# ... popularity for embedded systems grew.
#
# Still popular as an /IP Core/ (HDL library that you can encorporate
# in your own design.)
## MIPS Features
#
# Example of a RISC ISA, to be defined later.
#
# The MIPS is relatively elegant, as are some implementations.
#
################################################################################
## Machine Language Review
# :PH: 3
# :Def: Machine Language
#
# The language understood by the computer processor itself.
# An ISA describes the machine language, plus other details.
#
# :Def: Machine Code
#
# All or part of a machine language program.
# :Def: High-Level Language
#
# A computer programming language for humans.
#
# Examples: C, Basic, Java, Fortran.
#
# A program in a high-level language may be converted into machine
# language and then run.
#
# A high-level language can be converted into the machine language of
# (compiled for) many machines.
# :Def: Assembly Language
#
# A language for humans used to prepare machine code.
#
# Assembly language is human readable, machine language is not.
# (At least without great effort or rare talent.)
#
# For each machine language there is usually one assembly language.
# (In principle there could be many assembly languages for each
# machine language.)
#
# The machine language and corresponding assembly language are sometimes
# known by the same name, for example MIPS.
#
# Almost all examples will be in assembly language.
## A Short MIPS Assembly Language Program
#
#
add $s1, $s2, $s3 # s1 = s2 + s3
sub $s1, $s4, $s1 # s1 = s4 - s1
#
# Comments start with a #.
#
# $s1-$s4 are storage locations called /registers/.
#
# Each register holds 32 bits.
# The program again, showing initial, intermediate, and final register values.
#
# Initial: s1 = 10, s2 = 20, s3 = 30, s4 = 40
add $s1, $s2, $s3
# s1 = 50, s2 = 20, s3 = 30, s4 = 40
sub $s1, $s4, $s1
# Final: s1 =-10, s2 = 20, s3 = 30, s4 = 40
# The program again, in three forms:
#
# High-Level (C) Assembly (MIPS) Machine (MIPS)
# a = b + c; add $s1, $s2, $s3 0x02538820
# a = d - a; sub $s1, $s4, $s1 0x02918822
#
# Note: the relationship between high-level code and assembly code
# is rarely one machine instruction per high-level statement.
################################################################################
## Instructions, Registers, Immediates, and Memory
# :PH: 3.3
# :Mv1: 2.8.4, 2.8.5 MIPS register descriptions
## Description is of MIPS-I (MIPS 32)
## Where MIPS Instructions Get Data
#
# A MIPS instruction can get data from ..
# .. the immediate field of the instruction itself,
# .. registers, and
# .. memory locations.
#
# Immediates: Data stored in instruction.
# Registers: A small number of high-speed 32-bit storage locations.
# Memory: A large number (2^32) of low-speed 8-bit storage locations.
addi $a0, $a0, 1 # Gets data from register ($a0) and immed. (1)
lbu $t1, 0($a0) # Gets data from memory (address in $a0)
## What MIPS Instructions can Modify
#
# A MIPS instruction can modify ..
# .. register contents and
# .. memory locations.
#
addi $a0, $a0, 1 # Modifies register, $a0.
sb $t1,-1($a0) # Modifies memory, address is $a0-1
## Registers
#
# Most registers are 32 bits. (64 bits in MIPS-64)
#
# General-Purpose Registers (GPRs, a.k.a., Integer Registers)
# $0-$31
#
# Special Registers (Not part of a set.)
# PC: Program Counter
# $lo, $hi: Used for multiplication and division.
#
# Co-processor 0: Processor and system control.
# Co-processor 1: MIPS-32 floating-point
# $f0-$f31:
# Co-processor 2: Reserved for special-purpose designs.
# Co-processor 3: 64-bit floating-point
## General-Purpose Register (GPR) Names
#
# There are 32 (arguably 31) general purpose registers (GPRs).
#
# Each register holds 32 bits. (MIPS-32)
#
# Each has a name and a number.
#
# Numbers range from 0 to 31.
#
# Names indicate suggested use.
#
# Either names or numbers can be used in assembly language.
# In machine language only numbers are used.
#
# Ways to Reference GPR Number 1 (varies by assembler, textbook author, etc.)
#
# By number: 1, $1, r1, R1
#
# By name: $at
# List of General-Purpose Registers. (Will be explained later.)
# See :PH: A-23
#
# The value of register 0 ($zero) is always zero.
#
# The value of the other registers is the last value written.
#
#
## Names Numbers Suggested Usage
# $zero: 0 The constant zero.
# $at: 1 Reserved for assembler.
# $v0-$v1: 2-3 Return value
# $a0-$a3: 4-7 Argument
# $t0-$t7: 8-15 Temporary (Not preserved by callee.)
# $s0-$s7: 16-23 Saved by callee.
# $t8-$t9: 24-25 Temporary (Not preserved by callee.)
# $k0-$k1: 26-27 Reserved for kernel (operating system).
# $gp: 28 Global Pointer
# $sp: 29 Stack Pointer
# $fp: 30 Frame Pointer
# $ra: 31 Return address.
# :Example:
#
# The two instructions below are identical, the first uses register
# names, the second uses register numbers.
add $s1, $t2, $sp
add $17, $10, $29
####
## Memory
#
# Memory consists of 2^32 locations. [MIPS-64 has 2^64 locations.]
#
# Each location stores 8 bits, called a character or a byte.
#
# Each location has an address, an integer ranging from 0 to 4294967295
#
# Memory access is usually slower than register access.
# :Example:
#
# Examples of instructions accessing memory. The first loads
# something from memory into a register, the second stores something
# from a register to memory. These will be covered in detail later.
lw $4, 0($19)
sw $31, 72($sp)
####
## Immediates
#
# An immediate is a constant value stored in the instruction itself.
#
# In MIPS immediates are usually 16 bits and can be interpreted as
# signed or unsigned numbers (depending on the instruction).
# :Example:
#
# An instruction using an immediate, in this case 100.
addi $1, $2, 100
################################################################################
## Basic Three-Register Instructions
# :PH: Throughout Chapter 3.
# :Mv2: A complete list of instructions.
# The three-register instructions each read two source registers and
# write one destination register.
## The Plain Old Add Instruction
#
# :Syntax: ADD rd, rs, rt
# rd <- rs + rt
#
# How to read the syntax shown above:
#
# The mnemonic (name) of the instruction is ADD. A lower-case
# version of the mnemonic (add) should be used in assembly language.
#
# The instruction has three operands, rd, rs, rt.
# These symbols refer to general-purpose register operands.
# In assembly language they would be replaced by a register name or number.
# (Machine language coding will be covered later.)
#
# The line rd <- rs + rt indicates what the instructions does.
#
# ADD instruction assembly language examples:
add $1, $2, $3
add $s1, $t2, $v1
# The instruction below is NOT an add instruction because $rt is not a GPR.
# A "strict" assembler would NOT be able to convert that in to machine
# code. (A "liberal" assembler would correct the mistake by replacing
# "add" with "addi".)
add $1, $2, 100
# There is an instruction that can take the constant 100, "addi."
## Other Basic Three-Operand Instructions
#
# :Syntax: SUB rd, rs, rt
# rd <- rs - rt
#
# :Syntax: AND rd, rs, rt
# rd <- rs & rt
#
# :Syntax: OR rd, rs, rt
# rd <- rs | rt
#
# :Syntax: NOR rd, rs, rt
# rd <- ~( rs | rt )
#
# :Syntax: XOR rd, rs, rt
# rd <- rs ^ rt
#
# :Syntax: SLT rd, rs, rt # Set less than.
# rd <- rs < rt ? 1 : 0;
# Comparison as signed integers.
# There's no SGT, which makes sense if you think about it.
#
# :Syntax: SLLV rd, rs, rt # Shift Left Logical Variable
# rd <- rs << rt[4:0]
# Note: Only five low-order bits of rt are used (other bits ignored).
#
# :Syntax: SRLV rd, rs, rt # Shift Right Logical Variable
# rd <- rs >> rt[4:0]
# Note: "Vacated" bit positions are zero.
# Note: Only five low-order bits of rt are used (other bits ignored).
#
# :Syntax: SRAV rd, rs, rt # Shift Right Arithmetic Variable
# rd <- {rs[31],rs[31],..., rs >> rt[4:0] }
# Note: Sign is extended: bit (rs[31]) placed in vacated positions.
# Note: Only five low-order bits of rt are used, the rest are ignored.
# :Example:
#
# Simplified assembler for the following line of C:
#
# x = a + b - ( c + d );
#
# Asm regs: x, $8; a, $9; b, $10; c, $11; d, $12
add $8, $9, $10 # a + b
add $13, $11, $12 # c + d
sub $8, $8, $13
####
# :Example:
#
# Use of register zero.
#
# Simplified assembler for the following line of C:
#
# x = -a;
# y = -1;
#
# Asm regs: x, $8; a, $9; y, $10
# Reminder: register $0 is always zero.
sub $8, $0, $9
nor $10, $0, $0
####
# :Example:
#
# Simplified assembler for the following line of C:
#
# x = ( ir >> off ) & mask;
#
# Asm regs: x, $8; ir, $9; off, $10; mask, $11.
srlv $8, $9, $10
and $8, $8, $11
####
# :Example:
#
# Simplified assembler for the following line of C:
#
# x = a + b > ( c & mask | d );
#
# Asm regs: x, $8; a, $9; b, $10; mask, $11; c, $12; d, $13
add $20, $9, $10 # a + b
and $21, $12, $11 # c & mask
or $21, $21, $13 # c & mask | d
slt $8, $21, $20 # >
################################################################################
## Other Basic Instructions
# :PH: Throughout Chapter 3.
# :Mv2: A complete list of instructions.
# :Def: Immediate
#
# A constant stored in the instruction itself.
#
# In MIPS most immediates are 16 bits, including the ones in this section.
## Assembler Metasyntactic Symbols for Immediates
#
# Metasyntactic symbols are used in syntax descriptions.
#
# immed: 16-bit immediate, for general use.
# sa: 5-bit immediate (shift amount), used in shift instructions.
## The Plain-Old Addi Instruction
#
# :Syntax: ADDI rt, rs, immed # Add Immediate
# rt <- rs + sign_extend(immed)
#
# Notes on the syntax above.
#
# The destination register is now called rt.
#
# Symbol immed refers to a 16 bit value which is stored in the instruction.
#
# For the ADDI instruction immed is interpreted as a signed integer.
## Some More Instructions
#
# The following are NOT MIPS32 instructions:
# SUBI, NORI
#
# :Syntax: ANDI rt, rs, immed # And Immediate
# rt <- rs & immed
#
# :Syntax: ORI rt, rs, immed
# rt <- rs | immed
#
# :Syntax: XORI rt, rs, immed
# rt <- rs ^ immed
#
# :Syntax: SLTI rt, rs, immed # Set Less Than Immediate
# rt <- rs < sign_extend(immed) ? 1 : 0;
# Comparison as signed integers, immed is sign-extended.
# There's no SGT, which makes sense if you think about it.
#
# :Syntax: SLL rd, rt, sa # Shift Left Logical
# rd <- rt << sa
#
# :Syntax: SRL rd, rt, sa # Shift Right Logical
# rd <- rt >> sa
# Note: "Vacated" bit positions are zero.
#
# :Syntax: SRA rd, rt, sa # Shift Right Arithmetic
# rd <- {rt[31],rt[31],..., rs >> sa }
# Note: Sign is extended: bit (rt[31]) placed in vacated positions.
#
# :Syntax: LUI rt, immed # Load Upper Immediate
# rt <- {immed,16'b0}
# :Example:
#
# Simple examples to illustrate what some instructions do.
#
# Assuming $9 = 23
addi $8, $9, 1
# $8 <- 24
# Assuming $9 = 23
addi $8, $9, -1
# $8 <- 22
# Assuming $9 = 23
addi $8, $9, 0x12345 # ASSEMBLER SHOULD REJECT THIS INSTRUCTION.
# No result because no such instruction exists.
# Assuming $9 = 0x12345678
andi $8, $9, 0xff # Called a "mask" operation.
# $8 <- 0x78
# Assuming $9 = 23
slti $8, $9, 20 # if ( $9 < 20 ) $8 = 1; else $8 = 0;
# $8 <- 0
slti $8, $9, 30
# $8 <- 1
# Assuming $9 = 1
sll $8, $9, 1
# $8 <- 2
sll $8, $9, 3
# $8 <- 8
# Assuming $9 = 16
srl $8, $9, 1
# $8 <- 8
srl $8, $9, 3
# $8 <- 2
sra $8, $9, 1
# $8 <- 8
sra $8, $9, 3
# $8 <- 2
# Assuming $9 = -1 = 0xffffffff
srl $8, $9, 1
# $8 <- 2147483647 = 0x7fffffff
srl $8, $9, 3
# $8 <- 536870911 = 0x1fffffff
sra $8, $9, 1
# $8 <- -1 = 0xffffffff
sra $8, $9, 3
# $8 <- -1 = 0xffffffff
# Assuming $9 = -7 = 0xfffffff9
srl $8, $9, 1
# $8 <- 2147483644 = 0x7ffffffc
srl $8, $9, 3
# $8 <- 536870911 = 0x1fffffff
sra $8, $9, 1
# $8 <- -4 = 0xfffffffc
lui $8, 0x1234
# $8 <- 0x12340000
## Uses for Immediates
#
# Register Initialization
# Constants
# :Example:
#
# Register initialization examples.
#
# Simplified assembler for the following line of C:
#
# a = 23;
# b = 105;
# c = 0x1234a678; // Sixteen bits not enough.
# d = 0;
#
# Asm regs: a, $8; b, $9; c, $10; d, $11
addi $8, $0, 23 # a = 23
addi $9, $0, 105 # b = 105
lui $10, 0x1234 # c = 0x12340000 (so far)
ori $10, $10, 0xa678 # c = 0x1234a678
add $11, $0, $0 # d = 0 (lots of ways to do this)
#
####
# :Example:
#
# Simplified assembler for the following line of C:
#
# rs = ( ir >> 21 ) & 0x1f;
#
# Asm regs: rs, $8; ir, $9.
srl $8, $9, 21
andi $8, $8, 0x1f
####
################################################################################
## Instruction Coding
# :PH: 3.4
# :Mv1: 4.2
## The Three MIPS Instruction Formats
#
# R Format: Typically used for three-register instructions.
# I Format: Typically used for instructions requiring immediates.
# J Format: Used for jump instructions (not covered yet).
#
# Every integer MIPS instruction is in one of these formats.
## R Format
# _________________________________________________________________
# | opcode | rs | rt | rd | sa | function |
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#
# Bits Field Name Unabbreviated Name Typical Use
#
# 31:26: opcode First part of opcode.
# 25:21: rs (Register Source) Source register one.
# 20:16: rt (Register Target) Source register two.
# 15:11: rd (Register Destination) Destination register.
# 10:6: sa (Shift Amount) Five-bit immediate.
# 5:0 function Second part of opcode.
#
## I Format
# _________________________________________________________________
# | opcode | rs | rt | immed |
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#
# Bits Field Name Unabbreviated Name Typical Use
#
# 31:26: opcode Entire opcode (for I and J).
# 25:21: rs (Register Source) Source register one.
# 20:16: rt (Register Target) Source register two.
# 15:0: immed (Immediate) Immediate value.
## J Format
# _________________________________________________________________
# | opcode | ii |
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#
# Bits Field Name Unabbreviated Name Typical Use
#
# 31:26: opcode Entire opcode (for I and J).
# 25:0: ii (Instruction Index) Part of jump target.
## Field Values
#
# Values for fields can be found in the following places:
# :PH: Page A-55 on (2nd edition) Listed by instruction.
# :Mv2: Listed by instruction. "Official" MIPS documentation.
#
# opcode, function
#
# Determined by the instruction.
# For R-format instructions opcode is limited to a few values: e.g., 0, 1.
# The function field takes on a larger range of values.
#
# Values for opcode and function can be found in the following places:
# :PH: Figure A.19 (page A-54) Compact, but perhaps intimidating at first.
# :PH: Page A-55 on (2nd edition) Listed by instruction.
# :Mv2: Listed by instruction. "Official" MIPS documentation.
#
#
# rs, rt, rd
#
# Usually register numbers represented using 5-bit unsigned integers.
# Occasionally used as part of opcode or to specify something other
# than a register.
#
#
# sa (Shift Amount)
#
# A 5-bit constant usually used by shift instructions.
#
#
# immed
#
# A 16-bit quantity.
#
#
# ii (Instruction Index)
#
# A 26-bit quantity used to form a jump target address.
## R Format Examples
# _________________________________________________________________
# | opcode | rs | rt | rd | sa | function |
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#
# :Syntax: ADD rd, rs, rt
add $2, $3, $4
#
# Based on the instruction above:
# rd -> 2, rs -> 3, rt -> 4
#
# Using something in :PH: Appendix A or looking up the instruction in :Mv2:
# opcode -> 0, function -> 0x20, sa -> 0
#
# Machine code for the instruction above:
# 0 3 4 2 0 0x20 (By field, each field in hexadecimal)
# = 000000 00011 00100 00010 00000 100000 (By field, binary)
# = 0000 0000 0110 0100 0001 0000 0010 0000 (Groups of four bits)
# = 0x00641020 (Hexadecimal)
#
#
# :Syntax: SLL rd, rt, sa # Shift Left Logical
sll $2, $3, 4
# Based on the instruction above:
# rd -> 2, rt -> 3, sa -> 4
#
# Using something in :PH: Appendix A or looking up the instruction in :Mv2:
# opcode -> 0, function -> 0, rs -> 0
#
# Machine code for the instruction above:
# 0 0 3 2 4 0 (By field, each field in hexadecimal)
# = 000000 00000 00011 00010 00100 000000 (By field, binary)
# = 0000 0000 0000 0011 0001 0001 0000 0000 (Groups of four bits)
# = 0x00031100 (Hexadecimal)
#
## I Format Examples
# _________________________________________________________________
# | opcode | rs | rt | immed |
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#
# :Syntax: ORI rt, rs, immed
ori $2, $3, 4
#
# Based on the instruction above:
# rt -> 2, rs -> 3, immed -> 4
#
# Using something in :PH: Appendix A or looking up the instruction in :Mv2:
# opcode -> 13
#
# Machine code for the instruction above:
# 0xd 3 2 4 (By field, each field in hexadecimal)
# = 001101 00011 00010 0000000000000100 (By field, binary)
# = 0011 0100 0110 0010 0000 0000 0000 0100 (Groups of four bits.)
# = 0x34620004 (Hexadecimal)
#
################################################################################
## Pseudo Instructions
# :PH: 3.9 (Briefly under assembler heading.)
# A.K.A. Synthetic Instructions
# :Def: Pseudo Instruction
#
# An assembly language instruction that does not (necessarily)
# correspond to a machine language instruction. The assembler will
# substitute one or two real machine instructions. Pseudo instructions
# are intended to make assembler code more readable and to support
# future ISA extensions. (Some pseudo instructions may become real
# instructions.)
#
# When these notes are viewed in HTML or with the class Emacs package,
# pseudo instructions (those recognized by the SPIM simulator) will be
# italicized. See examples.
## Some Pseudo Instructions
#
# This is not a complete list of pseudo instructions.
#
# (Note: the examples show both pseudo and real instructions. In
# actual assembly code you would use one or the other.)
#
# :Syntax: NOP # No Operation
#
# A special NOP instruction is not needed because many instructions
# will do nothing if register zero is used as the destination.
# Instruction sll is the "official" NOP because its coding is all
# zeros.
#
nop # Pseudo
sll $0, $0, 0 # Real.
#
# :Syntax: MOVE rd, rs # Move
# rd <- rs
#
move $1, $2 # Pseudo
addu $1, $0, $2 # Real
#
# :Syntax: LA rd, imm32 # Load Address
# :Syntax: LI rd, imm32 # Load Integer
# rd <- imm32
# Note: SPIM resolves la and li into the same instructions.
# (That is, they do the same thing. Use the one that better
# conveys intent to the human assembly code reader.)
#
#
li $2, 0x12345678 # Pseudo
lui $1, 0x1234 # Real (First of two.)
ori $2, $1, 0x5678 # Real (Second of two.)
li $2, 0x12 # Pseudo
ori $2, $0, 0x12 # Real (Assembler realizes lui not needed.)
################################################################################
## Types of Control-Transfer Instructions
# :PH: Material covered in a different order.
# :Mv1: 4.1.3 (Brief overview.)
# :Def: Control-Transfer Instruction (CTI)
#
# An instruction that changes PC, conditionally or unconditionally.
# Types: branch, jump, trap, etc.; all are CTIs.
# :Def: CTI Target Instruction (Branch Target, Jump Target, etc.)
#
# The instruction the CTI takes execution to if CTI taken.
# If a conditional branch is not taken, execution doesn't go to target.
## ISA Goals
#
# Efficiently implement common code sequences:
#
# if/then/else
# loops
# call/return
# switch/case
# function pointers
# operating system access
## Implementation Goals
#
# CTI performance can determine overall performance.
# Will see difficulties when we look at implementations.
## Types of Control Transfers in MIPS
#
# Branch (beq, etc.)
# Instruction specifies a condition and an address, the target.
# Used for loops, ifs, etc. Most commonly used CTI.
# If condition is true continue execution at target.
#
# Branch-and-Link (Not in MIPS-I)
# Instruction specifies a condition and an address, the target.
# Used for procedure calls.
# If condition is true save PC in $31 and continue execution at target.
#
# Direct Jump (j)
# Always taken, instruction specifies a fixed target.
# Used for part of if/else, loops, etc.
# Indirect Jump (jr)
# Always taken, but target address is in a register.
# Used for returns, switch, function pointers, etc.
#
# Jump-and-Link (jal, jalr)
# Always taken, instruction saves a return address in a register.
# Target can be in instruction (jal) or register (jalr).
# Used for procedure calls and returns and other purposes.
#
# Trap (Not covered in detail in this set.)
# Conditional, (similar to branch).
# If condition true continue at specified entry in OS-prepared trap table.
# Used for OS Code.
#
## Other ISAs' CTIs
#
# Similar types of instructions but names can vary.
## Conditions and Targets
#
# The methods used to specify conditions and targets vary by instruction.
# See descriptions in following sections
## Delayed CTI <- PAY ATTENTION TO THIS.
#
# All of the CTIs covered here are delayed (except traps).
#
# The instruction after an ordinary delayed CTI IS ALWAYS EXECUTED.
#
add $8, $0, $0
j FORJOY
addi $8, $8, 1
addi $8, $8, 2
FORJOY:
addi $8, $8, 4
addi $8, $8, 8
################################################################################
## A Simple Jump Instruction
# :PH: 3.5
# :Mv2:
# Simple jump (j) covered here, others (jr,jal,jalr) covered in a
# later selection.
# Assembler :Syntax: J target
# Coding :Syntax: J ii
# After next instruction go to { PC[31:28], ii, 2'b0 },
# where ii is bits 27:2 of target.
#
# In assembly language "target" is the line label for the target.
# In machine language "target", the ii field, is bits 27:2 of the
# target address.
# Bits 31:28 of the target address must match bits 31:28 of the jump
# instruction's address. (If not, use the jr instruction.)
# :Example:
#
# Code used to illustrate how target is determined.
FIRSTLINE: # Address of add: 0x400000
add $8, $0, $0
j FORJOY
addi $8, $8, 1
addi $8, $8, 2
FORJOY: # Address of addi: 0x400010
addi $8, $8, 4
addi $8, $8, 8
# In the code above:
#
# FORJOY is a line label, part of the assembly language.
# Suppose the assembler [really the linker] sets FORJOY = 0x400010
################################################################################
## A Branch Instruction
# :PH: 3.5
# :Mv2:
# One branch instruction covered here (bne), others (beq, bltz, etc.)
# covered in a later section.
# Assembler :Syntax: BNE rs, rt, target # Branch Not Equal
# Coding :Syntax: BNE rs, rt, offset
# if rs != rt, after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
#
# "target" is the line label to continue at.
# "offset" is the number of instructions to skip, starting at
# the instruction after the branch.
# :Example:
#
# Code to illustrate the offset.
FIRSTLINE:
add $9, $0, $0
addi $10, $9, 1
bne $9, $10, LINE
addi $8, $8, 1 # Offset computed from this instruction.
addi $8, $8, 2
LINE:
addi $8, $8, 4 # The branch target, offset = 2 instructions.
addi $8, $8, 8
# :Example:
#
# Use of a branch in a loop.
add $8, $0, $0 # $8 -> 0
addi $9, $0, 10 # $9 -> 10
add $10, $0, $0 # $10 -> 0 (i)
LOOP:
add $8, $8, $10 # $8 = $8 + i
addi $9, $9, -1
bne $9, $0, LOOP
addi $10, $10, 1 # i = i + 1
################################################################################
## More Branch Instructions
# :PH: 3.5
# :Mv2:
# Assembler :Syntax: BEQ rs, rt, target # Branch Equal
# Coding :Syntax: BEQ rs, rt, offset
# if rs == rt after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
#
# Assembler :Syntax: BGEZ rs, target # Branch >= Zero
# Coding :Syntax: BGEZ rs, offset
# if rs >= 0 after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
#
# Assembler :Syntax: BGTZ rs, target # Branch > Zero
# Coding :Syntax: BGTZ rs, offset
# if rs > 0 after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
#
# Assembler :Syntax: BLEZ rs, target # Branch <= Zero
# Coding :Syntax: BLEZ rs, offset
# if rs <= 0 after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
#
# Assembler :Syntax: BLTZ rs, target # Branch < Zero
# Coding :Syntax: BLTZ rs, offset
# if rs < 0 after next instruction
# go to PC + 4 + 4 * sign_extend(offset)
################################################################################
## More Jump Instructions
# :PH: 3.5
# :Mv2:
# Assembler :Syntax: JAL target # Jump and link.
# Coding :Syntax: JAL ii
# $31 <- PC + 8
# After next instruction go to { PC[31:28], ii, 2'b0 },
# where ii is bits 27:2 of target.
# Note: $31 a.k.a. $ra
#
# :Syntax: JR rs # Jump register.
# After next instruction go to address in rs.
#
# :Syntax: JALR rs, rt # Jump and link register.
# $rt <- PC + 8
# After next instruction go to address in rs
# Note: $31 a.k.a. $ra
#
# :Example:
#
# Use of j instruction.
# Jump to LINEX
j LINEX
nop
nop
LINEX:
addi $t2, $t2, 1
# :Example:
#
# Use of jal instruction.
LINEA: # LINEA = 0x12345678
# Instruction below is stored at (PC=) 0x12345678
# Set $ra -> PC + 8 = 0x12345680 and jump to LINEX
jal LINEX
nop
nop
LINEX:
addi $t2, $t2, 1
# :Example:
#
# Use of jr instruction.
# Load the address of a line into $to.
# Without using pseudo: la $t0, LINEX
lui $t0, hi(LINEX)
ori $t0, $t0, lo(LINEX)
# Jump to the line.
jr $t0
nop
nop
LINEX:
addi $t2, $t2, 1
# :Example:
#
# Use of jalr instruction.
LINEA: # LINEA = 0x12345678
la $t0, LINEX # Note: this resolves to two instructions.
# Instruction below is stored at (PC=) 0x12345680
# Set $ra -> PC + 8 = 0x12345688 and jump to LINEX
jalr $t0
nop
nop
LINEX:
addi $t2, $t2, 1
################################################################################
## Procedure Call Example
# :PH: 3.6
# :Example:
#
# Use of jal, jr, and jalr instructions to call and return from
# a procedure.
#
# The called procedure, times_three, puts 3 times $a0 in $v0.
#
# The procedure is called correctly three times, after which the code
# goes into an infinite loop.
#
# For clarity CTI delay slots are filled with nops. In many examples
# and in assignments they should be filled, where possible, with
# useful instructions.
.globl __start
__start:
addi $a0, $0, 12 # Set value to be tripled.
jal times_three # Jump and save PC + 8 in $ra ($31)
nop
addi $a0, $0, 3755 # Returns here after jal above.
jal times_three # Call times_three again.
nop
nop # Returns here after jal above.
la $s1, times_three # Store address of times_three in $s1
addi $a0, $0, 2002 # Value to triple.
jalr $s1 # Call times_three again, this time using jalr.
nop
addi $a0, $0, 22 #
jr $s1 # THE WRONG WAY TO CALL A PROCEDURE!!
nop
addi $a0, $0, 0 # Never reached.
times_three:
sll $v0, $a0, 1 # Start of times_three.
add $v0, $v0, $a0
jr $ra # Jump using return address.
nop
################################################################################
## Typical CTI Uses
# :PH: 3.5
# Branches (bne, beq, bltz, etc.)
# if/else
# Loops
#
# Regular Jump (j)
# if/else, loops (along with branches)
#
# Jump and Link: (jal, jalr)
# Procedure calls.
#
# Jump Register
# Procedure returns.
# switch statements.
## CTIs for if/else Statement
#
# - Use branch and jump.
# - Distances small.
# - Very frequent.
# :Example:
# Typical if/else statement.
#
# if ( a + b > c )
## -- Condition --
# {
# d = d >> 1; e++;
## -- If Part --------------
# }
# else
# {
# d = d << 1; e--;
## -- Else Part ----------
# }
#
# i++;
#
# Reg Usage: a, $8; b, $9; c, $10; d, $11; e, $12; i, $13
## Condition
#
# Compute condition.
#
add $16, $8, $9 # $16 = a + b
slt $17, $10, $16 # $17 = c < a + b
#
# Branch based on condition.
#
beq $17, $0, ELSEPART
nop
## If Part
#
sra $11, $11, 1 # d = d >> 1
j LINEX
addi $12, $12, 1 # e++;
## Else Part
#
ELSEPART:
sll $11, $11, 1 # d = d << 1
addi $12, $12, -1 # e--
# Done with the if/else
LINEX:
addi $13, $13, 1 # i++
## CTIs for Loop
#
# - Branch and jump.
# - Distances small to medium
# - Frequently encountered.
# :Example:
#
# Typical for loop.
#
# for ( i = a - 5; i < b + c; i = i + d ) x = x ^ ( x >> 1 );
## Initialization Test Increment Body
#
# Reg Usage: a, $8; b, $9; c, $10; d, $11; x, $12; i, $13
## Initialization
#
addi $13, $8, -5 # i = a - 5
j TEST
nop
LOOP:
## Body
#
sra $16, $12, 1 # $16 = x >> 1
xor $12, $12, $16 # x = x ^ $16
## Increment
#
add $13, $13, $11 # i = i + d
## Test
TEST:
add $16, $9, $10 # $16 = b + c Note: Can be moved out of loop.
slt $17, $13, $16 # i < $16
bne $17, $0, LOOP
nop
## CTIs for Switch
#
# - Direct and Indirect Jump.
# - Distances small to medium.
# - Occasionally encountered.
# :Example:
#
# Switch statement
#
# Indirect jump, jr used to jump to correct case.
#
# If cases are dense (consecutive or almost consecutive) compiler will
# create a dispatch table of case statement addresses.
#
# switch ( t1 ) {
# case 1: t0++; break;
# case 2: t0--; break;
# case 3: t0=>1; break;
# }
# s2 = t0 & s3;
.data
## Dispatch table, holding address of case statements.
DTABLE:
.word CASE0
.word CASE1
.word CASE2
.word CASE3
.text
la $t5, DTABLE
sll $t6, $t1, 2
add $t6, $t6, $t5 # Compute dispatch table address.
lw $t7, 0($t6) # Load address of case statement.
jr $t7 # Use jr to jump to case statement.
nop
CASE1:
j ENDCASE
addi $t0, $t0, 1
CASE2:
j ENDCASE
addi $t0, $t0, -1
CASE3:
j ENDCASE
srl $t0, $t0, 1
ENDCASE:
and $s2, $t0, $s3
################################################################################
## Load Byte (Unsigned)
# :Syntax: LBU rt, offset(rs) # Load Byte Unsigned
# rt <- { 24'b0, Mem[ rs + offset ] }
# Note: rs and rt are registers.
# Offset is a 16-bit immediate.
#
# :Example:
#
# Simple uses of lbu.
# Initially: $a2 -> 0x1000
# At Mem[ 0x1004 ] = 0x12
#
lbu $a0, 4($a2)
#
# Effective address is 4 + 0x1000 = 0x1004.
# $a0 loaded with 0x12.
addi $a2, $a2, 4 # $a2 -> 0x1004
lbu $a0, 0($a2)
#
# Effective address is 0 + 0x1004 = 0x1004 (same as above.)
# $a0 loaded with 0x12 (again)
####
# :Example:
#
# Procedure to determine the length of a C-style string. Includes
# code to call the procedure.
.data
str:
.asciiz "I Love NO"
msg:
.asciiz "The length of string \n \"%/a1/s\"\nis %/v1/d.\n"
.text
.globl __start
__start:
la $a0, str # Load address of string.
jal strlen # Call strlen procedure.
nop
addi $a1, $a0, 0 # Move address of string to $a1
addi $v1, $v0, 0 # Move length of string to $v1
addi $v0, $0, 11 # System call code for message.
la $a0, msg # Address of message.
syscall
addi $v0, $0, 10 # System call code for exit.
syscall
strlen:
## Register Usage
#
# $a0: Address of first character of string.
# $v0: Return value, the length of the string.
#
# $t0: Character being examined.
# $t1: Address of current character being examined.
#
addi $t1, $a0, 0
LOOP:
lbu $t0, 0($t1)
addi $t1, $t1, 1
bne $t0, $0, LOOP
nop
addi $t1, $t1, -1
jr $ra
sub $v0, $t1, $a0
####
################################################################################
## Store Byte
# :Syntax: SB rt, offset(rs) # Store Byte
# Mem[ rs + offset ] = rt[7:0]
# :Example:
#
# Simple uses of sb.
# Initially: $a2 -> 0x1004
# At Mem[ 0x1004 ] = 0
#
addi $t0, $0, 0x14 # t0 -> 0x14
sb $t0, 0($a2)
#
# Effective address is 0 + 0x1004 = 0x1004
# 0x14 written to Mem[ 0x1004 ]
addi $t0, $0, 0x1234 # t0 -> 0x1234
sb $t0, 0($a2)
#
# Effective address is 0 + 0x1004 = 0x1004
# 0x34 written to Mem[ 0x1004 ]
# Note that only bits 7:0 of $t0 written to memory.
####
# :Example:
#
# Program to convert a C-style string to upper case.
.data
str:
.asciiz "I Love NO"
before:
.asciiz "Before: %/s1/s\n"
after:
.asciiz "After: %/s1/s\n"
.text
.globl __start
__start:
la $s1, str
la $a0, before
addi $v0, $0, 11
syscall
jal upper
add $a0, $s1, $0
la $a0, after
addi $v0, $0, 11
syscall
li $v0, 10
syscall
upper:
## Register Usage
#
# $a0: (Call) Address of string to convert.
#
# $a0: Address of character being examined.
# $t1: Character being examined.
# $t2: Comparison result.
LOOP:
lbu $t1, 0($a0)
addi $a0, $a0, 1
beq $t1, $0, DONE
slti $t2, $t1, 97 # < 'a'
bne $t2, $0 LOOP
slti $t2, $t1, 123 # 'z' + 1
beq $t2, $0, LOOP
addi $t1, $t1, -32
j LOOP
sb $t1,-1($a0)
DONE:
jr $ra
nop
####
################################################################################
## Load Byte
# :Syntax: LB rt, offset(rs) # Load Byte
# rt <- sign_extend( Mem[ rs + offset ] );
# Note: rs and rt are registers.
# Offset is a 16-bit immediate.
# :Example:
#
#
# Initially: $a2 -> 0x1000
# At Mem[ 0x1000 ] = 0x12
# At Mem[ 0x1001 ] = 0x7f
# At Mem[ 0x1002 ] = 0x80
# At Mem[ 0x1003 ] = 0xff
#
lb $t0, 0($a2) # $t0 -> 0x12 18
lb $t1, 1($a2) # $t1 -> 0x7f 127
lb $t2, 2($a2) # $t2 -> 0xffffff80 (-128)
lb $t3, 3($a2) # $t3 -> 0xffffffff (-1)
####
## Usage
#
# lbu: Characters, unsigned integers.
# lb: Signed integers.
################################################################################
## Load Word, Store Word
## Note
#
# Each memory location holds 8 bits.
# Register size: 32 bits.
#
# To load a register use lw (load word).
# Loads for consecutive bytes into a register.
# :Syntax: LW rt, offset(rs)
# rt <- { Mem[ rs + offset + 0 ], Mem[ rs + offset + 1 ],
# Mem[ rs + offset + 2 ], Mem[ rs + offset + 3 ] }
# Load register rt with four bytes of memory starting at address
# rs + offset.
# Address rs + offset must be a multiple of 4.
# :Example:
#
# Assume: $a2 -> 0x1004
# At Mem[ 0x1004 ] = 0x00003755
# More precisely: (Big Endian)
# Mem[ 0x1004 ] = 0x00
# Mem[ 0x1005 ] = 0x00
# Mem[ 0x1006 ] = 0x37
# Mem[ 0x1007 ] = 0x55
#
lw $a0, 0($a2)
# 0x3755 loaded into $a0
lw $a0, 2($a2) # Error
# Effective address = 0x1006, not a multiple of 4
addi $a2, $a2, -2
lw $a0, 2($a2) # No problem
# Effective address = 0x1004, is a multiple of 4
# :Example:
#
.data
my_word:
.word 123
.word 456
.text
la $t0, my_word
lw $t1, 0($t0) # t1 <- 123
lw $t2, 4($t0) # t2 <- 456
addi $t0, $t0, 4
lw $t3, 0($t0) # t3 <- 456 (Another way to load 456)
addi $t0, $t0, 4
lw $t4, -4($t0) # t4 <- 456 (And another way to load 456)
# Error, instruction will never finish because address not a multiple of 4.
lw $t9, 1($t0)
####
# :Syntax: SW rt, offset(rs)
# Mem[ rs + offset ] = rt[31:24]
# Mem[ rs + offset + 1 ] = rt[23:16]
# Mem[ rs + offset + 2 ] = rt[15:8]
# Mem[ rs + offset + 3 ] = rt[7:0]
# Write memory starting at address offset + rs with contents of rt.
# Effective address, rs + offset, must be a multiple of 4.
# :Example:
#
# Assume: $a2 -> 0x1004
# At Mem[ 0x1004 ] = 0x00003755
# More precisely: (Big Endian)
# Mem[ 0x1004 ] = 0x00
# Mem[ 0x1005 ] = 0x00
# Mem[ 0x1006 ] = 0x00
# Mem[ 0x1007 ] = 0x00
#
lui $a0, 0x1234
ori $a0, $a0, 0x5678 # $a0 -> 0x12345678
sw $a0, 0($a2)
# Mem[ 0x1004 ] = 0x12
# Mem[ 0x1005 ] = 0x34
# Mem[ 0x1006 ] = 0x56
# Mem[ 0x1007 ] = 0x78
lbu $t0, 0($a2) # $t0 -> 12
lbu $t1, 1($a2) # $t1 -> 34
lbu $t2, 2($a2) # $t2 -> 56
lbu $t3, 3($a2) # $t3 -> 78
lw $a0, 2($a2) # Error
# Effective address = 0x1006, not a multiple of 4
addi $a2, $a2, -2
lw $a0, 2($a2) # No problem
# Effective address = 0x1004, is a multiple of 4
####
################################################################################
## Load and Store Half
# :Syntax: LH rt, offset(rs) # Load Half
# rt <- sign_extend( { Mem[ rs + offset ], Mem[ rs + offset + 1] } )
# Load register rt with two bytes of memory starting at address
# rs + offset.
# Address rs + offset must be a multiple of 2.
#
# :Syntax: LHU rt, offset(rs) # Load Half Unsigned
# rt <- { 16'b0, Mem[ rs + offset ], Mem[ rs + offset + 1] }
# Load register rt with two bytes of memory starting at address
# rs + offset.
# Address rs + offset must be a multiple of 2.
#
# :Syntax: SH rt, offset(rs) # Store Half
# Mem[ rs + offset + 0 ] = rt[15:8]
# Mem[ rs + offset + 1 ] = rt[7:0]
# Effective address, rs + offset, must be a multiple of 2.
################################################################################
## Array Access Examples
# Given the base address of an array (address of first element, say &a[0]),
# need to compute the address of an element at index i, (say, &a[i]).
# To do this compute:
#
# English: Address of i'th element of a = address of a + i * size of element.
# :Example:
#
# Array accesses. In most examples i is the index (the number of the
# element to load). Note that i must be multiplied by the size of the
# element before adding it on to the address of the first element.
#
# Registers: a, s1; b, s5; s, s2; us, s3; c, s4; i, t0; x, t1
# char *c; ... # $s4 = c; $t0 = i
# x = c[i];
#
add $t5, $s4, $t0 # $t5 -> &c[i] (Address of c[i].)
lb $t1, 0($t5) # x = c[i]; $t1 -> c[i]
# char *c; ... # $s4 = c; $t0 = i
# x = c[i+1] + c[i+2];
#
add $t5, $s4, $t0 # $t5 -> &c[i] (Address of c[i].)
lb $t6, 1($t5) # $t6 -> c[i+1]
lb $t7, 2($t5) # $t7 -> c[i+2]
add $t1, $t6, $t7 # x = c[i+1] + c[i+2]
# int *a; ... # $s1 = a; $t0 = i
# x = a[i];
sll $t5, $t0, 2 # $t5 -> i * 4; Each element is four characters.
add $t5, $s1, $t5 # $t5 -> &a[i] (Address of a[i].)
lw $t1, 0($t5) # x = a[i]; $t1 -> a[i]
# int *a; ... # $s1 = a; $t0 = i
# x = a[i+1] + a[i+2];
#
sll $t5, $t0, 2 # $t5 -> i * 4; Each element is four characters.
add $t5, $s1, $t5 # $t5 -> &a[i] (Address of a[i].)
lw $t6, 4($t5) # $t6 -> a[i+1]
lw $t7, 8($t5) # $t7 -> a[i+2]
add $t1, $t6, $t7 # x = a[i+1] + a[i+2]
# int x, j, *a, *b; # $t1 = x; $t2 = j; $s1 = a; $s2 = b
# j = 3;
# b = a + j;
# x = *b; // x = a[3];
addi $t2, $0, 3 # j = 3;
sll $t5, $t2, 2 # $t5 -> j * 4
add $s5, $s1, $t5 # b = a + j;
lw $t1, 0($s5) # x = *b = a[j]
# short *s; ... # $s2 = s; $t0 = i
# x = s[i];
#
sll $t5, $t0, 1 # $t5 -> i * 2; Each element is two characters.
add $t5, $s2, $t5 # $t5 -> &s[i] (Address of s[i].)
lh $t1, 0($t5) # x = s[i]; $t1 -> s[i]
# $s3 = us; $t0 = i
# unsigned short *us;
# x = us[i];
#
sll $t5, $t0, 1 # $t5 -> i * 2; Each element is two characters.
add $t5, $s3, $t5 # $t5 -> &us[i] (Address of us[i].)
lhu $t1, 0($t5) # x = us[i]; $t1 -> us[i]
# struct str { int i; char c; int j;} ;
# str a;
# ..
# x = a.i + a.c; // $t1 -> x; $a1 -> &a (address of a)
lw $t1, 0($a1) # $t1-> a.i;
lb $t2, 4($a1) # $t2-> a.c;
add $t1, $t1, $t2
####
################################################################################
## Miscellaneous Integer Arithmetic Instructions
# :PH: Throughout Chapter 3.
# :Mv2: A complete list of instructions.
## Miscellaneous Integer Arithmetic Instructions
#
# "Unsigned" Instructions: The name is misleading.
# Multiplication
# Division
## "Unsigned" Instructions
#
# Instructions SUBU, ADDU and ADDIU are NOT UNSIGNED.
# The "U" means ignore overflow for these instructions.
#
# Instructions SLTU and SLTIU are unsigned.
#
# :Syntax: ADDU rd, rs, rt # Add, overflow ignored.
# rd <- rs + rt
# Note: Identical to ADD except an overflow is ignored.
#
# :Syntax: SUBU rd, rs, rt # Sub, overflow ignored.
# rd <- rs - rt
# Note: Identical to SUB except an overflow is ignored.
#
# :Syntax: ADDIU rt, rs, immed # Add Immediate, overflow ignored.
# rt <- rs + sign_extend(immed)
# Note: Identical to ADDI except an overflow is ignored.
# Yes, the immediate IS sign extended.
#
# :Syntax: SLTU rd, rs, rt # Set Less Than Unsigned
# rd <- rs < rt ? 1 : 0;
# Comparison as unsigned integers.
#
# :Syntax: SLTIU rt, rs, immed # Set Less Than Immediate Unsigned
# rt <- rs < immed ? 1 : 0;
# Comparison is for unsigned integers, immed IS sign-extended.
## Integer Overflow
#
# Because C expects integer overflow to be ignored, C compilers emit
# ADDU, SUBU, ADDIU, SUBIU for integer arithmetic.
## Difference between add and addu, etc.
#
# With add, sub, and addi overflow causes an error.
# With addu, subu, addui overflow is ignored.
# :Example:
#
# Note: In C integer overflow is silently ignored.
# C Code:
#
# int x, a, b;
#
# a = 0x7fffffff; // Largest 32-bit signed integer.
# b = 1;
# x = a + b;
#
# Asm regs: a, $8; b, $9; x, $10
lui $8, 0x7fff;
ori $8, $8, 0xffff;
addi $9, $0, 1
# $8 = 0x7fffffff = 2147483647
# $9 = 1
addu $10, $8, $9
# $10 = 0x80000000 = -2147483648 (Addition overflowed.)
# :Example:
#
# Language in a C-like language in which integer overflow is an error.
#
# int x, a, b;
#
# a = 0x7fffffff; // Largest 32-bit signed integer.
# b = 1;
# x = 3755;
# x = a + b;
#
# Asm regs: a, $8; b, $9; x, $10
lui $8, 0x7fff;
ori $8, $8, 0xffff;
addi $9, $0, 1
addi $10, $0, 3755
# $8 = 0x7fffffff = 2147483647
# $9 = 1
# $10 = 3755;
add $10, $8, $9
# Instruction above causes an error (exception, $10 not changed.)
# $10 = 3755
# :Example:
#
# Sign extension of immediate.
# addi, addui, and ori
# Remember that immediate is 16 bits.
addi $8, $0, 1
# $8 = 1
addi $8, $0, -1
# $8 = 0xffffffff = -1 (-1 sign extended)
addiu $8, $0, 1
# $8 = 1
addiu $8, $0, -1
# $8 = 0xffffffff = -1 (Yes, -1 sign extended.)
ori $8, $0, 1
# $8 = 1;
ori $8, $0, -1
# $8 = 0xffff (-1 not sign extended.)
## Multiplication and Division
#
# Integer multiplication instructions write product to special
# hi and lo registers: lo gets bits 31:0, hi gets bits 63:32.
#
# :Syntax: MULT rs, rt
# {hi,lo} <- rs * rt
# Operands signed.
# Overflow does not raise an exception.
#
# :Syntax: MULTU rs, rt
# {hi,lo} <- rs * rt
# Operands unsigned.
# Overflow does not raise an exception.
#
# :Syntax: DIV rs, rt
# lo <- rs / rt; hi <- rs % rt
# Operands signed.
# Never raises an exception, even for division by zero.
#
# :Syntax: DIVU rs, rt
# lo <- rs / rt; hi <- rs % rt
# Operands unsigned
# Never raises an exception, even for division by zero.
#
# :Syntax: MTLO rs # Move to lo register.
# lo <- rs
#
# :Syntax: MTHI rs # Move to hi register.
# hi <- rs
#
# :Syntax: MFLO rd # Move from lo register.
# rd <- lo
#
# :Syntax: MFHI rd # Move from hi register.
# rd <- hi
# :Example:
#
# Simple multiplication and division examples.
#
# integer x, y, z, a, b;
# ...
# x = a * b;
# y = a / b;
# z = a % b;
#
# Asm regs: x, $8; y, $9; z, $10; a, $11; b, $12
mult $11, $12
mflo $8
div $11, $12
mflo $9
mfhi $10
#
####
## Multiply Pseudo Instruction
#
# :Syntax: MUL rd, rs, rt
# rd <- rs * rt;
# Note: SPIM treats this as a pseudo instruction, but it is
# a real instruction in MIPS32.
#
mul $2, $3, $4 # Pseudo
mult $3, $4 # Real (First of two.)
mflo $2 # Real (Second of two.)
################################################################################
## Histogram Program
## Histogram Program.
#
# Computes how many times each letter appears in a string.
#
# For example, for the following string:
#
# Do you know what it means to miss New Orleans
# And miss it each night and day
# I know I'm not wrong... this feeling's gettin' stronger
# The longer, I stay away
# Miss them moss covered vines...the tall sugar pines
# Where mockin' birds used to sing
# And I'd like to see that lazy Mississippi...hurryin' into spring
#
# The moonlight on the bayou.......a creole tune.... that fills the air
# I dream... about magnolias in bloom......and I'm wishin I was there
#
# Do you know what it means to miss new orleans
# When that's where you left your heart
# And there's one thing more...i miss the one I care for
# More than I miss New Orleans
#
# -- Louis Armstrong
#
# The program would generate the counts shown below:
#
# Letter A count: 35 ( 5.66) *****************
# Letter B count: 4 ( 0.65) **
# Letter C count: 5 ( 0.81) **
# Letter D count: 13 ( 2.10) ******
# Letter E count: 48 ( 7.77) ************************
# Letter F count: 4 ( 0.65) **
# Letter G count: 13 ( 2.10) ******
# Letter H count: 26 ( 4.21) *************
# Letter I count: 45 ( 7.28) **********************
# Letter K count: 5 ( 0.81) **
# Letter L count: 17 ( 2.75) ********
# Letter M count: 21 ( 3.40) **********
# Letter N count: 42 ( 6.80) *********************
# Letter O count: 40 ( 6.47) ********************
# Letter P count: 4 ( 0.65) **
# Letter R count: 27 ( 4.37) *************
# Letter S count: 42 ( 6.80) *********************
# Letter T count: 41 ( 6.63) ********************
# Letter U count: 11 ( 1.78) *****
# Letter V count: 2 ( 0.32) *
# Letter W count: 14 ( 2.27) *******
# Letter X count: 1 ( 0.16)
# Letter Y count: 10 ( 1.62) *****
# Letter Z count: 1 ( 0.16)
#
#
# Here is such a histogram procedure written in C:
#
#
# Unoptimized:
#
# void
# histo(char *str, int *table)
# {
# upper(str);
#
# for (; *str; str++)
# {
# char c = *str;
# int index = c - 'A';
#
# if ( index >= 0 && index < 26 )
# table[ index ]++;
# }
# }
#
#
# Optimized:
#
# void
# histo2(unsigned char *str, int *table)
# {
# upper(str);
#
# for (; *str; str++)
# {
# unsigned int index = *str - 'A';
#
# if ( index < 26 )
# table[ index ]++;
#
# }
# }
#
#
# The assembler version of the procedure is to be called with register
# $a0 set to the address of the first character of the string and $a1
# set to the address of the first element of the histogram table.
#
# The code below is just the histogram procedure. The program
# used to generate the table above can be found at:
# https://www.ece.lsu.edu/ee4720/2019/histo.s.html
histo:
## Register Usage
#
# Call: $a0 String to analyze.
# $a1 Address of table. Each element is an integer.
addi $s0, $ra, 0 # Make a copy of the return address.
jal upper # Convert to upper case.
addi $t0, $a0, 0 # Make a copy of string start address.
addi $ra, $s0, 0 # Restore return address.
LOOP:
lbu $t1, 0($t0) # Load a character.
addi $t0, $t0, 1 # Increment address.
beq $t1, $0, DONE # Check for null termination.
addi $t1, $t1, -65 # Set $t1 to table index. ( A->0, B->1, etc.)
sltiu $t2, $t1, 26 # If $t1 is >= 26 then it's not a letter.
beq $t2, $0, LOOP # Note that comparison above is unsigned.
sll $t1, $t1, 2 # Scale index based on table element size (4).
add $t3, $a1, $t1 # Add index on to address of first element
lw $t4, 0($t3) # Load histogram entry.
addi $t4, $t4, 1
j LOOP
sw $t4, 0($t3) # Store the incremented value.
DONE:
jr $ra
nop
####
# Assembly language generated by gcc for unoptimized version:
#
# Comment text in square brackets describe activities not yet covered.
#
$Lscope0:
.align 2
.globl histo
.text
$LM6:
# hist.c:11: {
.ent histo
histo:
.frame $sp,32,$ra # vars= 0, regs= 3/0, args= 16, extra= 0
.mask 0x80030000,-8
.fmask 0x00000000,0
$LBB2:
subu $sp,$sp,32 # [Increment stack pointer.]
sw $s0,16($sp) # [Save register s0, restored before return.]
move $s0,$a0
sw $s1,20($sp) # [Save register s1, restored before return.]
sw $ra,24($sp) # [Save register ra, restored before return.]
$LM7:
# hist.c:12: upper(str);
.set noreorder
.set nomacro
jal upper
move $s1,$a1 # Make a copy of $a1.
.set macro
.set reorder
$LM8:
# hist.c:14: for (; *str; str++)
lb $v0,0($s0) # Load first character of string, sign extended.
lbu $a0,0($s0) # Load first character of string again.
.set noreorder
.set nomacro
beq $v0,$zero,$L26
sll $a3,$a0,24 # First of two instructions to sign-extend
.set macro # loaded character. (I don't know why
.set reorder # compiler didn't just use $v0.)
$LBB3:
$LM9:
# hist.c:16: char c = *str;
$L27:
sra $v1,$a3,24 # Finish sign extension.
$LM10:
# hist.c:17: int index = c - 'A';
addu $a1,$v1,-65
sll $a2,$a1,2
$LM11:
# hist.c:19: if ( index >= 0 && index <= 26 )
sltu $a0,$a1,27 # Note: unsigned comparison, so no need
# to check for index >= 0.
$LM12:
# hist.c:16: char c = *str;
addu $s0,$s0,1 # This is really : str++
$LM13:
# hist.c:19: if ( index >= 0 && index <= 26 )
.set noreorder
.set nomacro
beq $a0,$zero,$L11
addu $v1,$a2,$s1 # $v1 -> &table[ index ];
.set macro
.set reorder
$LM14:
# hist.c:20: table[ index ]++;
lw $t1,0($v1)
#nop
addu $t0,$t1,1
sw $t0,0($v1)
$LBE3:
$LM15:
# hist.c:14: for (; *str; str++)
$L11:
lb $t2,0($s0) # Load character of string, sign extended.
lbu $a0,0($s0) # Load character of string again.
.set noreorder
.set nomacro
bne $t2,$zero,$L27
sll $a3,$a0,24 # First of two instructions to sign-extend
.set macro # loaded character. (I don't know why
.set reorder # compiler didn't just use $t2.)
$L26:
lw $ra,24($sp) # [Restore saved $ra]
lw $s1,20($sp) # [Restore saved $s1]
lw $s0,16($sp) # [Restore saved $s0]
#nop
.set noreorder
.set nomacro
j $ra
addu $sp,$sp,32 # [Restore stack pointer.]
.set macro
.set reorder
$LBE2:
.end histo