IBM 4704 Keyboard Analysis - 6019284(62-key)
============================================
2013/02/09, 2019/07/12

IBM 4704 Keyboard
=================
IBM capacitive switch models:
    6019273 Model 100 50-key (grid layout)      http://kishy.ca/?p=894
    6019284 Model 200 62-key Alpha(60% layout)  http://kishy.ca/?p=894
    6019303 Model 300 77-key Expanded Alpha     http://deskthority.net/photos-f62/ibm-6019303-t8502.html
    6020218 Model 400 107-key Full key          http://kishy.ca/?p=894

Alps switch(vintage Green) models:
    5954339 Japanese 102-key    http://deskthority.net/post87127.html#p87127
    6112883 Japanese 102-key    http://geekhack.org/index.php?topic=52888.msg1194489#msg1194489
    6112884 Japanese 102-key    http://geekhack.org/index.php?topic=50437.msg1193047#msg1193047
    6341739 Chinese 102-key     http://geekhack.org/index.php?topic=52888.msg1176566#msg1176566



Resourse
--------
The IBM 4704: lots of pictures and info
http://kishy.ca/?p=894
http://imgur.com/a/LaABs

Brochure:
http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf



4704 Keyboard Protocol
======================
On powering up keyboard sends keyboard ID; A3h for 6019284(62-key), for example.
After that the keyboard enters FC command mode and waits for parameter data from host
so that it doesn't send any scancode until you send 'FF'(End of FC command mode).


    Keyboard                    ID
    -------------------------------
    Model 100 50-key            A2h
    Model 200 62-key            A3h
    Model 300 77-key            A4h
    Model 400 107-key           A5h
    Japanese/Chinese 102-key    A6h


Connector
---------
    Keyboard Plug from front

    DSUB-9
    -------------
    \ N 2 3 4 5 /
     \ N N N N /
      ---------
    2   GND
    3   VCC 5V
    4   DATA
    5   CLOCK
    N   No connection/No pin.


Keyboard to Host
----------------
Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part.

            ____       __   __   __   __   __   __   __   __   __   _______
    Clock       \_____/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
                 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
    Data    ____/    X____X____X____X____X____X____X____X____X____X________
                Start   0    1    2    3    4    5    6    7    P  Stop

Start bit:  can be long as 300-350us.
Inhibit:    Pull Data line down to inhibit keyboard to send.
Timing:     Host reads bit while Clock is hi.(rising edge)
Stop bit:   Keyboard pulls down Data line to lo after 9th clock.



Host to Keyboard
----------------
Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part.

            ____        __   __   __   __   __   __   __   __   __   ________
    Clock       \______/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
                ^   ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
    Data    ____|__/    X____X____X____X____X____X____X____X____X____X   \___
                |  Start   0    1    2    3    4    5    6    7    P   Stop
                Request by host

Start bit:  can be long as 300-350us during start up and upto 2500us while key scanning
Request:    Host pulls Clock line down to request to send a command.
Timing:     After Request keyboard pull up Data and down Clock line to low for start bit.
            After request host release Clock line once Data line becomes hi.
            Host wirtes a bit while Clock is hi and Keyboard reads while low.
Stop bit:   Host releases or pulls up Data line to hi after 9th clock and waits for keybaord pull down the line to lo.



Scancodes
---------
Keyboard doesn't send Break code for all keys except for Alt by default.

    6019284 62-key:
    ,-----------------------------------------------------------.
    |  `|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|**1|BS |
    |-----------------------------------------------------------|
    |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P| ￠|  \|  PD2|
    |-----------------------------------------------------------|
    |Ctrl  |  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  '| {}| PD3|
    |-----------------------------------------------------------|
    |Shif| <>|  Z|  X|  C|  V|  B|  N|  M|  ,|  ,|  /|**2|Shift |
    |-----------------------------------------------------------|
    |Reset|blk|Alt  |         Space             |Alt  |blk|Enter|
    `-----------------------------------------------------------'
    +----------+---------------------+----------+----------+
    |`       00|PD1     04|Caps    20|LShift  30|Reset   31|
    |1       18|q       05|a       21|<>      3E|Rblank  41|
    |2       19|w       06|s       22|z       32|Alt     3F|
    |3       1A|e       13|d       23|x       33|Space   40|
    |4       10|r       14|f       24|c       34|Alt     3F|
    |5       11|t       15|g       25|v       35|Lblank  42|
    |6       12|y       16|h       26|b       36|Enter   2F|
    |7       08|u       17|j       27|n       37|          |
    |8       09|i       01|k       28|m       38|          |
    |9       0A|o       02|l       29|,       39|          |
    |0       0F|p       03|;       2A|.       3A|          |
    |-       1F|￠      1B|'       2B|/       3B|          |
    |=       0D|\       1C|{}      2C|**2     3C|          |
    |**1     0C|PD2     1D|PD3     2D|RShift  3D|          |
    |BS      0E|          |          |          |          |
    +----------+---------------------+----------+----------+
    Bit7 is 'press flag' which set 1 on press and 0 on release when break code is enabled.

NOTE: When break code is enabled the key sends scancode with setting 7th bit on press
and without it on release. That is, '`' sends 80h on press and 00h on release.


Keyboard command
----------------
Keyboard accepts these commands from host.

        Description                             Entry point
    -----------------------------------------------------------
    FF  Soft Reset                              0008h
    FE  Resend                                  00e8h
    FD  Buzzer(emits a short beep)              00edh
    FC  Set Key Flag                            00f6h
    FB  Soft Reset                              0008h
    FA  Reset                                   0000h


Keyboard response
-----------------
Keyobard sends these bytes to host.

        Description                             Entry point
    -----------------------------------------------------------
    FE  Overflow(key event/receive data)        00c5h, 0346h
        Memory test error                       0224h
    FD  Command out of bound                    00d8h
        Key out of bound
    7E  Read/Parity error in receive from host  00bch
    80-FB? scan code(make)
    00-7B? scan code(break)
    note: Alps model spits scan code 7B(FB) at least.


Set Key Flag command(FC)
------------------------
After 'Power on Reset' firmware enters this command mode and waits for data from host,
so that you don't need to send 'FC' and it doesn't send any scancode until you send 'FF' to exit this mode.
With Alps models you need to send 'FC' command to enter this mode.

