Heath8080A — Product Design : I/O Package |
Page last updated |
26-January-2002 |
|
On this page
ports Related links
system architecture |
I/O Package The I/O package provides the glue between the 8080A IN/OUT instructions and the emulator's various I/O device emulations. Its primary responsibility is to classify the port address and dispatch the device-specific data handling. 8250 UART emulation is done completely in the I/O package. Minimal 8251 USART emulation is done, sufficient for PAM/8 to read and write tapes using its load/dump functions. And all of the PAM/8 port handling is done here. Ports The primary function of the I/O package is to determine whether the port is implemented and dispatch processing to a device-specific routine. Port tables are maintained that define and categorize all implemented I/O ports: typedef struct { unsigned char dataIn, // in/out are reg 0 dataOut, IER, // reg 1 IIR, // reg 2 LCR, // reg 3 MCR, // reg 4 LSR, // reg 5 MSR, // reg 6 DLL, // divisor latch DLH, // divisor latch SCR; // reg 7 } u8250, *u8250Ptr; typedef struct { unsigned char lowPort, highPort; portType type; int intMask; u8250Ptr portStructure; unsigned char (*driverStatus) (void); void (*outDriver) (unsigned char); } IOtable, *IOtablePtr; Let's fill in I/Otable and then we can walk through the whole thing group by group. IOtable ports[portCount] = { { 0360, 0361, pamPort, 0, nil, nil, nil}, { 0350, 0357, u8250Port,intMask3,&TTY, &h19Status,&h19Out}, { 0340, 0347, u8250Port,0, &Printer,nil, &lpOut}, { 0330, 0337, u8250Port,intMask6,&Modem, &mdStatus, &mdOut}, { 0320, 0327, u8250Port,0, &Aux, &atStatus, &atOut}, { 0370, 0371, tapePort, 0, nil, nil, nil}, { 0362, 0362, h17Port, 0, nil, nil, nil}, { 0174, 0177, h17Port, 0, nil, nil, nil} };
The (*driverStatus) call is one of the emulator's internal flow-control mechanisms. The target task is able to determine, based on its own momentary status, whether to return a txEmpty or rxAvailable flag to the 8080 program. This call also makes most incoming character I/O event-driven by the user program, greatly reducing emulation overhead. This feature is described further in Serial I/O and Tape I/O. The (*outDriver) call was a major performance improvement over the earlier, internal-polling method of pulling characters off the 8250 chip. By calling the device's output processing routine, character output becomes entirely event driven by the user program, greatly reducing emulation overhead. However, this also interferes with the use of transmitter-empty interrupts, which should not be used with the emulator. 8250 Emulation When the user program INs or OUTs an 8250 port, the port number is reduced to a zero-based index by subtracting the base port address, and in8250 or out8250 are called to handle the operation. Each is discussed below, register by register. in8250
out8250
Due to the architecture of the emulator, the content of the divisor latch is completely irrelevant. But the register pair is implemented for a correct emulation of the chip. Backside Emulation The above routines address emulation from the viewpoint of INs and OUTs from the H8. There are several routines that can be called by device emulators that affect 8250 emulation:
Interrupt Handling Any change in the status of a register that might cause an interrupt condition will cause a call to the interrupt scheduler, which will inspect the registers to set the Interrupt ID register in priority order — line status, receiver full, transmitter empty, and modem status. If the result of the call is that an interrupt condition is present, H8 Processing is called to set the appropriate mask bit. Otherwise, H8 Processing is called to clear the appropriate mask bit. 8251 Emulation This is a bit of a misnomer: there is precious little 8251 emulation done here. We do just enough that PAM/8 can load and dump tapes reliably. Which is all that counts, really. When a tape input and/or output file is opened or closed, Tape I/O calls the I/O package to record the flags it wants returned on an IN to the 8251 status port (371q). Any IN to that port will get whatever bits were recorded. Port 371q is also the 8251 configuration port. Any OUTs to this port are simply ignored; the emulator doesn't need any of the provided configuration information. If the receiver ready bit is set in the status byte and there is an IN to the data port (370q), tapeGetByte is called and the provided byte is returned to the caller. Otherwise, a zero is returned. If the transmitter empty bit is set in the status byte and there is an OUT to the data port (370q), tapePutByte is called to record the output byte. Otherwise it's discarded. PAM/8 Port Handling As described on the PAM/8 GUI page, when there is a mouse-down on the front panel keypad or a key-down on the gui window associated with one of the keypad keys, the I/O package is called to put the key value on the PAM/8 input port (360q). On a mouse-up event or when the key-down times out, the no-key-down value (377q) is placed on the PAM/8 input port. An IN to the input port will return the current key value. Reading the keypad is a polling process; there are no interrupts. On an OUT to the control port (360q), the LED select bits (the low 4 bits) are stored, and then the hardware control bits (the high 4 bits) are processed:
The CB.CLI (clock interrupt enable) bit and the CB.SSI (single-step enabled bit) are simply stored. They are decoded when needed by H8 Processing. An OUT to the segment select port (361q) will cause the LED select bits and the segment select bits to be sent to panelDigit to be stored for the next scheduled LED refresh. |