+IBM 4704 Keyboard Analysis - 6019284(62-key)
+============================================
+2013/02/09, 2019/07/12
+
IBM 4704 Keyboard
=================
IBM capacitive switch models:
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.dyndns.org/?p=648#more-648
+http://kishy.ca/?p=894
+http://imgur.com/a/LaABs
Brochure:
http://ed-thelen.org/comp-hist/IBM-ProdAnn/4700.pdf
-IBM 4704 Keyboard Protocol
-==========================
+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
____ __ __ __ __ __ __ __ __ __ _______
Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
- ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
+ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
Data ____/ X____X____X____X____X____X____X____X____X____X________
Start 0 1 2 3 4 5 6 7 P Stop
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.
| Start 0 1 2 3 4 5 6 7 P Stop
Request by host
-Start bit: can be long as 300-350us.
+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.
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| -| =|???|BS |
+ | `| 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| ,| ,| /|???|Shift |
+ |Shif| <>| Z| X| C| V| B| N| M| ,| ,| /|**2|Shift |
|-----------------------------------------------------------|
|Reset|blk|Alt | Space |Alt |blk|Enter|
`-----------------------------------------------------------'
|9 0A|o 02|l 29|, 39| |
|0 0F|p 03|; 2A|. 3A| |
|- 1F|¢ 1B|' 2B|/ 3B| |
- |= 0D|\ 1C|{} 2C|??? 3C| |
- |??? 0C|PD2 1D|PD3 2D|RShift 3D| |
+ |= 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.
FC Set Key Flag 00f6h
FB Soft Reset 0008h
FA Reset 0000h
-
+
Keyboard response
-----------------
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'.
+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:
| `-----`--- scan code
`------------- enable bit(0: enable repeat, 1: enable break)
- 00-7B? Enable repeat
- 80-FB? Enable break
+ 00-7B Enable repeat
+ 80-FB Enable break
FE Resend(011ah) no need to use
FF End(0114h) exits FC command mode.
-- OK - No response means that command is accepted.
Examples:
- To enable break code of all keys.
+ 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