Heath8080A — Product Design : I/O Package

Page last updated

home   release   support   design   resources   legal   site map

26-January-2002

 

On this page

ports
8250 emulation
8251 emulation
pam/8 ports

Related links

system architecture
8080a emulation
h8 processing
h-17
h-19
serial i/o
tape i/o
pam/8 gui

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} };
pamPort

Ports 360q and 361q are PAM/8 front panel control ports. They are handled in the I/O package as described in PAM/8 Port Handling below. They use none of the other features of IOtable.

u8250Port

These are all 8250 ports and are handled by 8250 Emulation.

  • Port range 350q-357q is on the TTY UART. Interrupts are raised on vector 3. The I/O package calls h19Status for Line Status Register (LSR) bits when the program INs the LSR, and it calls h19Out to deliver output when the program OUTs the data port.

  • Port range 340q-347q is on the Printer UART, which is not tied to an interrupt vector. LSR contents are generated entirely in the I/O package. We call lpOut to deliver output.

  • Port range 330q-337q is on the Modem UART, which is tied to interrupt vector 6. We call mdStatus for LSR bits and we call mdOut to deliver output.

  • Port range 320q-327q is on the auxiliary UART, used here by the AT: driver. This UART is not tied to an interrupt vector. We call atStatus for LSR bits and we call atOut to deliver output.

tapePort

These two ports are used by PAM/8 to read and write tape. They're handled by 8251 emulation.

h17Port

Ports 174q through 177q are H-17 control ports. On a real H8, port 362q is on the optional ORG/0 quarter card; it contains the side-select bit for double-sided drives and is considered an H-17 port by the emulator. (None of the other functions of the ORG/0 card are implemented in this emulator.) All I/O to this range of ports is handled by the H-17 Disk System on a pass-through basis.

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.

go to top


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

Data Register (offset 0)

If the divisor latch access bit is not set in the LCR, the last-received data byte is returned. The dataReady bit in the LSR is reset, and if the receipt of this byte was the cause of an interrupt that interrupt condition is cleared. If the loopback bit is set in the MCR, the txEmpty bit is reset as well.

If the divisor latch access bit is set in the LCR, the low-order byte of the baud rate divisor is returned.

Interrupt Enable Register (offset 1)

If the divisor latch access bit is not set in the LCR, this simply returns the value of the IER. Otherwise, the high-order byte of the baud rate divisor is returned.

Interrupt ID Register (offset 2)

Returns the content of the IID register. If there was a transmitter-empty interrupt pending, this is sufficient to clear the interrupt.

Line Control Register (offset 3)

Simply returns the content of the LCR.

Modem Control Register (offset 4)

Simply returns the content of the MCR.

Line Status Register (offset 5)

If there is a (*driverStatus) routine associated with this chip, that routine is called and its results OR'd with any line status bits generated locally. This combined value is returned to the caller.

If the txEmpty flag has made a transition from 0 to 1, a transmitter empty interrupt is scheduled if enabled. (This is done only when the bit first transitions from 0 to 1. The user program will read the IID, which clears the interrupt. Then if no character is written, this interrupt should not take place again until after the next character written causes that transition.)

Finally, any error bits are cleared.

Modem Status Register (offset 6)

The modem status bits and modem status delta bits are returned. All delta bits are cleared. If there was a modem status interrupt pending, this is sufficient to clear the condition.

Scratch Register (offset 7)

The scratch register contents are returned.

out8250

Data Register (offset 0)

If the divisor latch is not set in the LCR, the output byte is stored in the outbound data register. If there is a (*outDriver) routine associated with this chip, that routine is called to handle the character. txEmpty is reset.

If the divisor latch is set in the LCR, the output byte is stored in the low-order divisor latch register.

Interrupt Enable Register (offset 1)

If the divisor latch is not set in the LCR, the output byte is stored in the IER. Any affected interrupt conditions are set or reset.

If the divisor latch is set in the LCR, the output byte is stored in the high-order divisor latch register.

Line Control Register (offset 3)

The output byte is stored in the LCR. If the addressed 8250 chip is associated with the modem and the sendBreak bit is set, mdBreak is called to replicate the break out the modem.

Modem Control Register (offset 4)

The output data is stored in the MCR.

Scratch Register (offset 7)

The output data is stored in the MCR.

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:

ioPutSerialData

This is called by any task to put a data byte on an 8250 data input port. If the dataReady flag was already set, the overrunError flag is set. Otherwise, dataReady is set.

If receiver interrupts and/or line status interrupts are enabled, this will cause an interrupt to be scheduled.

ioRaiseSignals

Sets the DSR, CTS and CD modem signal flags, and the associated delta bits. If modem status interrupts are enabled, this will cause an interrupt to be scheduled.

ioLowerSignals

Clears the DSR, CTS and CD modem signal flags, and sets the associated delta bits. If modem status interrupts are enabled, this will cause an interrupt to be scheduled.

ioBreak

Sets the break and framing error flags, and puts a null on the data port. If line status interrupts are enabled, this will cause an interrupt to be scheduled.

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.

go to top


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.

go to top


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:

  • CB.MTL (bit 5) — Turns the MON lamp on and off.
  • CB.SPK (bit 7) — Sounds the H8 speaker (ref. PAM/8 GUI for an explanation of how this works).

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.

go to top



home   release   support   design   resources   legal   site map