Data sent from host:

    bit: 7   6 ... 0
         en  |     |
         |   `-----`--- scan code
         `------------- enable bit(0: enable repeat, 1: enable break)

    00-7B   Enable repeat
    80-FB   Enable break
    FE      Resend(011ah) no need to use
    FF      End(0114h) exits FC command mode.

Response from keyboard:
    FD      Out of bound - Invalid scancode
    --      OK - No response means that command is accepted.

Examples:
    To enable break code of all keys you have to send following commands.

    FC 80 81 ... FB FF



4704 Hardware
=============
Power consumption
-----------------
This keyboard is very power greedy, it consumes around 170mA
and USB port may not be able to supply enough current.

    5.061V  -               No load. Power from Powered USB Hub.
    4.946V  133.6mA max     without Buzzer
    4.911V  171.0mA max     with Buzzer


Controller Board
----------------
NOTE: TWO BOLTS OF CONTROLLER BOARD IS CRITICAL.
Controller PCB and tab of bottom plate of key assembly with two hex bolts, these
connect between controller ground to the metal bottom plate of key switch assembly.
This connection is very critical to sense key state, keys will not be registered
unless they are tightened up with the bolts

    Controller: 8048 DIP40 with 1KB ROM and 64B RAM(8748H?)
    Clock:      ??MHz   Resonator? TODO: machine cycle: ??us
    Buffer:     7917 hex buffer
    Sensor:     IBM custom chip for capacitive sense


8048 Pin configuration
----------------------
Bus:
    bit: D7  D6  D5  D4  D3  D2  D1  D0
    use: BZ  CLK DAT ??? G   S2  S1  S0

    use dir     description
    ----------------------------------------------------------------------
    S0  out     Sensor select
    S1  out     Sensor select
    S2  out     Sensor select
    G   out     Sensor strobe?
    ???         Sensor state out(drive/charge? via 7917 buffer)
    DAT out     Data via buffer logic with 2K pull up resistor
    CLK out     Clock via buffer logic with 2K pull up resistor
    BZ  out     Drive Buzzer via 7917 buffer with 2KOhm pull up resistor(H:on/L:off)
T0:
    input of Sensor state(H:on/L:off)
T1:
    input of Clock line with 1KOhm pull up resistor
INT:
    input of Data line with 1KOhm pull down resistor
PORT1:
    P10-P17 matrix row0-7
PORT2:
    P20     matrix row8 or I(keyboard identity bits row)


Connections
-----------
    8048            Sensor
    -----------------------------
    D0-2 ====/===== S0-2(Sensor)
    D3   ---------- STR(Sensor)
           7917 buffer
    D4   --|>--+--- OUT(Sensor)
    T0   ------'

    8048            line
    -----------------------------
           Vcc  Vcc
            |    |
            R 1K R 2K
    T1   ---+-<|-+- CLK
    D6   ---|>---'
                Vcc
                 |
                 R 2K
    D6   ---|>---+- DAT
    T1   -+---<|-'
          R 1K
          |
         GND
                Vcc
                 |
                 R 2K
    D7   ---|>---+- BZ


Interruption
------------
I       disable at 0015h
TCNTI   disable at 0014h


IBM Capacitive sensor chip
--------------------------
Silver canned package

    Pin             Connection      Desciption
    ----------------------------------------------------------------
    Input(C0-7)     Matrix Col0-7   8 column line inputs
    Col select(S0-2)8048:D0-D2      Select column line to sense
    Strobe(STR)     8048:D3         Strobe
    Output(OUT)     848:T0          Read Key state(0:pressed/1:released)

    Pinout from bottom:
    +-----------++------+-------+-------+-------+
    | 1 2 3 4 5 ||1:LCL |6:LCC  |B:S0   |G:C5   |
    | 6 7   8 9 ||2:GND |7:LCM  |C:?    |H:C4   |
    | A       B ||3:Out |8:S2   |D:C6   |I:C3   |
    | C D   E F ||4:STR |9:S1   |E:C0   |J:C2   |
    | G H I J K ||5:VCC |A:C7   |F:?    |K:C1   |
    +-----------++------+-------+-------+-------+

    8048            Sensor
    D0-2 ====/===== S0-2
    D3   ---------- STR
           7917 buffer
    D4   --|>--+--- OUT
    T0   ------'

    Speculation: 8048:D4 is used to prepare to sense capacitance.(charge key capcitor?)

Procedure:
    at 030dh:
    D0-2=<column>   ; select column S0-2
    D4=1            ; Prepare sensor(Charge?)
    P1/P2=<row>     ; select row
    D0-4=<default>  ; 00010(bus=c2h)
    D3=1            ; Strobe
    P1/P2=0         ; unselect row
    read T0         ; see key state

    at 01afh:
    D0-2=<column>
    D4=1
    D0-2=2(010)     ; select col2
    P2=01h          ; select row
    D3=1            ; Strobe
    P2=00h          ; unselect row
    read T0


Keyswitch Matrix
----------------
6019284(62-key):
     |0       1       2       3       4       5       6       7
    -|--------------------------------------------------------------
    0|Enter   RShift  JIS_    PD3     PD2     \|      LofBS   BS
    1|RAlt    RBlank  /?      '"      {}      Cent!   -       =
    2|,       .       l       ;       o       p       9       0
    3|m       n       k       j       u       i       7       8
    4|Spc     b       g       h       t       y       5       6
    5|v       c       d       f       e       r       3       4
    6|LAlt    z       x       s       a       w       q       2
    7|Reset   LBlank  ISO\    LShift  CapLock PD1     `~      1
    8|_       x       _       _       x       x       _       _ (Identity bits: 32h)

    Two 15-line flat cables shown from bttom of PCB:

          Flatcable A    Flatcable B
        /             \/             \
        0123456789ABCDE0123456789ABCDE
        --8-----01234567----76543210--
          Id    row         col         -:GND


Keyboard Identity Bits
----------------------
4704 keyboards has its identity bit marks on PCB matrix and it is readable
from firmware so that it can select key layout depending on this.

PCB pictures:
    Model 100:
        http://kishy.dyndns.org/wp-content/uploads/2013/02/6019273_0011.jpg
    Model 200:
        http://kishy.dyndns.org/wp-content/uploads/2013/02/6019284_0020_capacitive-pcb-top.jpg
    Model 300:
        http://kbtalking.cool3c.com/article/23272
    Model 400:
        http://kishy.dyndns.org/wp-content/uploads/2011/09/6020218_distrib_0019.jpg



4704 Firmware
=============

Startup sequence
----------------
Power on Reset(0000h):
    Short Buzzer
        turns Buzzer(BZ=L) on at 0002h
        turns Buzzer(BZ=H) off at 01adh
    Initialize all memory(3fh-00h)
    Initialize other registers
    Read keyboard id and set default parameter at 01afh
        set break flag for Alt key by default
    Test and clear memory(3fh..00h) at 0202h
    Test program memory at 0214h
    r4=($21&07h)|50h at 0020h
    Send test result at 022dh
        sends [a0h | (keyboard id&f0h)>>4] on success
        6019284 seneds a3h on success
    Wait for data from host - it expects FC command data followed by ffh(end)
    Main loop

Soft Reset(0008h):
    Initialize all memory(20h-00h) It retains parameter memory.
    Initialize other registers
    r4=($21&07h)|50h at 0020h
    Main loop


Memory Map
----------
RAM(64 bytes):
$01-07  *Bank0* Registers r0-r7
        r0  temporary use
        r1  temporary use
        r2  temporary use
        r3  row mask of scan 024dh, 0257h
        r4  bus default value
            7 6 5 4 3 2 1 0
            | | | | | | | |
            | | | | | `-`-`------ Sensor column select
            | | | | `------------ Sensor strobe?
            | | | `-------------- Sensor column set?
            | | `---------------- Data
            | `------------------ Clock
            `-------------------- Buzzer control(L:on/H:off)023ch
            =$21&07h|50h: call 0020h at 001ch soft reset (52h=0101 0010)
            =$21&07h|50h: call 0020h at 0109h command FC (52h=0101 0010)
            =r4|80h: at 00f4h(FD command)
            =r4&7fh: at 023ch(Main)
            =r4&f0h: at 0200h
        r5  repeat dealy/interval
            used at 02d7h
            =07h at 02d9h
            =28h at 02ddh
            =28h at 02e1h
       *r6  0bh at 00edh(FD command)
            used at 0232h
        r7  received data from host
            temporary use at 01afh
            temporary use at 005dh
            =r4&c0h(current bus value?) 0247h
$08-17  8-level stack(2*8)
    $0E
    :       last key state(1:pressed/0:released)
    $15     (0E-15)=8*8=64 matrix(for 50-key and 62-key?)
    $16
    :       last key state(1:pressed/0:released)
    $1C     (16-1C)=7*8=56 (extension for 77-key?)

$18-1F  *Bank1* Registers 0-r7
    Outgoing buffer of data sent to host
    $1D     r5      outgoing buffer top
    $1E     r6      outgoing buffer
    $1F     r7      outgoing buffer bottom


$20     Resend buffer: code last sent used by 'Resend'(FE)

