Input / Output Instructions

(to be completed)

Hardware devices need a way to communicate with the CPU, and visa versa. The Nova provides several features to allow this.

First, any given device must have a device address in the range of 01 to 76. Device 00 is not used, and device 77 is the CPU itself. Every I/O instruction must identify which device it is communicating with by including the device address as part of the instruction (and resulting machine code). In the interest of consistency, these device codes were standardized by Data General, and the following table shows the codes supported by simH and the mnemonics assigned to access them in the simH console language. The one obvious omission is device 027 which was used by many 3rd party vendors of disk controllers.

CODE  ADDR    DESCRIPTION
MDV   001   /* multiply/divide */
ECC   002   /* ECC memory control */
MAP   003   /* MMPU control */
TTI   010   /* console input */
TTO   011   /* console output */
PTR   012   /* paper tape reader */
PTP   013   /* paper tape punch */
CLK   014   /* clock */
PLT   015   /* plotter */
CDR   016   /* card reader */
LPT   017   /* line printer */
DSK   020   /* fixed head disk */
MTA   022   /* magtape */
DCM   024   /* data comm mux */
QTY   030   /* 4060 multiplexor */
DKP   033   /* disk pack */
CAS   034   /* cassette */
ALM   034   /* ALM/ULM multiplexor */
TTI1  050   /* second console input */
TTO1  051   /* second console output */

Next, a device can have up to three INPUT registers and three OUTPUT registers. The terms ‘input’ and ‘output’ are viewed from the perspective of the CPU. So an OUTPUT register is for the CPU to send data (output it) to the device, and and INPUT register is for the CPU to receive data. The three registers are identified by the letters ‘A’, ‘B’, and ‘C’.

So a simple device like a terminal would normally have a single ‘A’ output register which can be used to output bytes to the terminal, and a single ‘A’ input register for receiving bytes from the keyboard. On the other hand, a disk controller probably needs three output and three input registers in order to communicate the cylinder, track, sector, block-count, and so on as well as complex status information.

The Nova instruction set has commands that transfer data between these hardware registers and the CPU’s accumulators. For example.

DOA 1,11  ; send contents of AC1 to register 'A' on device 11
DOB 2,33  ; send contents of AC2 to register 'B' on device 33
DOC 0,27  ; send contents of AC0 to register 'C' on device 27
DIA 3,10  ; get contents of register 'A' on device 10, store in AC3
DIB 2,33  ; store contents of register 'B' of dev. 33 in AC2
DIC 1,27  ; store contents of register 'C' of dev. 27 into AC1

Note that some registers are 16-bit words, and I/O commands transfer all 16 bits. Other registers (like TTY devices) are byte size (8-bits) and only transfer those 8 bits. For byte-oriented registers, Data-Out commands simply ignore the upper bits of the AC, and Data-In commands store the byte in the lower 8 bits and clear the upper 8 bits of the AC.

Some devices like disk controllers also have access to the “High Speed Memory Bus” which allows them to access memory directly. So while the I/O registers can be used to tell the controller what block to read and where in memory the block is wanted, the controller can use the Bus to transfer the 256 words directly into memory.

In addition to the I/O registers, devices also support 3 specific control lines which can be thought of as on-off binary switches. The three lines are called Busy, Done, and Pulse (many byte-oriented devices do not use Pulse). The CPU can turn these lines on and off. The lines can be set as part of the transfer instruction, or they can be controlled without any transfer occurring by using the No-I-O syntax, NIO <device>. For example, NIOC 10 would clear Busy and Done on device 10 without any transfer taking place.

The CPU can also test Busy and Done to see what their current status is. The device, in turn, has the ability to turn off Busy and turn on Done when it completes a given task.

How this all comes together is best described in a simple scenario — sending a single byte from the CPU to the master port and displaying it on the screen. The master port zero is usually run as device 10-11. Device 10 is the input keyboard and device 11 is the output screen. Technically, however, the device is actually a hardware controller board which the CPU communicates with. It is the job of the board to communicate with the screen and keyboard. Sending a character to the screen, then, involves a number of steps.

  1. The driver for the terminal does a DOA command to send the byte to device 11, register ‘A’. It also turns on Busy by issuing a “Start” command. For example, DOAS 0,11.
  2. The terminal controller receives the byte and sets Busy.
  3. The controller sends the character to the screen, down a serial line, one bit at a time.
  4. When the byte has been completely sent, the controller turns off Busy and sets Done.
  5. The CPU receives an interrupt from device 11 and runs the appropriate routine.
  6. The driver for the terminal performs a clear by issuing NIOC 11. No I/O takes place at that time, but the Done line is turned off so that it will not interrupt again.

A similar sequence takes place in order to support input.

  1. The driver tells the controller that it is ready to receive data by turning on the Busy line with NIOS 10.
  2. The user presses a key on the keyboard, and a byte is sent to the controller.
  3. The controller turns off Busy and sets Done, interrupting the CPU.
  4. The CPU runs the appropriate driver routine which gets the byte and turns off done with DIAC 0,10.