; KB2-BOB2.ASM ~ Implements a TV Typewriter with Decade Engineering's BOB-II, ; using the Motorola 68HC705J1A microcontroller and a PC/AT keyboard. ; ; Distributed without warranty. User must accept all risks associated with ; application of this code. (February 15, 1999) ; .pagewidth 132t .pagelength 50t .header 'PC KB2ASCII' ****************************************************************************** .PAGE * * ****************************************************************************** * IBM PC keyboard decoder BJO 12/10/98 * * This program has been written to be assembled with casm05. * * * ****************************************************************************** #nolist #INCLUDE 'H705J1A.FRK' ;Include the equates for the HC705J1A ;so that all labels can be used. #list ****************************************************************************** * * * MOR Bytes Definitions for the Main Routine * * * ****************************************************************************** org MOR fcb $20 ;enable the oscres kbinput EQU PB5 ;KB serial data input ;The IRQ input (P19) is the KB clock. rs232tx EQU PB1 ;RS232 output port. *** Program Constant Equates: ; Baud rate select table: BAUD_SEL equ $08 ; BAUD_SEL 4MHz osc 2MHz osc ; $04 19.2k 9600 ; $08 9600 4800 ; $10 4800 2400 ; $20 2400 1200 ; $40 1200 600 ; $80 600 300 org RAM clkcyc rmb 1 ;used by the IRQ service routine kbraw rmb 1 ;used by the IRQ service routine kbdata rmb 1 ;IRQ service > Main oldata rmb 1 ;used by Main echar rmb 1 ;used by Main shift rmb 1 ;used by put_char kdata rmb 1 ;used by put_char char rmb 1 ;used by send_char org EPROM Start: RSP LDA #$FF ; make port a an STA PORTA STA DDRA ; output port STA PORTB ; write 0's to port b LDA #$1F ; make portb bit 5 an input STA DDRB ; LDX #RAM ;Point to the start of RAM ClrLoop CLR 0,X ;Clear a byte INCX ;Point to the next location BNE ClrLoop ;No, Continue to clear RAM bset IRQE,ISCR ;enable the IRQ input CLI ***************************************************************************** * Main waits for the variable 'kbdata' to become a scan code from the * keyboard. The variable 'kbdata' is modified by the interrupt routine * IRQ_SVR. * ***************************************************************************** Main: lda kbdata ;wait for a key beq Main cmpa oldata beq Main ;no auto repeats allowed cmpa #$F0 ;if A=$F0, the key was released beq mn_0 ; wait for the repeat, then delete it cmpa #$E0 ;if A=$E0, it was an enhanced key beq mn_2 ; go light the enhanced LED sta oldata ; else kbdata was a ligit key jsr put_char ; translate it, and send it to BOB2 clr kbdata bra Main mn_0 clr kbdata mn_1 tst kbdata ;get the same char again beq mn_1 clr kbdata ;delete the repeated kbdata clr oldata clr echar bset 0,PORTB ;turn the enhanced LED off bra Main mn_2 bclr 0,PORTB ;turn the enhanced LED on clr kbdata mn_3 tst kbdata ;get the enhanced char beq mn_3 lda kbdata cmpa echar ;no auto repeats allowed beq mn_4 cmpa #$F0 beq mn_0 sta echar jsr put_char mn_4 clr kbdata BRA Main ***************************************************************************** * put_char converts the kb scan code in A to a ASCII character. * * * ***************************************************************************** put_char sta kdata cmpa #$76 ;if it is a ESC, blank the screen beq pc_5 cmpa #$12 ;left shift key? beq pc_4 cmpa #$59 ;right shift key? beq pc_4 clrx ;init X for a cruise thru the table tst shift ;is this an UC char? bne pc_2 pc_0 lda lctable,X ;get a token beq pc_x ;end of table? cmpa kdata ; A=scan code ? beq pc_1 ; yes, get acsii char incx ; no, increment x to the incx ; next scan code bra pc_0 ; test again pc_1 incx ; increment pointer to the char lda lctable,X ; get the char sta char jsr send_char ; send it to the BOB2 bra pc_x pc_2 lda uctable,X ;get a token beq pc_x ;end of table? cmpa kdata beq pc_3 incx incx bra pc_2 pc_3 incx lda uctable,X sta char jsr send_char clr shift bra pc_x pc_4 lda #$FF sta shift bra pc_x pc_5 jsr blank pc_x clr kbdata rts ****************************************************************************** * NOTE: These tables were built for the BOB2 character set. * * ****************************************************************************** lctable: FCB $45,$30 ;0 (scan code from keyboard,ascii char) FCB $16,$31 ;1 FCB $1E,$32 ;2 FCB $26,$33 ;3 FCB $25,$34 ;4 FCB $2E,$35 ;5 FCB $36,$36 ;6 FCB $3D,$37 ;7 FCB $3E,$38 ;8 FCB $46,$39 ;9 FCB $1C,$61 ;a FCB $32,$62 ;b FCB $21,$63 ;c FCB $23,$64 ;d FCB $24,$65 ;e FCB $2B,$66 ;f FCB $34,$67 ;g FCB $33,$68 ;h FCB $43,$69 ;i FCB $3B,$6A ;j FCB $42,$6B ;k FCB $4B,$6C ;l FCB $3A,$6D ;m FCB $31,$6E ;n FCB $44,$6F ;o FCB $4D,$70 ;p FCB $15,$71 ;q FCB $2D,$72 ;r FCB $1B,$73 ;s FCB $2C,$74 ;t FCB $3C,$75 ;u FCB $2A,$76 ;v FCB $1D,$77 ;w FCB $22,$78 ;x FCB $35,$79 ;y FCB $1A,$7A ;z FCB $76,$1B ;ESC FCB $0E,$60 ;` FCB $29,$20 ;space FCB $5A,$0D ;enter FCB $66,$08 ;back space FCB $4A,$2F ;/ FCB $4C,$3A ;: FCB $4E,$2D ;- FCB $49,$2E ;. FCB $55,$3D ;= FCB $00 ; END OF TABLE uctable: FCB $1C,$41 ;A FCB $32,$42 ;B FCB $21,$43 ;C FCB $23,$44 ;D FCB $24,$45 ;E FCB $2B,$46 ;F FCB $34,$47 ;G FCB $33,$48 ;H FCB $43,$49 ;I FCB $3B,$4A ;J FCB $42,$4B ;K FCB $4B,$4C ;L FCB $3A,$4D ;M FCB $31,$4E ;N FCB $44,$4F ;O FCB $4D,$50 ;P FCB $15,$51 ;Q FCB $2D,$52 ;R FCB $1B,$53 ;S FCB $2C,$54 ;T FCB $3C,$55 ;U FCB $2A,$56 ;V FCB $1D,$57 ;W FCB $22,$58 ;X FCB $35,$59 ;Y FCB $1A,$5A ;Z FCB $4A,$3F ;? FCB $55,$2B ;+ FCB $00 ; END OF TABLE ****************************************************************************** * This routine sends the string '{A' out to the BOB2 for a screen blank. * * ****************************************************************************** blank lda #'{' sta char jsr send_char lda #'A' sta char jsr send_char RTS ****************************************************************************** * send_char - transmit data byte in char out onto TXD pin; called by main * * * * input cond. - TXD pin defined as an output pin and TXD = 1; * * char contains byte to be tranmitted. * * output cond. - X,ACC,char = undefined; * * stack used - 2 bytes * * variables used - char: storage for transmitted data (1 byte) * * ROM used - 31 bytes (35 if sending two stop bits) * ****************************************************************************** send_char coma sta PORTA ;display the byte on port A ldx #9 ; be sending 8 data bits clc ; clear carry for start bit put_data_bits bcc send_0 ; if carry<>0, then bset rs232tx,PORTB ; send out a 1 bra jmp_bit ; finished sending a 1 send_0 bclr rs232tx,PORTB ; else send a 0 bra jmp_bit ; finished sending a 0 jmp_bit lda #2*(BAUD_SEL-1)-1 ; prepare for a 1 bit delay bsr delay_13a ; 3a+12] execute delay routine tsta ; for timing purposes only ror char ; get next data bit to send decx ; one bit sent, so dec count bne put_data_bits ; loop if more bits to send put_stop_bit nop ; for timing purposes only bset rs232tx,PORTB ; send out a one lda #2*(BAUD_SEL-1) ; prepare for a 1 bit delay bsr delay_13a ; 3a+12] execute delay routine * add the next two lines to guarantee sending two stop bits: * lda #2*(BAUD_SEL-1)+1 ; prepare for a 1 bit delay * bsr delay_13a ; a+12] execute delay routine rts ; exit (put_char) ****************************************************************************** * delay_13a - delay for 13*ACC + 12 cycles; called by get_char and put_char * * * * input cond. - ACC set to appropriate value (13*ACC + 12 cycles) * * output cond. - ACC = 0 * * stack used - 0 bytes * * variables used - none * * ROM used - 7 bytes * ****************************************************************************** delay_13a nop ; this is a 13-cycle loop nop ; tsta ; deca ; decrement loop count bne delay_13a ; loop if count not zero rts ; exit (delay_13a) ****************************************************************************** * This interrupt is set to trigger on the falling edges of the KB clock * on the IRQ input. * ****************************************************************************** IRQ_SVR: inc clkcyc ;pre_inc lda clkcyc ;which edge are we on? cmp #$01 ;the first clock is a start bit beq irq_x ;just exit cmp #$0B ;is this the last clock? bne irq_1 ;if it isn't, keep recieving lda kbraw ;if it is, get the data sta kbdata clr clkcyc ;else get ready for another one clr kbraw bra irq_x irq_1: cmp #$09 bhi irq_x ;I'm ignoring the parity bit sec ;the data is lsb first brset PB5,PORTB,irq_2 ;sample the KB data bit clc irq_2: ror kbraw ;LSB first, rotate right irq_x: bset IRQR,ISCR ;clear this interrupt RTI Here: FDB Here-Start ****************************************************************************** * * * Interrupt and Reset vectors for Main Routine * * * ****************************************************************************** ORG Vectors org Timer_INT fdb Start org IRQ_INT fdb IRQ_SVR org SWI_INT fdb Start org RESET fdb Start