$21     Keyboard identity bits
        0011 0010  (6019284: 32h read from Row(I))
         ||| ||||
         ||| |```- Sensor chip control(bus value)??
         ||| `---- ???
         ```------ keyboard model id

        set at 01fah on Power on Reset:  32h from row8(I)(6019284)
        got at 0020h on Soft Reset:
        got at 034eh on translate into scan code:
        got at 0125h on command FC:
        set from scan 8(I) row at 01fdh

        Keyboard model id:
            Model 100 6019273 50-key (grid layout):     22h(from picture)
            Model 200 6019284 62-key Alpha(60% layout): 32h
            Model 300 6019303 77-key Expanded Alpha:    42h?(from dump list)
            Model 400 6020218 107-key Full key:         no identity
                Looks like this firmware does not support 107-key.

        IBM 4704 keyboards:
            It seems Model 100, 200 and 300 keyboards share one firmware code and
            have small square copper patterns on righ side of PCB to identify
            its layout. See following pictures. Model 400 may use another firmware.

$22-3F  30-byte Parameter RAM(Repeat and Break flags)
        Parameter byte is comprised of four flag pairs. Flags occupies two bits each a key.
        Parameter RAM can have flags for 120(4*30) keys.

        Parameter byte and flags:
            bit 7   6   5   4   3   2   1   0
                3r  3b  2r  2b  1r  1b  0r  0b
:
$3F     End of Memory(64 bytes)




Entry points
------------
0020    Soft Reset  r4=($21&07h)|50h = (32h&07h)|50h=52h
0029    r1=r1+(a), a=r0 (page 0)
002c    (F0=0: send or receive data with 'interpret command mode')
002d    Receive data or Send scan code
0035    Send scan code
        return: F1=1
0082    Receive data from host
        condition: F0==0   interpret command
                   F0==1   return receive data(a)
        return:    F1=1(ERROR) 00c7 (Receive ACK/Parity Error) 00b6,00ce
                   F1=0?
                   a=recieve data, (with F0=0 00dc) F0==0 means 'data received'
00bc    push 7f(error) into outgoing buffer
00be    push data/response into outgoing buffer(r5,r6,r7)
00d2    interpret keyboard command
00de    calculate parity

01a4    r1=r1+(a), a=r0 (page 1)
01a5    r1=r1+a, a=r0
01a9    Buzzer and Scan row8(*) and set param: call from Power on Reset 0018h
01af    Read keyboard identity bits from row8(I) and set param: - call from command FC 0107h
0202    Memory Test(Power on Reset)

0230    Main loop:  send, receive data and scan
        send/receive: call 002c
0263    **Scan matrix**(F1==0): F1=1, r1=15h, r2=3fh, r3=01h
0287    **Scan matrix**(F1==1): F1=0, r1=1ch, r2=77h, r3=02h
0325    get key configure flags(a=-----rb; where r:repeat enable, b:break enable)
0339    queue data at bottom of outgoing buffer
034e    translate into scan code
        scan code table1/table2


Keyboard command entry points
-----------------------------
FF: jump_table0   Soft Reset(008h)
FE: jump_table1   Resend(return content of $20)
FD: jump_table2   Short beep BZ
FC: jump_table3   parameter configuration(100h)
FB: jump_table4   Soft Reset(008h)
FA: jump_table5   Reset(000h)




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  8048 Disassembly of IBM 6019284 ROM dump
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; label mnemonic                ; address   comment
;-------------------------------------------------------------------------------------
	org	000h
; jump_table:5  Hard Reset/Power on Reset
	mov	a,#07fh		; 0000 - a=7f        Power on Reset
	outl	bus,a		; 0002 - BZ=L(off), others=H
	mov	r0,#03fh	; 0003 - r0=3fh
	clr	f1		; 0005 - F1=0
	jmp	X000c		; 0006 -
; jump_table:0,4 Soft Reset
	mov	r0,#020h	; 0008 - r0=20h      $20=resend buffer
	clr	f1		; 000a -
	cpl	f1		; 000b - F1=1

;;;;;;;;;;;;;;;;;;
;   initialize memory
;       hard reset  clear 3f-00h    F1=0
;       soft reset  clear 20-00h    F1=1
X000c:	clr	f0		; 000c - F0=0
	clr	a		; 000d - a=0
X000e:	mov	@r0,a		; 000e - @r0=0   r0=$3f(hard)/$20(soft)
	djnz	r0,X000e	; 000f - clear RAM 3f/20h to $00
	mov	psw,a		; 0011 - psw=0
	outl	p1,a		; 0012 - p1=0
	outl	p2,a		; 0013 - p2=0
	dis	tcnti		; 0014 - disable timer overflow
	dis	i		; 0015 - disable INT
	jf1	X001c		; 0016 - jump if F1==1(Soft Reset?)

; F1==0 Power on Reset
	call	X01a9		; 0018 - read keyboard id and set default parameter
	jmp	X0202		; 001a - Memory Test and go to Main

; F1==1 Soft Reset
X001c:	call	X0020		; 001c - ; r4=$21&07h|50h(52h?), a=r4
	jmp	X0230		; 001e - ; go to Main

;;;;;;;;;;;;;;;;;;
; Set r4
: INPUT:    r4???
: RETURN:   a=r4(original)
;           r4=$21&07h|50h
;
X0020:	mov	r0,#021h	; 0020 -  r0=21h(keyboad identity bits)
	mov	a,@r0		; 0022 -  a=($21)
	anl	a,#007h		; 0023 -  a=a&07h
	orl	a,#050h		; 0025 -  a=a|50h
	xch	a,r4		; 0027 -  swap a,r4
	ret			; 0028 -

; read program memory @page0
; INPUT: a:address
; OUTPUT: a=(a)@page0
X0029:	movp	a,@a		; 0029 -
	jmp	X01a5		; 002a - r1=r1+a, a=r0



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Receive data or Send scan code
; INPUT:    F0=0:interpret command/1:retern data            used in Receive command/data
; OUTPUT:   F0=0(received)/1(not received)
; DONE: a=0, F1=1, buffer rotate
X002c:	clr	f0		; 002c - F0=0
X002d:	jnt1	X0082		; 002d - go to receive if T1(CLK)==L
	sel	rb1		; 002f - switch to bank1
	mov	a,r5		; 0030 - a=r5(bank1)            r5(bank1): scan code buffer
	sel	rb0		; 0031 - switch to bank0
	jnz	X0035		; 0032 - jump if r5(bank1)!=0
	retr			; 0034 - return if r5(bank1)==0 buffer empty

;;;;;;;;;;;;;;;;;;
; Send scan code
; INPUT:    a=data
; OUTPUT:   F1=1:Sent,Rotate,Data ready/0:???
X0035:	dec	a		; 0035 - a--
	clr	c		; 0036 - c=0
	call	X00de		; 0037 - c=parity calc
	jnt1	X0082		; 0039 - go to receive if T1(CLK)=L
; Start bit
	anl	bus,#0bfh	; 003b - [CLK=L]
	orl	bus,#020h	; 003d - [DATA=H]        [[[Start bit]]]
	mov	r0,#010h	; 003f - r0=10h


; check inhibited(DATA==L) - check DATA line released by host
X0041:	jni	X0047		; 0041 - jump if DATA==L LOOP>
	jni	X0049		; 0043 - jump if DATA==L
	jmp	X0054		; 0045 - cont. if DATA==H
X0047:	jmp	X0049		; 0047 -
X0049:	djnz	r0,X0041	; 0049 - <LOOP  timeout?
; time out - end
	orl	bus,#040h	; 004b - [CLK=H]
	anl	bus,#0dfh	; 004d - [DATA=L]       [[[idle state]]]
	retr			; 004f - return send end(give up with inhibited)


; check data==7eh   Keep data in 'Resend' buffer unless it is 7eh
X0050:	xrl	a,#07eh		; 0050 - revert a
	jmp	X005d		; 0052 -

X0054:	mov	r0,#020h	; 0054 - r0=20h 'Resend' Buffer
	xrl	a,#07eh		; 0056 - a=a^7eh(0111 1110)
	jz	X0050		; 0058 - jump if a==7eh
; a!=7eh        retain data to $20(resend buffer) if data is not 7eh
	xrl	a,#07eh		; 005a - revert a
	mov	@r0,a		; 005c - $20=a  retain a to 'Resend' buffer


; Data bit0-7 and Parity(c)
; Pulse H:18/L:9??
X005d:	mov	r7,#009h	; 005d - r7=9
X005f:	mov	r0,#009h	; 005f - r0=9 LOOP>>
	jb0	X0069		; 0061 - jump if a:bit0==1
; a:bit0==0
; send DATA=0
	anl	bus,#0dfh	; 0063 - [DATA=L]
	orl	bus,#040h	; 0065 - [CLK=H]
	jmp	X006f		; 0067 -
; a:bit0==1
; send DATA=1
X0069:	orl	bus,#020h	; 0069 - [DATA=H]
	orl	bus,#040h	; 006b - [CLK=H]
	jmp	X006f		; 006d -
; hold CLK=H
X006f:	djnz	r0,X006f	; 006f - 9*2cycle delay (around 60us??)
	anl	bus,#0bfh	; 0071 - [CLK=L]
	rrc	a		; 0073 - a=a>>1, c=a:bit0
	djnz	r7,X005f	; 0074 - <<LOOP
; Stop bit
; a=0, F1=1, buffer rotate
	anl	bus,#0dfh	; 0076 - [DATA=L]           [Idle]  End
	clr	a		; 0078 - a=0
	clr	f1		; 0079 -
	cpl	f1		; 007a - F1=1               [Sent?]
	orl	bus,#040h	; 007b - [CLK=H]            [Idle]  End
; remove from outgoing buffer: r7=0, r6=r7, r5=r6
	sel	rb1		; 007d - switch to bank1
	xch	a,r7		; 007e -
	xch	a,r6		; 007f -
	xch	a,r5		; 0080 - 0->r7->r6->r5->a  [Bank1 Buffer rotate]
	retr			; 0081 - retr reverts to bank0



;;;;;;;;;;;;;;;;;;
; Receive command/data from host
; INPUT:    F0=0:interpret command/1:return data(used by command)
; OUTPUT:   F0=0(received)/1(not received)
;           F1=1:Error/0:OK
; a: data
; c: parity
; F1: 0: Receive or Send 1: Receive
;
X0082:	jf1	X0086		; 0082 -  jump if F1==1
; F1==0
	jmp	X002d		; 0084 -  Can't recevie, do 'Receive or Send' again
; F1==1
X0086:	mov	r0,#006h	; 0086 -  r0=6h
X0088:	djnz	r0,X0088	; 0088 -  6*2cycle dealy
	jt1	X00cb		; 008a -  return if T1(CLK)==H
	anl	bus,#0bfh	; 008c -  [CLK=L]
	orl	bus,#020h	; 008e -  [DATA=H]                  [Start bit]
	mov	r0,#011h	; 0090 -
X0092:	djnz	r0,X0092	; 0092 -  11*2cycle delay
	mov	r7,#009h	; 0094 -  r7=9h
X0096:	orl	bus,#040h	; 0096 -  LOOP>[CLK=H]              [Clock up for receive]
	mov	r0,#008h	; 0098 -
X009a:	djnz	r0,X009a	; 009a -  8*2cycle delay
	anl	bus,#0bfh	; 009c -  [CLK=L]                   [Clock down]
	jni	X00a9		; 009e -  jump if INT(DATA)==L      [Read bit] Read twice for debounce?
; DATA==H
	orl	a,#001h		; 00a0 -  a:bit0=1
	jni	X00ad		; 00a2 -  jump if INT(DATA)==L
; DATA==H
X00a4:	rrc	a		; 00a4 -  a=a>>1 with carry         [Next bit]
	djnz	r7,X0096	; 00a5 -  <LOOP
	jmp	X00b0		; 00a7 -                            [go to Stop]
; DATA==L
X00a9:	anl	a,#0feh		; 00a9 - a:bit0=0
	jni	X00a4		; 00ab -  jump if INT(DATA)==L
; DATA==H
X00ad:	clr	f1		; 00ad -  F1=0                      [Receive Error]
	jmp	X00a4		; 00ae -


; wait for Stop/ACK (DATA=H)
; F0: 0=jump table, 1=return(with F0=0)
X00b0:	orl	bus,#040h	; 00b0 - [CLK=H]                    [Idle] End
	mov	r0,#004h	; 00b2 -
X00b4:	djnz	r0,X00b4	; 00b4 - 4*2cycle? 8*0.2us=1.6us?
	jni	X00c7		; 00b6 - jump if INT(DATA)==L       [Stop Error] *no error response?
; DATA==H
	anl	bus,#0dfh	; 00b8 - [DATA=L]                   [Idle] End
	jf1	X00cc		; 00ba - jump if F1==1
; F1==0                                                             [Receive Error]


; push 7eh into outgoing buffer (Receive Error at 00bah/Parity Error at 00ceh)
X00bc:	mov	a,#07eh		; 00bc - 7eh: error response

; push data into top of outgoing buffer(Error response)
; a:data
; r5=a, r6=r5, r7=r6
X00be:	sel	rb1		; 00be - switch to bank1
	inc	a		; 00bf - a++
	xch	a,r5		; 00c0 - a->r5->r6->r7->a
	xch	a,r6		; 00c1 -
	xch	a,r7		; 00c2 -
	jz	X00cb		; 00c3 - jump if a==0
	mov	r7,#0ffh	; 00c5 - r7=ffh overflow            [Over flow:FE]

X00c7:	anl	bus,#0dfh	; 00c7 - [DATA=L]                   [Idle] End
	clr	f1		; 00c9 -
	cpl	f1		; 00ca - F1=1                       [Error flag]
X00cb:	retr			; 00cb -



; check parity of recieve data
; F1==1
X00cc:	call	X00de		; 00cc - call parity calc
	jc	X00bc		; 00ce - jump if carryflag=1    (Parity ERROR)
; parity OK
	jf0	X00dc		; 00d0 - jump if F0==1


;;;;;;;;;;;;;;;;;
; F0==0
; Interpret command
;
	cpl	a		; 00d2 - compliment a       ffh-a(command)
	add	a,#jump_table	; 00d3 - a=a+#jump_table
	jc	X00d8		; 00d5 -
	jmpp	@a		; 00d7 - jump table             [Keyboard command]
; Command Out bound Error
X00d8:	mov	a,#0fdh		; 00d8 -    error response: FD
	jmp	X00be		; 00da -

;;;;;;;;;;;;;;;;;
; F0==1
; Return data
X00dc:	cpl	f0		; 00dc - F0=~F0(=0)
	ret			; 00dd -
;
; recieve data/command
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;
; calculate parity: 'c' depends on number of '1' in 'a'
;   INPUT: a=data
;   OUTPUT: c(carry flag)
X00de:	mov	r0,#008h	; 00de - b8 08	8.  r0=8h
X00e0:	rr	a		; 00e0 - 77	w   a=a>>1
	jb0	X00e4		; 00e1 - 12 e4	.d  jump if a:bit0==1
	cpl	c		; 00e3 - a7	'   compliment carry flag
X00e4:	djnz	r0,X00e0	; 00e4 - e8 e0	h`  jump if --r0!=0
	cpl	c		; 00e6 - a7	'
	ret			; 00e7 - 83	.



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Keyboard command  jump table
;
; jump_table:1 FE   Resend(return content of $20)
X00e8:	mov	r0,#020h	; 00e8 -  $20
	mov	a,@r0		; 00ea -  a=$20 get from resend buffer
	jmp	X00be		; 00eb -  push into outogoing buffer

