Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Data General Nova
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
===Instruction set=== The machine instructions implemented below are the common set implemented by all of the Nova series processors. Specific models often implemented additional instructions, and some instructions were provided by optional hardware. ====Arithmetic instructions==== All arithmetic instructions operated between accumulators. For operations requiring two operands, one was taken from the source accumulator, and one from the destination accumulator, and the result was deposited in the destination accumulator. For single-operand operations, the operand was taken from the source register and the result replaced the destination register. For all single-operand opcodes, it was permissible for the source and destination accumulators to be the same, and the operation functioned as expected. All arithmetic instructions included a "no-load" bit which, when set, suppressed the transfer of the result to the destination register; this was used in conjunction with the test options to perform a test without losing the existing contents of the destination register. In assembly language, adding a '#' to the opcode set the no-load bit. The CPU contained a single-bit register called the carry bit, which after an arithmetic operation would contain the carry out of the most significant bit. The carry bit could be set to a desired value prior to performing the operation using a two-bit field in the instruction. The bit could be set, cleared, or complemented prior to performing the instruction. In assembly language, these options were specified by adding a letter to the opcode: 'O' β set the carry bit; 'Z' β clear the carry bit, 'C' β complement the carry bit, nothing β leave the carry bit alone. If the no-load bit was also specified, the specified carry value would be used for the computation, but the actual carry register would remain unaltered. All arithmetic instructions included a two-bit field which could be used to specify a shift option, which would be applied to the result before it was loaded into the destination register. A single-bit left or right shift could be specified, or the two bytes of the result could be swapped. Shifts were 17-bit circular, with the carry bit "to the left" of the most significant bit. In other words, when a left shift was performed, the most significant bit of the result was shifted into the carry bit, and the previous contents of the carry bit were shifted into the least significant bit of the result. Byte swaps did not affect the carry bit. In assembly language, these options were specified by adding a letter to the opcode: 'L' β shift left; 'R' β shift right, 'S' β swap bytes; nothing β do not perform a shift or swap. All arithmetic instructions included a three-bit field that could specify a test which was to be applied to the result of the operation. If the test evaluated to true, the next instruction in line was skipped. In assembly language, the test option was specified as a third operand to the instruction. The available tests were: * {{mono|SZR}} β skip on zero result * {{mono|SNR}} β skip on nonzero result * {{mono|SZC}} β skip on zero carry * {{mono|SNC}} β skip on nonzero carry * {{mono|SBN}} β skip if both carry and result are nonzero * {{mono|SEZ}} β skip if either carry or result, or both, is zero * {{mono|SKP}} β always skip * Nothing β never skip The actual arithmetic instructions were: * {{mono|MOV}} β move the contents of the source accumulator to the destination accumulator * {{mono|COM}} β move the bitwise complement of the source accumulator to the destination accumulator * {{mono|ADD}} β add source accumulator to destination accumulator * {{mono|ADC}} β take the bitwise complement of the source accumulator and add it to the destination accumulator * {{mono|NEG}} β move the negative of the source accumulator to the destination accumulator * {{mono|SUB}} β subtract the contents source accumulator from the destination accumulator * {{mono|INC}} β add 1 to the contents of the source accumulator and move to the destination accumulator * {{mono|AND}} β perform the bitwise AND of the two accumulators and place the result in the destination accumulator An example arithmetic instructions, with all options utilized, is: {{sxhl|2=nasm|ADDZR# 0,2,SNC}} This decoded as: clear the carry bit; add the contents of AC2 (accumulator 2) to AC0; circularly shift the result one bit to the right; test the result to see if the carry bit is set and skip the next instruction if so. Discard the result after performing the test. In effect, this adds two numbers and tests to see if the result is odd or even. ====Memory reference instructions==== The Nova instruction set contained a pair of instructions that transferred memory contents to accumulators and vice versa, two transfer-of-control instructions, and two instructions that tested the contents of a memory location. All memory reference instructions contained an eight-bit address field, and a two-bit field that specified the mode of memory addressing. The four modes were: * Mode 0 β absolute addressing. The contents of the address field of the instruction is zero-filled on the left and used as the target address. * Mode 1 β relative addressing. The contents of the address field of the instruction is sign extended to the left and added to the current value of the program counter (which, by the time the instruction executes, points to the next instruction). The result is used as the target address. * Mode 2 β indexed addressing. The contents of the address field of the instruction is sign extended to the left and added to the current value of accumulator 2. The result is used as the target address. * Mode 3 β indexed addressing. The contents of the address field of the instruction is sign extended to the left and added to the current value of accumulator 3. The result is used as the target address. Obviously, mode 0 was only capable of addressing the first 256 memory words, given the eight-bit address field. This portion of memory was referred to as "page zero". Page zero memory words were considered precious to Nova assembly language programmers because of the small number available; only page zero locations could be addressed from anywhere in the program without resorting to indexed addressing, which required tying up accumulator 2 or 3 to use as an index register. In assembly language, a {{code|.ZREL}} directive caused the assembler to place the instructions and data words that followed it in page zero; an {{code|.NREL}} directive placed the following instructions and data words in "normal" memory. Later Nova models added instructions with extended addressing fields, which overcame this difficulty (at a performance penalty). The assembler computed relative offsets for mode 1 automatically, although it was also possible to write it explicitly in the source. If a memory reference instruction referenced a memory address in .NREL space but no mode specifier, mode 1 was assumed and the assembler calculated the offset between the current instruction and the referenced location, and placed this in the instruction's address field (provided that the resulting value fit into the 8-bit field). The two load and store instructions were: * {{code|LDA}} β load the contents of a memory location into the specified accumulator. * {{code|STA}} β store the contents of the specified accumulator into a memory location. Both of these instructions included an "indirect" bit. If this bit was set (done in assembly language by adding a {{code|@}} to the opcode), the contents of the target address were assumed to be a memory address itself, and that address would be referenced to do the load or store. The two transfer-of-control instructions were: * {{code|JMP}} β transfers control to the specified memory location * {{code|JSR}} ("jump subroutine") β Does the same as the {{code|JMP}} instruction, but additionally loads the return address (the instruction following the {{code|JSR}} instruction in line) into accumulator 3 before jumping. As in the case of the load and store instructions, the jump instructions contained an indirect bit, which likewise was specified in assembly using the {{code|@}} character. In the case of an indirect jump, the processor retrieved the contents of the target location, and used the value as the memory address to jump to. However, unlike the load and store instructions, if the indirect address had the most significant bit set, it would perform a further cycle of indirection. On the Nova series processors prior to the Nova 3, there was no limit on the number of indirection cycles; an indirect address that referenced itself would result in an infinite indirect addressing loop, with the instruction never completing. (This could be alarming to users, since when in this condition, pressing the STOP switch on the front panel did nothing. It was necessary to reset the machine to break the loop.) The two memory test instructions were: * {{code|ISZ}} β increment the memory location, and skip the next instruction if the result is zero. * {{code|DSZ}} β decrement the memory location, and skip the next instruction if the result is zero. As in the case of the load and store instructions, there was an indirect bit that would perform a single level of indirect addressing. These instructions were odd in that, on the Novas with magnetic core memory, the instruction was executed within the memory board itself. As was common at the time, the memory boards contained a "write-back" circuit to solve the destructive-read problem inherent to magnetic core memory. But the write-back mechanism also contained a mini arithmetic unit, which the processor used for several purposes. For the {{code|ISZ}} and {{code|DSZ}} instructions, the increment or decrement occurred between the memory location being read and the write-back; the CPU simply waited to be told if the result was zero or nonzero. These instructions were useful because they allowed a memory location to be used as a loop counter without tying up an accumulator, but they were slower than performing the equivalent arithmetic instructions. Some examples of memory reference instructions: {{sxhl|2=nasm|LDA 1,COUNT}} Transfers the contents of the memory location labeled {{code|COUNT}} into accumulator 1. Assuming that {{code|COUNT}} is in .NREL space, this instruction is equivalent to {{sxhl|2=nasm|LDA 1,1,(COUNT-(.+1))}} where '.' represents the location of the LDA instruction. {{sxhl|2=nasm|JSR@ 0,17}} Jump indirect to the memory address specified by the contents of location 17, in page zero space, and deposit the return address in accumulator 3. This was the standard method for making an RDOS system call on early Nova models; the assembly language mnemonic {{code|.SYSTM}} translated to this. {{sxhl|2=nasm|JMP 0,3}} Jump to the memory location whose address is contained in accumulator 3. This was a common means of returning from a function or subroutine call, since the JSR instruction left the return address in accumulator 3. {{sxhl|2=nasm|STA 0,3,-1}} Store the contents of accumulator 0 in the location that is one less than the address contained in accumulator 3. {{sxhl|2=nasm|DSZ COUNT}} Decrement the value in the location labeled {{code|COUNT}}, and skip the next instruction if the result is zero. As in the case above, if {{code|COUNT}} is assumed to be in .NREL space, this is equivalent to: {{sxhl|2=nasm|DSZ 1,(COUNT-(.+1))}} ====I/O instructions==== The Novas implemented a channelized model for interfacing to I/O devices. In the model, each I/O device was expected to implement two flags, referred to as "Busy" and "Done", and three data and control registers, referred to as A, B, and C. I/O instructions were available to read and write the registers, and to send one of three signals to the device, referred to as "start", "clear", and "pulse". In general, sending a start signal initiated an I/O operation that had been set up by loading values into the A/B/C registers. The clear signal halted an I/O operation and cleared any resulting interrupt. The pulse signal was used to initiate ancillary operations on complex subsystems, such as seek operations on disk drives. Polled devices usually moved data directly between the device and the A register. DMA devices generally used the A register to specify the memory address, the B register to specify the number of words to be transferred, and the C register for control flags. Channel 63 referred to the CPU itself and was used for various special functions. Each I/O instruction contained a six-bit channel number field, a four-bit to specify which register to read or write, and a two-bit field to specify which signal was to be sent. In assembly language, the signal was specified by adding a letter to the opcode: 'S' for start, 'C' for clear, 'P' for pulse, and nothing for no signal. The opcodes were: * {{code|DIA}} β move the contents of the device's A register to the specified accumulator * {{code|DOA}} β send the contents of the specified accumulator to the A register of the device on the specified channel * {{code|DIB}} β move the contents of the device's B register to the specified accumulator * {{code|DOB}} β send the contents of the specified accumulator to the B register of the device on the specified channel * {{code|DIC}} β move the contents of the device's C register to the specified accumulator * {{code|DOC}} β send the contents of the specified accumulator to the C register of the device on the specified channel * {{code|NIO}} β "no I/O", a misnomer. The instruction was used to send a signal to a device without doing a register transfer. In addition, four instructions were available to test the status of a device: * {{code|SKPBN}} β skip the next instruction if the device's busy flag is set * {{code|SKPBZ}} β skip the next instruction if the device's busy flag is clear * {{code|SKPDN}} β skip the next instruction if the device's done flag is set * {{code|SKPDZ}} β skip the next instruction if the device's done flag is clear Starting a device caused it to set its busy flag. When the requested operation was completed, conventionally the device cleared its busy flag and set its done flag; most devices had their interrupt request mechanism wired to the done flag, so setting the done flag caused an interrupt (if interrupts were enabled and the device wasn't masked). ====Special instructions==== These instructions performed various CPU control and status functions. All of them were actually shorthand mnemonics for I/O instructions on channel 63, the CPU's self-referential I/O channel. * {{code|INTA}} β interrupt acknowledge. Transferred the channel number of the interrupting device to the specified accumulator. * {{code|INTDS}} β disabled all interrupts * {{code|INTEN}} β enabled all interrupts * {{code|IORST}} β I/O reset. Sent a reset signal on the I/O bus, which stopped all I/O, disabled interrupts and cleared all pending interrupts. * {{code|MSKO}} β mask out. Used the contents of the specified accumulator to set up the interrupt mask. How the mask was interpreted was up to the implementation of each I/O device. Some devices could not be masked. * {{code|READS}} β transferred the contents of the 16 front panel data switches to the specified accumulator. * {{code|HALT}} β stopped the CPU. Once halted, the CPU could be made to start again only by manual intervention at the front panel.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)