10 REM > USRKBD/src v0.01
   20 REM User port parallel ASCII keyboard driver
   30 REM  D0-D7  -> PB0-PB7
   40 REM  STROBE -> CB1
   50 REM  SELECT <- CB2
   60 :
   70 OSBYTE=&FFF4:IRQ2V=&206:FXESC=&26C
   80 via=&FE60
   90 :
  100 DIM mcode% &200:load%=&FFFF0A80
  110 FOR P=0 TO 1
  120   P%=load%:O%=mcode%
  130   [OPT P*3+4
  140   .exec%
  150   PHP:SEI:LDX #1
  160   .kbdInitLp1
  170   LDA IRQ2V,X:STA oldIRQ2+1,X    :\ Claim IRQ2V
  180   LDA kbdVectors+0,X:STA IRQ2V,X
  190   DEX:BPL kbdInitLp1
  200   LDA via+12:AND #&0F
  210   ORA #&C0:STA via+12            :\ CB2=low, CB1=negative edge
  220   LDA #&90:STA via+14            :\ Enable CB1
  230   LDA #&00:STA via+2             :\ PB=input
  240   PLP:RTS
  250   .kbdVectors
  260   EQUW kbdIRQ
  270   \ Should also claim KEYV to test SHIFT+CTRL for scrolling
  280   :
  290   .kbdIRQ
  300   LDA via+13:BPL oldIRQ2         :\ b7=0 - Not VIA IRQ
  310   AND #&10:BEQ oldIRQ2           :\ b4=0 - Not CB1 IRQ
  320   TYA:PHA:TXA:PHA                :\ Save registers
  330   LDA #&00:STA via+2             :\ PB=input
  340   LDA via+12:ORA #&E0:STA via+12 :\ CB2=high
  350   LDX via+0                      :\ Get kbdstatus, clear CB1
  360   AND #&0F:ORA #&C0:STA via+12   :\ CB2=low, CB1=negative edge
  370   LDA via+0                      :\ Get kbddata
  380   CPX via+0:BNE kbdIRQ3          :\ If data=status, no status
  390   LDX #0                         :\ Make status=0
  400   .kbdIRQ3
  410   \ A=character
  420   \ X=status
  430   \   b7=strobe       - ignored
  440   \   b6=special case - ignored
  450   \   b5=ctrl  \    so EOR gives
  460   \   b4=shift / function key codes
  470   :
  480   TAY:BPL kbdIRQ4                  :\ Not top-bit character
  490   TXA:AND #&30:EOR via+0:TAY       :\ Mask in CTRL+SHIFT
  500   .kbdIRQ4
  510   LDX #3
  520   .kbdSave
  530   LDA &EE,X:PHA:DEX:BNE kbdSave    :\ Save OSBYTE parameters
  540   LDA #153:JSR OSBYTE:LDX #&FD     :\ Insert with Escape processing
  550   .kbdRestore
  560   PLA:STA &F2,X:INX:BNE kbdRestore :\ Restore OSBYTE parameters
  570   PLA:TAX:PLA:TAY                  :\ Restore registers
  580   .oldIRQ2
  590   JMP oldIRQ2                      :\ And pass on
  600   :
  610   ]
  620 NEXT:IF (P%AND&FFFF)>&B00:PRINT"Code overrun":END
  630 IF (kbdIRQ AND &FFFF)<&900:PRINT "Code start too early":END
  640 PRINT"*SAVE USRKBD ";~mcode%;" ";~O%;" ";~exec%OR&FFFF0000;" ";~load%