; jump_table:2 FD   r6=0bh, r4=r4|80h
	mov	r6,#00bh	; 00ed -  r6=0bh  BZ duration(scan cycles)?
	orl	bus,#080h	; 00ef -  BZ=H(on)
	mov	a,r4		; 00f1 -
	orl	a,#080h		; 00f2 -  BZ=H
	mov	r4,a		; 00f4 -  r4=r4|80h BZ=H(on) bus-default
	retr			; 00f5 -

; jump_table:3 FC
	mov	r1,#01eh	; 00f6 -  r1=1eh
	jmp	X0100		; 00f8 -

;
; keyboard commands:
;
; FF: jump_table0   Soft Reset(008h)
; FE: jump_table1   Resend(return content of $20)
; FD: jump_table2   BZ set BZ=H(on) to bus and r4(bus-default), duration to r6
; FC: jump_table3   Set key configuration
; FB: jump_table4   Soft Reset(008h)
; FA: jump_table5   Reset(000h)
;
jump_table:	db	008h,0e8h,0edh,0f6h,008h,000h		; 00fa .hmv..
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; command FC    parameter configuration
;   clear $22-3f, then set data received from host
;
; r4:
;   set to $21&07h|50h
; r7: received data
;   r7=data|7fh
;       F0=0 if data:bit7=1
;       F0=1 if data:bit7=0
;
; data received(r7):
;   FF      End(0114h)
;   FE      Resend and receive again(011ah)
;   FF-80   F0=0    if bit7 of r7 is set
;   7F-00   F0=1    if bit7 of r7 is reset
;
;

;;;;;;;;;;;;;;;;;;
; clear parameter configuration RAM $3f..22
; INPUT: r1=1eh=30
;   called at 00f6h
X0100:	clr	a		; 0100 - a=0
	mov	r0,#03fh	; 0101 - r0=3f
X0103:	mov	@r0,a		; 0103 - $3f=a
	dec	r0		; 0104 - r0--
	djnz	r1,X0103	; 0105 -
	call	X01af		; 0107 - Read keyboar id and set parameter flags
	call	X0020		; 0109 - r4=($21 & 07h | 50h) =52h

;;;;;;;;;;;;;;;;;;
; data receive from host
;
X010b:	clr	f0		; 010b - LOOP>>
	cpl	f0		; 010c - F0=1
X010d:	call	X002d		; 010d - receive/send data with F0=1
	jf0	X010d		; 010f - LOOP while F0==1


; received data from host(F0==0)
	mov	r7,a		; 0111 - r7=data received
	cpl	c		; 0112 - c=~c
	cpl	a		; 0113 - a=~a

;;;;;;;;;;;;;;;;;
; a==FF *End*
	jz	X013b		; 0114 - return if a==FF
	xrl	a,#001h		; 0116 -
	jnz	X011e		; 0118 - jump if a!=FE

;;;;;;;;;;;;;;;;;
; a==FE *Resend*
	call	X00e8		; 011a - Resend         and continue...
	jmp	X010b		; 011c - <<LOOP         Send/Receive loop again

;;;;;;;;;;;;;;;;;
; else  *Set flag*
;   data:bit7=1:enable break/0:enable repeat
X011e:	mov	a,r7		; 011e - a=r7(data received)
	jb7	X0122		; 011f - jump if a:bit7==1  (1xxx xxxx)
	cpl	f0		; 0121 - F0=~F0=1   if a:bit7==0    [F0=1 means data:bit7==0]
X0122:	anl	a,#07fh		; 0122 - a=a&7fh                    [data:bit6-0=scan code]
	mov	r7,a		; 0124 - r7=a


; identify keybaord from $21=keyboar identity bits
	mov	r1,#021h	; 0125 - r1=21h
	mov	a,@r1		; 0127 - a=($21)
	anl	a,#0f0h		; 0128 - a=a&f0h
	xrl	a,#020h		; 012a - a=a^20h
	jz	X013c		; 012c - jump if $21==0010 xxxx     6019273 50-key?
	xrl	a,#010h		; 012e - a=a^10h
	jz	X0142		; 0130 - jump if $21==0011 xxxx     *6019284 62-key*
	xrl	a,#070h		; 0132 - a=a^70h
	jz	X0148		; 0134 - jump if $21==0100 xxxx     6019303 77-key?

