
file :  /kb/simplekbrd.text
date :  08-Feb-1982   kb

This is the design for the simple keyboard driver for the Boot PROM.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

1) only returns single character ASCII sequences for keypresses.  NO release
   character sequences either.
2) only has control,shift, and shift-lock qualifiers.
3) in key table, a value of $FF means ignore key.
4) Release only process qualifiers.
5) has type-ahead and interrupt driven.
6) Get character routine returns one character at a time in register D0.B.
7) Shift and Regular tables on external document.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Interrupt Routine :

Get Keycode.    <--ignore errors??
if (bit D7 of Keycode set) then begin {closure}
  set Closure flag.
  clear bit D7 of Keycode.
end else clear Closure flag;

if (Shift flag set) then char := Shift_table[Keycode]
                    else char := Regular_table[Keycode];

if (char <> $FF) then {have a good key}
  if (char > $7F) then Qualifiers {process a qualifier key}
  else
    if (Closure flag set) then begin {put a character in the buffer}
       if (Control flag set) then Clear bits D7,D6,D5 of char
                                     - char := AND.B  #$1F,char
       else if (Shift_lock flag set) then {if a lower case make upper case}
         if ( (char>=$61) and (char<=$7A) ) then char := Shift_table[Keycode];

       if (not Buffer_full) then begin
         put char in Buffer at Rear.
           Rear^ := char;
         Rear := Rear+1;
         if (Rear > (@Buffer)+BufferLength) then Rear := @Buffer;
         if (Front=Rear) then Buffer_full := true;
         Buffer_empty := false;
       end;
    end;
do RTE.

++++

 Qualifiers :

   if (char = $FE) then {shift}
      if (Closure flag set) then set Shift flag
                            else clear Shift flag;
   if (char = $FD) then {control}
      if (Closure flag set) then set Control flag
                            else clear Control flag;

   if (char = $FC) then {shift lock}
      if (Closure flag set) then set Shift_lock flag
                            else clear Shift_lock flag;

   Return.

---------------------------------------------------------------------------
GetCharacter :

 while (Buffer_empty) do;
 Disable Keyboard Interrupt.
 char := Front^;
 Front := Front+1;
 if (Front > (@Buffer)+BufferLength) then Front := @Buffer;
 if (Front=Rear) then Buffer_empty := true;
 Enable Keyboard Interrupt;
 Return(char);

---------------------------------------------------------------------------
Initialize :      {can use portons of the Keyboard driver's Unitinstall code}

 Turn off interrupts on Keyboard UART.
    Set UART Command Register ($30F05) to $02.
 BufferLength := 256;
 Front := @Buffer;
 Rear := @Buffer;
 Buffer_empty := true;          {false means clear, true means set}
 Buffer_full := false;
 Closure flag := false;
 All Qualifier flags := false;

 Set baud rate and byte size for UART.
    Reset UART by writing any byte value to the Status Register ($30F03)
    Clear receive by writing any byte value to the Data Port ($30F01).
    Write a $17 to the Control Register ($30F07) for 8 bit byte, 600 baud.
 Put address of Interrupt routine entry point in Interrupt vector 6 ($78).
 Turn on interrupts on Keyboard UART.
    Force Break of Keyboard by writing $08 to the Command Register.
    Wait about 34 milliseconds for Keyboard to Reset.
    Write a $09 into Command Register to allow UART interrupt and receive data.
 set 68000 interrupt level to at least 5 so Keyboard can interrupt.
 Return.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Flags used :

  1) Buffer_empty   :  interrupt routine, get character routine
  2) Buffer_full    :  interrupt routine only
  3) Closure flag   :  interrupt routine only
  4) Control        :  qualifier flag - interrupt routine only
  5) Shift          :  qualifier flag - interrupt routine only
  6) Shift_lock     :  qualifier flag - interrupt routine only

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Code segment for GetChar :

Register useage :  A0 = Front pointer
                   A1 = address of end of buffer + 1
                   A2 = updated Front pointer
                   A3 = address of front pointer
                   A4 = address of Flag byte
; BUFMTY is the bit flag for Buffer_empty in the Flag byte.
;
; Exit : (D0.b)-next character in buffer.
;
GetChar         LEA     FLAGS,A4                ;address of Flag byte
;
; Wait for a character in the Buffer.
;
WAIT            BTST    #BUFMTY,(A4)            ;while (Buffer_empty) do;
                BNE.S   WAIT
;
; have char, check for wrap around before get char
;
                LEA     FRONT,A3                ;pointer to Front save loc
                MOVE.L  (A3),A0                 ;Front pointer
                LEA     BUFFER+BUFLEN,A1        ;end of buffer + 1
                MOVE.L  A0,A2
                ADDQ.L  #1,A2                   ;add one to pointer to get next addr
                CMP.L   A0,A2                   ;Front=end of buffer + 1 ?
                BNE.S   NOWRAP                  ;No
                LEA     BUFFER,A2               ;yes, then pointer wraps back to beginning
;
; get char - disable interrupts before hand
;
NOWRAP          ORI.W   #$0700,SR
                MOVE.B  (A0),D0                 ;get char
                MOVEA.L A2,(A3)                 ;save new Front value
                CMPA.L  REAR,A2                 ;if Front=Rear then
                BNE.S   ENBLINT                 ;Buffer_empty := true;
                BSET    #BUFMTY,(A4)
;
; enable interrupts before exit
;
ENBLINT         ANDI.W  #$F500,SR
                RTS
