BBC micro compatible - Keypad interface assembly listing.
By Lee Davison.
Back
; assembly code for CUBE keyboard interface ; notes for R6501AQ .... ; internal RAM is from $0040 to $00FF ; the contents of the 32 bytes from $0040 to $005F may be maintained ; by battery (not used) ; the stack pointer is 8 bits and ranges from $00FF down to $0040 LAB_00 = $00 ; port A ; bit function ; --- -------- ; 7 serial Rx ; 6 serial Tx ; 5 enable serial Tx buffer ; 0 buzzer driver ; other bits unused LAB_01 = $01 ; port B ; bit function ; --- -------- ; 7 watchdog timer reset ; other bits unused LAB_02 = $02 ; port C LAB_12 = $12 ; interrupt enable register LAB_14 = $14 ; mode control register LAB_15 = $15 ; serial comms control register LAB_16 = $16 ; serial comms status register LAB_17 = $17 ; serial comms Tx/Rx byte LAB_18 = $18 ; lower latch A LAB_1A = $1A ; upper latch A LAB_1C = $1C ; lower latch B LAB_1E = $1E ; upper latch B LAB_40 = $40 ; keyboard matrix p (written) LAB_41 = $41 ; keyboard matrix q (read) LAB_42 = $42 ; this key LAB_43 = $43 ; last key LAB_44 = $44 ; key held flag (bit 0 only) LAB_45 = $45 ; 1/2 cycle count low byte LAB_46 = $46 ; 1/2 cycle count high byte ; $47 to $FF is the available stack space .ORG $F000 ; reset vector gets here LAB_F000 JMP LAB_F00C ; go do reset ; IRQ vector gets here LAB_F003 JMP LAB_F070 ; go do IRQ ; NMI vector gets here LAB_F006 JMP LAB_F00C ; go do NMI ; start main code from here LAB_F009 JMP LAB_F09E ; go do main ; reset vector gets here - eventually ; NMI vector gets here - eventually LAB_F00C LDX #$40 ; set index LDA #$00 ; set byte LAB_F010 STA LAB_00,X ; clear memory byte INX ; increment index CPX #$00 ; all done? (redundant compare) BNE LAB_F010 ; loop if not LDX #$FF ; set X TXS ; set stack ; note that the 6501 stack grows down from $00FF ; not $01FF as on the 6502! CLD ; clear decimal flag JSR LAB_F02B ; set A, B and C ports as inputs (floating) JSR LAB_F038 ; set serial comms control & status JSR LAB_F041 ; set A and B timer values JSR LAB_F052 ; set modes and interrupts CLI ; enable interrupts JMP LAB_F009 ; go do main loop (goes to LAB_F09E) ; set A, B and C ports as inputs LAB_F02B LDA #$FF ; byte all 1's STA LAB_00 ; float port A LDA #$FF ; byte all 1's STA LAB_01 ; float port B LDA #$FF ; byte all 1's STA LAB_02 ; float port C RTS ; set serial comms control & status LAB_F038 LDA #$C0 ; set for enable Tx/Rx, ASYNC, 8NO STA LAB_15 ; set serial comms control register LDA #$00 ; disable wake-up and EOTx STA LAB_16 ; set serial comms status register RTS ; set A and B timer values LAB_F041 LDA #$19 ; set 4800 baud for 2MHz clock STA LAB_18 ; save to lower latch A LDA #$00 ; set 4800 baud for 2MHz clock STA LAB_1A ; save to upper latch A, init counter, clr flag LDA #$D0 ; set 1mS timeout low byte STA LAB_1C ; save to lower latch B LDA #$07 ; set 1mS timeout high byte STA LAB_1E ; save to upper latch B, init counter, clr flag RTS ; the 6501 is set in 'normal' mode which means 14 bit addressing only ; A13 and A14 are not present. ; set modes and interrupts LAB_F052 LDA #$40 ; normal, tristate D, input B, timer B, timer A STA LAB_14 ; set mode control register LDA #$20 ; counter B underflow only STA LAB_12 ; set interrupt enable register RTS ; serial Tx byte LAB_F05B RMB #5,LAB_00 ; enable Tx buffer PHA ; save A STA LAB_17 ; Tx serial comms byte LAB_F060 BBR #6,LAB_16,LAB_F060 ; wait for Tx empty LAB_F063 BBR #7,LAB_16,LAB_F063 ; wait for Tx under run SMB #5,LAB_00 ; disable Tx buffer PLA ; restore A CLC ; clear carry JMP LAB_F06F ; exit (RTS would be better) ; unreferenced code PLA ; restore A SEC ; set carry LAB_F06F RTS ; IRQ vector gets here - eventually LAB_F070 PHA ; save A TXA ; copy X PHA ; save X TYA ; copy Y PHA ; save Y LDA LAB_1C ; read lower counter B, clear flag SMB #7,LAB_01 ; watchdog bit high RMB #7,LAB_01 ; watchdog bit low SMB #7,LAB_01 ; watchdog bit high (reset watchdog) LDA LAB_45 ; get 1/2 cycle count low byte ORA LAB_46 ; OR with 1/2 cycle count high byte BEQ LAB_F098 ; exit if zero SEC ; set carry for subtract LDA LAB_45 ; get 1/2 cycle count low byte SBC #$01 ; decrement it STA LAB_45 ; save new 1/2 cycle count low byte BCS LAB_F08E ; branch if no underflow DEC LAB_46 ; decrement 1/2 cycle count high byte LAB_F08E BBS #0,LAB_00,LAB_F096 ; go reset sounder bit if set SMB #0,LAB_00 ; else set sounder bit if reset JMP LAB_F098 ; skip reset LAB_F096 RMB #0,LAB_00 ; reset sounder bit LAB_F098 PLA ; get A TAY ; restore Y PLA ; get A TAX ; restore X PLA ; restore A RTI ; after setup we get here ; main keyboard poll loop LAB_F09E JSR LAB_F0CD ; poll keyboard, Cb=1 if key pressed BCS LAB_F0AC ; branch if key pressed RMB #0,LAB_44 ; flag no key held LDA #$00 ; clear A STA LAB_43 ; clear last key JMP LAB_F09E ; loop ; detected key pressed LAB_F0AC JSR LAB_F0E8 ; get byte from table LDA LAB_42 ; read this key (was in A already) CMP LAB_43 ; compare with last key BEQ LAB_F0BF ; branch if same STA LAB_43 ; else make last key this key RMB #0,LAB_44 ; reset key held flag JSR LAB_F113 ; do 28.6715mS delay JMP LAB_F09E ; loop ; is same key as last key LAB_F0BF BBS #0,LAB_44,LAB_F09E ; loop if key held ; same key as last key and held for ??mS SMB #0,LAB_44 ; set key held flag JSR LAB_F126 ; set cycle time & count from A JSR LAB_F10F ; serial Tx byte JMP LAB_F09E ; loop ; poll keyboard, Cb=1 if key pressed LAB_F0CD LDA #$FE ; set start bit pattern STA LAB_40 ; save keyboard matrix p LAB_F0D1 LDA LAB_40 ; get keyboard matrix p bit pattern STA LAB_01 ; to port B LDA LAB_02 ; get port C EOR #$FF ; invert it BEQ LAB_F0E0 ; branch if no bits set STA LAB_41 ; else save keyboard matrix q bit pattern SEC ; set carry (flag key) BCS LAB_F0E7 ; branch always (exit) LAB_F0E0 SEC ; set carry (to move into b0) ROL LAB_40 ; rotate keyboard matrix p bit pattern BBS #4,LAB_40,LAB_F0D1 ; loop if not all done CLC ; clear carry (flag no key) LAB_F0E7 RTS ; get byte from table,00pq where .. ; p is # of first bit set in LAB_40 * 8 (keyboard matrix p) ; q is # of first bit set in LAB_41 (keyboard matrix q) ; byte saved in LAB_42 (this key) LAB_F0E8 LDA LAB_41 ; get keyboard matrix q JSR LAB_F104 ; get # of first A bit set in Y STY LAB_42 ; save bit # temp LDA LAB_40 ; get keyboard matrix p EOR #$FF ; invert it JSR LAB_F104 ; get # of first A bit set in Y TYA ; copy # to A ASL ; *2 ASL ; *4 ASL ; *8 CLC ; clear carry for add (is always clear here!) ADC LAB_42 ; add bit # temp TAY ; copy to index LDA LAB_F1F1,Y ; get key from table STA LAB_42 ; save this key RTS ; get # of first A bit set in Y LAB_F104 CLC ; clear carry LDY #$00 ; clear bit # LAB_F107 LSR ; bit into carry BCS LAB_F10E ; branch if set INY ; increment bit # JMP LAB_F107 ; loop LAB_F10E RTS ; serial Tx byte LAB_F10F JSR LAB_F05B ; serial Tx byte RTS ; do 28.6715mS delay (57343 cycles @ 2MHz) LAB_F113 PHA ; save A TYA ; copy Y PHA ; save Y LDY #$20 ; set outer loop count LAB_F118 LDA #$FF ; set inner loop count LAB_F11A SEC ; set carry for subtract SBC #$01 ; -1 BNE LAB_F11A ; loop if not = 0 DEY ; decrement count BNE LAB_F118 ; loop if not = 0 PLA ; get A TAY ; restore Y PLA ; restore A RTS ; set cycle time & count from A LAB_F126 PHP ; push status SEI ; disable interrupts STA LAB_45 ; save in temp PHA ; push A TYA ; copy Y PHA ; save Y SEC ; set carry for subtract LDA LAB_45 ; restore from temp SBC #$30 ; subtract "0" ASL ; *2 (2 bytes per word) TAY ; copy to index LDA LAB_F14D,Y ; get timer word low byte STA LAB_1C ; save to lower latch B LDA LAB_F14E,Y ; get timer word high byte STA LAB_1E ; save to upper latch B, init counter, clr flag LDA LAB_F19F,Y ; get timer cycles word low byte STA LAB_45 ; save 1/2 cycle count low byte LDA LAB_F1A0,Y ; get timer cycles word high byte STA LAB_46 ; save 1/2 cycle count high byte PLA ; pull A TAY ; restore Y PLA ; restore A PLP ; restore status RTS ; timer B 1/2 cycle time words LAB_F14D LAB_F14E = LAB_F14D+1 ; product frequency (Hz) duration (S) .word $0341 ; 30CF0 1200.48 0.09996 .word $030D ; 30D00 1280.41 0.099968 .word $02DF ; 30CF0 1360.54 0.09996 .word $02B6 ; 30CC0 1440.92 0.099936 .word $0291 ; 30C30 1522.07 0.099864 .word $0271 ; 30D40 1600.00 0.1 .word $0253 ; 30CF0 1680.67 0.09996 .word $0238 ; 30D00 1760.56 0.099968 .word $021F ; 30C90 1841.62 0.099912 .word $0208 ; 30C00 1923.08 0.09984 .word $01F4 ; 30D40 2000.00 0.1 .word $01E0 ; 30C00 2083.33 0.09984 .word $01CE ; 30BA0 2164.50 0.099792 .word $01BE ; 30C80 2242.15 0.099904 .word $01AF ; 30D30 2320.19 0.099992 .word $01A0 ; 30C00 2403.85 0.09984 .word $0193 ; 30CD0 2481.39 0.099944 .word $0186 ; 30C00 2564.10 0.09984 .word $017A ; 30BA0 2645.50 0.099792 .word $016F ; 30BE0 2724.80 0.099824 .word $0165 ; 30CF0 2801.12 0.09996 .word $015B ; 30CC0 2881.84 0.099936 .word $0151 ; 30B50 2967.36 0.099752 .word $0148 ; 30B00 3048.78 0.099712 .word $0140 ; 30C00 3125.00 0.09984 .word $0138 ; 30C00 3205.13 0.09984 .word $0130 ; 30B00 3289.47 0.099712 .word $0129 ; 30BA0 3367.00 0.099792 .word $0122 ; 30B60 3448.28 0.09976 .word $011C ; 30D00 3521.13 0.099968 .word $0115 ; 30B10 3610.11 0.09972 .word $010F ; 30B20 3690.04 0.099728 .word $0109 ; 30A70 3773.58 0.09964 .word $0104 ; 30C00 3846.15 0.09984 .word $00FF ; 30CF0 3921.57 0.09996 .word $00FA ; 30D40 4000.00 0.1 .word $00F5 ; 30CF0 4081.63 0.09996 .word $00F0 ; 30C00 4166.67 0.09984 .word $00EB ; 30A70 4255.32 0.09964 .word $00E7 ; 30BA0 4329.00 0.099792 .word $00E3 ; 30C50 4405.29 0.09988 ; 1/2 cycle count words ; see above for frequencies and durations LAB_F19F LAB_F1A0 = LAB_F19F+1 .word $00F0 .word $0100 .word $0110 .word $0120 .word $0130 .word $0140 .word $0150 .word $0160 .word $0170 .word $0180 .word $0190 .word $01A0 .word $01B0 .word $01C0 .word $01D0 .word $01E0 .word $01F0 .word $0200 .word $0210 .word $0220 .word $0230 .word $0240 .word $0250 .word $0260 .word $0270 .word $0280 .word $0290 .word $02A0 .word $02B0 .word $02C0 .word $02D0 .word $02E0 .word $02F0 .word $0300 .word $0310 .word $0320 .word $0330 .word $0340 .word $0350 .word $0360 .word $0370 ; keyboard matrix decode table LAB_F1F1 .byte "QRST","ABCD","7890","EFGH" .byte "456U","IJKL","123V","MNOP" ; vector words at top of ROM .ORG $FFFA .word LAB_F006 ; NMI vector .word LAB_F000 ; reset vector .word LAB_F003 ; IRQ vector .END |