; Unknown keyboard
	mov	a,r7		; 0136 - a=r7(received data)
	call	X015f		; 0137 -                                [Set flag]
	jmp	X010b		; 0139 - <<LOOP receive again

; End
X013b:	retr			; 013b -



; Set 'index' and 'size' scan code table for each keyboard model
;   r1: end of scan code table(index)
;   r2: number of scan code table(size)
; 6019273 50-key?
X013c:	mov	r1,#0afh	; 013c - r1=afh     address@page3   03afh(table1)
	mov	r2,#038h	; 013e - r2=38h     0011 10(00)     56keys
	jmp	X014c		; 0140 -

; *6019284 62-key*
X0142:	mov	r1,#0efh	; 0142 - r1=efh     address@page3   03efh(table2)
	mov	r2,#040h	; 0144 - r2=40h     0100 00(00)     64keys
	jmp	X014c		; 0146 -

; 6019303 77-key?
X0148:	mov	r1,#0ffh	; 0148 - r1=ffh     address@page3   03ffh(table2)
	mov	r2,#050h	; 014a - r2=50h     0101 00(00)     80keys



; get scancode from table and test loop
LOOP>>
X014c:	mov	a,r1		; 014c - a=r1
	movp3	a,@a		; 014d - a=(r1)     read scan code table
	xrl	a,r7		; 014e - a=a^r7     a==r7(received scan code)
	jnz	X0156		; 014f -

; scan code(a) == received data(r7)
	dec	r2		; 0151 - r2--
	mov	a,r2		; 0152 - a=r2
	call	X015f		; 0153 - call                           [Set flag]
	inc	r2		; 0155 - r2++

; check next scan code
X0156:	dec	r1		; 0156 - r1--               r1: address of table
	djnz	r2,X014c	; 0157 - <<LOOP while --r2  r2: number of table

	jnc	X015d		; 0159 - jump if r1>=0
	call	X00d8		; 015b - Error: FD and cont.            [Out of bound Error: FD]
X015d:	jmp	X010b		; 015d - <<LOOP Receive next data
;;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set flag routine
;
; INPUT: a=table index(number of table)
;        a: AAAA AAFF(AAAAAA:index of parameter RAM, FF: flag position(0-3))
;
X015f:	clr	c		; 015f - c=0
                                ; calculate RAM address
	mov	r2,a		; 0160 - r2=a       r2=data
	rr	a		; 0161 - a=a>>1
	rr	a		; 0162 - a=a>>1     a/4(four keys per a parameter byte)
	add	a,#022h		; 0163 - a=a+22h    start of parameter bytes
	mov	r0,a		; 0165 - r0=a       r0=parameter address

	mov	a,r2		; 0166 - a=r2
	anl	a,#003h		; 0167 - a=a&03h            [a=flag position]
	jz	X017e		; 0169 - if FF==0b00
	dec	a		; 016b - a--
	jz	X018a		; 016c - if FF==0b01
	dec	a		; 016e - a--
	jz	X0197		; 016f - if FF==0b10

;
; Parameter byte and configure flags
;   bit 7   6   5   4   3   2   1   0
;       3r  3b  2r  2b  1r  1b  0r  0b

;;;;;;;;;;;;;;;;;;
; FF==11b:  3r/3b
	mov	a,@r0		; 0171 - a=(r0)             r0=parameter address
	anl	a,#03fh		; 0172 - a=a&0011 1111b     clear 3r/3b
	jf0	X017a		; 0174 - jump if F0==1
; F0==0(received data:bit7==1)
; a=a|40h
	orl	a,#040h		; 0176 - a=a|0100 0000b     3b: break enabled



;;;;;;;;;;;;;;;;;;
; store to RAM and return
X0178:	mov	@r0,a		; 0178 - (r0)=a store parameter to RAM
	ret			; 0179 - return a: command/received data
; End of Set flag
;;;;;;;;;;;;;;;;;;



; F0==1 (data:bit7==0)
; a=a|80h
X017a:	orl	a,#080h		; 017a - a=a|1000 0000b     3r: repeat enabled
	jmp	X0178		; 017c -
;;;


;;;;;;;;;;;;;;;;;;
; FF==00b:  0r/0b
X017e:	mov	a,@r0		; 017e - a=(r0)
	anl	a,#0fch		; 017f - a=a & 1111 1100b   clear 0r/0b
	jf0	X0186		; 0181 - jump if F0==1
; F0==0(data:bit==1)
	inc	a		; 0183 - a++                0b: break enabled
	jmp	X0178		; 0184 -
; F0==1(data:bit==0)
X0186:	orl	a,#002h		; 0186 -                    0r: repeat enabled
	jmp	X0178		; 0188 -
;;;


;;;;;;;;;;;;;;;;;;
; FF==01b:  1r/1b
X018a:	mov	a,@r0		; 018a -
	anl	a,#0f3h		; 018b -                    clear 1r/1b
	jf0	X0193		; 018d -
; F0==0(data:bit==1)
	orl	a,#004h		; 018f -                    1b: break enabled
	jmp	X0178		; 0191 -
; F0==1(data:bit==0)
X0193:	orl	a,#008h		; 0193 -                    1r: repeat enabled
	jmp	X0178		; 0195 -
;;;


;;;;;;;;
; FF==10b   parameter|10h / parameter|20h
X0197:	mov	a,@r0		; 0197 -
	anl	a,#0cfh		; 0198 -                    clear 2r/2b
	jf0	X01a0		; 019a -
; F0==0(data:bit==1)
	orl	a,#010h		; 019c -                    2b: break enabled
	jmp	X0178		; 019e -
; F0==1(data:bit==0)
X01a0:	orl	a,#020h		; 01a0 -                    2r: repeat enabled
	jmp	X0178		; 01a2 -
;;;


;
; End of command FC
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;
; read program memory @page1
;   INPUT: a=address of program memory
X01a4:	movp	a,@a		; 01a4 - a=(a)@page1

;   OUTPUT: r1=r1+a, a=r0
; r1=r1+a,a=r0
X01a5:	add	a,r1		; 01a5 -
	mov	r1,a		; 01a6 - r1=a+r1
	mov	a,r0		; 01a7 - a=r0
	ret			; 01a8 -



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Scan row8(I) and set parameter flags(on Power on Reset)
;
; call from hard reset 0018h with a=0, r0=0, r1=0?
;   INPUT: r0, r1: for wait loop
;   OUTPUT: $21=keybaord identity bits, r4=$21&f0h
;

;;;;;;;;;;;;;;;;;;
; delay to make Buzzer audible when powering up??
X01a9:	djnz	r0,X01a9	; 01a9 - r0*2cycle
	djnz	r1,X01a9	; 01ab - r1*(r0*2cycle+2cycle) 256*(256*2+2)=131584(2us?/cycle) around 260ms??
	anl	bus,#0c0h	; 01ad - BZ=_,CLK=_,DATA=L  line is idle


