* keyboard debouncer (e.g. for Sch„n keyboard)
* by Jan Bredenbeek; 09/12/91
* Can only be used with MINERVA ROM installed!
* Use at your own risk. When distributing modified versions, please distribute
* also the source and give clear notice about your modifications.

* Assembled with GST 68000 Macro Assembler.

* Various definitions

err.nc   equ      -1

lf       equ      10

mt.inf   equ      0
mt.lpoll equ      $1c
sv_cheap equ      4
sv_chtop equ      $7c

ut_mtext equ      $d0

sx_kbenc equ      $10               Vector for keyboard decoding routine

string$  macro    a
[.lab]   dc.w     .e.[.l]-*-2
         dc.b     [a]
.e.[.l]  equ      *
         endm

         section  code              can be assembled with -NOLINK option

         moveq    #mt.inf,d0
         trap     #1
         move.l   sv_chtop(a0),a4
         cmpa.l   sv_cheap(a0),a4
         beq.s    nominnie          'hope this will do...
         lea      newkbenc,a1
         cmpa.l   sx_kbenc(a4),a1
         beq.s    installd
         lea      oldkbenc,a0
         move.l   sx_kbenc(a4),(a0) save addr of existing decoding routine
         move.l   a1,sx_kbenc(a4)   make our debouncer the new one
         moveq    #mt.lpoll,d0
         lea      intlink,a0
         lea      deb_intr,a1
         move.l   a1,4(a0)
         trap     #1                link in timing routine
         moveq    #0,d0
         rts
nominnie lea      min_msg,a1
         bra.s    exit_err
installd lea      inst_msg,a1
exit_err suba.l   a0,a0
         move.w   ut_mtext,a2
         jsr      (a2)
         moveq    #err.nc,d0        print error message and exit
         rts

min_msg  string$  {'DEBOUNCE requires MINERVA rom!',lf}
inst_msg string$  {'DEBOUNCE already installed!',lf}

* Polled interrupt routing; used for timing

deb_intr lea      deb_cnt,a3        point to counter
         tst.b    (a3)              if zero, it's OK for new key
         beq.s    intr_end
         subq.b   #1,(a3)           else decrement
intr_end rts

* our debounce routine. this actually works by suppressing any keystroke which
* occurs less than 5 frames (ie 0.1s) after any identical keystroke.
* Note that this does not affect auto-repeat since that is handled internally
* by the calling code in QDOS and the keyboard decode routine doesn't get
* called in that case.

newkbenc andi.b   #$3f,d1           only bits 0-5 are significant
         lea      lastkey,a3
         cmp.b    (a3),d1           last key was different?
         bne.s    key_ok            yes, it's always OK then
         tst.b    1(a3)             has the counter reached zero?
         beq.s    key_ok            yes, it's OK too
         addq.l   #4,(a7)           else, ignore this key (see notes supplied
         rts                        with Minerva decode routines)

key_ok   move.b   d1,(a3)           store new key
         move.b   #5,1(a3)          reset counter to 5 frames
         move.l   oldkbenc,a3
         jmp      (a3)              jump to actual decode routine

* our storage area. note that presently it's not ROMable. it could of course be
* made so (e.g. by using the polled interrupt linkage block) but I find that
* this has too much hassles (e.g. one has to scan the polled interrupt list on
* every call to the decode routine) so I'm doing it the quick and dirty way.
* Of course, feel free to modify this if you like to...

intlink  dc.l     0,0               polled interrupt link
oldkbenc dc.l     0                 addr of actual decode routine
lastkey  dc.b     0                 key value of last key
deb_cnt  dc.b     0                 counter. NOTE: must be at lastkey + 1!

         end
