CSE410 System ISA Manual

Introduction
The x86 architecture dates back to 1978. It has been extended over time in a way that preserves backward compatibility. The result is an architecture that is complicated in ways that have little to do with understanding the hw/sw interface.

The CSE 410 machine is a simplified architecture that contains just (some of) the ideas important to understanding the hw/sw interface. The architecture is simple enough that we can master it easily, allowing us to write small programs for it. It is realistic enough that it will give you a good impression of what actual machine instruction set architectures look like (and a good start toward mastering a real one if you should ever want to).

The CSE 410 machine is implemented by a simulator, written in C. The simulator includes a program loader, which would normally be a part of the operating system. Additionally, it integrates a crude debugger, which would normally be implemented as a user-level process.

This manual describes the 410 Instruction Set Architecture (ISA). Additional documents describe the assembler, the executable file format, and the simulator/debugger.

The 410 Hardware
The 410 is a sixteen-bit processor. It has eight registers, each 16-bits wide. A "word" is 16-bits. Register 0 has the value 0. Writing to register 0 has no effect. There is a 16-bit program counter (PC) register that holds the address of the instruction being fetched or operated on. There is a two-bit condition code (CC) register that indicates EQUAL (00), LESS than zero (01), or GREATER than zero (10). The condition code is set based on the last value stored into a register. It is also set by the compare (CMP) instruction. The conditional branch instructions use the CC to decide whether or not to branch.

The memory bus is sixteen bits wide, so memory addresses range from 0x0000 (0) to 0xFFFF (65535). A maximally configured instance has 64KB of memory. Words are stored big-endian. For example, if the word in a register is stored in memory at address 0x0400, the high order (big end) byte is stored at 0x0400 and the lower order byte is stored at 0x0401.