;;;;;;;;;;;;;;;;;;
;
; Read keyboard identity bits from row8(I) and set parameter flags(on command FC)
;   INPUT: a=0
;   OUTPUT: r4=a=scanned data of row8(I)=keyboard identity bits
;
;   F0: 1:read(frist)/0:read(second)&settle
;        It needs to read same value twice to settle.
;
;   Keyboar id bit pattern on PCB:
;       mark:       1
;       brank:      0
;   Sensor value meaning:
;       Sensor:     0           1
;       Kbd id:     1(mark)     0(blank)
;       Key:        1(pressed)  0(released)
;
; called from command FC 0107h
X01af:	mov	r7,#008h	; 01af - r7=08h                 [column]
X01b1:	rl	a		; 01b1 - a=a<<1 LOOP_0{         [next column]
X01b2:	mov	r4,a		; 01b2 - LOOP{  r4=a            [data]
	cpl	f0		; 01b3 - F0=~F0     toggle F0   [read twice to debounce]
	mov	a,r7		; 01b4 - a=r7
	dec	a		; 01b5 - a--
	orl	a,#0c0h		; 01b6 - col(7-0)|c0h = c7-c0h  BZ=H:on [Beep during FC command]
	outl	bus,a		; 01b8 -                        [Select column]
	orl	bus,#010h	; 01b9 - D4=1                   [charge sensor out=H?]
	mov	a,#0d2h		; 01bb - 1101 0010
	outl	bus,a		; 01bd - bus=d2h   D4-0=10010   select column 2?

;
	orl	p2,#001h	; 01be - P2:0=1                 [select row8(I)]
	mov	a,r4		; 01c0 - a=r4(data)
	orl	bus,#008h	; 01c1 - bus=d2h|08h=dah  D4=1  [Strobe?](1101 1010)
	anl	p2,#000h	; 01c3 - P2:0=L                 [unselect row8(I)]

; check sensor out(T0)
	jt0	X01d5		; 01c5 - jump if T0==H
	jf0	X01cd		; 01c7 - jump if F0==1
	jb0	X01d9		; 01c9 - jump if a:bit0==1      [Settle]
        ; TO(sensor)==0 && F0==0 && a:bit0==0
	jmp	X01b2		; 01cb -  }LOOP

; record 1(a=a|01h) when key is on(T0=L) and F0==1
; T0(sensor)==L(off) && F0==1 (from 01c7)
X01cd:	orl	a,#001h		; 01cd - a=a|1                  [Set a:bit0=H]
	jmp	X01b2		; 01cf - LOOP

; record 0(a=a&feh) when key is off(T0=H) and F0==0
; T0(sensor)==H(on) && F0==0 && a:bit0==1(off) (from 01d7)
X01d1:	anl	a,#0feh		; 01d1 - a=a&feh                [Set a:bit0=L]
	jmp	X01b2		; 01d3 - LOOP

; scan LOOP again
; T0(sensor)==H(on) && F0==1 (from 01c5)
X01d5:	jf0	X01b2		; 01d5 - LOOP while F0==1

; T0(sensor)==H(on) && F0==0
	jb0	X01d1		; 01d7 - jump if a:bit0==1 [need to change r4(a) to 0]

; next column
; T0(sensor)==H && F0==0 && a:bit0==0 OR
; T0(sensor)==L && F0==0 && a:bit0==1   (from 01c9)
X01d9:	djnz	r7,X01b1	; 01d9 - }LOOP_0 while --r7>0 [Next column]
	mov	r4,a		; 01db - r4=a               a=r4=scanned data of Row8(I)


;;;;;;;;;;;;;;;;;;
;  Set parameters from scanned data of row 8(I)
;
;   INPUT:  a=r4=keyboard identity bits
;   OUTPUT: $21=keybaord identity bits, r4=$21&f0h
;
	anl	a,#0f0h		; 01dc - a=a&f0h
	xrl	a,#020h		; 01de - a=a^20h            (a==0010 xxxx)  6019273
	jz	X01ec		; 01e0 - jump if a==0
	xrl	a,#010h		; 01e2 - a=a^10h            (a==0011 xxxx) *6019284 when power on reset
	jz	X01f2		; 01e4 - jump if a==0
	xrl	a,#070h		; 01e6 - a=a^70h            (a==0100 xxxx)  6019303
	jz	X01f2		; 01e8 - jump if a==0
	jmp	X01fa		; 01ea -

; $21==(0010 xxxx)  for 6019273(50-key)
; set break enalbe flag for Reset(or on other layout?)
X01ec:	mov	r0,#022h	; 01ec -
	mov	@r0,#001h	; 01ee - $22=1      $22:bit0=break enable falg of ????
	jmp	X01fa		; 01f0 -

; $21==(0011 0010 | 0100 xxxx)  for 6019284(62-key) or 6019303(77-key) layout
; set break enable flag for LAlt and RAlt *6019284
X01f2:	mov	r0,#02eh	; 01f2 -
	mov	@r0,#001h	; 01f4 - $2e=1      $2e:bit0=break enable flag of LAlt
	mov	r0,#024h	; 01f6 -
	mov	@r0,#001h	; 01f8 - $24=1      $24:bit0=break enable flag of RAlt

; set $21 to scanned data of row 8(I)   [keyboard identity bits]
X01fa:	mov	r0,#021h	; 01fa -
	mov	a,r4		; 01fc -
	mov	@r0,a		; 01fd - ($21)=r4     $21: r4=identity bits(row 8(I))
	anl	a,#0f0h		; 01fe -
	mov	r4,a		; 0200 - r4=r4&f0h
	ret			; 0201 -
;
; End of Scan row8(I)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Test and clear memory(3fh..00h) on Power on Reset
;
X0202:	mov	r0,#03fh	; 0202 -  $3f
X0204:	mov	a,@r0		; 0204 -  LOOP>>
	mov	r1,a		; 0205 -  r1=(r0) r0=3f..00
	mov	a,#0ffh		; 0206 -  a=ffh
	mov	@r0,a		; 0208 -  (r0)=ffh
	xrl	a,@r0		; 0209 -  a=a^ffh =0??
	jnz	X0224		; 020a -  jump if a!=ffh    *always should be a=zero*
	mov	@r0,a		; 020c -  (r0)=a    (=0)
	mov	a,@r0		; 020d -  a=(r0)
	jnz	X0224		; 020e -  jump if a!=ffh    *always should be a=zero*
	mov	a,r1		; 0210 -  a=r1
	mov	@r0,a		; 0211 -  (r0)=a (revert to origin value)
	djnz	r0,X0204	; 0212 -  <<LOOP --r0

;
; Test program memory(0,255..1 @page0,1,2,3)
;
; INPUT: r0=0 r4=??
; OUTPUT: r4=$21&07h|50h, a=swapHL(r4(original)) or feh
X0214:	mov	a,r0		; 0214 -  LOOP>>   a=r0=0
	call	X0029		; 0215 -  r1=r1+(a), a=r0 (page0)
	call	X01a4		; 0217 -  r1=r1+(a), a=r0 (page1)
	movp	a,@a		; 0219 -
	call	X01a5		; 021a -  r1=r1+(a), a=r0 (page2)
	movp3	a,@a		; 021c -
	call	X01a5		; 021d -  r1=r1+(a), a=r0 (page3)
	djnz	r0,X0214	; 021f -  <<LOOP --r0
	mov	a,r1		; 0221 -  a=r1  sum of program memory data
	jz	X0226		; 0222 -  sum of program memory data != 0 if no error ???

; Send FE on error and r4 on success
X0224:	mov	r4,#0efh	; 0224 -  r4=efh    Memory error
X0226:	call	X0020		; 0226 -  r4=$21&07h|50h, a=r4(keyboard id or efh)
	swap	a		; 0228 -  swap a:h<->a:l
	orl	a,#0a0h		; 0229 -  a=a|a0h(1010 iiii)    i:keyboard id(hi-bits)
	call	X0339		; 022b -  queue data(a) to buffer
	call	X010b		; 022d -  send kbd ID and wait for data from host   [FC command]
	strt	t		; 022f -  start timer
; Usually first data form keyboard at startup is A3h(sum of program memory?).
; FEh for memory error??
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Main??
;
; check scan code buffer to send
X0230:	call	X002c		; 0230 - receive/send data
	mov	a,r6		; 0232 - a=r6 set by command FD Short Beep(0bh at 00edh)
	jz	X023d		; 0233 -
	djnz	r6,X023d	; 0235 - r6--
; Buzzer off
	anl	bus,#07fh	; 0237 - BZ=L(off)   when get to r6==0  [Short Beep ends]
	mov	a,r4		; 0239 -
	anl	a,#07fh		; 023a -
	mov	r4,a		; 023c - r4=r4&7fh(BZ=L:off) r4=bus-default

; delay for scan    192*32cycle?
X023d:	mov	a,t		; 023d - a=t(timer)
	add	a,#064h		; 023e - a=a+64h
	jnc	X023d		; 0240 - delay for scan
	clr	a		; 0242 - a=0
	mov	t,a		; 0243 - t=0    timer clear

; Start matrix scan
; r7=r4&c0h
X0244:	mov	a,r4		; 0244 - a=r4
	anl	a,#0c0h		; 0245 - a=a&c0h        BZ=_,CLK=_,DAT=L:
	mov	r7,a		; 0247 - r7=r4&c0h      r7=bus-current
	jf1	X0253		; 0248 - jump if F1==1 (p1/p2)

; F1==0
	cpl	f1		; 024a - F1=1(=~F1)
	mov	r2,#03fh	; 024b - r2=3fh         scan code seed
	mov	r3,#001h	; 024d - r3=01h         row mask
	mov	r1,#015h	; 024f - r1=15h         last key state
	jmp	X0263		; 0251 - scan matrix p1 row

; F1==1
X0253:	clr	f0		; 0253 - F0=0
	clr	f1		; 0254 - F1=0
	mov	r2,#077h	; 0255 - r2=77h         scan code seed
	mov	r3,#002h	; 0257 - r3=02h
	mov	r1,#01ch	; 0259 - r1=1ch         last key state
	jmp	X0287		; 025b - Scan matrix p2 row
;
; INPUT:    F1=0
X025d:	cpl	f1		; 025d - F1=~F1=1
	call	X002c		; 025e - receive/send data
	clr	f1		; 0260 - F1=0
	jmp	X0244		; 0261 -

