This document will attempt to describe the Data General NOVA line of 16 bit computers in sufficient detail to allow a hobbyist to begin to program the device at a machine- code level.
This document is not intended to be an in- depth analysis of the machine, nor is it intended to be a tutorial on programming the device. I've prepared it primarily as an aid to hobbyists who may have acquired one of these systems and who wish to use said system as an amusement or part of a working collection. I've tried to be as accurate as possible, but I'm sure there are errors and will welcome E-mail with any corrections.
This document is arranged in sections which cover:
Data General Corporation, of Southborough (now Westborough), Massachusetts introduced the original Nova in 1969. From those beginnings the Nova line grew into a family of compatible machines which were formidable competitors to DEC's pdp11 series.
The Nova can be simply described as a 16-bit 4-accumulator machine which operates on a load/store basis. This, in plain language, means that the ALU and data paths are sixteen bits wide (from a programmer's viewpoint), there are four ACs (Accumulators, aka "registers"), and there are no fancy addressing modes (as in the pdp11). In addition to the four 16-bit accumulators there is a single-bit register known as "Carry" which participates in arithmetic and logic instructions.
Words in memory are represented in this document thusly:
+---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+
The Nova has separate I/O and memory buses and separate classes of instructions to access each of them. Memory transfers are typically 16-bit words (although the Nova 4 can transfer 8-bit bytes) and I/O transfers are either 8-bit bytes or full 16-bit words. Both buses are sixteen bits in width.
The I/O system in the NOVA is defined by a six bit address bus yielding a total of 64 possible devices. I/O transfers involve the full 16-bit word, but devices may choose to only use a subset of those bits. A data channel facility is available for DMA functionality.
The mainstore in the Nova machines operates on a word basis, 16 bits at a time. This means that for byte- level accesses, a 16 bit quantity is taken from memory, and, in necessary, masked/ shifted to provide the desired eight bit byte. In most of the Nova machines (excepting the Nova 4) there is no hardware byte- access capability; packing and unpacking words is the responsibility of the programmer.
The Program Counter (PC) in the Nova is 15 bits in width. This feature defines the basic 32 kW memory capacity of the machine. Some Novas, beginning rather early in fact, supported memory management and mapping schemes which could boost the physical memory capacity to as high as 128 kW; logical program space, however, remained at 32 kW.
Data General chose to use the octal (base eight) numbering scheme to represent values stored in the Nova's memory and in its operation. I'll stick to that convention here; unless otherwise specified, all numbers in this document will be expressed in octal.
As mentioned earlier, Novas operate on a load/ store basis. This implies the existence of (at the very least) instructions to load an AC from main memory and to store data back to memory. There are also instructions which access memory for the purposes of program flow control (jumps) and instructions which modify memory locations (increments). All of the instructions which access, or modify, memory share the same basic instruction format.
Novas support three addressing modes, known as "Page Zero", "PC Relative", and "AC Indexed". Two of the four Accumulators may be used as index registers, these being AC2 and AC3.
The Nova produces its target (or Effective) address (E) in two steps. It first step computes the so-called "intermediate address" which is the base it uses if indirection is later required. In many cases, the intermediate address is the value required and address calculation stops there; in others, indirection is required and the intermediate address forms the first address for that process. Indirection is discussed below.
The basic format for any memory- reference instruction in the Nova is:
I /---------- Displacement ----------\ / \ / \ +---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+ \ / Mode
Bits zero through four control the instruction operation and what ACs (if any) are to participate in the instruction. The rest of the fields will be discussed here.
The Mode field controls what mode the Nova will use to access memory. As mentioned above, the Nova supports three different memory addressing models; the use of the Displacement field will vary according to the mode in use. The modes are as follows:
Here's how they work:
Once the intermediate address is formed, the machine examines the value in bit five of the instruction word. If that bit is a "1", then indirection is called for and further address computation is performed; if this bit is a "0", then the intermediate address is deemed the effective address and is used unmodified.
In indirection, the value which is fetched from the intermediate address becomes the next address in the chain. This value may, itself, be an indirect address if bit zero is a "1". If bit zero is "1", then the word specified by bits one through fifteen is fetched and the indirection cycle continues. When bit zero of the fetched word is "0", then the chain is said to be complete and the final address is the value which last came from memory.
Note that on unmapped Novas it is possible to disable (hang) the machine by way of an indirection loop. Pressing "stop" on the console will have no effect on this condition; the machine needs to be reset, and in doing so all context will be lost. Mapped Novas can have their memory management hardware cause a trap if an indirection chain goes longer than sixteen references, but this is not enabled by default. Don't do indirection loops.
Memory locations 20-27 and 30-37 behave in very special ways when accessed indirectly. These are auto-increment and auto-decrement locations, respectively. When these locations are addressed in an indirection chain, their value is increased or decreased by one before their value is fetched for use. They are especially useful for traversing lists and arrays in linear fashion. When accessed non- indirectly, they behave as normal memory locations.
The Nova has a fairly simple interrupt scheme compared to many computers. It's implemented as a single line system which implies that priority is associated with a device's physical position on the I/O bus. This is partly true, but the Nova uses a neat trick with interrupt masks which can be used to mask out interrupts from certain devices creating a form of ``interrupt priority''. In these paragraphs, I'll attempt to convey to the reader a sense of how the Nova interrupt system works.
The normal power- up default state of the machine is to have the interrupt system turned off and interrupts disabled on all the I/O devices. This is also the state following the issuance of an ``IORST'' instruction. The interrupt system is ``primed'' by the ``INTEN'' instruction and goes active after the first instruction following the INTEN.
When an (interrupt- capable) I/O device requires service, it raises an interrupt request. The CPU checks this line between each instruction and if an interrupt request is pending it enters the ``interrupt state''. In this state the interrupt flag is reset, the current PC (the next instruction to be executed, in lieu of interrupts) is saved to physical location zero, and the machine executes an indirect jump through physical location one.
It is the programmer's responsibility to place the address of the interrupt handler into location one, to enable interrupts in the first place, and to re-enable them following the completion of the interrupt. It is also the programmer's responsibility to save the state of the machine (e.g. all ACs and Carry) so the interrupted program can continue on.
With interrupts disabled immediately following an interrupt, the handler need not be concerned with itself being interrupted (unless the programmer sets it up that way) and can identify the interrupting device. This can be done either by polling or via the ``INTA'' (Interrupt Acknowledge) instruction. ``INTA'' will load the device address of the interrupting device into a selected AC when it is executed (remember to save the AC before using it!). From there, the driver program can dispatch the device and handle the request.
The basic Nova architecture isn't too big on reserved locations or ``magic'' locations, but there are a few. Locations zero and one in physical memory are reserved for the interrupt system, and there are a bank of ``special'' locations in the auto-increment and auto-decrement areas. I'll describe those here. Later machines, of course, have more reserved locations, but those are beyond the scope of this document.
Locations 20 through 37 (octal) in the logical address space (there may be two location 20s in MAPped machines) behave in a special manner when accessed indirectly. When hit via an indirection operation, these locations either increment by one or decrement by one automatically before the value is taken to be used in the effective address. 20 through 27 are the auto-incrementing addresses and 30 through 37 are the auto-decrementing ones. They behave normally when accessed directly. This makes them useful for traversing lists and areas of core.