I/O Units are interfaces between Apple memory and the peripherals. In the emulator, it is an interface between core layer and hardware layer.
I/O Units are represented by child classes of the CUnit
class.
On the Apple memory side, only two methods are used : read
and write
. This
is much like Memory, except that the addressing is on 8 bits rather than
16.
On the peripheral side, there is no specification. Most units only consist of
soft switches. To each switch corresponds a get_<switch>
method and, if changeable, a set_<switch>
method, where
<switch>
is the switch name in lowercase.
Units have a reset
method which is
supposed to reset the unit. It is called both at the unit instantiation and when
the user presses the reset button (this is in the hardware layer).
All units are observable and should notify whenever any change occurs. Hardware layer objects should observe units to be informed of what's happening.
Compatibility: All models.
This unit is in charge of keyboard. On Apple II computer there was no keyboard buffer. This unit can only handle one key at once.
void press_key(BYTE key);
Tells the unit that key is being pressed. Note that if the previous key has not been read yet, it will be forgotten. The key code must be an Apple ASCII code.
void release_key();
Tells the unit that the pressed key has been released.
bool key_waiting();
Tells if there's a key waiting to be read by the Apple. This method could be very convenient for developing a buffered keyboard or a copy paste tool.
Compatibility: All models.
The Apple speaker is quite basic : it has only two levels. Speaker level is toggled by accessing to the SPKR soft switch. On the peripheral side, the current speaker level can be read.
Compatibility: All models (maybe except //c).
Game unit has three different kinds of devices : Three push buttons, four annunciators and four analog inputs.
Push buttons are connected to the joystick or paddles buttons. Button 0 is also connected to the open apple keyboard key and button 1 to the closed apple key. On a few //e models, the button 2 is connected to the shift key.
Annunciators are outputs on the game plug, capable of outputting an two levels signal (they have not been used so much, maybe not at all).
Analogs inputs are connected to the joystick X and Y axis (usually inputs 0 and 1) or to the paddles. These analog inputs worked by measuring the discharge time of a capacitor into variable resistance of paddle or joystick. The unit was only able to trigger the capacitor load and sense when it was discharged. The time is measured by a program in ROM.
It is important to simulate this mechanism as some software implements their own measuring routine. The difficulty is that it is important to synchronize the simulator to the clock so the cycle count, seen from the inside, is correct.
Switch | Off | On |
---|---|---|
AN0 | Annunciator 0 level is low | Annunciator 0 level is high |
AN1 | Annunciator 1 level is low | Annunciator 1 level is high |
AN2 | Annunciator 2 level is low | Annunciator 2 level is high |
AN3 | Annunciator 3 level is low | Annunciator 3 level is high |
PB0 | Push button 0 is released | Push button 0 is pressed |
PB1 | Push button 1 is released | Push button 1 is pressed |
PB2 | Push button 2 is released | Push button 2 is pressed |
PADDL0 | Paddle 0 capacitor is empty | Paddle 0 capacitor is loaded |
PADDL1 | Paddle 1 capacitor is empty | Paddle 1 capacitor is loaded |
PADDL2 | Paddle 2 capacitor is empty | Paddle 2 capacitor is loaded |
PADDL3 | Paddle 3 capacitor is empty | Paddle 3 capacitor is loaded |
PTRIG | Paddle capacitors are discharging | Paddle capacitors are loading |
Address | Name | Access | Effect |
---|---|---|---|
0x58 | CLRAN0 | WR | Turn AN0 switch off |
0x59 | SETAN0 | WR | Turn AN0 switch on |
0x5A | CLRAN1 | WR | Turn AN1 switch off |
0x5B | SETAN1 | WR | Turn AN1 switch on |
0x5C | CLRAN2 | WR | Turn AN2 switch off |
0x5D | SETAN2 | WR | Turn AN2 switch on |
0x5E | CLRAN3 | WR | Turn AN3 switch off |
0x5F | SETAN3 | WR | Turn AN3 switch on |
0x61 | PB0 | R7 | Read PB0 switch state |
0x62 | PB1 | R7 | Read PB1 switch state |
0x63 | PB2 | R7 | Read PB2 switch state |
0x64 | PADDL0 | R7 | Read PADDL0 switch state |
0x65 | PADDL1 | R7 | Read PADDL1 switch state |
0x66 | PADDL2 | R7 | Read PADDL2 switch state |
0x67 | PADDL3 | R7 | Read PADDL3 switch state |
0x70 | PTRIG | R | Trigger capacitor discharges* |
* : When the capacitor charge is triggered, the PTRIG switch goes true, observers are notified, then it goes back false (and observers are notified again). All that in the same clock cycle (actually during the same method call). This is the way the Game unit informs observers that they should begin discharge simulation.
Compatibility: All models.
Reference: Apple IIe Technical Reference Manual page 29 (PDF p63)
This unit takes care of graphic and text modes switching, except the double hires mode which was implemented later. The Apple ][ has one text mode and two graphic modes (low resolution and high resolution). A mixed mode allows to split the screen having 4 lines of text at the bottom and the rest in graphic mode. Each mode has two pages corresponding to different memory spaces.
Address | Name | Access | Effect |
---|---|---|---|
0x50 | TXTCLR | RW | Turn TEXT switch off |
0x51 | TXTSET | RW | Turn TEXT switch on |
0x52 | MIXCLR | RW | Turn MIXED switch off |
0x53 | MIXSET | RW | Turn MIXED switch on |
0x54 | TXTPAGE1 | RW | Turn PAGE2 switch off |
0x55 | TXTPAGE2 | RW | Turn PAGE2 switch on |
0x56 | LORES | RW | Turn HIRES switch off |
0x57 | HIRES | RW | Turn HIRES switch on |
And, on //e and later, some read addresses were added :
Compatibility: All models.
This units manages the expansion slots of the Apple. It just forwards read and write requests on the $C090-$C0FF memory space to the corresponding card's I/O unit.
Like Slot ROM Bus, this unit has to be informed when a card is inserted or removed.
void insert_card(int slot, CUnit *cardUnit);
Tells the unit that a card has been inserted. slot
is the slot number (1-7) and cardUnit
is the I/O
unit of the expansion card.
void remove_card(int slot);
Tells the unit that a card has been removed. slot
is the slot number (1-7).
Address | Name | Access | Effect |
---|---|---|---|
0x90-0x9F | RW | Forwarded to addresses 0x00-0x0F of card in slot 1 | |
0xA0-0xAF | RW | Forwarded to addresses 0x00-0x0F of card in slot 2 | |
0xB0-0xBF | RW | Forwarded to addresses 0x00-0x0F of card in slot 3 | |
0xC0-0xCF | RW | Forwarded to addresses 0x00-0x0F of card in slot 4 | |
0xD0-0xDF | RW | Forwarded to addresses 0x00-0x0F of card in slot 5 | |
0xE0-0xEF | RW | Forwarded to addresses 0x00-0x0F of card in slot 6 | |
0xF0-0xFF | RW | Forwarded to addresses 0x00-0x0F of card in slot 7 |
Compatibility: All models (probably not ][).
Reference : Apple IIe Technical Reference Manual pages 79 to 83 (PDF pp113-117)
This unit drives the Language Card Bus using three switches : LCRAM, LCBNK2 and LCWRITE.
Only LCRAM and LCBNK2 are visible from inside the Apple. LCWRITE is not an official name for this switch (I chose this one because I did not found any name in documentation).
To change state of LCWRITE, two read requests must be done on the appropriate address. A fourth switch is used in Vinace to manage that double read and is called LCWCHG.
Address | Name | Access | Effect |
---|---|---|---|
0x11 | RDLCBNK2 | R7 | Read LCBNK2 switch state |
0x12 | RDLCRAM | R7 | Read LCRAM switch state |
0x81 | R | Turn LCBNK2 on, LCRAM on, LCWRITE off | |
0x81 | RR | Turn LCBNK2 on, LCRAM off, LCWRITE on | |
0x82 | R | Turn LCBNK2 on, LCRAM off, LCWRITE off | |
0x83 | RR | Turn LCBNK2 on, LCRAM on, LCWRITE on | |
0x84-0x87 | Same as 0x80-0x83 | ||
0x88 | R | Turn LCBNK2 off, LCRAM on, LCWRITE off | |
0x89 | RR | Turn LCBNK2 off, LCRAM off, LCWRITE on | |
0x8A | R | Turn LCBNK2 off, LCRAM off, LCWRITE off | |
0x8B | RR | Turn LCBNK2 off, LCRAM on, LCWRITE on | |
0x8C-0x8F | Same as 0x88-0x8B |
Compatibility: //e and later.
This unit takes care of 40/80 columns display switching and charset switching.
Compatibility : //e, IIgs
Some Apple models had more than 12k of ROM. To access the rest of the ROM, the space $C100-$CFFF, usually reserved for peripheral ROM could be used. A window in $C300-$C3FF, corresponding to the 80 column card, can be specifically selected.
This unit drives the I/O Rom bus that takes care of $C100-$CFFF ROM switching between slot ROM and internal ROM.