;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; scan matrix p1 row
; INPUT: F1=1, r1=15h, r2=3fh, r3=01h, r7=r4&c0h
;       (r1): last state
;
; r0:col, r7:bus-current, r3:row(drive H), r4=bus-default
;
; $15: bit7
;
; bus:  xxxS Gccc
;
X0263:	mov	a,#008h		; 0263 - a=8 LOOP>>>
	mov	r0,a		; 0265 - r0=08h =column
	orl	a,r7		; 0266 - a=08h|r7
	mov	r7,a		; 0267 - r7=a     =xxxx  1ccc(G:1 column:ccc) r7=P1 value
X0268:	dec	r7		; 0268 - LOOP>> r7--
	mov	a,r7		; 0269 - a=r7
	outl	bus,a		; 026a -                        [select column]
	orl	bus,#010h	; 026b - sensor out=H           [sensor clamp=H]???
	mov	a,r3		; 026d - a=r3                   current row
	outl	p1,a		; 026e - drive line with H      [select row]
	mov	a,r4		; 026f - a=r4                   bus default value
	outl	bus,a		; 0270 -                        [revert bus default]
	orl	bus,#008h	; 0271 - D3:H sensor-G          [strobe]??? hold? clean Sensor?
	anl	p1,#000h	; 0273 -                        [unselect row]

	jnt0	X02ab		; 0275 - sensor out==0
; Sensor==1[key is on]
	mov	a,@r1		; 0277 - a=$(r1); r1=15...  last key state
	jb7	X02e5		; 0278 - jump if a:bit7==1(off) press
; a:bit7==0(last key state is on)  same as last
;On->On


; Go to next column
X027a:	rl	a		; 027a - a=a<<1
	mov	@r1,a		; 027b - (r1)=a; (r1)=(r1)<<1   next col of last key state
X027c:	dec	r2		; 027c - r2--                   [key index of scan code table]
	djnz	r0,X0268	; 027d - <<LOOP(8)              [next col]

	dec	r1		; 027f - r1--   15,14,13,12,11,10,0F,0E? [last key state]
	mov	a,r3		; 0280 -
	rl	a		; 0281 -
	mov	r3,a		; 0282 - r3=r3<<1 next row
	jb0	X0230		; 0283 - jump if a:bit0==1  scan end(goto Main loop)
	jmp	X0263		; 0285 - <<<LOOP                [next row]


;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Scan matrix p2 row(F1==1)
; INPUT: F0=0, F1=0, r1=1ch, r2=77h, r3=02h, r7=bus-current, r4=bus-default
;
; r0:col, r7:bus-current, r3:row(drive H), r4=bus-default
;   key index: 77h-
X0287:	mov	a,#008h		; 0287 - a=8    LOOP>>
	mov	r0,a		; 0289 - r0=8
	orl	a,r7		; 028a - a=a|r7
	mov	r7,a		; 028b - r7=a
X028c:	dec	r7		; 028c - r7-- LOOP>>
	mov	a,r7		; 028d - a=r7
	outl	bus,a		; 028e -                        [select column]
	mov	a,r4		; 0293 -                        bus default value
	outl	bus,a		; 0294 -                        [revert bus default]
	orl	bus,#008h	; 0295 -                        [strobe]
	anl	p2,#000h	; 0297 - p2=00h                 [unselect row]
	jnt0	X02ab		; 0299 - jump if sensor out==0(key is on)
; sensor==1(key is off)
	mov	a,@r1		; 029b - a=(r1)                 [last key state]
	jb7	X02e5		; 029c - jump if a:bit7==1(off)  press

; a:bit7==0(last key state is on)
X029e:	rl	a		; 029e - a=a<<1
	mov	@r1,a		; 029f - (r1)=a                 [next last key bit]
X02a0:	dec	r2		; 02a0 - r2--(77h)
	djnz	r0,X028c	; 02a1 - jump if r0--!=0 <<LOOP(8)
	dec	r1		; 02a3 - r1--                   [next last key byte]
	mov	a,r3		; 02a4 -
	rl	a		; 02a5 -
	mov	r3,a		; 02a6 - r3=r3<<1   [next row]??
	jb0	X025d		; 02a7 -
	jmp	X0287		; 02a9 - <<LOOP

;
; debouncing and change last key state
;
; sensor out==0(press; key is on)
;
; debouncing
X02ab:	call	X030d		; 02ab - a=0(sensor out=1), ffh(sensor out=0)   [Sense key]
	jz	X02f8		; 02ad - if a==0(key is off)
	call	X030d		; 02af -                                        [Sense key]
	jz	X02f8		; 02b1 - if a==0(key is off)

; Sensor==0(a=ffh; press)
	mov	a,@r1		; 02b3 - a=(r1) last key state????
	jb7	X02ca		; 02b4 -

;
; [release](off->on)
;
; last:bit7==0(off) && sensor=0(on)
	orl	a,#080h		; 02b6 - 0:on   1:off
	rl	a		; 02b8 -
	mov	@r1,a		; 02b9 - (r1)=(r1)<<1   next column
	call	X0325		; 02ba - key configure flag
                                ;        (a:bit1=repeat enable, a:bit0=break enable)
; if keyconf:bit0==1 then set release flag
	jb0	X02fd		; 02bc - r2=r2|80h          [press flag]
; if keyconf:bit1==1 then set repeat
	jb1	X02e1		; 02be - r5=repeat delay    [repeat]

; get scan code and queue it into buffer
X02c0:	call	translate034E	; 02c0 - a=scancode
	call	X0339		; 02c2 - queue data to buffer
	call	X0303		; 02c4 -                    [r1=a=address of last key state]
X02c6:	jf1	X027c		; 02c6 - next col(F1==1)
	jmp	X02a0		; 02c8 - next col(F1==0)

;
; [hold key]
;
; last key is on and sensor==0(on)     (on->on)
X02ca:	rl	a		; 02ca -
	mov	@r1,a		; 02cb - (r1)=(r1)<<1
	call	X0325		; 02cc - key configure flag
                                ;        (a:bit1=repeat enable, a:bit0=break enable)
; repeat:flag
	jb1	X02d4		; 02ce -                    [repeat]

; if repeat:flag(bit1)==0  (no repeat)
X02d0:	call	X0303		; 02d0 - r1=r2&0fh+0eh      address of last key state
	jmp	X02c6		; 02d2 - goto next col

; if flag:bit1==1  (repeat)
X02d4:	jf0	X02dd		; 02d4 -

; F0==0
	cpl	f0		; 02d6 - F0=~F0=1
	djnz	r5,X02d0	; 02d7 -
	mov	r5,#007h	; 02d9 - r5=07h             repeat interval
	jmp	X02c0		; 02db - send scan code

; F0==1
X02dd:	mov	r5,#028h	; 02dd - r5=28h             repeat delay(for first repeat)
	jmp	X02d0		; 02df -
;
X02e1:	mov	r5,#028h	; 02e1 - r5=28h             repeat delay(for first repeat)
	jmp	X02c0		; 02e3 - send scan code


;
; debouncing and change last key state: press
;
;   INPUT: (r1): last key status
;
; (r1):bit7==1(last key is on) &&  Sensor==1(key is off)  [release]
X02e5:	call	X030d		; 02e5 - a=0(sensor out=1), ffh(sensor out=0)   [Sense key]
	jnz	X02f8		; 02e7 -
	call	X030d		; 02e9 -                                        [Sense key]
	jnz	X02f8		; 02eb - \_debouncing
; Sensor==1(a=0)                                                                [Debounced]

;
; on->off [release]
;
	mov	a,@r1		; 02ed - a=(r1) RAM
	anl	a,#07fh		; 02ee - a=a&7fh        last state=0(0:on 1:off)
	rl	a		; 02f0 - a=a<<1
	mov	@r1,a		; 02f1 - (r1)=a
;
	call	X0325		; 02f2 - key configure flag
                                ;        (a:bit1=repeat enable, a:bit0=break enable)
	jb0	X02c0		; 02f4 - goto translate if a:bit0==1
	jmp	X02d0		; 02f6 -

; go to next col scan   Sensor==1
X02f8:	mov	a,@r1		; 02f8 -
	jf1	X027a		; 02f9 - goto next col scan(p1) if F1==1        [Next column]
	jmp	X029e		; 02fb - goto next col scan(p2) else            [Next column]

;
; add press flag(bit8)
; r2=key index
X02fd:	mov	a,r2		; 02fd -                                        [key index]
	orl	a,#080h		; 02fe -
	mov	r2,a		; 0300 - r2=r2|80h  **press flag**
	jmp	X02c0		; 0301 -

