Assembly Language Programming
Assembly Language Programming
1
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
2
Assembly Language
Assembly language is a low level programming
language that provides direct access to registers and
memory.
Assembly language is dependent on the
microprocessor family.
An assembly language program consists of a sequence
of instructions.
There is a direct correspondence between an assembly
language instruction and a machine language
instruction (raw 1s and 0s).
3
ANNA Architecture
In this class, we will be using the ANNA Architecture. It has these
characteristics:
16 bit data words (can represent two's complement integers or
addresses)
16 bit instructions
(216) 64K words of word-addressable main memory
16 different instructions
8 general purpose 16-bit registers (numbered from r0 to r7)
16 bit ALU
16 bit program counter (PC)
Register r0 always has the value 0
No hardware support / instructions for floating point values
4
Assembly Language Programming Process
Assembly Language Programming Process (in ANNA):
5
Registers and Variables
Registers are memory locations inside the CPU.
Registers can be: r0, r1, r2, r3, r4, r5, r6, r7.
Remember that r0 always has the value 0, even if you to try to
write to it.
Variables within a program can either be stored in memory or
registers.
In addition, registers need to store temporary values for longer
expressions such as "a = 3 * b + c / d;"
Initially, in this unit we are going to assume that all variables
are stored in registers. Later, we will discuss how to handle
variables stored in memory.
6
Program Counter
The program counter (PC) is a special register that
keeps track of the address of which instruction is
currently executing.
The machine program is stored in memory starting at
address 0.
The PC cannot be directly accessed by assembly
instructions.
The PC is incremented each cycle.
Some instructions (branches and jumps) can update the
PC. This is needed to implement control decisions (if,
switch), loops, and function calls.
7
ANNA Simulator
The simulator performs these steps upon startup:
1. Each location in memory is filled with zero.
2. All of the registers are set to zero.
3. The program counter (PC) is set to zero.
4. The program is loaded into memory from a file.
8
ANNA Simulator
The simulator is then controlled by the user. The
simplest command is to run the program. In this mode,
the simulator:
9
Assembly Instructions
All instructions have an opcode that describes the operation.
Each of the 16 instructions in ANNA have a unique opcode.
Most instructions have up to three operands or fields that
specify…
where to get data that is used by the instruction (registers,
memory, input, the instruction itself).
where to put data that is produced by the instruction (registers,
memory, output).
The opcodes and the fields are delimited by spaces.
Each instruction appears on its own line (no semicolons to
delimit instructions).
10
Comments and Assembler Directives
Comments are specified by using '#'.
Anything after the '#' sign on that line is treated as a
comment.
Comments can either be placed on the same line after an
instruction or as a standalone line.
In addition to the 16 instructions, the ANNA assembler
supports two assembler directives (.halt and
.fill).
Assembler directives are commands to the assembler.
11
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
12
add
Your first ANNA assembly instruction, add, has the following format:
add Rd Rs1 Rs2 R(Rd) R(Rs1) + R(Rs2)
• add is the opcode.
• Rd refers to the destination register: the result of the add is stored in the
specified register.
• Rs1 and Rs2 refer to the source registers: they contain the numbers of the
registers that contain the numbers to be added together.
Examples:
add r3 r2 r7 R(r3) = R(r2) + R(r7)
add r5 r5 r5 R(r5) = R(r5) + R(r5)
13
Additional Notes about add
This instruction only accesses registers, it does not
access memory.
14
Other Arithmetic and Logic Instructions
Other arithmetic and logic instructions:
sub Rd Rs1 Rs2 subtract R(Rd) R(Rs1) –
R(Rs2)
and Rd Rs1 Rs2 bitwise and R(Rd) R(Rs1) &
R(Rs2)
or Rd Rs1 Rs2 bitwise or R(Rd) R(Rs1) | R(Rs2)
not Rd Rs1 bitwise notR(Rd) ~R(Rs1)
15
Fetch and Execute Loop
Fetch and execute loop for arithmetic and logic
instructions:
1. Fetch the instruction at the offset in memory
indicated by the PC.
2. Set PC PC + 1.
3. Get the value of the source register(s).
4. Perform the specified operation.
5. Place the result into the destination register.
16
Class Problem
What is the state of the register file after this instruction
sequence?
Before After
and r1 r2 r3 r1 0xbead
or r2 r4 r3 r2 0xface
add r6 r2 r7 r3 0xaced
sub r3 r3 r5
r4 0x42a5
r5 0x0005
r6 0x4567
r7 0xfffa
17
Conversion to Machine Language
Remember that instructions in ANNA are 16 bits.
18
Conversion to Machine Language
The opcode identifies the Opcode Opcode
instruction and is in bits 15-12 for mnemonic bits
all instructions. add 0000
Sixteen instructions four bits of sub 0001
and 0010
opcode
or 0011
The opcode bits for the arithmetic
not 0100
and logic instructions are shown
in the table. Register Register
The register fields indicate the Number bits
register number used in that r0 000
r1 001
operand.
r2 010
The not instruction only uses two
r3 011
of the three fields: the Rs2 field is r4 100
ignored (can by any value). r5 101
r6 110
19 r7 111
Machine Language Examples
Example: What is the machine language representation
for these instructions?
1. and r4 r7 r2
20
Machine Language Examples
2. sub r3 r0 r1
3. add r5 r5 r5
21
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
22
in
The input instruction in gets a word from input:
in Rd
This instruction asks the user for a 16-bit number and
places it into register Rd.
The number specified by the user (of the simulator)
can be specified using a signed number (-32,768 to
32,767) or a 4 digit hex number.
23
out
The output instruction out displays the contents of a
register onto the screen.
out Rd
The instruction displays contents of Rd onto the screen
in both decimal and hexadecimal format.
24
Input / Output Instruction Notes
Both the in and out instruction are R-type
instructions (Rs1 and Rs2 fields are ignored).
Opcode bits for in: 1110
Opcode bits for out: 1111
Input / output instructions are extremely simplified in
ANNA (more on I/O later in the course).
25
Ending the Program
The out instruction can also be used to halt the
program: simply use r0 as the register.
The simulator will stop executing when an out r0
instruction is executed.
For readability purposes, the assembler directive
.halt can (and should) be used instead of out r0.
The directive .halt has no operands – it is simply
shorthand for an out r0 instruction.
26
Example Program
Write a program that adds three numbers from input
and displays the sum.
in r1
in r2
in r3
add r4 r1 r2
add r4 r4 r3
out r4
.halt
27
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
28
Immediates
Some instructions have immediates – a constant value
in an instruction.
This allows assembly instructions to work with
constant operands.
For example, consider the C++ instruction:
x = y + 3;
29
addi
The add immediate instruction addi has the following format:
addi Rd Rs1 Imm6 R(Rd) R(Rs1) + Imm6
This instruction adds the contents of register Rs1 with the 6-bit
immediate Imm6.
What should be the range of the immediate (Imm6)?
The immediate is a signed two's complement number that can range from -32
to 31.
Examples:
addi r3 r5 -12 R(r3) R(r5) + -12
addi r2 r2 1 R(r2) R(r2) + 1 (increments r2)
30
shf
The shift instruction has a similar format:
shf Rd Rs1 Imm6
This instruction shifts the contents of Rs1 and places the results in Rd.
The number of the bits and direction of the shift is determined by the
immediate:
If Imm6 is positive shift the contents of Rs1 left by Imm6 bits.
If Imm6 is negative shift the content of Rs1 logically right by abs(Imm6) bits.
Examples:
shf r3 r4 2 R(r3) R(r4) << 2 (shift left 2 bits)
shf r7 r6 -3 R(r7) R(r6) >> 3 (shift right 3 bits)
31
Larger Immediates
What if you want a larger immediate?
One solution is have an instruction that initializes a
register based on an immediate.
Example: ir r3 12345
Unfortunately, there is a problem. What is the
problem?
32
lli / lui
The load register immediate instructions lli and lui
are used in tandem to initialize registers.
33
lli / lui
The lli instruction is used to initialize the lower 8 bits (bits
7-0) of register Rd.
The lower 8 bits are copied verbatim from the immediate.
The upper 8 bits of register Rd are equal to bit 7 (sign bit) of the
immediate (sign extension).
The lui instruction is used to initialized the upper 8 bits (bits
15-8) of register Rd.
The 8 bits of the immediate are copied into the upper 8 bits of
register Rd.
The lower 8 bits of register Rd are unchanged.
15 8 7 0
Upper half Lower half
34
lli / lui
This results in the following consequences:
Only an lli instruction is needed to initialize a
register if it is 8 bits or less (-128 to 127).
Most immediates fall into the range.
When executing lli/lui as a pair, the lli
instruction must be executed before the lui
instruction.
Why?
35
Using lli / lui
In the ANNA assembler, there are three ways of specifying 8-bit
immediates for lui/lli:
signed 16 bit decimal number: The appropriate 8 bits are placed in
the immediate field.
8 bit hexadecimal number: The 8 bits (two hex digits) represented
by the hexadecimal number are placed in the immediate field.
labels: Will be discussed later.
36
Fetch and Execute Loop
Fetch and execute loop for immediate instructions:
15 I8-type
12(lli,
11 lui)
9 8 7 0
Opcode Rd Imm8
2. lui r3 -13
3. addi r4 r5 -1
39
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
40
Conditional Branches
Conditional branches and jumps allow the programmer
to jump to another portion of code.
In other words, they set the PC to something other than
PC+1.
Conditional branch instructions are based on a
condition: if (condition_test) go to target_address
Only jumps to target_address if condition_test is true.
Continue to PC+1 if false.
41
bez / bgz
There are two conditional branch instructions in ANNA:
bez Rd Imm8 branch if equal to zero
bgz Rd Imm8 branch if greater than zero
Rd is used in the condition test
bez: Branches if the word in Rd is equal to zero.
bgz: Branches if the word in Rd is strictly greater than zero.
Imm8 is used to compute the target address.
The target address is computed: PC + 1 + Imm8.
The immediate is an 8 bit signed number.
42
PC-relative addressing
PC-relative addressing: process of creating an
address by using the current value of the PC.
In essence, the offset is the number of instructions
away you want to jump.
Negative offset: jump backwards
Positive offset: jump forwards
Typical use for branches is for if-else statements and
loops: the target address is usually not that far away.
43
Converting to Machine Language
Branches are I8-type instructions:
bez opcode bits: 1010
bgz opcode bits: 1011
44
Fetch and Execute Loop
Fetch and execute loop for branch instructions:
45
Unconditional Branches
What if I need to use an unconditional branch?
46
Big Jumps
What is the max you can jump in either direction using
bez and bgz?
2^(8-1)
47
Offsets
When I add/remove instructions from the program, it’s a
pain to change all of the offsets.
48
Labels
Labels can optionally precede any instruction. Rules:
Only one label per instruction (must be on same line).
A label name can only be declared once.
A label is a string followed by a colon (colon is not part
of label).
The label can be referenced in the immediate field of
other instructions.
Cannot be used for I6-type instructions.
Must be preceded by ‘&’ sign.
The assembler replaces the label using the address of the
instruction marked by the label.
49
Labels for Branches
When a label is used as an immediate for a branch
instruction, the assembler will automatically determine
the proper offset.
Example:
51
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
52
Converting C++ into ANNA
In this section, we will be discussing examples on how
to convert if statements and loops written in C++ into
ANNA assembly language.
We will assume that int in C++ refers to a 16-bit
integer.
53
Comparing Two Numbers
How do we compare two numbers?
54
If Statements
Convert this code to ANNA assembly.
Assume x is in r3 and y is in r4.
int x, y;
if (x == y)
x++;
else
y++;
x = x – y;
55
If Statements
Repeat the previous example but change the if statement to…
if (x >= y) if ((x == y) && (x > 0))
56
Loops
Convert this code to ANNA assembly. Assume sum is in r1 and i is in r2.
sum = 0;
for (i = 0; i < 100; i++) {
sum = sum + i;
}
Similar to:
sum = 0
i=0
while(I < 100){
sum = sum + I;
i++;
}
57
Loops
Convert this code to ANNA assembly. Assume sum is in r1 and i is in r2.
sum = 0;
for (i = 0; i < 100; i++) {
sum = sum + i;
}
60
lw
The load word lw instruction obtains a word from
memory and places into a register:
lw Rd Rs1 Imm6 R(Rd) M[R(Rs1) + Imm6]
61
Memory Addresses
The effective address is computed by adding the
contents of Rs1 with the immediate.
Addresses in ANNA are unsigned. The value of
register Rs1 is treated as an unsigned number.
The immediate is signed and represents an offset from
the address.
If the resulting addition results in a negative address,
the ANNA simulator will wraparound to a larger
unsigned address.
62
sw
The store word sw instruction writes a word to memory:
63
Memory Instruction Notes
ANNA is a load/store architecture. Only lw and sw
instructions are allowed to access memory directly.
Both instructions are I6-type instructions:
lw opcode bits: 1000
sw opcode bits: 1001
64
Fetch and Execute Loop
Fetch and execute loop for memory instructions:
1. Fetch the instruction at the offset in memory
indicated by the PC.
2. Set PC PC + 1.
3. Compute the effective address.
4. (sw only): Get the value of the data register.
5. Access memory.
6. (lw only): Place the result into the destination
register.
65
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
66
Variables in Assembly Language
Variables are often stored in memory as there are not enough
registers to store all variables.
However, variables must be placed in registers before they
can be used in operations. One possible, yet very slow,
method:
1. Place the addresses of the desired variables into registers.
2. Load the operands into registers.
3. Perform the desired operation.
4. Store the result into memory.
If a variable is used frequently, it is better to keep in a
register for performance purposes. Register allocation is a
key responsibility carried out by the compiler.
67
Variables in Assembly Language Example
Translate c = a – b; into ANNA assembly.
Assume a is at address 0x1000, b is at address
0xac23, and c is at address 0x78ac.
68
.fill
The assembler directive .fill tells the assembler to fill
in the next word in memory with the entire 16 bit
immediate value:
.fill Imm16
Imm16 is a signed 16 bit immediate.
Immediate can be either a signed immediate or a four
digit hexadecimal number.
69
Initializing Variables
The .fill directive is used to initialize variables:
A label is used to identify the variable (often the same
name as the variable).
.fill is used to initialize the value of the variable.
Example: Translate the variable declaration
int count = 5; into ANNA assembly:
70
Using Labels for Addresses
Once labels are used to declare variables, they can be
used in lui and lli instructions.
The immediate corresponds to the address of the word
defined by the label.
Example (assume count is at address 0x5678):
lli r4 &count is identical to lli r4 0x78
lui r4 &count is identical to lui r4 0x56
Useful so programmers do not have to keep track of
the addresses of the variables they declare.
71
Memory Sections
For assembly programs that require memory beyond
registers, it is useful to divide the assembly program
into a code section and a data section.
Real programs, from a memory perspective, consists
of four sections:
Code: Machine code instructions
Data: Global variables / constants used by the program
Stack: Stores activation records (which store parameters
and local variables)
Heap: Memory dynamically allocated by the program
(using new)
72
Example
Write code that initializes x to 25, then executes y =
x + 2;
73
Class Problem
Write an assembly sequence to reflect for this code segment:
x = 5;
y = 52;
x = x + (y >> 2); // >> is right shift
74
Pointers
Pointers store addresses of other variables.
We have already seen registers hold addresses.
Example: Convert p = &x; into ANNA assembly. Assume
that x and p are declared using labels in the data section.
75
Pointer Dereference Example
Convert *p = 3; into ANNA assembly.
76
Dynamic Memory
Pointers are often used to point to dynamically-allocated
memory. This can be accomplished in ANNA assembly
language:
Memory is set aside for heap data.
A small chunk of this memory is used as a table (or logically
equivalent data structure) that keeps track of which memory
is used and which memory is available.
Underlying implementation for new and delete manipulate
this table.
Different algorithms / data structures can be used to managing
dynamic memory. These are discussed in CPSC 3400.
77
Arrays
Arrays are sequentially laid out in memory:
78
Declaring Arrays
Convert int list[5]; into ANNA assembly.
79
Referencing Arrays
Convert list[3] = 10; into ANNA assembly.
80
Base + Offset Addressing
The form of addressing used in the previous example
is called base + offset:
The register holds the base (start of the array)
The immediate holds the offset (index of the array)
This is effective for arrays with small constant indices.
81
Referencing Arrays
Convert y = list[x]; into ANNA assembly.
Assume that x is in r5 and y is in r6.
82
Multidimensional Arrays
Consider a two dimensional array: int a[3][4];
Number of rows: 3
Number of columns: 4
83
Multidimensional Arrays
Since memory is modeled using a one-dimensional array, the
2D array gets flattened.
row-major order: rows are stored sequentially (used by C++)
a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]
a[0][0] a[1][0] a[2][0] a[0][1] a[1][1] a[2][1] a[0][2] a[1][2] a[2][2] a[0][3] a[1][3] a[2][3]
84
Multidimensional Array Addresses
How do you determine the address of a[row][col]?
Row major order:
85
Outline
Introduction to Assembly Language
Arithmetic and Logic Instructions
Input / Output Instructions
Arithmetic Instructions with Immediates
Branches and Jumps
Conditional Execution and Loops
Memory Instructions
Variables in Assembly Language
Function Calls
86
jalr
The final ANNA assembly instruction jalr (jump and link register):
jalr Rd Rs1
Jumps to an address stored in a register and saves PC + 1 in a
different register.
Rd contains the address of the function to jump to.
Rs1 will contain the return address (PC + 1).
Operation summary for jalr:
R(Rs1) PC + 1
PC R(Rd)
87
More on jalr
It is used predominantly in function calls.
Uses direct addressing (not PC-relative).
R-type instruction (Rs2 ignored)
Opcode bits: 1101
88
Fetch and Execute Loop
Fetch and execute loop for jump and link register
instruction:
89
Using jalr in function calls
To call the function foo:
90
Function Call Caveats
No parameters were passed into foo.
The function foo did not return a value.
It is assumed that foo did not overwrite the return
address stored in r2.
All registers and memory locations are "global" in that
they are shared by all functions.
A problem occurs if the calling function has designated
that x is stored in r3 and then foo overwrites r3.
91
Thank You!
92