The BLITZ Architecture
Harry H. Porter
III
Computer Science
Department
Portland State
University
This document provides an overview of the BLITZ architecture and instruction set. The BLITZ microprocessor is designed specifically to support Computer Science education. The architecture is similar to contemporary RISC microprocessor architectures, but is simplified appropriately for student use. The BLITZ processor will normally be implemented by software emulation, although a hardware implementation of the CPU architecture presented here is also possible.
In this document, we use the terms ÒbyteÓ, ÒhalfwordÓ, ÒwordÓ, and ÒdoublewordÓ to refer to various sizes of binary data.
number number
of bytes of bits example (in hex)
======== ======= =================
byte 1 8
A4
halfword 2 16 C4F9
word 4 32
AB12CD34
doubleword
8
64
01234567 89ABCDEF
The bits within an 8-bit byte are numbered from 0 (least significant) to 7 (most significant).
7654
3210
====
====
0000
0000
The bits within a 16-bit halfword are numbered from 0 (least significant) to 15 (most significant).
15
12 8 4 0
====
==== ==== ====
0000
0000 0000 0000
The bits within a 32-bit word are numbered from 0 (least significant) to 31 (most significant).
31
28 24 20 16 12 8 4 0
====
==== ==== ==== ====
==== ==== ====
0000
0000 0000 0000 0000
0000 0000 0000
The bits within a 64-bit doubleword are numbered from 0 (least significant) to 63 (most significant).
63
60 ... 20 16 12 8 4 0
==== ====
==== ==== ==== ==== ====
0000 ...
0000 0000 0000 0000
0000 0000
A single hex digit can be used to represent 4 bits (half a byte, sometimes called a ÒnibbleÓ), as follows.
Binary Hex
====== ===
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 F
The 8 bits within a byte are conveniently expressed with two hex digits:
8-bit byte In Hex
========== ========
1010 0100 A4
The 32 bits in a word are given with 8 hex digits.
32-bit word
In Hex
============================================= ========
1010 1011 0001 0010
1100 1101 0011 0100 AB12CD34
The 64 bits (8 bytes) in a doubleword are conveniently expressed with 16 hex digits.
Other architectures use ÒquadwordsÓ of 128 bits, but the BLITZ architecture does not provide instructions for manipulating quadword data.
Memory
Main memory is byte addressable. Addresses are 4 bytes (i.e., 32 bits) long, allowing for up to 4 gigabytes to be addressed.
Memory can be viewed either as a sequence of bytes:
address data
(in hex) (in hex)
======== ========
00000000 89
00000001 AB
00000002 CD
00000003 EF
00000004 01
00000005 23
00000006 45
00000007 67
... ...
FFFFFFFC E0
FFFFFFFD E1
FFFFFFFE E2
FFFFFFFF E3
or as a sequence of words:
address data
(in hex) (in hex)
======== ========
00000000 89ABCDEF
00000004 01234567
... ...
FFFFFFFC E0E1E2E3
Both are equivalent and show the same memory contents.
Alignment
A Òword-aligned addressÓ is an address that is a multiple 4. The last 2 bits of an aligned address will always be zeros.
Word-sized data and doubleword-sized data must always be stored in word-aligned memory locations. Every instruction is one word (i.e., 4 bytes) long. All instructions must be stored at word-aligned addresses.
Any violation of these alignment requirements will result in an error exception. For example, the load and store instructions will cause an error exception if an attempt is made to move a word to or from an address that is not divisible by 4.
Byte-sized data may be stored at any location in memory; there is no alignment requirement.
This architecture uses only word-alignment; there is no ÒhalfwordÓ or ÒdoublewordÓ alignmentÓ requirement. Henceforth, whenever we say ÒalignmentÓ, it is understood that we mean Òword-alignmentÓ.
Big
Endian
The BLITZ architecture is ÒBig EndianÓ, meaning that when a word-sized quantity is stored in 4 bytes of memory, the most significant byte is stored in the first byte (i.e., lowest numbered address) and the least significant byte is stored in the last byte (i.e., the byte with the greatest address). In other words, if a word is stored at address x, the most significant byte will be stored in byte x and the least significant byte will be stored in address x+3.
Some other (non-BLITZ) computers use ÒLittle EndianÓ order, in which the least significant byte is stored in the lowest numbered address.
Load
Store Architecture
The BLITZ uses a Òload-storeÓ architecture. Operations (such as arithmetic and logical functions) can only be performed on data stored in registers. It is necessary to move the data from memory to registers (load it) and back to memory (store it) with separate instructions. The instructions in the following example are not exactly BLITZ instructions, but they give you the idea of load-store architectures. Here, ÒxÓ, ÒyÓ, and ÒzÓ are the names of some memory locations and Òr1Ó, Òr2Ó, and Òr3Ó are the names of registers.
load x,r1
load y,r2
add
r1,r2,r3
store r3,z
The first instruction moves data from memory into register Òr1Ó. The second instructions moves a number into register Òr2Ó. The third instruction adds the values in Òr1Ó and Òr2Ó, placing the result into register Òr3Ó. The final instruction moves data from register Òr3Ó back to main memory.
BLITZ is a Reduced Instruction Set Computer (RISC) architecture. In a RISC architecture, each instruction is kept very simple, so that instructions may be executed at a fast clock rate. Of course, certain operations are inherently complex, so a couple of instructions may be required in a RISC machine, whereas in another architecture the same operation may require only a single instruction.
Each BLITZ instruction either does a memory access or does a computation. The idea is that each instruction will be executed in one machine (clock) cycle. The goal is to keep each instruction simple so that a faster clock rate can be used, thereby speeding the overall performance of the CPU.
(The BLITZ machine is expected to be emulated in software. When emulated, the RISC architecture may not translate into any increase in speed.)
The
BLITZ Register Set
The state of the BLITZ CPU is given by the following registers.
User Registers:
===============
r0 -
Always zero
r1
r2
...
r13
r14 - Frame Pointer
r15 – Stack Pointer
System Registers:
=================
r0 -
Always zero
r1
r2
...
r13
r14 - Frame Pointer
r15 – Stack Pointer
Floating-Point Registers:
=========================
f0
f1
f2
...
f15
Miscellaneous Registers:
========================
PC
- Program Counter (32 bits)
PTBR -
Page Table Base Register (32 bits)
PTLR -
Page Table Length Register (32 bits)
SR
- Status Register (32 bits-see below)
Status Register (32 bits):
==========================
31
28 24 20 16 12 8 4 0
----
---- ---- ---- ----
---- ---- ----
0000
0000 0000 0000 0000
0000 00IS PZVN
I = Interrupts Enabled (1=Enabled, 0=Disabled)
S = System Mode (1=System, 0=User)
P = Paging Enabled (1=Enabled, 0=Disabled)
Z = Zero (1=Result was zero)
V = Overflow (1=Overflow occurred)
N = Negative (1=Result was negative)
(All other bits are unused.)
The
Registers
Each running process can access 16 general purpose registers and 16 floating-point registers.
Each general purpose register contains one word (32 bits) of data. These registers are numbered from 0 to 15 and are named r0, r1, ..., r15. They typically contain signed integer values. Sometimes the general purpose registers are called the Òinteger registersÓ to distinguish them from the floating-point registers.
The floating-point registers each contain two words (64 bits) of data. They are numbered from 0 to 15 and are named f0, f1, ..., f15. Each floating point register contains a double-precision floating point number, stored in the IEEE standard format.
Almost all instructions use at least one of the general purpose integer registers, and some use two or three integer registers. Where ever an integer register is used, any of the 16 registers may be specified. Most integer registers are identical and which register is used is a question for the programmer to determine. However, some registers (in particular, registers r0, r14, and r15) have special uses and functions, as described later.
A subset of instructions (called the Òfloating-point instructionsÓ) access and modify data in the floating-point registers. These instructions all begin with the letter ÒfÓ. For example there are two addition operations. The integer operation is named ÒaddÓ and the floating-point operation is named ÒfaddÓ.
User
Registers and System Registers
There are two sets of general purpose registers. Each set has 16 registers. One set is called the ÒUserÓ register set and the other is called the ÒSystemÓ register set. In each set, the registers are numbered 0 through 15 and named Òr0Ó, Òr1Ó, ... , Òr15Ó.
At any time, the BLITZ processor is executing either in ÒUser ModeÓ or ÒSystem ModeÓ. When the processor is in User Mode, the User Registers are used; when the processor is in System Mode, the System Registers are used.
The use of two sets of integer registers allows kernel traps (for example, ÒsyscallÓ system calls) to be executed quickly. The user-level process will execute in User mode and will use the User registers. The kernel will execute in System Mode and will use the System registers. During the ÒsyscallÓ processing, no register saving is necessary; the processor simply changes the Mode to switch to the other register set.
There is only one set of floating-point registers. This set is shared among between User and System processes.
Register
r0
Register r0 is special. Its value is always zero. Any attempt to read from this register will result in zero being returned. Any attempt to store data into this register is perfectly legal; the data will simply be discarded.
Register
r14 - The Frame Pointer
By convention, register r14 is used as a Òframe pointerÓ. The frame-pointer register is used in the standard subroutine calling sequence. In conjunction with r15 (the stack pointer), it is used to locate activation records (i.e., Òstack framesÓ) in the activation calling stack.
There is no direct architectural support for the frame pointer. In other words, no instruction treats r14 any differently than any other register. In fact, any register could be used with no change to the assembler or machine emulator.
Register
r15 - The Stack Pointer
By convention, register r15 points to a stack in memory. This stack is used during procedure calls and returns. This stack is also used during interrupt processing. The ÒpushÓ and ÒpopÓ instructions also use the stack. The push and pop instructions will actually work with any register, but synthetic versions of ÒpushÓ and ÒpopÓ make the use of r15 more convenient. (Synthetic instructions are implemented entirely within the assembler and serve as shorthand for other instructions. They are discussed later.)
By convention, the stack grows downward (toward lower-numbered addresses) from high memory. Register r15 points to the item at the ÒtopÓ of the stack, i.e., r15 points to the lowest numbered byte that contains stack data. Thus, during a ÒpushÓ operation, the stack-top register will be decremented before the item is moved to memory, whereas during a pop operation, the data will be moved from memory before the stack-top register is incremented.
address memory
------
00000000: | |
00000001: | |
00000002: | |
| |
| |
| |
| AA | <-- r15
| BB |
| CC |
FFFFFFFF: | DD |
Normally, the kernel will maintain its own stack, which will be indexed by the stack-top pointer stored in register r15 in the System Register set. Each user-level process will presumably have its own stack, although this is an operating system issue, not a processor feature. Each user-level process will have a set of User Registers, and its stack-top register r15 will index its stack.
Status
Register (and Condition Codes)
The Status Register is defined as a 32 bit register; however, only six of the bits are actually used. When the Status Register is stored as part of the syscall / interrupt processing, the unused bits are set to zero. When the Status Register is loaded during a return from interrupt (the ÒretiÓ instruction), the unused bits are ignored.
Three of the status bits (Z=Zero, V=Overflow, and N=Negative) are referred to as the ÒCondition CodesÓ. These bits are set during certain arithmetic operations to reflect the nature of the computed result. The following instructions modify the condition codes:
add, sub, mul, div, sll, srl, sra, or, and, andn, xor,
rem
Note that the following synthetic instructions are shorthand for some of these instructions. Therefore, they also modify the condition codes:
mov, cmp, neg, not, clr, btst, bset, bclr, btog
Of course the ÒretiÓ instruction also modifies the condition codes since it reloads the entire Status Register.
The condition code bits are tested with the various branch instructions, which will conditionally jump according to how these bits are set. Thus, the program can test the result of an operation, such as a ÒcmpÓ instruction, and can branch accordingly.
I = Interrupts Enabled (1=Enabled,
0=Disabled)
==============================================
If this bit is set, then interrupts will be processed. If this bit is zero, then interrupts are disabled and incoming interrupts will not be processed; instead they will remain pending until interrupts are once again enabled. At that time, a pending interrupt (if any) will be processed. Only maskable interrupts can be disabled and remain pending. Unmaskable interrupts will always be processed, regardless of the state of this bit, and will never remain pending.
This bit may only be changed by the kernel. That is, this bit may only be changed by privileged instructions, and privileged instructions can only be executed in System Mode.
S = System Mode (1=System, 0=User)
==================================
At any time, the BLITZ processor is executing in either System Mode or in User Mode and this bit determines which mode the processor is in. Presumably the operating system kernel will execute in System Mode and all user-level programs will execute in User Mode. All instructions may be executed when in System Mode. In User Mode, some instructions are forbidden. (The forbidden instructions are called ÒprivilegedÓ instructions.) An attempt to execute a privileged instruction while in User Mode will cause a Privileged Instruction exception and will trap into System Mode.
This bit may only be changed by the kernel. That is, it may only be changed by privileged instructions, which may only be executed in System Mode.
P = Paging Enabled (1=Enabled,
0=Disabled)
==========================================
The BLITZ architecture provides support for virtual memory via a page table with automatic address translation. If this bit is set, then address translation will occur whenever the program accesses main memory. Whenever an instruction accesses memory, the address it provides will be interpreted as a ÒlogicalÓ address (also called a ÒvirtualÓ address). This logical address will be translated into a physical address by the CPUÕs translation hardware before being used. The physical address will then be used to determine which bytes in memory are examined or modified by the instruction. If this bit is zero, then every memory address generated by an instruction will be used as is, with no translation. Presumably, an operating system kernel will run with paging disabled and user-level programs will run with paging enabled.
This bit may only be changed by the kernel. That is, it may only be changed by privileged instructions, which may only be executed in System Mode.
Z = Zero (1=Result was zero)
============================
If the result of the arithmetic operation is zero (i.e., all bits are zero), then this bit will be set to 1. Otherwise, it will be cleared to zero.
V = Overflow (1=Overflow occurred)
==================================
If the execution of the arithmetic operation caused overflow, then this bit will be set to 1. Otherwise, it will be cleared to zero. Overflow may occur for add, sub, mul, div, rem, and fcmp.
N = Negative (1=Result was
negative)
====================================
If the result of the arithmetic operation is negative (i.e., the most significant bit is Ò1Ó), then this bit will be set. Otherwise, it will be cleared to zero.
The
Program Counter (PC) Register
There is a 32-bit register called the ÒPCÓ, which contains the address of the next instruction to execute. It is modified with instructions that branch or transfer the flow of control.
The
Page Table Base Register (PTBR) Register
The Page Table Base Register (ÒPTBRÓ) contains the address of the page table. The page table is stored in main memory and this register will always contain a word-aligned address. This register is used whenever the page table is consulted by the CPUÕs address translation hardware. In particular, when a virtual address is translated into a physical address, this register will be used to locate the page table in main memory. This only happens when paging is enabled by the ÒPaging EnabledÓ bit in the Status Register. If paging is disabled, this register is ignored. This register will contain a physical address, not a virtual address.
This register can only be loaded with the ÒldptbrÓ instruction, and it cannot be examined directly.
The
Page Table Length Register (PTLR) Register
The Page Table Length Register (ÒPTLRÓ) is used in conjunction with the Page Table Base Register. The page table consists of a number of entries, stored sequentially in memory. Each entry is 4 bytes (one word) long. This register contains the number of bytes in the table and therefore it will always be a multiple of 4.
This register can only be loaded with the ÒldptlrÓ instruction, and it cannot be examined directly.
Instruction
Formats
Every BLITZ instruction is 4 bytes long. The first byte of the instruction is the op-code, indicating what the instruction is. The remaining 3 bytes are interpreted differently. Some instructions have no operands, in which case the remaining 3 bytes are ignored. Other instructions take several operands, in which case the operands are encoded into the remaining 3 bytes. There are seven different instruction formats, named Format A, Format B, ... , Format G.
Here are the instruction formats. Each line shows how the 32 bits of an instruction are to be interpreted.
Format A:
xxxx xxxx ---- ----
---- ---- ---- ----
Format B:
xxxx xxxx cccc ----
---- ---- ---- ----
Format C:
xxxx xxxx cccc aaaa
---- ---- ---- ----
Format D:
xxxx xxxx cccc aaaa
bbbb ---- ---- ----
Format E:
xxxx xxxx cccc aaaa
vvvv vvvv vvvv vvvv
Format F:
xxxx xxxx rrrr rrrr
rrrr rrrr rrrr rrrr
Format G:
xxxx xxxx cccc ----
vvvv vvvv vvvv vvvv
The various fields in the instructions are given by the following legend:
xxxx xxxx
Op code (8 bits)
aaaa
Register A (4 bits)
bbbb
Register B (4 bits)
cccc
Register C (4 bits)
vvvv vvvv vvvv vvvv Immediate value (16-bits, sign-extended)
rrrr rrrr
... rrrr Relative
displacement (24-bits, sign-extended)
----
(These bits are ignored)
There are 16 general purpose registers and they are encoded in the obvious way in 4-bit fields (shown above as ÒaaaaÓ, ÒbbbbÓ, and ÒccccÓ) in the instructions:
0000 - Register r0
0001 - Register r1
0010 - Register r2
...
1111 - Register r15
Many instructions take one or more general purpose registers as operands. These are referred to as Register A, Register B, and Register C. For example, the general format of the multiply instruction is:
mul
regA,regB,regC
A specific instance of this instruction might be:
mul
r7,r8,r13
! Multiply r7 by r8 and place result in r13.
In this instruction we have:
aaaa = RegA = r7
= 0111
bbbb = RegB = r8
= 1000
cccc = RegC = r13 = 1101
The op code for the ÒmulÓ instruction (Format D) is 98 (in binary: 0110 0010). Thus, this instruction would be encoded as:
Format D:
xxxx xxxx cccc aaaa
bbbb ---- ---- ----
0110 0010 1101 0111
1000 0000 0000 0000
In hex:
6 2 D 7 8 0 0 0
Some instructions operate on the floating-point registers instead of the general purpose registers. An example is the floating-point multiply instruction:
fmul
fregA,fregB,fregC
A specific instance of this instruction might be:
fmul f3,f4,f9 ! Multiply f3 by f4 and place result in f9.
There are 16 floating-point registers and (like the general purpose registers) they are encoded in the obvious way in 4-bit fields (shown above as ÒaaaaÓ, ÒbbbbÓ, and ÒccccÓ) in the instructions:
0000 - Register f0
0001 - Register f1
0010 - Register f2
...
1111 - Register f15
The floating-point instructions (like ÒfmulÓ) interpret the 4-bit register fields (aaaa, bbbb, and cccc) as indicating floating-point registers; all other instructions interpret the 4-bit fields as meaning general purpose registers. Thus, the bit pattern
0101
may mean either Òr5Ó or Òf5Ó, depending on which instruction it is used in.
The op-codes are assigned in such a way that the first 3 bits of the op-code indicate the format of the instruction.
op-code
op-code
format
range
in binary
======
=======
=========
A 0-31 000- ----
B 32-63 001- ----
C 64-95 010- ----
D 96-127 011- ----
E 128-159 100- ----
F 160-191 101- ----
G 192-223 110- ----
- 224-255 111- ----
16-Bit
Sign-Extended Immediate Values
Many of the instructions allow for an immediate (or ÒliteralÓ) value to be included directly in the instruction. (In particular, all Format E and Format G instructions allow it.) For example, the subtract instruction may include a value directly:
sub r3,27,r4
This instruction subtracts 27 from the value stored in register r3 and stores the result in r4. The data (27) is specified immediately; it is not stored in a register. Instructions such as these include a 16 bit field in the instruction to contain the value. When executed, the 16 bits are interpreted as a signed integer. Thus, the 16 bit value is Òsign-extendedÓ. In other words, the most significant bit (bit 15) is duplicated to fill the value out to 32 bits. This means that any value between -32768 and 32767 can be specified literally. If you wish to subtract a number outside this range, you can not use a literal value; you will have to first place the value in a register of its own. (For example, you might use the ÒsetÓ instruction to accomplish this.)
Note that the logical operations (such as shift left logical ÒsllÓ and exclusive-or ÒxorÓ) can also take 16-bit immediate values. These values are also treated as signed integers and are signed-extended to 32 bits before being used. Any attempt to use an out-of-range number, as in the following example, will be caught by the assembler and flagged as an error.
xor r3,0xAB12CD34,r4 ERROR!
The programmer must be careful in situations like the following. Presumably the programmer is trying to flip a single bit (bit 15).
xor r3,0x8000,r4
The assembler will not flag this as an error and will produce the same code as for this instruction:
xor r3,0xFFFF8000,r4
One exception to the sign-extension rule is for the ÒsethiÓ and ÒsetloÓ instructions. These instructions are Format G instructions, so they contain a 16-bit immediate value. However, in these instructions, the value is not sign-extended before use.
24-Bit
Relative Displacements
Format F instructions are concerned with branching and jumping. The following instructions have Format F version: the ÒcallÓ instruction, the ÒjmpÓ instruction, and the conditional branch instructions (such as ÒbneÓ, ÒblÓ, and ÒbgeÓ).
Format F instructions contain a 24-bit field, which gives a displacement (also called an ÒoffsetÓ). This displacement is relative to the current location. More precisely, the 24-bit offset is sign-extended to 32-bits. This is then added to the address of the instruction (not the address following the instruction, as in some architectures) to give the target address. The target address is the address to be jumped to. If the branch is taken, the next instruction to be executed will be the instruction stored at the target address.
In the BLITZ architecture, logical (i.e., virtual) address spaces are limited to 16M bytes. (Recall that any byte in a 16M byte address space can be addressed with 24 bits.) Therefore, any byte in the logical address space may be addressed using a 24-bit relative displacement in a Format F instruction located anywhere in that address space. The address computation (adding the current address to the 24-bit displacement) is done using 32-bit arithmetic, but any bits beyond 24 are simply ignored when paging is enabled.
The benefit of using relative displacements instead of absolute addresses is that the code can be relocated (i.e., moved) from one area of memory to another, without having to be modified. As long as the relative separation of the Format F (branch) instruction and the target instruction of the branch remains unchanged, no modification of the branch instruction is necessary.
Consider the following code, for example:
loop:
add
r5,5,r5
add
r3,1,r3
cmp r3,17
ble loop
The branch instruction will contain a displacement of -12, meaning that the target instruction is 12 bytes before the branch instruction. At runtime, this code may be loaded at any address. For example, it might be loaded at addresses starting at 0x65432100:
6543 2100 loop: add r5,5,r5
6543 2104
add
r3,1,r3
6543 2108
cmp r3,17
6543 210C
ble loop
When the processor executes the branch instruction, it takes the current value of the program counter (6543210C) and adds the relative offset in the instruction (i.e., -12), giving the address of the instruction labeled ÒloopÓ. Obviously, if this code had been loaded at some other address at run-time, it would still work correctly.
To be precise, the 24 bit displacement is signed extended to 32 bits. Then this value is added to the address of the branch instruction. This means that the target of a branch instruction must lie within –8,388,608 to 8,388,607 bytes of the branch instruction. If the machine is operating with paging enabled, then the target address is a virtual address. It will be truncated to 24 bits before being translated into a 32-bit physical address.
(Since the branch instruction must be at an aligned address and since the target address must be aligned, the displacement in a branch instruction should also be divisible by 4. Therefore, the last 2 bits of any 24-bit displacement in a Format F instruction should be zero; if the displacement is not divisible by 4, an Alignment Exception will occur.)
Addressing
Memory
In order to fetch or store data to / from memory, the address must first be placed in a register. The ÒsetÓ instruction is ideal for moving the address into a register. For example, the following code first moves the address of ÒmyVarÓ into register r1. Then it uses that register to fetch from memory. This code increments the word whose address is ÒmyVarÓ.
set myVar,r1 ! Move address
of myVar into r1
load [r1],r2 ! Move data from myVar into r2
add r2,1,r2 !
Increment r2
store r2,[r1] ! Store data back, using same
address
A second addressing mode allows an integer offset to be added to a register to compute the effective address. For example, assume ÒmyArrÓ is the address of the first element of an array of words. We wish to increment the sixth element of this array. We will need an offset of 20, since each element is 4 bytes long.
set myArr,r1
load [r1+20],r2
add r2,1,r2
store r2,[r1+20]
A third addressing mode allows us to add the contents of two registers together to compute the effective address. For example, if the offset into the array has been computed and placed in register r3, then we can use the following code to access the desired element.
set myArr,r1
load [r1+r3],r2
add r2,1,r2
store r2,[r1+r3]
A common thing to do is to access fields in the activation record (or ÒframeÓ). Assume that variable x is a local variable stored at offset -12 in the frame. Then the following code would be used to increment x.
load [r14-12],r2
add r2,1,r2
store r2,[r14-12]
In this example, we assume that the Òstandard subroutine calling conventionsÓ have been followed and that Òr14Ó points into the frame stored on the top of the stack. In the standard calling conventions, which are described elsewhere, the frame pointer will point into the middle of the frame, not to the lowest byte in the frame. The local variables will actually be stored in the frame at negative offsets from the frame pointer.
Synthetic
Instructions
There are several ÒsyntheticÓ instructions. Technically, these are not true BLITZ instructions. Instead, they are introduced to make life easier for the programmer. Whenever the assembler sees a ÒsyntheticÓ instruction, it will translate it into one or two legal BLITZ instructions and will use those instructions instead.
For example, ÒsetÓ is a synthetic instruction. It will be expanded into two instructions. Consider the following code:
set myArr,r1
load [r1],r2
The ÒsetÓ instruction will be automatically expanded by the assembler into two instructions, giving:
sethi hi(myArr),r1
setlo lo(myArr),r1
load [r1],r2
Here we are using ÒloÓ and ÒhiÓ to indicate the lo-order and hi-order 16 bits of the full 32-bit value given by the symbol ÒmyArrÓ, although these are not really part of the assembler syntax.
The ÒsethiÓ and ÒsetloÓ instructions are discussed later, but in short, ÒsethiÓ moves 16 bits of data into the register, and the ÒsetloÓ instruction brings in the remaining 16 bits of data.
You might consider the following code sequence, which would be more efficient. However, this code sequence is subject to a very subtle bug.
sethi hi(myArr),r1
! Warning: This code sequence
load [r1+lo(myArr)],r2 ! may not do what you expect.
Recall that the 16-bit immediate value Òlo(myArr)Ó in the load instruction would be sign-extended. The above instruction sequence will work only if the most significant bit of Òlo(myArr)Ó was zero; otherwise it would be sign-extended, causing the address computation to result in a very different address. Since code may be relocated during linking, it is difficult to know whether this condition would be met. Therefore, the ÒsetloÓ instruction should always be used when moving 32-bit constant values.
Assembler
Comments
The exclamation point (!) is used to begin comments. The comment runs through the end-of-line. As a point of style, every line of assembler code should probably be commented.
When a single comment applies to several instructions, I prefer to use a period as demonstrated below to indicate that a multi-line comment applies to several instructions.
set myVal,r1
! Increment myVal
load [r1],r2 ! . by one
add
r2,1,r2 ! .
store r2,[r1] ! .
cmp r2,47
! If myVal >= 47
bge loop
! . then goto loop
Labels
and White Space
Each instruction may be preceded by an optional label. This label may then be the target of a ÒbranchÓ or ÒcallÓ instruction. Data locations in memory may also be labeled, in which case the label could be used in ÒloadÓ or ÒstoreÓ instructions.
If a label is present, it must be at the beginning of the line and must be followed by a colon. The instruction op-code is separated from the label by some white-space (usually a single tab character). The instruction op-code is followed by white space (usually a tab or two) and the operands. These can optionally be followed by some white space and a comment.
A label may also appear on a line by itself, in which case it applies to the current location counter, and will therefore be set to the address of the next instruction (notwithstanding things like Ò.alignÓ pseudo-ops that may change the location counter). Op-codes (both legal BLITZ instructions and pseudo-ops) must be preceded by white space, typically a tab or two.
The convention is to try to make things line up neatly. For example:
myLoop:
! myLoop:
set myVal,r1 ! Increment myVal
load
[r1],r2 ! .
by one
add r2,1,r2 ! .
store
r2,[r1]
! .
cmp r2,47
! If myVal >= 47
bge myLoop
! . then goto myLoop
...
myVal: .word 0
! myVal: counter of things
The
Program Counter
Every computer processor contains a register called the Program Counter (or ÒPCÓ) which contains the address of the next instruction to be executed. In the simplest model of computer operation, the processor repeatedly executes this algorithm:
pc := 0;
loop
fetch next instruction from
memory[pc];
pc := pc + 4;
execute the instruction:
Decode the instruction
Fetch operands from memory or registers
Perform computation
Store results back into memory or registers
endLoop
Sometimes the instruction will modify the flow of control (a ÒcallÓ or ÒbranchÓ instruction). For such instructions, a ÒresultÓ will be stored into the PC register, causing the next instruction to be fetched from a new address.
In the BLITZ processor, each instruction executes to completion before the next instruction begins. There is no pipelining of instructions. (Not included in this discussion is the processing of exceptions, asynchronous interrupts, or ÒsyscallÓ traps. When such interrupts occur, the above processing loop is more complex.)
The
Location Counter
As the assembler scans and processes each line of code, it keeps track of the current memory location into which each instruction will be placed. To do this, the assembler keeps a variable called the ÒLocation CounterÓ, which should not be confused with the ÒProgram CounterÓ. The location counter and the program counter are different.
It is important to understand that the location counter is an assembly-time concept; it does not exist at run time. On the other hand, the program counter is a run-time register (named ÒPCÓ) and only has a value when the program is running. When the assembler encounters a branch instruction, it never ÒtakesÓ the branch; instead it simply moves on to the next instruction in the source file by incrementing the location counter. Later, at runtime, when the CPU encounters a branch instruction, it may take the branch by modifying the PC.
Every time the assembler encounters an instruction, the location counter is advanced by 4 (i.e., by the size of the instruction). Even when a branch instruction is processed, the location counter is always advanced by 4 and the instruction on the line following the branch is then processed. To repeat, a branch is never ÒtakenÓ by the assembler.
When the assembler encounters a label, it adds a new definition to its symbol table, using the current value of the location counter as the definition of the symbol. When the assembler encounters a branch instruction or a load or store instruction using some label, it looks that label up in the symbol table. It will use the value of that symbol in assembling the branch instruction.
Assemblers make two passes over the source program. In the first pass, the location counter is set to zero, and the source code file is scanned line-by-line. Each time an instruction is encountered, the location counter is advanced by the length of the instruction, but no code is generated in the first pass. Whenever a label is encountered, it is entered into the symbol table, using the current value of the location counter as the symbolÕs definition.
In the second pass, the location counter is reset to zero. Then, the source code is examined again line-by-line from beginning to end. This time, machine code is generated and written to the output as each instruction is scanned.
This two-pass approach allows branches and other instructions to use labels that are defined either before or after the instruction. As the second pass begins, all symbols are already defined. As the second pass proceeds, the machine code for each instruction can be determined by plugging in the symbolsÕ values as necessary.
Branch and call instructions in the BLITZ architecture are ÒrelativeÓ, and not ÒabsoluteÓ. Each branch and call instruction contains a 24 bit field to specify the target address to be jumped to. This 24 bit field does not contain the absolute address of the target instruction. Instead, this field is interpreted as a signed number, which will be added to the current program counter at run-time to give the target address. Although the assembler does not know where the program will ultimately be loaded in memory, it is able to compute the relative distance between a branch instruction and its target address. Thus, it can produce code containing the correct relative displacement.
The assembler can be used to place data and instructions into different segments. The three segments are named Ò.textÓ, Ò.dataÓ, and Ò.bssÓ. The assembler maintains a distinct location counter for each segment. Thus, there is a Ò.dataÓ location counter, a Ò.textÓ location counter, and a Ò.bssÓ location counter. At any one time, the assembler is ÒinÓ only one segment, as determined by the .data, .text, and .bss pseudo-ops. For example, if the last pseudo-op was .text, all generated data following it will be placed in the Ò.textÓ segment and the corresponding location counter will be incremented.
Pseudo-Ops
(Assembler Directives)
The following sections describe several Òpseudo-operationsÓ, which control and direct the assembler in its task. Pseudo-ops are sometimes called Òassembler directivesÓ.
Pseudo-ops are included in the assembly language program file, mixed in among the real BLITZ instructions. However, pseudo-ops are not executed at runtime; instead they tell the assembler how to assemble other instructions and what to put into memory before program execution begins. For example, a pseudo-op could be used to initialize a variable with some particular value. The value can be coded using convenient (C-like) notation, freeing the programmer from having to specify the precise bit-pattern used to represent the value.
Pseudo-ops begin with a period to make it easy to distinguish them from BLITZ instructions.
Character
Data
Here are examples of the Ò.asciiÓ pseudo-op:
.ascii "abc"
.ascii "BLITZ programming is fun!\n"
The Ò.asciiÓ pseudo-op places N bytes of data in memory, where N is the number of bytes in the character string. A number of escapes (such as Ò\nÓ) can be used to place non-printable ASCII codes in string.
The standard ÒCÓ string convention is to terminate every string of characters with the NULL character. Note that the .ascii pseudo-op does not place a terminating NULL character in the string. If this is what you want, you must include it explicitly. For example:
.ascii "Hello, world.\n\0"
Data
.byte expression
.word expression
These pseudo-ops place data values in memory. In each case, arbitrary expressions may be provided, as long as they can be fully evaluated at assembly-time. These expressions may include many of the operators (such as + and *) available in the C language.
Double
Constants
.double value
This pseudo-op places an 8 byte (64 bit) double precision floating-point value in memory. Here are some examples, showing the ways in which the value may be specified.
.double 123.456
.double -123.456
.double +123.456
.double 123.456e10
.double 123.456e-10
.double 123.456e+10
.double 123.456E10
Alignment
The Ò.alignÓ pseudo-op will force the location counter to be word aligned. In other words, one or more bytes of padding may be inserted to round the location counter up to an address divisible by 4.
.align
In the first line of the following example, up to 3 bytes will be inserted (if necessary) to bring the location counter up to a multiple of 4. In the second line, 6 bytes will be allocated. In the next line, 2 additional bytes will by allocated so the next word will be placed in an aligned address.
.align
.ascii ÒabcdefÓ
.align
.word 43
.word "cs30"
.word -1
.word 0x0123abcd
If the location counter is already .aligned, this pseudo-op will insert no padding bytes. Thus, it never hurts to place an .align pseudo-op directly before instructions that require a particular alignment, and it is necessary if the preceding instructions may have left the alignment wrong.
Uninitialized
Data Space
.skip N
This pseudo-op skips over N bytes, where N is any expression. The assembler and linker will fill these bytes with zeros.
Segment
Control
A running process is loaded into main memory before execution begins. In Unix, a running process is divided into four ÒsegmentsÓ. These segments have the following names:
.data
.text
.bss
.stack
Before a program begins execution, initial data will be loaded into the Ò.dataÓ, Ò.textÓ, and Ò.bssÓ segments. The assembler is used to specify exactly what will be loaded into the Ò.dataÓ, Ò.textÓ, and Ò.bssÓ segments and how long they will be. For example, the Ò.dataÓ segment might be loaded with 100 bytes giving the initial values of several variables. The Ò.textÓ segment might be loaded with 11,000 bytes of machine instructions. Often the Ò.bssÓ segment is not used and will have a length of 0 bytes.
After loading, the OS will usually mark the bytes in the Ò.dataÓ segment read/write, and the bytes in the Ò.textÓ segment will be marked Òread-onlyÓ. Any attempt at run-time to modify a byte in the Ò.textÓ segment will result in an exception and the user-level program will be aborted by the OS. Any attempt to access a byte outside of any segment will also result in a similar error.
The Ò.stackÓ segment will be marked read/write, and has no fixed size; instead any attempt to access bytes beyond the end of the Ò.stackÓ segment will result in new pages being added to that segment.
There are three pseudo-ops that allow control over which segment to place data and instructions into. They are:
.data
.text
.bss
These pseudo-ops determine into which segment the
following instructions and/or data will be placed. Each Òremains in effectÓ
until a new .data or .text or .bss pseudo-op is encountered.
The .bss segment contains data that will be initialized to zero. Thus, no space will actually be consumed in the executable Òa.outÓ file; the file will merely contain information about which bytes of the virtual address space must be initialized to zero before execution begins. As a consequence, the .bss segment may contain only .align and .skip pseudo-ops. Instructions and other pseudo-ops are not allowed in the .bss segment.
At assembly time, each of the three segments is assumed to start at location zero. Later, when the program is loaded into main memory, an address will be selected. Also, the size of the segment is rounded up to the nearest page boundary. In a machine with 8K byte pages, our Ò.dataÓ segment with 100 bytes would be rounded up to 8K bytes. The Ò.textÓ segment, with 11,000 bytes would be rounded up to 16K bytes. Then an address is selected for each of the four segments and the initial data is loaded into the appropriate memory locations.
Symbols
Symbols may be defined in several ways. The most common way is when an instruction is labeled. Another way is when the location of data in memory is allocated (e.g., with a Ò.wordÓ pseudo-op) and a label is present.
When the assembler encounters a label, it makes a new entry in its symbol table, associating the symbol with the current value of the location counter. It also makes a note in its symbol table of which segment this address is in. Later, when the several separately-assembled pieces of the program are linked together, each segment will be assigned a specific address. This will require the value of the symbol to be adjusted. Furthermore, every instruction that uses the symbol must be modified to reflect the fact that the symbol is being adjusted. Obviously, there is a lot of information in the Ò.oÓ files that indicates which symbols are used as well as where and how they are used, so that the linker can make these adjustments when the various segments are put together.
Symbols may also be defined directly using the Ò=Ó pseudo-op. Here is an example:
set myVal,r1 ! Increment myVal
load [r1],r2 ! .
by ÒincrAmtÓ
add r2,incrAmt,r2 ! .
store r2,[r1] ! .
...
incrAmt = 3
Note that Ò=Ó is a pseudo-op (like Ò.alignÓ or Ò.textÓ) although Ò=Ó differs in that it is not given an alphabetic name beginning with a period.
In this example, we have introduced a symbol called ÒincrAmtÓ and set its value to 3. Such a symbol is an assembly-time constant: it can never change. This symbol is absolute, which means it is not relative to any segment. During linking, when the segments are assigned addresses, no adjustment will be needed to the ÒaddÓ instruction. The value of 3 will be used. The symbol ÒincrAmtÓ may be used any place the constant 3 may be used.
In this example, the operand of the Ò=Ó pseudo-op is Ò3Ó. In general, the operand can be any expression, as long as it can be evaluated at assembly-time.
External
Symbols
.export
localSymbol
.import
foreignSymbol
It is assumed that ÒlocalSymbolÓ is defined within the Ò.sÓ source file that contains the .export pseudo-op. It is assumed that ÒforeignSymbolÓ is not defined in the file containing the Ò.importÓ pseudo-op but is defined in some other file that is assembled at some other time and linked with this file. The assembler and linker will check that .export and .import are used correctly.
When the assembler processes a Ò.sÓ source file and produces a Ò.oÓ object file, it will include information in the Ò.oÓ file to identify the symbols used and give information about their values (or about their locations, if they are labels). The .export pseudo-op will make ÒlocalSymbolÓ visible to other Ò.oÓ files with which this file is linked. The .import pseudo-op will make a symbol called ÒforeignSymbolÓ defined in some other file visible and usable within the current file.
Consider this example:
.export
main
.import
printf
...
main: add r1,234,r3
...
call printf
...
When an imported symbol (such as ÒprintfÓ in this example) is used in this file, the linker will look for a definition of it in other Ò.oÓ files and will modify instructions (such as the ÒcallÓ instruction) in the executable file to point to it. In this example, a routine called ÒmainÓ is defined and exported. Thus, this routine can be called from other Ò.sÓ files which are assembled separately.
It is a good idea to put an Ò.alignÓ pseudo-op before the first instruction, in case a previous data item left the location counter on a non-word aligned boundary.
.align
main:
add r1,234,r3
Note that the following is in error since the symbol ÒmainÓ would be set to point to the ÒpaddingÓ bytes inserted by the Ò.alignÓ.
main:
.align
add r1,234,r3
Interrupt
Processing
In this document, we use the term ÒinterruptÓ very generally to refer to an interruption in the normal sequential execution of instructions. We use the terms ÒexceptionÓ and ÒtrapÓ more specifically, as discussed next.
Asynchronous interrupts may occur at anytime. These are triggered by events outside of the instruction processing sequence of the CPU. For example, a hardware device (such as a disk or the interval timer) may suddenly require attention. The device will send an electrical signal to the processor, which will trigger interrupt processing. This sort of interrupt is referred to as an Òasynchronous interruptÓ or a Òhardware interruptÓ.
Synchronous interrupts occur as a result of executing instructions within the CPU. These can be divided into two categories: those that are the result of problems and those that are specifically intended. Interrupts that are the result of problems arising during instruction execution are called ÒexceptionsÓ. Examples include ÒIllegal InstructionÓ and ÒAlignment ExceptionÓ. In the case of an exception, some unexpected event occurred during the execution of an instruction.
The only intentional interrupt is caused by the system call instruction (ÒsyscallÓ). This sort of an interrupt is often referred to as a ÒtrapÓ, rather than as an ÒexceptionÓ. It is used by a user-level program to enter (or invoke) the kernel of the operating system.
This table summarizes our terminology and lists all types of interrupts:
Interrupt:
Asynchronous Interrupts (Hardware):
- PowerOnReset
- TimerInterrupt
- DiskInterrupt
- SerialInterrupt
- HardwareFault
Synchronous Interrupts:
Exceptions:
-
IllegalInstruction
- Arithmetic
- Address
-
PageInvalid
-
PageReadOnly
-
PrivilegedInstruction
- Alignment
-
ExceptionDuringInterrupt
Trap:
- Syscall
When an interrupt occurs and is serviced, the following actions occur. (If the interrupt is not serviced, it remains pending, as discussed later, and will be serviced at some other time.)
First, the currently executing instruction is finished. In the case of an asynchronous (hardware) interrupt, the current instruction runs to completion and the PC is left pointing at the next instruction. In the case of an exception, the instruction execution is preempted and the PC is left pointing to the offending instruction. Furthermore, in the case of an exception, the offending instruction has no effect; the state of the CPU and memory is not altered. It is as if the instruction had never been attempted. In the case of a ÒsyscallÓ trap, the PC is left pointing to the instruction following the ÒsyscallÓ.
Second, an Òexception info wordÓ is pushed onto the stack. In the case of a PageInvalid or PageReadOnly exception, the offending virtual memory address will be pushed onto the system stack. In the case of a ÒsyscallÓ trap, the Òsystem trap numberÓ will be pushed onto the system stack. By pushed onto the system stack, we mean that System Register Òr15Ó (not User Register r15) will be used. For all other interrupt types, the Òexception info wordÓ will be all zeros.
Third, the Status Register will be pushed onto the system stack.
Fourth, the PC will be pushed onto the system stack. At this point, the system stack looks like this:
|
|
r15-->| Return Address |
| Status
Register |
| Except.
Info Word |
| .
|
| . |
| .
|
---------------------
Fifth, the following bits of the Status Register will be changed. This will change the CPU to System Mode, disable subsequent interrupts, and disable address translation via the page table.
I := 0
S := 1
P := 0
Sixth, the PC will be loaded with the address of one of the Interrupt Vector entries. This has the effect of causing a branch to the appropriate interrupt handler code. The interrupt vector consists of several words stored in low memory, as shown below. In particular, there is one word for each type of interrupt. The table below gives the addresses of the table entries (in hex). (Normally, the OS would have stored into each word of this table a ÒjumpÓ instruction, which will branch to the first instruction of the interrupt handler for that type of interrupt.) In this step, the PC is simply loaded with the corresponding address from the following table.
Interrupt Vector in Low Memory
Address
Description
Maskable
=======
==========================
========
000000 Power On Reset
No
000004 Timer Interrupt
Yes
000008 Disk Interrupt
Yes
00000C Serial Interrupt Yes
000010 Hardware Fault
No
000014 Illegal Instruction
No
000018 Arithmetic Exception Yes
00001C Address Exception
No
000020 Page Invalid Exception No
000024
Page Readonly
Exception No
000028 Privileged Instruction No
00002C Alignment Exception
No
000030 Exception During Interrupt No
000034 Syscall Trap
Yes
To repeat what happens, given the type of the interrupt, the corresponding address (from the above table) is moved into the PC. This will cause a transfer of control directly into the table. Normally, each table entry will hold a ÒjumpÓ instruction; if so, this jump instruction will be executed on the following instruction cycle, causing a second transfer of control to the correct interrupt handler routine.
Some interrupts can be handled simply by the interrupt handler routine and a return to the interrupted process can be made fairly quickly. (For example, a Serial Interrupt may indicate that the user has pressed a character key on the keyboard. It may be adequate to simply query the device and save the character in some sort of a buffer before returning to the interrupted process. The details are operating system dependent.)
The Return From Interrupt instruction (the ÒretiÓ instruction) would normally be used to return from an interrupt handler routine to the interrupted process. The ÒretiÓ instruction works as follows. First, the ÒretiÓ instruction will restore the PC by popping the top value from the from system stack and moving it into the PC, thereby preparing a return in the flow-of-control back to the interrupted process. Then, ÒretiÓ will restore the Status Register, by popping the next value from the from system stack into the Status Register. Then, ÒretiÓ will pop and discard the next value (the exception info word) from the system stack. After ÒretiÓ has completed, instruction execution will then resume in the interrupted process.
Generally, the interrupted process will be a user-level process and so will have been executing in User Mode, although sometimes interrupts will occur while the kernel itself is executing. If a User Mode process was interrupted, none of its registers will have been modified while the handler routine serviced the interrupt, since the interrupt handler executed in System Mode. If the handler routine was written correctly, the interrupted process will be entirely unaffected and unaware that it was interrupted.
For example, if the interrupt was a PageInvalid or PageReadOnly exception, then presumably the necessary page will have been moved into a memory frame during the execution of the interrupt handler. The PC will have been left pointing to the instruction that caused the exception. Upon return, the interrupted instruction will be re-tried and will succeed this time (unless another different interrupt occurs first).
Masking
Interrupts
Some interrupt types are said to be ÒmaskableÓ and the rest are ÒunmaskableÓ. When an unmaskable interrupt occurs, it will be serviced as soon as possible, namely on the next instruction cycle. Maskable interrupts may be serviced either immediately or at some later time, when the software is ready to deal with the interrupt. (By ÒservicedÓ, we mean that the interrupt processing sequence discussed above will be performed. Three words will be pushed onto the system stack and a branch will be made to the interrupt handling routine.)
The Interrupt Enabled bit (the ÒIÓ bit) in the Status Register determines whether a maskable interrupt will be serviced when it occurs. If the ÒIÓ bit is set to one, then the interrupt will be serviced immediately, without delay (i.e., within the current or next instruction cycle) and a transfer will be made to the handler routine.
If the interrupt type is unmaskable, then interrupt processing will occur regardless of the state of the ÒIÓ bit. The interrupt cannot be masked or disabled. If the interrupt is signaled, the interrupt sequence will occur and a transfer will be made to the corresponding handler.
If the interrupt type is maskable, and the ÒIÓ was previously cleared to zero, then the interrupt servicing sequence will not occur. No transfer to the handler routine will be made and instruction execution will continue without interruption. Furthermore, the interrupt will remain ÒpendingÓ. That is, the moment that interrupts are re-enabled (by setting the ÒIÓ bit to one), the interrupt servicing sequence will be initiated and a transfer to the interrupt handler will occur.
There may be several interrupts pending, but within a single interrupt type, there will be at most one pending interrupt. For example, there could be a Disk Interrupt and a Timer Interrupt both pending, but there can be at most one Disk Interrupt pending. Of course the disk device may repeatedly request a Disk Interrupt after the first has been fully serviced (and the ÒIÓ has been reset to one, re-enabling interrupts) causing the handler to be invoked a second time.
Exception
During Interrupt
During interrupt servicing, data is pushed onto the system stack. If system register Òr15Ó is not aligned properly or points to an invalid address, there are going to be problems. In other words, an ÒAddress ExceptionÓ or an ÒAlignment ExceptionÓ can occur during the processing of interrupts.
(Note that an exception may occur during the servicing of an exception. To be precise and avoid infinite regress, we should probably avoid saying that Òan exception occurs during the servicing of an exceptionÓ and just talk about what happens.)
What happens when we have problems while servicing an interrupt? The current interrupt is abandoned and the PC is loaded with the address of the ExceptionDuringInterrupt entry in the low-memory interrupt vector. While processing the original interrupt, the processor may have successfully pushed one or two words onto the system stack before encountering a problem. In any event, no further attempt to push words onto the stack is made. Instead, the branch is immediately made to the ExceptionDuringInterrupt handler.
Presumably, an ExceptionDuringInterrupt indicates a catastrophic software failure of the operating system itself and will be handled by printing a final message before terminating the operating system.
Virtual
Memory Address Translation and The Page Table
The Paging Enabled bit in the Status Register (the ÒPÓ bit) tells whether virtual memory address translation is turned on or not. If the ÒPÓ bit is cleared to zero, then there is no address translation. Every address generated during instruction execution is used Òas isÓ as an index into physical memory. By Òphysical memoryÓ, we mean the main memory of the processor.
Physical addresses are a full 32 bits. If a physical address is beyond the end of the installed memory, then an Address Exception occurs and interrupt servicing begins (as discussed later). A 32 bit address allows up to 4G bytes to be installed and addressed, although since I/O devices are memory-mapped, several addresses will be unavailable for use. The Interrupt vector lies in low memory and memory-mapped I/O devices will be mapped into the highest addresses in the physical address space.
The BLITZ processor includes a Memory Management Unit (MMU), which is either enabled or disabled, as determined by the ÒPÓ bit. When enabled, the MMU provides a simple page-table based translation scheme, which may be used by an operating system to implement virtual memory.
As a program is running and instructions are being executed one after another, ÒlogicalÓ addresses are generated. Every instruction must be fetched from memory, so the execution of each instruction always begins by fetching a 32-bit word from memory. The current value of the PC is used as the logical address of the word to fetch. Many instructions will not access memory again; all of their action will be done using CPU registers only. However, several instructions (such as ÒloadÓ and ÒstoreÓ) will go to memory a second time. The ÒloadÓ instruction will fetch from memory and the ÒstoreÓ will write data to memory. One instruction, the Òtest and setÓ (ÒtsetÓ) instruction, will go to memory two more times. The tset instruction will fetch a word and then will store data to that same word. Regardless of which instruction is being executed, the CPU will generate a stream of ÒlogicalÓ addresses that will be used to fetch and store data from/to memory. Logical addresses are 32-bits long.
When address translation is disabled, the ÒlogicalÓ addresses will be used as ÒphysicalÓ addresses directly. There will be no translation: the address will be used as is.
When address translation is enabled, the logical address will be broken into three fields, denoted ÒxxxÓ, ÒpppÓ, and ÒoooÓ below. The full 32-bit logical address is shown below, with the bits numbered.
31
28 24 20 16 12 8 4 0
====
==== ==== ==== ====
==== ==== ====
xxxx
xxxx pppp pppp pppo
oooo oooo oooo
xxxxxxxx - high order bits (8 bits)
ppppppppppp - page number (11 bits)
ooooooooooooo - offset (13 bits)
Page Size = 8K bytes
Page Table Entry = 4 bytes (32-bits)
Max Page Table Size = 2K entries = 8K bytes
The high-order 8 bits of a logical address (ÒxxxÓ) are ignored and zeros are used. This limits the amount of addressable memory to 16M bytes, i.e., the amount that can be addressed with only 24 bits of address. This limits each logical address space to 16M bytes. Since the upper bits are ignored, it is not an error to address bytes outside the 16M byte limit; instead wrap-around occurs with no fanfare. Note that with a 24-bit offset (as is provided in all Format F instructions), every byte within the logical address space can be addressed.
The logical address space is broken into ÒpagesÓ and each page is 8K bytes long. Since the logical address space is 16M bytes long, there are 2K (i.e., 2048) pages in each logical address space. The ÒpppÓ field is 11 bits long and is used to select the page. Since each page is 8K bytes long, 13 bits are needed to select the individual byte within the page. This is given by the ÒoooÓ (offset) field in the logical address.
Physical memory is divided into ÒframesÓ and each frame is 8K bytes long. Frames always begin on even (8K) boundaries. Each frame can hold exactly one page, but there need not be a simple one-to-one mapping between the pages in a logical address space and the frames in physical memory. (In a simple one-to-one mapping, frame 0 holds page 0, frame 1 holds page 1, frame 2 holds page 2, and so on.) The page table allows the mapping to be more complex.
A page table is an array of Òpage table entriesÓ. Each page table entry is one word (32 bits) long. A page table may have up to 2K entries, but it may have fewer (possibly zero) entries as well. (Note that a page table of the maximum size will exactly fit into a single page/frame.)
A page table is stored in memory, not in special MMU registers. In fact, the MMU has no visible state or registers of its own, beyond the ÒPage Table Base RegisterÓ and the ÒPage Table Length RegisterÓ. At any one time, there is a current page table and this is given by the contents of these two registers. If paging is disabled, these registers and the table they point to are ignored. If paging is enabled, then these two registers define the current page table, which is used during address translation. An operating system may store other page tables in memory, but these are ignored by the hardware. Only the current table counts and it is only used if paging is enabled.
The format of an entry in a page table is given by the following fields:
31
28 24 20 16 12 8 4 0
====
==== ==== ==== ====
==== ==== ====
ffff
ffff ffff ffff fff-
---- ---- DRWV
fffffffffffffffffff - frame number (19 bits)
D - Dirty bit (1=updated, 0=not updated)
R - Referenced bit (1=referenced, 0=not
referenced)
W - Writable bit (1=writable, 0=read-only)
V - Valid bit (1=valid, 0=not valid)
(other bits) - unused (9 bits)
The frame number serves to address the frame in physical memory. 19 bits can select one out of 512K frames. (Each frame is 8K bytes. This allows addressing any byte in physical memory, since 512K * 8K bytes = 4G bytes.)
The Valid bit is checked during translation; it must be set to one. If not, a Page Invalid Exception will occur. If the CPU is trying to store into memory, the Writable bit will also be checked; it must be set to one. If not, a Page Read-Only exception will occur. The Referenced bit will be set to one by the MMU when a page is either queried or updated. The Dirty bit will be set whenever a page is updated.
The remaining 9 bits are not examined or updated. The operating system is free to store information in these bits if desired.
When presented with a logical address, if paging is enabled, the MMU will perform the following functions.
First, the appropriate entry from the current page table will be fetched into an internal (hidden and unnamed) register within the MMU. If the Valid bit is zero, a Page Invalid exception will be signaled and no further processing will be done on this instruction. If this is an attempt to store into memory, the Writable bit will be tested. If it is zero, a Page Read-Only exception will be signaled and no further processing will be done on this instruction. If both bits are OK, the frame number will be concatenated with the offset, to give the following physical address:
31
28 24 20 16 12 8 4 0
====
==== ==== ==== ====
==== ==== ====
ffff
ffff ffff ffff fffo
oooo oooo oooo
If this is an illegal address in physical memory, an Address exception will be signaled and no further processing will be done on this instruction. Otherwise, the data will be either fetched from or stored into memory at this physical address. (In the case of the ÒtsetÓ instruction, a word will be both fetched and written to the selected address.) The Referenced bit will then be set to one and, if data was stored into memory, the Dirty bit will also be set to one. All other bits will be unchanged. Finally, the page table entry will be written back to memory from the internal MMU register.
The BLITZ architecture is designed to accommodate shared memory multiprocessing, although it will be mostly used as a uniprocessor. With shared memory multiprocessing, several concurrently executing CPUs will share a single physical memory. Multiprocessor interaction and frame locking are discussed next.
Note that when the CPU generates a single memory operation (for example, an instruction fetch) there are actually several reads and writes performed on main memory. A typical memory access will include (1) a read from the page table, (2) a read and/or write to the target frame, and (3) a final update to the page table. Technically, the write back to the page table entry will occur before the actual target location is queried or updated.
In the case of a multiprocessor system, we have the possibility of interleaving of memory accesses from several processors. For example, one processor might conceivably change a page table entry that is being used by another processor.
There are several design choices in how the various memory operations are interleaved in a multi-processor system. Here are several options that were considered in the design of the BLITZ architecture.
First, an architecture might specify that the memory accesses are done independently, with no coordination or synchronization. The only thing that would be done atomically is the read-write pair performed by the ÒtsetÓ instruction. Unfortunately, with this design option, it is possible that a page table entry may not be updated correctly. For example, assume that some page table entry has its Dirty bit clear. Assume two processors both fetch the same entry, more or less simultaneously. Next, one processor updates the entry first, writing back an entry in which the Dirty bit has been changed to one. Then, the second processor writes back its version of the entry, in which the Dirty bit is still clear. The problem is that the update to the Dirty bit is lost. This is clearly unacceptable.
Second, an architecture might specify that all memory accesses (from (1) the initial read from the page table, through (2) the read and/or write to the target frame, and to (3) the final update to the page table) will be executed atomically, without interference from other processors. This could be implemented by locking each of the page frames involved. Up to two frames may be involved in a single CPU-initiated memory operation: the frame containing the page table and the target frame containing the data to be fetched and/or updated. If the architecture specifies that a processor will first get a lock on the frame containing the page table entry and then will try to get a lock on the frame containing the data before releasing the first lock, there is the possibility of deadlock. Two processors could each hold a lock on their first page while waiting to acquire a lock held by the other processor. Another serious problem with this design option is that for every single memory operation, the MMU holds a lock on a frame containing a page table entry longer than absolutely necessary, and this could slow performance whenever two processors try to run in the same logical address space.
In the BLITZ architecture, a lock is associated with each frame in memory. The lock on a frame may be acquired and released by the MMU during its operation. To perform a memory access, the MMU will first obtain a lock on the frame containing the page table entry, waiting for other processors to release locks on this frame, if necessary. The MMU will then fetch the page table entry, update it, determine if any exceptions will be signaled, write the entry back, and release the lock on the frame. Only after the lock is released, will the MMU perform the memory operation to the target address. Then, if necessary, a lock will be acquired on the second frame (containing the target address) with the CPU waiting again, if necessary. Finally, the memory operation will be performed and the second lock released. If the operation is to fetch a word or a fetch a byte, or update a word, the second lock (on the target frame) may be unnecessary if all transfers to and from the memory are in units of 32-bit words. If the memory operation is the ÒtsetÓ instruction, a second lock on the target frame must be acquired. If the memory only moves data in units of words, then an update to a single byte (e.g., the ÒstorebÓ instruction) will require a lock on the target frame as well, since an entire word must be fetched, the selected portion of the word updated, and the entire word written back to memory. Without using locks, it is possible that a second processor simultaneously updating a byte in the very same word will cause one of the updates to be lost, which is clearly unacceptable.
Note that the ÒfloadÓ and ÒfstoreÓ instructions read and write a doubleword (8 bytes) at a time. The ÒfloadÓ instruction fetches a doubleword from memory and places it in a floating-point register. The ÒfstoreÓ instruction copies a doubleword from a floating-point register to memory. In both instructions, the doubleword is moved in two separate steps, which each move a word (4 bytes). There is no locking between the two word-length operations. In a multi-processor system, there may be interleaving of these operations. As an example, consider two processors simultaneously attempting to store different doublewords into the very same address; it is possible that the words are stored in such a way that the final two-word result gets its first word from one processor and its second word from the other processor, due to interleaving of memory operations.
Exceptions
Common to All Instructions
Note that all instructions may cause the following exceptions:
Page Invalid
Address Exception
When an instruction is fetched, a word from memory must be read to obtain the instruction. If Paging is enabled, then the processor will first consult the Page Table to determine which frame in memory contains the data. If the page containing the instruction is not currently in memory, a page fault will occur, resulting in a Page Invalid exception.
Regardless of whether or not paging is enabled, a physical address will be produced before the instruction word is fetched. If this physical address points to a word that is not in the memory supplied on the specific machine (for instance, the memory address exceeds the amount of installed memory), then an Address Exception will occur.
Since these two exceptions may occur for every instruction, they are not listed separately under each instruction. However, if either of these exceptions could also be caused by attempts to fetch or store operands, that exception is listed explicitly.
Also, any of the asynchronous (hardware) interrupts or the ExceptionDuringInterrupt may occur during any instruction, so these are not listed individually for each instruction.
Alignment
Exceptions
Every BLITZ instruction is 32-bits long and must be stored in a word-aligned address in memory.
There are several ways that different architectures may enforce such an alignment restriction. The design options are: (1) Check for alignment on every instruction fetch and have Alignment Exceptions always possible. (2) Check for alignment whenever the PC is loaded (e.g., for the ÒjmpÓ, ÒcallÓ, ÒbxxÓ, and ÒretiÓ instructions) and have an Alignment Exception only for these instructions. (3) Never check for alignment; simply ignore the last 2 bits whenever the PC is loaded or used.
Option (1) requires the overhead of checking the PC on every instruction fetch. This is often wasted effort: if the previous instruction did not cause an Alignment Exception, then the next sequentially fetched instruction cannot possibly cause an exception. Option (3) requires the least overhead: since nothing is ever checked, an Alignment Exception will never occur.
The BLITZ architecture uses option (2). Any instruction that loads the PC will cause an Alignment Exception if the value being loaded into the PC is not divisible by 4. Due to a bug in some user program, it is possible that an attempt will be made to branch to an address that is not the address of a valid instruction sequence. If the bad address happens to be unaligned, it will cause an Alignment Exception and the kernel can then abort the program. (Of course it is possible that an erroneous target of a branching instructions happens to be aligned properly, in which case instruction execution will continue. What happens next depends on what data happens to lie at the target address.)
Several instructions query or modify data in memory. Some instructions move bytes and other instructions move words. Whenever a word is moved to or from memory, the address must be aligned; if it is not, these instructions will cause an Alignment Exception.
The following instructions may cause Alignment Exceptions:
load
(Format E)
loadv
(Format E)
store
(Format E)
storev (Format E)
call
jmp
bxx
push
pop
reti
ret
tset
readu (Format E)
writeu (Format E)
ldptbr
ldptlr
fload
(Format E)
fstore (Format E)
PowerOnReset
and HardwareFault
When first powered on, the BLITZ CPU begins with a PowerOnReset interrupt. At this time, volatile memory may or may not contain meaningful values, and the code that is branched to as a result of the PowerOnReset should lie in non-volatile memory. Typically, this will be ÒbootÓ code stored in read-only memory (ROM).
When the BLITZ emulator is used, the memory will be preloaded with a program (e.g., the OS kernel). When execution is initiated (e.g., with the ÒgoÓ command), the PowerOnReset interrupt processing will occur.
During normal CPU execution, the BLITZ hardware may continually perform a sequence of error and consistency checks in parallel with normal instruction execution. Normally, the software will be unaware of these checks. However, if a problem is detected by this error-checking hardware, it will be signaled by the generation of a HardwareFault interrupt. The interrupt handler might, for example, attempt a graceful shutdown of the operating system and display a message that a hardware fault has been detected.
In both the PowerOnReset and HardwareFault interrupts, we cannot assume that the system stack register has been properly initialized. An attempt to push onto this stack might result in an ExceptionDuringInterrupt. Thus, for both PowerOnReset and HardwareFault, nothing will be pushed onto the stack and the stack pointer (Òr15Ó) will be ignored. This makes any return to the interrupted process impossible. (Of course, with a PowerOnReset, there will not even be an interrupted process.)
Also, in the case of both PowerOnReset and HardwareFault interrupts, any other pending interrupts are ignored and cancelled. This is done to prevent the code invoked by the interrupt from being immediately interrupted by another interrupt, which is a distinct possibility in the case of the HardwareFault. Of course another interrupt may occur just after the HardwareFault handler begins execution, thereby confounding the shutdown sequence. To prevent this, the expectation is that the electrical signal that generates the PowerOnReset and HardwareFaults will be sent simultaneously as a ÒresetÓ signal to all peripheral devices capable of generating interrupts.
Synthetic
Instructions
Several instructions documented below are called ÒsyntheticÓ instructions. These instructions are not actually part of the BLITZ architecture. Instead, they are simple abbreviations for other BLITZ instructions. Normal, non-synthetic BLITZ instruction are referred to as ÒtrueÓ instructions.
Synthetic instructions are processed entirely by the Assembler. The assembler recognizes and accepts the synthetic instructions. The assembler produces a similar true BLITZ instruction, which performs the desired operation. Synthetic instructions are provided merely to make the programming task easier for assembly language programmers. This approach is intended to reduce the size and complexity of the BLITZ processor design and implementation.
For some instructions, there is a synthetic version in addition to one or more true BLITZ forms. The example, the Òload wordÓ instruction has the following two ÒtrueÓ formats:
load [regA+regB],regC ! Format D
load
[regA+data16],regC ! Format E
In addition, the following synthetic form is accepted by the assembler:
load [regA],regC
For this instruction, the assembler will produce a Format D instruction, using register Òr0Ó (which always contains zero) for the missing regB. In other words, the assembler will output the following instruction.
load [regA+r0],regC
For other instructions, there is only a synthetic form and no ÒtrueÓ form. For example, the Òmove into registerÓ instruction is translated by the assembler into an ÒorÓ instruction, using register Òr0Ó as the second operand. (Since Òr0Ó contains zeros, and since Òx OR zeroÓ is always just x, this simply moves the value unchanged.) The Òmove into registerÓ instruction has the following two forms:
Synthetic instruction: Assembled
identically to:
===========================
=========================
mov regA,regC
or
regA,r0,regC
mov data16,regC or r0,data16,regC
One synthetic instruction (namely ÒsetÓ) is assembled into two true BLITZ instructions, namely ÒsethiÓ and ÒsetloÓ. All other synthetic instructions are assembled into a single true BLITZ instruction.
Although synthetic instructions are not true BLITZ instructions, they are described in this document for convenience. BLITZ processors and emulators are completely ignorant of synthetic instructions; they see only true instructions.
Software tools (primarily the debugger) will occasionally disassemble memory contents, working in the reverse direction of an assembler by taking a 32-bit word, interpreting it as a BLITZ instruction, and attempting to produce a human-readable form. One consequence of using synthetic instructions is that a debugger will show only ÒtrueÓ instructions, not the synthetic instructions originally coded by the programmer.
The BLITZ Instruction Set: Notation
The next sections describe the instructions available in the BLITZ architecture.
Each section describes one, or several related, instructions. In the discussion, we use a number of abbreviations:
regA
regB
regC
data16
data24
The terms ÒregAÓ, ÒregBÓ, and ÒregCÓ stand for any of the general purpose registers, namely registers Òr0Ó, Òr1Ó, ... , Òr15Ó.
In general, the destination register or the register that is modified is denoted by ÒregCÓ and the data movement tends to be from left to right. For example, in this instruction:
add regA,regB,regC
the values in the first two registers are added and moved into the last register. This instruction is given in general form; examples of this instruction include the following:
add r5,r9,r2
add r7,r2,r0
Instructions in formats E and G contain a 16-bit field for an immediate value. Instructions in format F contain a 24-bit field for immediate data. These are denoted in the instruction descriptions with Òdata16Ó and Òdata24Ó. In most cases, the data in the fields will be sign-extended, but there are exceptions. Consult the specific instruction descriptions.
When a field is sign-extended, its most significant bit is copied into the high-order bits to fill it out to a full 32 bits. This means that the immediate fields can hold a signed value. In the case of Òdata16Ó, the value must lie between –32,768 and +32,767. In the case of Òdata24Ó, the value must lie between –8,388,608 and +8,388,607.
In some cases, the value is used as is, after being sign-extended. In this case, the data is considered to be ÒabsoluteÓ (i.e., will not change, even if the program and data are relocated to another area in memory).
In other cases, the immediate value is first added to a register before being used. For some instructions, this will be a general purpose register. For other instructions, the value will be signed-extended and added to the current value of the PC register, giving a ÒrelativeÓ address in memory, since the actual value used will change if the program and data are relocated to another area in memory.
Note that many of the instructions do not query or modify memory, while a few of the instructions will query or modify memory. The instructions that access memory all contain brackets around those operands that specify the address to be queried or modified. For example, the following instruction will store into memory; the address portion of the instruction is in brackets.
store r7,[r4+24]
If you see brackets, you know the instruction will read or update memory; if there are no brackets, memory will not be used to execute the instruction. The only exception to this rule is the short forms of the ÒpushÓ and ÒpopÓ instructions.
push r7 ! Modifies memory
pop r3 ! Queries memory at
location [r14]
Add
add regA,regB,regC
add regA,data16,regC
The contents of register regB or the immediate data value is added to the contents of regA and the result is placed in register regC. The immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The 32-bit result of binary addition is the same regardless of whether the data is interpreted as signed or unsigned. The condition codes are set based on signed arithmetic. If the mathematically correct result of the addition is not representable as a 32-bit twoÕs complement integer, the overflow bit in the Status Register will be set.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 96 (hex 60)
Format E: 128 (hex 80)
Possible Exceptions:
None
Subtract
sub regA,regB,regC
sub
regA,data16,regC
The contents of register regB or the immediate data value is subtracted from the contents of regA and the result is placed in register regC. The immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The 32-bit result of binary subtraction is the same regardless of whether the data is interpreted as signed or unsigned. The condition codes are set based on signed arithmetic. If the mathematically correct result of the subtraction is not representable as a 32-bit twoÕs complement integer, the overflow bit in the Status Register will be set.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 97 (hex 61)
Format E: 129 (hex 81)
Possible Exceptions:
None
Multiply
mul regA,regB,regC
mul regA,data16,regC
The contents of register regB or the immediate data value is multiplied by the contents of regA and the result is placed in register regC. The immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. All values are treated as signed quantities. The 32-bit result will be stored in regC. (In general, the multiplication of two 32-bit signed numbers will result in a 64-bit quantity, however this instruction only retains 32 bits of result.) The condition codes will be set according to the result of the computation. In particular, if the result of the multiplication is not representable as a 32-bit twoÕs complement integer, the overflow bit in the Status Register will be set.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 98 (hex 62)
Format E: 130 (hex 82)
Possible Exceptions:
None
Divide
div regA,regB,regC
div regA,data16,regC
The contents of register regB or the immediate data value is divided into the contents of regA and the result is placed in register regC. The immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. All values are treated as signed quantities. The condition codes will be set according to the result of the computation.
The ÒdivÓ and ÒremÓ instructions are passed two integers (ÒaÓ and ÒbÓ). They divide a by b to get a quotient (ÒqÓ) and remainder (ÒrÓ). The ÒdivÓ instruction moves ÒqÓ into regC and the ÒremÓ instruction moves ÒrÓ into regC.
Integer division is defined such that the following is always true:
a = b*q + r
Furthermore, the remainder follows the mathematical definition of the ÒmoduloÓ operator, namely that the remainder will have the same sign as b and that
0 <= abs(r) < abs(b)
Another way to look at this is that the quotient is the real quotient, rounded down to the nearest integer.
For example:
a b q r a =
b * q + r
a/b rounded
==
== == == ================= ====
=======
7 3 2 1 7 =
3 * 2 + 1
2.3
2
-7 3
-3 2 -7 = 3 * -3 + 2
-2.3 -3
7 -3
-3 -2 7 = -3 * -3 + -2 -2.3 -3
-7
-3 2 -1 -7 = -3 *
2 + -1
2.3
2
With this definition of ÒqÓ and ÒrÓ, problems can and will occur in exactly two situations.
The first problem is if ÒbÓ is zero (i.e., an attempt to divide by zero). There are no integers ÒqÓ and ÒrÓ that will satisfy the equations listed above. In this case, an Arithmetic Exception will be raised.
The second problem occurs with the following values:
a = -2147483648
b = -1
The mathematically correct answer is:
q = +2147483648
r = 0
Unfortunately, this value of q is not representable as a 32-bit twoÕs complement integer. In this case, the following values will be used and the overflow bit in the Status Register will be set.
q = -2147483648
r = 0
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 99 (hex 63)
Format E: 131 (hex 83)
Possible Exceptions:
Arithmetic Exception
Remainder
rem regA,regB,regC
rem regA,data16,regC
The contents of register regB or the immediate data value is divided into the contents of regA and the remainder is placed in register regC. The immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. All values are treated as signed quantities. The condition codes will be set according to the result of the computation
See the comments under the ÒdivÓ instruction.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 115 (hex 73)
Format E: 149 (hex 95)
Possible Exceptions:
Arithmetic Exception
Shift
Left Logical
sll regA,regB,regC
sll regA,data16,regC
The contents of register regA is shifted left by N bits and the result is placed in regC. N is a number from 0 through 31 and may be in register regB or may be specified literally. All bits except the least significant 5 bits are ignored, giving a number between 0 and 31. If N is zero, the data is not shifted. Zeros will be shifted in from the right. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 100 (hex 64)
Format E: 132 (hex 84)
Possible Exceptions:
None
Shift
Right Logical
srl regA,regB,regC
srl regA,data16,regC
The contents of register regA is shifted right by N bits and the result is placed in regC. N is a number from 0 through 31 and may be in register regB or may be specified literally. All bits except the least significant 5 bits are ignored, giving a number between 0 and 31. If N is zero, the data is not shifted. Zeros will be shifted in from the left. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 101 (hex 65)
Format E: 133 (hex 85)
Possible Exceptions:
None
Shift
Right Arithmetic
sra regA,regB,regC
sra regA,data16,regC
The contents of register regA is shifted right by N bits and the result is placed in regC. N is a number from 0 through 31 and may be in register regB or may be specified literally. All bits except the least significant 5 bits are ignored, giving a number between 0 and 31. If N is zero, the data is not shifted. The sign bit will be duplicated and shifted in from the left, thus preserving the sign of the value and implementing a signed divide by a power of 2. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 102 (hex 66)
Format E: 134 (hex 86)
Possible Exceptions:
None
Or
or regA,regB,regC
or regA,data16,regC
The contents of register regB or the immediate data value is logically ORed with the contents of regA and the result is placed in register regC. Note that the immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 103 (hex 67)
Format E: 135 (hex 87)
Possible Exceptions:
None
And
and regA,regB,regC
and regA,data16,regC
The contents of register regB or the immediate data value is logically ANDed with the contents of regA and the result is placed in register regC. Note that the immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 104 (hex 68)
Format E: 136 (hex 88)
Possible Exceptions:
None
And-Not
andn regA,regB,regC
andn regA,data16,regC
The contents of register regB or the immediate data value is first logically NEGATEDed. The resulting 32-bit value is then logically ANDed with the contents of regA and the result is placed in register regC. Note that the immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 105 (hex 69)
Format E: 137 (hex 89)
Possible Exceptions:
None
Exclusive-Or
xor regA,regB,regC
xor regA,data16,regC
The contents of register regB or the immediate data value is logically EXCLUSIVE-ORed with the contents of regA and the result is placed in register regC. Note that the immediate value is encoded as a sign-extended 16-bit value; therefore it must lie between –32768 and 32767. The condition codes will be set according to the result of the computation.
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format D: 106 (hex 6A)
Format E: 138 (hex 8A)
Possible Exceptions:
None
Compare
Synthetic instruction: Assembled
identically to:
===========================
=========================
cmp regA,regB
sub
regA,regB,r0
cmp regA,data16
sub
regA,data16,r0
In the first form, the contents of regA are compared to the contents of register regB. In the second form, a 16-bit immediate value is sign extended to 32 bits. Register regA is compared with this value.
This instruction will normally be following by a conditional branch instruction. In the following example code, the branch to ÒlabelÓ would be taken if the value in register r4 is less than 100.
cmp r4,100
bl label
Condition Codes:
Modified to reflect the comparison
Privileged:
No
Opcodes:
(see the "sub" instruction)
Possible Exceptions:
None
Arithmetic
Negation
Synthetic instruction: Assembled
identically to:
===========================
=========================
neg
regB,regC
sub
r0,regB,regC
neg regC
sub
r0,regC,regC
This instruction negates a word, using 2Õs complement, 32-bit arithmetic. In the first form, the value in register regB is negated and is moved into register regC. In the second form, the value in register regC is negated and returned to the same register. In either case, the condition codes are set to reflect the result.
Note that an attempt to negate the most negative value (0x80000000) will result in the same value, rather than the mathematically correct answer. (Due to the nature of 2Õs complement arithmetic, there is always one more negative integer than there are positive integers; thus one integer, when negated, cannot be represented in the same number of bits.)
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "sub" instruction)
Possible Exceptions:
None
Logical
Negation
Synthetic instruction: Assembled
identically to:
=========================== =========================
not regA,regC
xor
regA,0xFFFF,regC
not regC
xor
regC,0xFFFF,regC
This instruction logically negates a 32-bit word, flipping each bit. In the first form, the value in register regA is negated and is moved into register regC. In the second form, the value in register regC is negated and returned to the same register. In either case, the condition codes are set to reflect the result.
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "xor" instruction)
Possible Exceptions:
None
Clear
Synthetic instruction: Assembled
identically to:
===========================
=========================
clr regC
or r0,r0,regC
This instruction moves 32 bits of zeros into register regC.
Condition Codes:
Modified (Z:=1, N:=0, V:=0, C:=0)
Privileged:
No
Opcodes:
(see the "or" instruction)
Possible Exceptions:
None
Bit
Test
Synthetic instruction: Assembled
identically to:
===========================
=========================
btst regA,regB
and
regA,regB,r0
btst data16,regB
and
regB,data16,r0
This instruction tests bits in register regB to see if any are set to Ò1Ó and sets the condition codes accordingly. In the first form, register regA should contain a ÒmaskÓ with a Ò1Ó in every bit position of interest. In the second form, the instruction contains 16-bits of immediate data and these comprise the mask.
After the test, a ÒbeÓ branch will be taken if ALL the bits selected by the mask were zero, while a ÒbneÓ branch will be taken if ANY of the bits selected by the mask were one.
Note that in the second form, the immediate value will be sign-extended before being used.
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "and" instruction)
Possible Exceptions:
None
Bit
Set
Synthetic instruction: Assembled
identically to:
===========================
=========================
bset regB,regC
or
regC,regB,regC
bset data16,regC
or
regC,data16,regC
This instruction sets selected bits in register regC. In the first form, register regB should contain a ÒmaskÓ with a Ò1Ó in every bit position of interest. In the second form, the instruction contains 16-bits of immediate data and these comprise the mask. All bits in register regC that were selected by the mask will be set to Ò1Ó, while the other bits in register regC will remain unchanged.
Note that in the second form, the immediate value will be sign-extended before being used.
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "or" instruction)
Possible Exceptions:
None
Bit
Clear
Synthetic instruction: Assembled
identically to:
===========================
=========================
bclr regB,regC
andn
regC,regB,regC
bclr data16,regC
andn
regC,data16,regC
This instruction clears selected bits in register regC. In the first form, register regB should contain a ÒmaskÓ with a Ò1Ó in every bit position of interest. In the second form, the instruction contains 16-bits of immediate data and these comprise the mask. All bits in register regC that were selected by the mask will be cleared to Ò0Ó, while the other bits in register regC will remain unchanged.
Note that in the second form, the immediate value will be sign-extended before being used.
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "andn" instruction)
Possible Exceptions:
None
Bit
Toggle
Synthetic instruction: Assembled
identically to:
===========================
=========================
btog regB,regC
xor
regC,regB,regC
btog data16,regC
xor
regC,data16,regC
This instruction flips selected bits in register regC. In the first form, register regB should contain a ÒmaskÓ with a Ò1Ó in every bit position of interest. In the second form, the instruction contains 16-bits of immediate data and these comprise the mask. All bits in register regC that were selected by the mask will be flipped from Ò0Ó to Ò1Ó or vice versa, while the other bits in register regC will remain unchanged.
Note that in the second form, the immediate value will be sign-extended before being used.
Condition Codes:
Modified
Privileged:
No
Opcodes:
(see the "xor" instruction)
Possible Exceptions:
None
Move
Into Register
Synthetic instruction: Assembled
identically to:
===========================
=========================
mov regA,regC
or
regA,r0,regC
mov data16,regC
or
r0,data16,regC
In the first form, the contents of regA are moved into register regC. In the second form, a 16-bit immediate value is sign extended to 32 bits and moved into register regC.
Condition Codes:
Modified to reflect the value moved
Privileged:
No
Opcodes:
(see the
"or" instruction)
Possible Exceptions:
None
Load
Word
load [regA+regB],regC
load [regA+data16],regC
Synthetic instruction: Assembled
identically to:
===========================
=========================
load [regA],regC
load
[regA+r0],regC
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur. A 32-bit (4 byte) word is moved from the memory location given by the address into register regC.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 107 (hex 6B)
Format E: 139 (hex 8B)
Possible Exceptions:
Address Exception
Page Invalid
Alignment
Load
Byte
loadb [regA+regB],regC
loadb [regA+data16],regC
Synthetic instruction: Assembled identically
to:
===========================
=========================
loadb [regA],regC
loadb
[regA+r0],regC
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. A single byte is moved from the memory location given by the address into the least significant bits of register regC. The high-order 24-bits of the register are cleared to zero.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 108 (hex 6C)
Format E: 140 (hex 8C)
Possible Exceptions:
Address Exception
Page Invalid
Load
Word Virtual
loadv [regA+regB],regC
loadv [regA+data16],regC
Synthetic instruction: Assembled
identically to:
===========================
=========================
loadv [regA],regC
loadv
[regA+r0],regC
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur. A 32-bit (4 byte) word is moved from the memory location given by the address into register regC.
The operation of this instruction differs from the ÒloadÓ instruction only when the Page Table is disabled. When the Page Table is disabled, the ÒloadÓ instruction will generate an address which will be used as a physical address to access physical memory directly; no address translation will occur. However, the ÒloadvÓ instruction will perform address translation, even though the Page Table is disabled. The instruction is intended to be used by the kernel to fetch arguments and other data from the logical address space of a user-level program. It will cause a Page Invalid exception if there are problems in accessing the virtual address space.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format D: 109 (hex 6D)
Format E: 141 (hex 8D)
Possible Exceptions:
Address Exception
Page Invalid
Alignment
Privileged Instruction
Load
Byte Virtual
loadbv [regA+regB],regC
loadbv [regA+data16],regC
Synthetic instruction: Assembled
identically to:
===========================
=========================
loadbv [regA],regC
loadbv [regA+r0],regC
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. A single byte is moved from the memory location given by the address into the least significant bits of register regC. The high-order 24-bits of the register are cleared to zero.
The operation of this instruction differs from the ÒloadbÓ instruction only when the Page Table is disabled. When the Page Table is disabled, the ÒloadbÓ instruction will generate an address which will be used as a physical address to access physical memory directly; no address translation will occur. However, the ÒloadbvÓ instruction will perform address translation, even though the Page Table is disabled. The instruction is intended to be used by the kernel to fetch arguments and other data from the logical address space of a user-level program. It will cause a Page Invalid exception if there are problems in accessing the virtual address space.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format D: 110 (hex 6E)
Format E: 142 (hex 8E)
Possible Exceptions:
Address Exception
Page Invalid
Privileged Instruction
Store
Word
store regC,[regA+regB]
store regC,[regA+data16]
Synthetic instruction: Assembled
identically to:
===========================
=========================
store regC,[regA]
store
regC,[regA+r0]
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur. A 32-bit (4 byte) word is moved from register regC to the memory location given by the address. A Page Read-only exception will occur if the Page Table is enabled and the page containing the address is marked read-only.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 111 (hex 6F)
Format E: 143 (hex 8F)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Alignment
Store
Byte
storeb regC,[regA+regB]
storeb regC,[regA+data16]
Synthetic instruction: Assembled
identically to:
===========================
=========================
storeb regC,[regA]
storeb regC,[regA+r0]
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. A single byte is moved from register regC to the memory location given by the address. A Page Read-only exception will occur if the Page Table is enabled and the page containing the address is marked read-only.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 112 (hex 70)
Format E: 144 (hex 90)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Store
Word Virtual
storev regC,[regA+regB]
storev regC,[regA+data16]
Synthetic instruction: Assembled
identically to:
===========================
=========================
storev regC,[regA]
storev regC,[regA+r0]
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur. A 32-bit (4 byte) word is moved from register regC to the memory location given by the address.
The operation of this instruction differs from the ÒstoreÓ instruction only when the Page Table is disabled. When the Page Table is disabled, the ÒstoreÓ instruction will generate an address which will be used as a physical address to access physical memory directly; no address translation will occur. However, the ÒstorevÓ instruction will perform address translation, even though the Page Table is disabled. The instruction is intended to be used by the kernel to store results and other data into the logical address space of a user-level program. It will cause a Page Invalid exception or a Page Read-only exception if there are problems in accessing the virtual address space.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format D: 113 (hex 71)
Format E: 145 (hex 91)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Alignment
Privileged Instruction
Store
Byte Virtual
storebv
regC,[regA+regB]
storebv
regC,[regA+data16]
Synthetic instruction: Assembled
identically to:
===========================
=========================
storebv
regC,[regA] storebv regC,[regA+r0]
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. A single byte is moved from register regC to the memory location given by the address.
The operation of this instruction differs from the ÒstorebÓ instruction only when the Page Table is disabled. When the Page Table is disabled, the ÒstorebÓ instruction will generate an address which will be used as a physical address to access physical memory directly; no address translation will occur. However, the ÒstorebvÓ instruction will perform address translation, even though the Page Table is disabled. The instruction is intended to be used by the kernel to store results and other data into the logical address space of a user-level program. It will cause a Page Invalid exception or a Page Read-only exception if there are problems in accessing the virtual address space.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format D: 114 (hex 72)
Format E: 146 (hex 92)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Privileged Instruction
Call
call regA+regC
call data24
Synthetic instruction: Assembled
identically to:
===========================
=========================
call regA
call regA+r0
In the first form, the contents of regA and regB are added together to give a target address. In the second form, a 24-bit immediate value is sign extended and added to the address of the ÒcallÓ instruction itself to give a target address.
This instruction is used to invoke a subroutine. First, this instruction pushes the address of the instruction following the ÒcallÓ instruction onto the stack. Then the ÒcallÓ instruction moves the target address into the program counter (PC). Therefore, the next instruction to be executed will be the first instruction of the subroutine.
The target address should be word-aligned; if it is not divisible by 4, this instruction will cause an Alignment Exception.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 64 (hex 40)
Format F: 160 (hex A0)
Possible Exceptions:
Alignment
Address Exception
Page Invalid
Page Read-only
Jmp
jmp regA+regC
jmp data24
Synthetic instruction: Assembled
identically to:
===========================
=========================
jmp regA
jmp
regA+r0
In the first form, the contents of regA and regB are added together to give a target address. In the second form, a 24-bit immediate value is sign extended and added to the address of the ÒjmpÓ instruction itself to give a target address.
This instruction is the unconditional ÒgotoÓ instruction. This instruction moves the target address into the program counter (PC), causing control to transfer to this address.
The target address should be word-aligned; if it contains a value not divisible by 4, this instruction will cause an Alignment Exception.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 65 (hex 41)
Format F: 161 (hex A1)
Possible Exceptions:
Alignment
Return
ret
This instruction is used to return from a subroutine call. (We assume that, when the routine was originally called, the ÒcallÓ instruction pushed the return address onto the stack. This was the address of the instruction following the ÒcallÓ instruction.) The ÒretÓ instruction will pop the top of the stack into the PC, thereby effecting a transfer of control back to the calling routine.
The stack pointer should be word-aligned. If register r15 contains a value not divisible by 4, this instruction will cause an Alignment Exception. All instructions must be word aligned. If the address popped into PC is not divisible by 4, it will cause an Alignment Exception.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format A: 9 (hex 09)
Possible Exceptions:
Alignment
Address Exception
Page Invalid
Page Read-only
Conditional
Branching
bxx regA+regC
bxx data24
Synthetic instruction: Assembled
identically to:
=========================== =========================
bxx regA
bxx
regA+r0
There are 36 different branch instructions (such as ÒbeÓ, ÒbneÓ, ÒblÓ, ÒbleÓ, and so on). The above forms are schematic: there is no ÒbxxÓ instruction.
In the first form, the contents of regA and regB are added together to give a target address. In the second form, a 24-bit immediate value is sign extended and added to the address of the branch instruction itself to give a target address.
Each branch instruction is a conditional ÒgotoÓ. The instruction first tests the condition. (Each instruction tests for a different condition. See the table below.) If the condition is true, the instruction moves the target address into the program counter (PC), causing control to transfer to the target address. If the condition is false, the PC is incremented as normal, causing the next sequential instruction to be executed.
All instructions must be word aligned. If register r15 contains a value not divisible by 4, this instruction will cause an Alignment Exception. The Alignment Exception will only occur if the branch is taken.
In the following table, I, S, P, Z, V, and N represent the values of the various bits in the status register.
opcode
condition tested meaning
====== ====================
==========================================
be Z
equal to, equal to zero
bne NOT Z
not equal to, not equal to zero
bl N XOR V
less than, negative
ble Z OR (N XOR V) less than or equal to,
negative or zero
bg NOT (Z OR (N XOR V)) greater than, positive
bge NOT (N XOR V) greater than or
equal to, positive or zero
bvs V
overflow occurred
bvc NOT V overflow
did not occur
bns N
negative result
bnc NOT N
non-negative result
bss S
in system mode
bsc NOT S
in user mode
bis I interrupts
enabled
bic NOT I
interrupts disabled
bps P
page table enabled
bpc NOT P
page table disabled
Condition Codes:
Not changed
Privileged:
No
Opcodes:
Format C: 66-83 (hex 42-53)
Format F: 162-179 (hex A2-B3)
Possible Exceptions:
Alignment
Push
push regC,[--regA]
Synthetic instruction: Assembled
identically to:
===========================
=========================
push regC
push
regC,[--r15]
This instruction first decrements the contents of register regA by 4. Then, it moves the contents of register regC into the memory word addressed by the new value of regA.
The push and pop instructions are used to support stacks that grow downward in memory, from higher addresses toward low memory. Register regA is the Òstack topÓ pointer; it always points to the last item pushed onto the stack. The push instruction decrements the stack top pointer before writing a word to memory, while the pop instruction retrieves a word from memory before incrementing the stack top pointer.
By convention, register r15 will point to a stack used during procedure call and return, although nothing prevents other registers from being used simultaneously to address other stacks. To support the use of r15 as a stack register, the assembler provides a synthetic version of push and pop that specifies r15 implicitly.
Note that the push and pop instructions have utility beyond just stack operations. These instructions may also be used to walk through an array of words, while simultaneously adjusting a pointer to the next word. The push instruction can be used to both store a word of data and decrement the pointer in one operation, working downwards through the array (towards low memory). The pop instruction can be used to fetch a word of data and increment a pointer in one operation, working upwards through the array (towards high memory).
The stack should always be word-aligned. If register regA is not word aligned, an Alignment Exception will be raised.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format C: 84 (hex 54)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Alignment
Pop
pop [regA++],regC
Synthetic instruction: Assembled
identically to:
===========================
=========================
pop regC
pop
[r15++],regC
This instruction moves the contents of the word pointed to by register regA into register regC. It then increments register regA by 4.
See the comments about stacks under the pop instruction.
The stack should always be word-aligned. If register regA is not word aligned, an Alignment Exception will be raised.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format C: 85 (hex 55)
Possible Exceptions:
Address Exception
Page Invalid
Alignment
Setlo
setlo data16,regC
This instruction moves the 16 bits of immediate data into the low-order (least significant) 16 bits of register regC. The high-order 16 bits of the register are unchanged.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format G: 193 (hex C1)
Possible Exceptions:
None
Sethi
sethi data16,regC
This instruction moves the 16 bits of immediate data into the high-order (most significant) 16 bits of register regC. The low-order 16 bits of the register are unchanged.
Note that the assembler expects a 32-bit value in this instruction. It will use only the hi-order 16 bits and will ignore the lo-order bits. For example, the instruction
sethi 0x12340000,r5
will load the data 0x1234 into the register as desired, while the instruction
sethi 0x1234,r5
will load only zeros, which is probably not intended. This approach allows the programmer to use external symbols, as in:
sethi myExtSym,r5
setlo myExtSym,r5
Condition Codes: Not affected
Privileged:
No
Opcode:
Format G: 192 (hex C0)
Possible Exceptions:
None
Set
Synthetic instruction: Assembled
identically to:
===========================
=========================
set data32,regC
sethi
HI(data32),regC
setlo LO(data32),regC
This instruction moves a 32-bit immediate value into register regC. It is a synthetic instruction which expands into two BLITZ instructions. Here, we use ÒHI(data32)Ó and ÒLO(data32)Ó to mean the high-order 16 bits, and the low-order 16 bits, of the immediate 32 bit value given. No sign extension is performed.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
(see the "sethi" and "setlo"
instructions)
Possible Exceptions:
None
Load
Address
ldaddr data16,regC
This instruction is provided with a 16 bit immediate value. This value is sign-extended and added to the contents of the PC. Specifically, it is added to the PC before it is incremented; i.e., it is added to the address of the ldaddr instruction itself. The result is placed in register regC.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format G: 194 (hex C2)
Possible Exceptions:
None
System
Call
syscall
regC+data16
Synthetic instruction: Assembled
identically to:
===========================
=========================
syscall
regC
syscall regC+0
syscall
data16
syscall r0+data16
The immediate 16 bit value is sign-extended to 32 bits and is then added to the contents of register regC. This value is called the Òsystem trap numberÓ. A ÒsyscallÓ trap then occurs, as follows:
First, a copy is made of the current status register and the current PC (after being incremented to point to the instruction following the ÒsyscallÓ instruction)
Then, the following bits in the status register are changed:
I := 0 (Interrupts are disabled)
S := 1 (Mode is changed to System)
P := 0 (Paging is turned off)
Then, the system trap number is pushed onto the system stack. (Since the Mode has been changed to System Mode, all pushes will be onto the system stack, pointed to by system register r15.) Then the old value of the status register is pushed onto the stack. Then the old value of the PC (after being incremented to point to the instruction following the ÒsyscallÓ instruction) is pushed onto the system stack.
Finally, a branch into the interrupt vector in low memory is made. In other words, the PC is set to point to the ÒsyscallÓ entry in the interrupt vector. Presumably, this word will contain a ÒjumpÓ instruction and execution will branch to the ÒsyscallÓ interrupt handler.
If problems arise during the ÒsyscallÓ sequence, then an ExceptionDuringInterrupt will occur. (In other words, even if an Address Exception or Alignment Exception occurs while pushing information onto the system stack, these exceptions will not be signaled.)
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format G: 195 (hex C3)
Possible Exceptions:
Syscall
ExceptionDuringInterrupt
No-op
nop
This instruction does nothing beyond taking up a little time.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format A: 0 (hex 00)
Possible Exceptions:
None
Wait
wait
This instruction causes the CPU to suspend instruction execution. The CPU will then remain dormant in a low-power state, waiting for interrupts. If and when an interrupt occurs, execution will resume according to the normal exception handling sequence.
Condition Codes:
Not
affected
Privileged:
Yes
Opcode:
Format A: 1 (hex 01)
Possible Exceptions:
Privileged Instruction
Debug
debug
This instruction is only used in conjunction with a virtual machine BLITZ instruction emulator. When running on a real machine, this instruction is equivalent to the ÒnopÓ instruction and has no effect. When running on an emulator, this instruction will cause the emulation to be interrupted and a debugger to be invoked.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format A: 2 (hex 02)
Possible Exceptions:
None
Debug2
debug2
This instruction is only used in conjunction with a virtual machine BLITZ instruction emulator. When running on a real machine, this instruction is equivalent to the ÒnopÓ instruction and has no effect.
This instruction performs an ÒupcallÓ to the emulator, much as a syscall instruction performs an upcall from a user process to the kernel. This instruction is provides kernel code a quick and easy way to print debugging messages from anywhere, including interrupt handlers, without the overhead required of interfacing with an I/O device. This instruction will take a single clock cycle, like other instructions, and execution will continue after this instruction, unless some error occurs.
Register Òr1Ó must contain a function code. Additional arguments may be passed in other registers; details will depend on the function code in r1. The following functions are implemented.
Register r1 = 1: PrintInt. Register Òr2Ó will contain an integer. The emulator will immediately print this value on the terminal.
Register r1 = 2: Print. Register Òr2Ó will contain a pointer to a string of characters and register r3 will contain a count. The emulator will immediately print this string on the terminal.
Register r1 = 3: PrintChar. Register Òr2Ó will contain a character. The emulator will immediately print this character on the terminal.
Register r1 = 4: PrintDouble. Register Òf0Ó will contain a double. The emulator will immediately print this value on the terminal.
Register r1 = 5: PrintBool. Register Òr2Ó should contain either 0x00000000 or 0x00000001. The emulator will immediately print this value as either FALSE or TRUE.
Register r1 = 6: PrintHex. Register Òr2Ó will contain an integer. The emulator will immediately print this value in hex, e.g., 0x000012AB.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format A: 10 (hex 0A)
Possible Exceptions:
None
Clear
Interrupt Flag
cleari
This instruction disables interrupt servicing by clearing the ÒIÓ bit in the Status Register to zero. In other words, any maskable interrupt occurring after this instruction is executed will not be serviced, but will remain pending. The servicing of unmaskable interrupts will be unaffected by this instruction.
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format A: 3 (hex 03)
Possible Exceptions:
Privileged Instruction
Set
Interrupt Flag
seti
This instruction enables interrupt servicing by setting the ÒIÓ bit in the Status Register to one. If a maskable interrupt is pending when this instruction is executed, interrupt servicing will occur immediately after this instruction completes.
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format A: 4 (hex 04)
Possible Exceptions:
Privileged Instruction
Clear
Paging Flag
clearp
This instruction disables paging (i.e., virtual memory address translation) by clearing the ÒPÓ bit in the Status Register to zero.
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format A: 5 (hex 05)
Possible Exceptions:
Privileged Instruction
Set
Paging Flag
setp
This instruction enables paging (i.e., virtual memory address translation) by setting the ÒPÓ bit in the Status Register to one.
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format A: 6 (hex 06)
Possible Exceptions:
Privileged Instruction
Clear
System Mode Flag
clears
This instruction returns to User Mode by clearing the ÒSÓ bit in the Status Register to zero. Another way to return to User Mode is via the ÒretiÓ (return from interrupt) instruction.
(Note that there is no corresponding ÒsetsÓ instruction; the only way to move from User Mode to System Mode is via an interrupt (e.g., a ÒsyscallÓ trap). Any instruction to change the System Mode bit ought to be a privileged instruction; but there is no point in a ÒsetsÓ instruction since any attempt to set the bit would result in a PrivilegedInstruction exception unless the bit was already set.)
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format A: 7 (hex 07)
Possible Exceptions:
Privileged Instruction
Return
From Interrupt
reti
This instruction can be used after an interrupt handler has finished its work. First, the ÒretiÓ instruction pops the saved PC off of the stack. (Since ÒretiÓ is a privileged instruction, all popping will be done from the system stack, not the user stack.) Then the saved Status Register is popped from the stack. Finally, an additional word (the Òexception info wordÓ) is popped and discarded. The PC and Status Register are then loaded from the popped values, which will cause a return to the interrupted process. Reloading the Status Register may change the processor from System Mode to User Mode and may also re-enable Interrupts and re-enable Paging.
Condition Codes:
Reloaded
Privileged:
Yes
Opcode:
Format A: 8 (hex 08)
Possible Exceptions:
Alignment
Privileged Instruction
Address Exception
Test
and Set
tset [regA],regC
Register regA contains the address of a word in memory. This instruction moves the contents of this word into register regC. Then, it writes the value 0x00000001 into the same word in memory. This is done atomically; there will be no interrupts or exceptions between the reading of memory and the subsequent writing to memory.
This instruction may be used as a synchronization primitive in multiprocessor architectures. In multiprocessor implementations of the BLITZ architecture, no other processors are allowed to query or alter the value of the word of memory during the operation of this instruction. This instruction may also be used for synchronization control in a single processor architecture with multiple threads.
The address in register regA should be word-aligned. If register regA is not word aligned, an Alignment Exception will be raised.
Condition Codes:
Not affected
Privileged:
No
Opcode:
Format C: 88 (hex 58)
Possible Exceptions:
Address Exception
Page Invalid
Page Read-only
Alignment
Read
From User Register
readu regC,regA
readu regC,[regA+data16]
Synthetic instruction: Assembled
identically to:
===========================
=========================
readu regC,[regA]
readu
regC,[regA+0]
This instruction is used to retrieve a 32-bit word from a User Register (regC) while running in System Mode. This instruction is privileged. Normally, when running in System Mode, all references to registers will query or modify the System Registers. In the case of this instruction, however, regC refers to a User Register. (Register regA still refers to a System Register.) This instruction might be used, for example, by the kernel to obtain arguments to a system call directly from the user-level processÕs registers.
In the first form, the word is moved from the User Register regC into System Register regA.
In the second form, the immediate 16-bit value is sign-extended to 32 bits and added to the contents of System Register regA to give an address. The word retrieved from the User Register is moved into this location in memory. In this form, the address should be word-aligned; if not, an Alignment Exception will be raised.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format C: 86 (hex 56)
Format E: 147 (hex 93)
Possible Exceptions:
Privileged Instruction
Possible Exceptions caused by
Format E (regC,[regA+data16]) only:
Alignment
Address Exception
Page Invalid
Page
Read-only
Write
To User Register
writeu regA,regC
writeu [regA+data16],regC
Synthetic instruction: Assembled
identically to:
===========================
=========================
writeu [regA],regC writeu [regA+0],regC
This instruction is used to store a 32-bit word into a User Register (regC) while running in System Mode. This instruction is privileged. Normally, when running in System Mode, all references to registers will query or modify the System Registers. In the case of this instruction, however, regC refers to a User Register. (Register regA still refers to a System Register.) This instruction might be used, for example, by the kernel to store results after a system call directly into the user-level processÕs registers.
In the first form, a 32-bit word is moved from System Register regA to the User Register regC.
In the second form, the immediate 16-bit value is sign-extended to 32 bits and added to the contents of System Register regA to give an address. A 32-bit word is fetched from this address and is moved into User Register regC. In this form, the address should be word-aligned; if not, an Alignment Exception will be raised.
Condition Codes:
Not affected
Privileged:
Yes
Opcodes:
Format C: 87 (hex 57)
Format E: 148 (hex 94)
Possible Exceptions:
Privileged Instruction
Possible Exceptions caused by
Format E ([regA+data16],regC) only:
Alignment
Address Exception
Page Invalid
Load
Page Table Base Register
ldptbr regC
This instruction moves the contents of register regC into the Page Table Base Register. The Page Table must always be located on a word-aligned boundary; thus, the contents of register regC should be divisible by 4. If the contents of register regC are not divisible by 4, an Alignment Exception will occur.
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format B: 32 (hex 20)
Possible Exceptions:
Alignment
Privileged Instruction
Load
Page Table Length Register
ldptlr regC
This instruction moves the contents of register regC into the Page Table Length Register. The Page Table Length Register gives the size of the Page Table in bytes. Each Page Table entry is 4 bytes long; thus, the Page Table is always be an even multiple of 4 bytes in length. The contents of register regC should be divisible by 4. If not, an Alignment Exception will occur..
Condition Codes:
Not affected
Privileged:
Yes
Opcode:
Format B: 33 (hex 21)
Possible Exceptions:
Alignment
Privileged Instruction
Floating-Point
to Integer Conversion
ftoi fregA,regC
The floating-point value in floating-point register fregA is converted into an integer value and the result is placed in integer register regC. The condition codes are not modified.
The conversion from a floating-point to an integer is done by truncating the value to the nearest integer toward zero. Many double-precision values exceed the range of integers representable with 32-bit integers; in this case the largest or smallest integer value will be used. These rules can be summarized with these examples:
4.9 --> 4
-4.9
--> -4
9e99
--> 2,147,483,647
-9e99
--> -2,147,483,648
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 89 (hex 59)
Possible Exceptions:
None
Integer
to Floating-Point Conversion
itof regA,fregC
The integer value in integer register regA is converted into a floating-point value (with the same numerical value) and the result is placed in floating-point register fregC. The condition codes are not modified.
Note that every integer representable in 32-bits can be represented with exact precision with a double-precision floating-point value. Therefore, this instruction will always produce an exactly correct conversion, and never an approximately correct result.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 90 (hex 5A)
Possible Exceptions:
None
Floating-Point
Add
fadd fregA,fregB,fregC
The contents of the register fregB is added to the contents of fregA and the result is placed in register fregC. All registers are floating-point registers. The condition codes are not modified.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 116 (hex 74)
Possible Exceptions:
None
Floating-Point
Subtract
fsub fregA,fregB,fregC
The contents of the register fregB is subtracted from the contents of fregA and the result is placed in register fregC. All registers are floating-point registers. The condition codes are not modified.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 117 (hex 75)
Possible Exceptions:
None
Floating-Point
Multiply
fmul fregA,fregB,fregC
The contents of the register fregB is multiplied by the contents of fregA and the result is placed in register fregC. All registers are floating-point registers. The condition codes are not modified.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 118 (hex 76)
Possible Exceptions:
None
Floating-Point
Divide
fdiv fregA,fregB,fregC
The contents of the register fregB is divided into the contents of fregA and the result is placed in register fregC. All registers are floating-point registers. The condition codes are not modified. In the case of divide-by-zero, the stored result will be NAN, PLUS_INF, or NEG_INF, as appropriate.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 119 (hex 77)
Possible Exceptions:
None
Floating-Point
Compare
fcmp fregA,fregC
The contents of the register fregA is comapred to the contents of fregC. Both registers are floating-point registers. Neither register is modified, but the condition codes are set to reflect the relationship between the values. Normally, this instruction would be immediately followed by a conditional branch instruction.
This instruction will set Z=1 if the values in fregA and fregC are equal. It will set N=1 if the value in fregA is less than the value in fregC. It will set V=1 if either fregA or fregC contains NAN (the Ònot-a-numberÓ value).
Condition Codes:
Modified
Privileged:
No
Opcodes:
Format C: 91 (hex 5B)
Possible Exceptions:
None
Floating-Point
Square Root
fsqrt fregA,fregC
This instruction computes the square root of the value in register fregA and stores the result in fregC. Both registers are floating-point registers.
Condition Codes:
affected
Privileged:
No
Opcodes:
Format C: 92 (hex 5C)
Possible Exceptions:
None
Floating-Point
Negation
fneg fregA,fregC
This instruction computes the negative of the value in register fregA and stores the result in fregC. Both registers are floating-point registers.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 93 (hex 5D)
Possible Exceptions:
None
Floating-Point
Absolute Value
fabs fregA,fregC
This instruction computes the absolute value of the value in register fregA and stores the result in fregC. Both registers are floating-point registers.
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format C: 94 (hex 5E)
Possible Exceptions:
None
Floating-Point
Load
fload [regA+regB],fregC
fload [regA+data16],fregC
Synthetic instruction: Assembled
identically to:
===========================
=========================
fload [regA],fregC fload [regA+r0],fregC
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur.
A 64-bit (8 byte) value is moved from the memory location given by the address into floating-point register fregC. (Registers regA and regB are integer registers, while fregC is a floating-point register.)
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 120 (hex 78)
Format E: 150 (hex 96)
Possible Exceptions:
Address Exception
Page Invalid
Alignment
Floating-Point
Store
fstore fregC,[regA+regB]
fstore fregC,[regA+data16]
Synthetic instruction: Assembled identically to:
===========================
=========================
fstore fregC,[regA] fstore fregC,[regA+r0]
In the first form, the contents of regA and regB are added together to give an address. In the second form, a 16-bit immediate value is sign extended and added to the contents of regA to give an address. In either case, the address must be word aligned, or an alignment exception will occur.
A 64-bit (8 byte) value is moved from register fregC to the memory location given by the address. A Page Read-only exception will occur if the Page Table is enabled and the page containing the address is marked read-only (Registers regA and regB are integer registers, while fregC is a floating-point register.)
Condition Codes:
Not affected
Privileged:
No
Opcodes:
Format D: 121 (hex 79)
Format E: 151 (hex 97)
Possible Exceptions:
Address Exception
Page Invalid
Alignment