; Address of last key state
; INPUT: r2=key index
; OUTPUT: r1=(r2>>3)&0fh+0eh    = address of last key state
X0303:	mov	a,r2		; 0303 - a=r2   key index
	rr	a		; 0304 -
	rr	a		; 0305 -
	rr	a		; 0306 - a= a>>3
	anl	a,#00fh		; 0307 - a= a & 0fh
	add	a,#00eh		; 0309 - a= a + 0eh
	mov	r1,a		; 030b - r1=a
	ret			; 030c -

;;;;;;;;;;;;;;;;;;;;;;;
; Sense key
;   INPUT: r7: bus-current, F1:0(p2),1(p1) r4=bus-default, r3=row
;   RETURN: a=0xff(sensor out=0, press), 0(sensor out=1, release)
;
X030d:	mov	a,r7		; 030d - r7: bus-current
	outl	bus,a		; 030e -                            [Select column]
	orl	bus,#010h	; 030f -                            [Charge: D4]
	mov	a,r3		; 0311 - r3: row(drive) select      p1(F1=1)/p2(F1=0) setting
	jf1	X0317		; 0312 -
; F1==0
	outl	p2,a		; 0314 - set p2                     [Select row]
	jmp	X0318		; 0315 -
; F1==1
X0317:	outl	p1,a		; 0317 - set p1                     [Select row]

X0318:	mov	a,r4		; 0318 - r4: bus-default
	outl	bus,a		; 0319 - set bus
	clr	a		; 031a - a=0
	orl	bus,#008h	; 031b -                            [Strobe: D3]
	anl	p1,#000h	; 031d - clear p1                   [Unselect row]
	anl	p2,#000h	; 031f - clear p2                   [Unselect row]

	jt0	X0324		; 0321 - sensor out==1
sensor out==0
	cpl	a		; 0323 -  a=0xff                    [press(on)]
sensor out==1
X0324:	ret			; 0324 -  a=0                       [release(off)]
;
; End of Main
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; key configure flags
;
; INPUT: r2=key index(p1:-3fh, p2:-77h)    (aaaaaaii)
: OUTPUT: a=Key configure 2-bit flags;  bit0 and 1 are only valid. (------rb)
;
:   Key configure flags are retained in RAM($22-3F) and
;   Key configure flags use 2bit per key so that a byte can has flags of four key like:
;       bit 7   6   5   4   3   2   1   0
;           3r  3b  2r  2b  1r  1b  0r  0b
;   where r=repeat enable, b=break code(release) eanble
;
X0325:	mov	a,r2		; 0325 - a=r2           index
	rr	a		; 0326 -
	rr	a		; 0327 - a=a>>2         bit7-2 of index(aaaaaa)
	add	a,#022h		; 0328 - a=a+22h        $22+aaaaaa
	mov	r1,a		; 032a - r1=a
	mov	a,@r1		; 032b - a=(r1)         $22-3F(ignored bit7,bit6)
	mov	r1,a		; 032c - r1=a           r1=($22-3F) ????
	mov	a,r2		; 032d - a=r2           index
	anl	a,#003h		; 032e - a=a&03h        a=bit0,bit1 of index
	xch	a,r1		; 0330 - a<->r1         r1=bit0,bit1 of index, a=($22-3F)
	inc	r1		; 0331 - r1++           =1-4
X0332:	djnz	r1,X0335	; 0332 - while --r1>0
	ret			; 0334 -

; place flags of the key on bit0 and 1
X0335:	rr	a		; 0335 -
	rr	a		; 0336 - a=a>>2; a=$22-3F
	jmp	X0332		; 0337 -

;
; Queue data to bottom of outgoing buffer(bank1:r5,r6,r7)
; INPUT: a=data, r2=???
; OUTPUT: r2=r2&07h
; a->r5->r6->r7
X0339:	sel	rb1		; 0339 -   switch to bank1
	inc	a		; 033a -   a++
	xch	a,r5		; 033b -   a<->r5
	jz	X0348		; 033c -
	xch	a,r5		; 033e -
	xch	a,r6		; 033f -
	jz	X0348		; 0340 -
	xch	a,r6		; 0342 -
	xch	a,r7		; 0343 -
	jz	X0348		; 0344 -
	mov	r7,#0ffh	; 0346 -   buffer overflow
X0348:	sel	rb0		; 0348 -   switch to bank0
	mov	a,r2		; 0349 -   a=r2
	anl	a,#07fh		; 034a -   a=a&7fh
	mov	r2,a		; 034c -   r2=a
	ret			; 034d -
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Translate key index into scancode
;
; INPUT: r2=keyindex [bit7:release flag(1:release/0:press), bit6-0:index]
; OUTPUT: a=scancode
translate034E:
	mov	r1,#021h	; 034e -
	mov	a,@r1		; 0350 - a=$21  $21:bit6,5,4 = traslate table
	anl	a,#0f0h		; 0351 - a=a & f0h
	xrl	a,#020h		; 0353 - a=a ^ 20h      $21:bit5(0010 0000) 0010 xxxx => table1
	jz	X0361		; 0355 - if a==0        read table1     (6019273 50-key)
	xrl	a,#010h		; 0357 - a=a ^ 10h      $21:bit4(0001 0000) 0011 xxxx => table2
	jz	X0370		; 0359 -                read table2     (6019284 62-key)
	xrl	a,#070h		; 035b - a=a & 70h      $21:bit6(0111 0000) 0100 xxxx => table2
	jz	X0370		; 035d -                read table2     (6019303 77-key)
	mov	a,r2		; 035f -                else use r2(keyindex) instead of scancode
	ret			; 0360 -
; table1(8x7=56)
X0361:	mov	a,r2		; 0361 - keyindex
	anl	a,#07fh		; 0362 -
	add	a,#078h		; 0364 - table1
; read table
X0366:	movp3	a,@a		; 0366 - read scancode from table a=scan code
	xch	a,r2		; 0367 - a=keyindex, r2=scancode
	jb7	X036c		; 0368 - if keyindex:bit7==1 [relase event]
	xch	a,r2		; 036a - a=scancode, r2=keyindex
	ret			; 036b -
; release flag
X036c:	xch	a,r2		; 036c -
	orl	a,#080h		; 036d - [[[[[release flag(bit7)]]]]]
	ret			; 036f - a: scan code
; table2(8X10=80)
X0370:	mov	a,r2		; 0370 -
	anl	a,#07fh		; 0371 -
	add	a,#0b0h		; 0373 - table2
	jmp	X0366		; 0375 - read table


; maybe 'salt' to make sum of program memory 'zero'(at 0222h)
	db	0b6h					; 0377 6


;;;;;;;;;;;;;;;;;;
;
; Scancode table
;

;;;;;;;;;;;;;;;;;;
; Used for 6019273                                        Add  Key              Parameter RAM
table1:	db	03fh,037h,03ah,036h,02ah,035h,022h,023h	; 0378
	db	03bh,02bh,039h,031h,032h,029h,021h,0ffh	; 0380
	db	033h,038h,0ffh,030h,028h,0ffh,020h,0ffh	; 0388
	db	017h,01dh,01ch,015h,00ch,00dh,004h,005h	; 0390
	db	00fh,01fh,01bh,013h,014h,00bh,003h,0ffh	; 0398
	db	00eh,01ah,019h,012h,009h,00ah,001h,002h	; 03a0
	db	016h,01eh,018h,010h,011h,008h,000h,0ffh	; 03a8

;;;;;;;;;;;;;;;;;;
; Used for 6019284 and 6019303                            Add  Key              Parameter RAM
table2:	db	02fh,03dh,03ch,02dh,01dh,01ch,00ch,00eh	; 03b0 Enter ... BS     $22, $23
	db	03fh,042h,03bh,02bh,02ch,01bh,01fh,00dh	; 03b8 RAlt ...         $24, $25
	db	039h,03ah,029h,02ah,002h,003h,00ah,00fh	; 03c0 ...              $26, $27
	db	038h,037h,028h,027h,017h,001h,008h,009h	; 03c8 ...              $28, $29
	db	040h,036h,025h,026h,015h,016h,011h,012h	; 03d0 ...              $2a, $2b
	db	035h,034h,023h,024h,013h,014h,01ah,010h	; 03d8 ...              $2c, $2d
	db	03fh,032h,033h,022h,021h,006h,005h,019h	; 03e0 LAlt ...         $2e, $2f
	db	031h,041h,03eh,030h,020h,004h,000h,018h	; 03e8 Reset ... 1      $30, $31
	db	071h,076h,075h,066h,055h,056h,045h,046h	; 03f0 Used for 77-key  $32, $33
	db	077h,067h,074h,064h,065h,054h,0ffh,044h	; 03f8 Used for 77-key  $34, $35
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;
;	symbol equates
;
;  these are symbols from the control
;  file that are referenced in the code
;
jump_table	equ	0fah
;
	end
