Difference between revisions of "Geneve keyboard control"

From Ninerpedia
Jump to navigation Jump to search
Line 15: Line 15:
It is set to 0 when a scancode is available in the shift register at F118. The input is configured to raise an interrupt which will make MDOS read the scancode and put it in a buffer, unless interrupts are masked out (using LIMI).  
It is set to 0 when a scancode is available in the shift register at F118. The input is configured to raise an interrupt which will make MDOS read the scancode and put it in a buffer, unless interrupts are masked out (using LIMI).  


The bit is reset to 1 with the next SBZ on the control bit 1.  
The bit is reset to 1 with the next SBZ on the control bit 1.
 
Use the TB command to get the value:
 
CLR  R12
TB  8
JEQ  NONE
JNE  GOTIT
 
The Equal bit is set to the value of the CRU bit, so when the bit is 1, EQ is set to one.


=== Control bit 0 ===
=== Control bit 0 ===

Revision as of 11:42, 10 November 2011

The Geneve uses a MF1 keyboard (PC-XT). Access to the keyboard is implemented as follows:

Keyboard interface

Shift register

In MDOS mode, the address F118 is used to access the 8-bit shift register in the Gate array which stores the most recent scancode. In TI mode, the address is 8008. The address is not fully decoded; the rightmost three bits are ignored (F118 is the same as F11F).

The shift register is readable throughout the receive period of the scancode; this means you can watch the scancode coming in, shifted from left to right. This also means that you must make use of the available flag to find out whether the shift register contains the full scancode.

Available flag

The bit at CRU address 0010 (or bit 8 at base 0) is set to 1 by default. The interrupt inputs at the 9901 are all negative logic, so we need a 0 to trigger an interrupt.

It is set to 0 when a scancode is available in the shift register at F118. The input is configured to raise an interrupt which will make MDOS read the scancode and put it in a buffer, unless interrupts are masked out (using LIMI).

The bit is reset to 1 with the next SBZ on the control bit 1.

Use the TB command to get the value:

CLR  R12
TB   8
JEQ  NONE
JNE  GOTIT

The Equal bit is set to the value of the CRU bit, so when the bit is 1, EQ is set to one.

Control bit 0

The bit at CRU address 1EF0 has two functions:

  • When set to 0 (SBZ), the keyboard clock is turned off. All following keystrokes are buffered in the keyboard and are not propagated to the Gate Array.
  • When set to 1 (SBO), a reset occurs (only if the previous state was 0; otherwise no effect). This means the states of CapsLock, NumLock, and ScrollLock are set to off, the keyboard performs a self-test, clears the scancode buffer, and sends a AA code to the computer. This scancode is transmitted as any other scancode, i.e. we have to check the available flag before getting it from the shift register.

Control bit 0 can be changed in this way:

LI   R12,>1EF0
SBO  0
SBZ  0

or, when using another base value

LI   R12,>1EE0
SBO  8
SBZ  8

(Remember that the bit number is added twice on the base address.)

Control bit 1

The bit at CRU address 1EF2 also has two functions:

  • When set to 0 (SBZ), the shift register is cleared, the available flag is set to 1, and the clock line is enabled. This means the keyboard will now begin to send its buffered scancodes. The shift register is locked to 0, and any incoming scancode will be lost.
  • When set to 1 (SBO), the shift register is set to receive. The next incoming scancode will be read into the shift register. Scancodes are transmitted LSB first, so the shift register is loaded from the left. When the complete scancode has been received, the available flag is set to 0, and the clock line is disabled.

Scancode reception is done in the background, without program control. The shift register will accept a scan code at any time after the SBO. This means that the shift register should be checked whether it contains a scancode that has been received in the meantime before setting the control bit 1 to 0, since this will wipe the shift register.

Control bit 1 can be changed in this way:

LI   R12,>1EF0
SBO  1
LI   R12,>1EE0
SBZ  9

Writing a keyboard driver

MDOS offers XOP operations to query the keyboard which differs significantly from the keyboard of the TI-99/4A. If we are interested in a more low-level access, the following code shows how to get the scan codes.

Get a scancode

GETSC  LIMI 0           // Do not disturb
LOOP   LI   R12,>1EE0   // Base address 1EE0
       SBZ  9           // Clear shift register, enable keyboard
       SBO  9           // Set shift register to receive mode
       CLR  R12         // Base address 0000
WAIT   TB   8           // Listen on the available flag
       JEQ  WAIT        // As long as it is 1 (EQ=1), do the loop.
       MOVB @>F118,R1   // Get the scan code from the shift register

R1 now has the scan code in its high byte. We are using the CRU base 1EE0, so control bit 0 is bit 8, and control bit 1 is bit 9. The SBZ 9 command releases the clock line of the keyboard so that the keyboard starts transmitting a scan code if there is one in its queue. With SBO 9 the Gate Array switches to receive mode and awaits the incoming bits. We should not waste time here: If the pause between the SBZ and the SBO exceeds 0.2 ms (about 600 CPU cycles) we miss some of the incoming bits, and the scan code is incorrect.

When all 8 bits have been assembled to a byte, this byte is made available via address F118. We know that there is a new byte by monitoring bit 8 (base 0000): The Gate Array pulls down this line, and as the 9901 input is configured as an interrupt input, it will trigger an interrupt and MDOS gets the key code itself. We therefore mask the interrupts away in order to do our own handling.

Note that scan codes are quite different from the keycodes of the TI:

  • Some keys create two scancodes in sequence (like E048 for Up Arrow).
  • Key releases have a separate scancode which is the key press code plus >80.

Two subsequent scancodes arrive at a 1.3 ms interval which means a maximum rate of 768 scancodes per second, each one having 11 bits (1 start, 8 data, 1 parity, 1 stop), so that means 8448 bits/second. (Note that a keystroke requires at least two scancodes; one for press, one for release.) Adding some processing overhead this yields a connection rate of 9600 baud. Key repetition occurs with about 42 ms intervals, i.e. 23.5 characters per second.

Initialize the keyboard

INITKB LIMI 0
       LI   R12,>1EE0
       SBO  9           // Enable shift register
       SBZ  8           // Disable keyboard
       LI   R4,60       // Wait a moment
WAIT   DEC  R4
       JNE  WAIT
       SBO  8           // Reset it  
       CLR  R12
WAIT0  TB   8           // Wait for incoming code
       JEQ  WAIT0  
       LI   R1,>AA00    
       CB   @>F118,R1
       JNE  FAILED      // If not AA, something went wrong      

This is quite similar to the above. The SBO 9 line is not required if we are sure that the last operation on the control bit was not a SBZ. The normal case, as shown above, is to set the control bit to 0 only for short, directly followed by a SBO. If you replace the SBO 9 by a SBZ 9, the shift register will not be loaded with the return code.

Experiments showed that between the SBZ and the SBO a minimum delay time of around 0.17 ms should pass (about 500 cycles), or no reset will occur.

Another thing to consider is that there should be no intermediate scancodes (possibly from key releases). Before the SBZ one should try to poll remaining scancodes from the keyboard.