CS 232: Assembly Language

Assembly Language Design

Main course page


An assembly language is fundamentally a set of mnemonics for machine instructions. It is a way of writing machine instructions using something that looks more like a human readable language. The simplest assembly languages require line numbers and do not allow the use of symbols to represent addresses in program or data memory.

A more sophisticated assembler allows the user to put labels into the code to represent memory addresses. For example, when branching, it is convenient to be able to label a location in the program and then use the label in a branch instruction instead of an actual memory address. It allows the assembler to assign the line numbers, releiving the programmer of that responsibility.


The assembly language for the simple CPU allows the programmer to use arbitrary symbols for program memory locations, mnemonics for the instructions, and mnemonics for the various registers.

The assembler uses the following rules for syntax.

Register Symbols
RA Register A
RB Register B
RC Register C
RD Register D
RE Register E
SP Stack Pointer
PC Program Counter
ZEROS 16-bit zeros
ONES 16-bit ones
IR Instruction register
CR Condition register

Instruction Symbols
LOAD D A Load from address A (0..255) to register D
LOADA D A Load from address [A + RE] to register D
STORE S A Store the value in register S to address A (0..255)
STOREA S A Store the value in register S to address [A + RE]
BRA L Unconditional branch to label L
BRAZ L Branch to label L if the CR zero flag is set
BRAN L Branch to label L if the CR negative flag is set
BRAO L Branch to label L if the CR overflow flag is set
BRAC L Branch to label L if the CR carry flag is set
PUSH S Push register S onto the stack and increment SP
POP S Decrement SP and put the top value on the stack into register S
OPORT S Send register S to the output port
IPORT D Assign to register D the value of the input port
ADD A B C Execute C <= A + B, where A, B, C are registers
SUB A B C Execute C <= A - B, where A, B, C are registers
AND A B C Execute C <= A and B, bitwise, where A, B, C are registers
OR A B C Execute C <= A or B, bitwise, where A, B, C are registers
XOR A B C Execute C <= A xor B, bitwise, where A, B, C are registers
SHIFTL A C Execute C <= A shifted left by 1, where A, C are registers
SHIFTR A C Execute C <= A shifted right by 1, where A, C are registers
ROTL A C Execute C <= A rotated left by 1, where A, C are registers
ROTR A C Execute C <= A rotated right by 1, where A, C are registers
MOVE A C Execute C <= A where A and C are registers
MOVEI A C Execute C <= A where A is an 8-bit 2's complement value and C is a register


Examples

This is the assembly version of the test program.mif file from last week. It should assemble to the identical MIF file.

tart:
movei 8 RA
movei 8 RB
movei 8 RC
movei 1 RD
movei 2 RE
add RD RE RA
sub RD RE RB
BRA start

Here is the expected output.

-- program memory file for test.a
DEPTH = 256;
WIDTH = 16;
ADDRESS_RADIX = HEX;
DATA_RADIX = BIN;
CONTENT
BEGIN
00 : 1111000100001000;
01 : 1111001100001000;
02 : 1111010100001000;
03 : 1111011100000001;
04 : 1111100100000010;
05 : 1000011000100000;
06 : 1001011001100000;
07 : 0010000000000000;
[08..FF] : 1111111111111111;
END

This is assembly to find the sum of the first 10 non-zero odd integers.

# setup
MOVEI 1 RA
MOVEI 0 RB
MOVEI 2 RC
MOVEI 10 RD

# loop
loop:
ADD RA RB RB
ADD RA RC RA
ADD ONES RD RD
BRAZ breakout
BRA loop

breakout: # RB contains the sum
OPORT RB

Here is the expected output.

-- program memory file for sumten.a
DEPTH = 256;
WIDTH = 16;
ADDRESS_RADIX = HEX;
DATA_RADIX = BIN;
CONTENT
BEGIN
00 : 1111000100000001;
01 : 1111001100000000;
02 : 1111010100000010;
03 : 1111011100001010;
04 : 1000000001001000;
05 : 1000000000010000;
06 : 1000111011011000;
07 : 0011000000001001;
08 : 0010000000000100;
09 : 0110001000000000;
[0A..FF] : 1111111111111111;
END