; Minimal PS/2 keyboard-scancode-reader for the Cherryside 68HC11 project ; Target: 68HC11E9 in single-chip mode with BUFFALO ; Uses IC3 to detect keyboard-clock falling-edges ; Uses PC3 to sample bits from the keyboard-data line ; Uses PB0 and PB1 to drive indicator/debug LEDs ; Uses SCI for command-input: ; r = report contents of scancode buffer ; 1 = toggle LED1 ; 2 = toggle LED2 ; q = restart BUFFALO monitor ; Mike Spooner, April 2017 ; Pass this file through cpp preprocessor, then the as11 assembler #include "board.def" /* target-board specific constants */ #include "hc11e.def" /* on-chip RAM size, etc */ #include "buffalo.def" /* monitor reset addr, mapped vectors, regions */ #include "mancon.def" /* manifest constants */ #include "lib.sym" /* utility routines (in on-chip EEPROM) */ ; pin-masks for PORTB LED1 EQU $01 LED2 EQU $02 OPT c ; show cycle-counts in listing-output ORG LORAM ; variables in direct-page rcur FCB 0 ; scancode-buffer next-read-cursor wcur FCB 0 ; scancode-buffer next-write-cursor bufsiz EQU 16 ; input buffer of received scancodes (size) buf RMB bufsiz ; input buffer of received scancodes (data) prompt FCC "Ready [r,1,2,q] " FCB 0 crlf FCB CR ; CR+LF string FCB LF FCB 0 bsc FCB -1 ; p2k bitstream cursor scip FCB 0 ; p2k scancode-in-progress ORG HIRAM ; memory page 1 ; initialise the time-protected control registers and ; then initialise the rest of the system init ldx #CSREGS ; use X index-reg as ptr to base of control regs ldab TMSK2,X orab #$01 ; timer prescaler = /16 stab TMSK2,X ; initialise the SCI: ; 9600 baud, 8n1 ; transmitter enabled, transmitter-interrupts disabled, ; reciever enabled, single-drop, receiver-interrupts disabled ldab #$0C stab SCCR2,X ;ldab #$30 ; uncomment these to get 1200 baud ;stab BAUD,X ; ... ; initialise PORTB ; PORTB pins 0-1 used to drive a pair of debug LEDs ; PORTB pin 7 used to programatically generate low-going edge ldab #$00 stab PORTB,X ; install ISR for IC3 (PS/2 kbd clock-line) interrupt ldaa #$7E ; opcode of jump-to-extended-address staa PVTIC3 ldd #p2k_isr ; address of ISR std PVTIC3+1 ; set IC3 capture mode ldaa #IC3BM ; clear any already-set IC3F flag staa TFLG1,X ldaa #$02 ; set to capture IC3 falling edges staa TCTL2,X ; configure PORTC ; set to wired-OR mode (open-drain) ; PC3: keyboard data bitstream input ; due to wired-OR, unconnected PORTC pins must be set as outputs ldaa #$F7 ; PC3 set as input, others set as output staa DDRC,X ldaa #$20 ; set wired-OR mode, and disable STRA interrupts staa PIOC,X ;ldaa #$88 ; force initial PC3/PC7 pin-state ;staa PORTC,X ; DEBUG: prime the buffer with a sentinel value ;ldab #0 ;stab wcur ;ldab #$11 ;stab buf ; enable relevant interrupts bsr p2k_enai ; unmask IC3 interrupts cli ; globally enable interrupts ; main program getcmd ldy #crlf ; emit the prompt to the SCI jsr sci_putstr ldy #prompt jsr sci_putstr jsr sci_getbyte ; wait for a command byte from the SCI cmpa #CR ; if got CR beq getcmd ; skip, get next command jsr sci_putbyte ; else echo received character back try1 cmpa #'1' ; toggle LED1? bne try2 ldab #LED1 bsr bptog bra getcmd try2 cmpa #'2' ; toggle LED2? bne tryq ldab #LED2 bsr bptog bra getcmd tryq cmpa #'q' ; quit? beq done cmpa #'r' ; report? bne getcmd ; report the contents of the received-scancode buffer ldaa #' ' jsr sci_putbyte report bsr p2k_getkey cmpa #0 ; nothing to report beq getcmd jsr sci_puthex ldaa #' ' jsr sci_putbyte bra report ; until no more to report done ldy #crlf jsr sci_putstr jmp #BUFFALO ; restart the BUFFALO monitor ;----------------------------------------------------------------------- ; clear only the specified PORTB pins (drive to logic-low) ; argument: B = pin bitmask ; clobbers: B bpclr comb ; invert mask andb PORTB,X bbstor stab PORTB,X rts ; set only the specified PORTB pins (drive to logic-high) ; argument: B = pin bitmask ; clobbers: B bpset orb PORTB,X bra bbstor ; set PORTB and return to caller ; toggle only the specified PORTB pins ; argument: B = pin bitmask ; clobbers: B bptog eorb PORTB,X bra bbstor ; set PORTB and return to caller ;----------------------------------------------------------------------- ; mask PS/2 kbd interrupts ; clobbers: B p2k_disi ldab TMSK1,X andb #IC3BM^$FF ; clear IC3I p2k_ima stab TMSK1,X rts ; unmask PS/2 kbd interrupts ; clobbers: B p2k_enai ldab TMSK1,X orb #IC3BM ; set IC3I bra p2k_ima ; get next PS/2-keyboard scancode from receive-buffer ; Returns: scancode in A if any available, else returns zero ; Clobbers: Y,B ; p2k_getkey ldab rcur cmpb wcur ; if buffer logically empty... bne _grab clra ; then return 0 rts _grab ldy #buf ; retval = buf[rcur++] aby ldaa 0,Y incb cmpb #bufsiz ; if past end of buffer... blt _savrc clrb ; then wrap _savrc stab rcur rts ; p2k interrupt-service-routine, ; triggered by keyboard-clock-line falling-edges ; decodes incoming data-line bitstream into scancodes and ; appends each one to circular buffer ; p2k_isr ldaa #IC3BM ; acknowledge interrupt; clear IC3F flag staa TFLG1,X inc bsc ; advance bitstream cursor ldaa bsc beq _starb cmpa #10 beq _stopb cmpa #9 beq _rti // ignore parity-bit _datab // data-bit lsr scip ; make room for incoming data-bit ldab PORTC,X ; retrieve incoming data-bit from PC3 lslb lslb lslb lslb orb scip ; insert bit into scancode-in-progress stab scip rti _starb // start bit staa scip ; reset scancode-in-progress rti _stopb // stop bit ldab wcur ; buf[wcur++] = scancode-in-progress ldx #buf abx ldaa scip staa 0,X incb cmpb #bufsiz ; if end-of-buffer, then wrap blt _savwc clrb _savwc stab wcur ldaa #-1 ; reset bitstream cursor (-1) staa bsc _rti rti end EQU *