All arithmetic instructions operate on signed (2's complement) values. All address computations are unsigned. When an instruction includes an immediate value, that value is first sign-extended. If it is subsequently used in an address calculation, the sign-extended value is interpreted as unsigned, but with no change to the bit string representing it.

The processor "throws an exception" in two situations:

  1. An attempt is made to divide by zero
  2. An instruction has an invalid opcode
The exception causes the processor to halt. (On a real machine, the exception would cause an upcall to the operating system.)
410 Instruction Formats
The 410 supports 24 instructions. All instructions are encoded as bit strings. Instructions may be 1, 2, or 3 bytes long. There are five instruction formats:
NameFormatLength
B
OPx
62
[8 bits]
O
OPIMMED_10
610
[16 bits]
R
OPRARBRCx
63331
[16 bits]
RI
OPRARBIMMED_12
63312
[24 bits]
LI
OPRAIMMED_15
6315
[24 bits]
('x' means unused.)

All instructions are encoded in one of these five formats. Some instructions may not use all the fields of the format in which it is encoded.

410 Instructions

opcodeNameFormatExample instruction
000000STOPBSTOP
0000 0000

Halts processor and causes dump of machine state.
opcodeNameFormatExample instruction
000001NOPBNOP
0000 0100
Does nothing.
opcodeNameFormatExample instruction
000010Load wordLWLW r2 r3 r4
0000 1001 0011 1000
(RA) <- MemWord[(RB) + (RC)]
Load the word at memory location (RB)+(RC) into register RA. The word is stored in memory in big-endian order.
opcodeNameFormatExample instruction
000011Load byteRLB r2 r3 r4
0000 1101 0011 1000
(RA) <- MemByte[(RB) + (RC)]
Load the byte at memory location (RB)+(RC) into the low order byte of register RA. The high order byte of RA is set to 0.
opcodeNameFormatExample instruction
000100Store wordRSW r2 r3 r4
0001 0001 0011 1000
MemWord[(RB) + (RC)] <- (RA)
Store the value in register RA into the word in memory at location (RB)+(RC). The word is stored in memory in big-endian order.
opcodeNameFormatExample instruction
000101Store byteRSB r2 r3 r4
0001 0101 0011 1000
MemByte[(RB) + (RC)] <- (RA)
Store the low order byte in register RA into the byte of memory at location (RB)+(RC).
opcodeNameFormatExample instruction
000110AddRADD r2 r3 r4
0001 1001 0011 1000
(RA) <- (RB) + (RC)
Store the sum of (RB) and (RC) in register RA. Addition is done using signed arithmetic.
opcodeNameFormatExample instruction
000111SubtractRSUB r2 r3 r4
0001 1101 0011 1000
(RA) <- (RB) - (RC)
Store the result of subtracting (RC) from (RB) into register RA. Subtraction is done using signed arithmetic.
opcodeNameFormatExample instruction
001000MultiplyRMUL r2 r3 r4
0010 0001 0011 1000
(RA) <- (RB) * (RC)
Store the low order 16 bits of the result of multiplying (RB) and (RC) into register RA. Multiplication is done using signed arithmetic.
opcodeNameFormatExample instruction
001001DivideRDIV r2 r3 r4
0010 0101 0011 1000
(RA) <- (RB) / (RC)
Store the result of dividing (RB) by (RC) into register RA. Division is done using signed arithmetic. (Any remainder is ignored.) If (RC) is zero a machine check occurs.
opcodeNameFormatExample instruction
001010Add ImmediateRIADDI r2 r3 0xfff
0010 1001 0011 1111 1111 1111
(RA) <- (RB) + sign_extend(IMMED_12)
Store into register RA the result of adding (RB) and the sign extended immediate.
opcodeNameFormatExample instruction
001011AndRAND r2 r3 r4
0010 1101 0011 1000
(RA) <- (RB) & (RC)
Store into register RA the result of bitwise and'ing (RB) and (RC).
opcodeNameFormatExample instruction
001100OrROR r2 r3 r4
0011 0001 0011 1000
(RA) <- (RB) | (RC)
Store into register RA the result of bitwise or'ing (RB) and (RC).
opcodeNameFormatExample instruction
001101Exclusive OrRXOR r2 r3 r4
0011 0101 0011 1000
(RA) <- (RB) ^ (RC)
Store into register RA the result of bitwise xor'ing (RB) and (RC).
opcodeNameFormatExample instruction
001110Shift LeftRISHFTL r2 r3 $4
0011 1001 0011 0000 0000 0004
(RA) <- (RB) << sign_extend(IMMED_12)
Store into register RA the result of shifting (RB) left the sign extended immediate value number of bits. The result is undefined if the shift amount is negative or larger than 16.
opcodeNameFormatExample instruction
001111Shift RightRISHFTR r2 r3 $4
0011 1101 0011 0000 0000 0004
(RA) <- (RB) >> sign_extend(IMMED_12)
Store into register RA the result of doing an arithmetic right shift of (RB) the sign extended immediate value number of bits. The result is undefined if the shift amount is negative or larger than 16.
opcodeNameFormatExample instruction
010000CompareRCMP r0 r3 r4
0010 0000 0011 1000
The CC is set according to the result of (RB) cmp (RC). RA is ignored.
opcodeNameFormatExample instruction
010001Branch equalOBE 0xffe
0100 0111 1111 1110
The PC is set to (PC)+sign_extend(IMMED_10) if the CC is 00 (EQUAL). Otherwise, PC is set to (PC)+2.
opcodeNameFormatExample instruction
010010Branch less thanOBLT 0xffe
0100 1011 1111 1110
The PC is set to (PC)+sign_extend(IMMED_10) if the CC is 01 (LESS). Otherwise, PC is set to (PC)+2.
opcodeNameFormatExample instruction
010010Branch greater thanOBGT 0xffe
0100 1111 1111 1110
The PC is set to (PC)+sign_extend(IMMED_10) if the CC is 10 (GREATER). Otherwise, PC is set to (PC)+2.
opcodeNameFormatExample instruction
010100Jump registerRJR r0 r3 r4
0101 0000 0011 1000
The PC is set to (RB)+(RC). RA is ignored.
opcodeNameFormatExample instruction
010101CallLICALL r1 0x123
0101 0100 1000 0001 0010 0011
Register RA is set to the return address, (PC)+3. The PC is set to sign_extend(IMMED_15). (Note that this is not a PC-relative jump.)
opcodeNameFormatExample instruction
010110Print registerRPRINTR r2 r3 r4
0101 1001 0011 1000
(This is a very unrealistic instruction.) The value of register RA is printed to stdout.
opcodeNameFormatExample instruction
010111Print memoryRPRINTM r2 r3 r4
0101 1101 0011 1000
(This is a very unrealistic instruction.) The word stored in memory at (RB)+(RC) is printed to stdout.
opcodeNameFormatExample instruction
011000Print charRPRINTC r2 r3 r4
0110 0001 0011 1000
(This is a very unrealistic instruction.) The byte stored in memory at (RB)+(RC) is printed as an ASCII character to stdout.