-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathKBD_CORRCTED.asm
1301 lines (1120 loc) · 45.1 KB
/
KBD_CORRCTED.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Sources written in Atmel AVR Studio 5.1
*
* upload using command: avrdude -p atmega8 -c USBasp -U flash:w:KBD_CORRCTED.hex -U lfuse:w:0xCF:m -U hfuse:w:0xC7:m
*/
;------------------------------------------------
; set MCU type
; 0 - ATMega8
; 1 - ATMega48/88/168/328
;------------------------------------------------
#define MCU_TYPE 0
///////////////////////////////////////////////
// English -----------------------------------------------------
// PS2 keyboard timings, MAX=25
// the higher oscillator frequency, the higher the value
// not all controllers support oscillators >20MHz but many can support 24MHz, and some can up to 40MHz, but it is rare...
// Russian -----------------------------------------------------
// Êîýôôèöèåíò òàéìèíãîâ PS2 êëàâèàòóðû, MAX=25
// ÷åì âûøå ÷àñòîòà êâàðöà, òåì áîëüøå êîýôôèöèåíò è íàîáîðîò
// íå âñå êîíòðîëëåðû ìîãóò ðàáîòàòü ñ êâàðöàìè áîëåå 20ÌÃö, ò.ê. Atmega8-16PU, 16Ìãö :-D
// íî áîëüøèíñòâî ìîæåò òÿíóòü 24ÌÃö, à ðåäêèå ýêçåìïëÿðû ìîãóò è 40ÌÃö
.equ TIMING_COEFF = 18
; 24 for 32 MHz (60000ns/31ns/80 = 24) 31ns 1 cycle time for 32MHz
; 23 for 30 MHz (60000ns/33ns/80 = 23) 33ns 1 cycle time for 30MHz
; 21 for 28 MHz (60000ns/36ns/80 = 21) 36ns 1 cycle time for 28MHz
; 20 for 27 MHz (60000ns/37ns/80 = 20) 37ns 1 cycle time for 27MHz
; 19 for 25 MHz (60000ns/40ns/80 = 19) 40ns 1 cycle time for 25MHz
; 18 for 24 MHz (60000ns/42ns/80 = 18) 42ns 1 cycle time for 24MHz
; 15 for 20 MHz (60000ns/50ns/80 = 15) 50ns 1 cycle time for 16MHz
; 12 for 16 MHz (60000ns/62ns/80 = 12) 62ns 1 cycle time for 16MHz
///////////////////////////////////////////////
;r0 - used
;r1 - used
.def PARITY=r2
;r3 - used
.def CONST00=r4
.def KBD_BYTE_PREV=r5
.def KBD_E0_FLAG=r6
.def CONST80=r7
.def KA08_ROW=r8
.def KA09_ROW=r9
.def KA10_ROW=r10
.def KA11_ROW=r11
.def KA12_ROW=r12
.def KA13_ROW=r13
.def KA14_ROW=r14
.def KA15_ROW=r15
;r16 tmp (used)
.def CONST7F=r17
;r18 tmp (used)
.def KBD_LOOP_CNT=r19
;r20 - used in INT interrupt
.def CONSTFF=r21
;r22 - free
.def KBD_STATE=r23
.def KBD_IND=r24
.def KBD_BYTE=r25
; KBD_STATE
; bit 0 symbol shift key (CTRL) released
; bit 1 indicates #F0 prefix
; bit 2 caps shift key (SHIFT) released
; bit 3 áèò îòêëþ÷åíèÿ ïðîâåðêè ñáðîñà SHIFT ñòàòóñîâ
; bit 4 symbol shift flag
; bit 5 caps shift flag
; bit 6 -----
; bit 7 Ext Mode set
; KBD_E0_FLAG - bit 7 indicates #E0 prefix
; SRAM MAP
; 0x100-0x1FF - Port #FE data
; 0x200-0x207 - Key Buffer
; 0x208-0x20F - Prepared data for port #FE
.CSEG
.ORG 0x0000
;-----------------------------------------------------
; SET PROGRAM INTERRUPT VECTORS
;-----------------------------------------------------
RJMP _RESET ;(1, Power-on/Reset)
///////////////////////////////////////////////////////////////////////////////////////////
// INT 0 Interrupt Handler 4+14 cycles
// 16MHz: 1 cycle = 62ns, 62*9=558ns from falling edge to data set on port B äîñòàòî÷íî ìíîãî ïîëó÷àåòñÿ, ìîæåò íå ðàáîòàòü
// 20MHz: 1 cycle = 50ns, 50*9=450ns from falling edge to data set on port B
// 24MHz: 1 cycle = 42ns, 42*9=378ns from falling edge to data set on port B
// 25MHz: 1 cycle = 40ns, 40*9=360ns from falling edge to data set on port B
// 27MHz: 1 cycle = 37ns, 37*9=333ns from falling edge to data set on port B
// 28MHz: 1 cycle = 36ns, 36*9=324ns from falling edge to data set on port B
// 30MHz: 1 cycle = 33ns, 33*9=297ns from falling edge to data set on port B
// 32MHz: 1 cycle = 31ns, 31*9=279ns from falling edge to data set on port B
// ×åì áûñòðåå ðàáîòàåò ýòî ïðåðûâàíèå, òåì ëó÷øå, à äëÿ ýòîãî ÷àñòîòà êâàðöà äîëæíà áûòü âûøå!
///////////////////////////////////////////////////////////////////////////////////////////
INT0_Handler:
in YL,PinD ; PinD -> YL receive data from bus ; 1 cycle
// ------- 2 cycle both -------------
sbic PinC,0x03 ; if (PinC.3=0) skip next line (IF KA10=0) ; 1/2 cycle, 2 byte instruction
bld YL,2 ; move bit 3 of port C to bit 2 of data from port D ; 1 cycle, 2 byte instruction
// ----------------------------------
ldd r20,Y+0x00 ; put data to r20 from SRAM key table at 0x100+YL ; 2 cycles, 4 byte instruction
//4+5 cycles before set data on port FE
out DDRB,r20 ; 1 cycle, 2 byte instruction
// ------ 3 cycle, 6 bytes
HOLD_BUS: ; hold data on bus while /RDFE=0
sbis PinD,0x02 ;if PinD.2=1 skip rjmp
rjmp HOLD_BUS
// --------------
out DDRB,CONST00 ; turn data bus to HI-Z state ; 1 cycle, 2 byte instruction
reti ; 4 cycles
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// PROGRAM START
///////////////////////////////////////////////////////////////////////////////////////////
_RESET:
// Port C setup first for not switching keys (turbo,magic)
ldi r18,0x08 ; set LOW output on C0-C2,C4-C5 C3 Pull Up
out PortC,r18
// Init constant
ser CONSTFF ; 0xFF -> CONSTFF
// Port D
out PortD,CONSTFF ; all pins with pullup
// Init constant
clr CONST00 ; 0x00 -> CONST00
; disable Analog Comparator ==============================
#if MCU_TYPE == 0
sbi ACSR,ACD ; for atmega8
#elif MCU_TYPE == 1
ldi r16,ACD ; for ATMEGA48/88/168/328
rcall SET_BIT
out ACSR,r18
#endif
;=========================================================
// init stack pointer 0x45F
ldi r16,low(RAMEND)
out SPL,r16
ldi r16,high(RAMEND)
out SPH,r16
#if MCU_TYPE == 0
; set INT0 ATMEGA8 =========================================
ldi r16,ISC01 ; falling edge int 0
rcall SET_BIT
out MCUCR,r18
ldi r16,INTF0 ; clear int0 flag
rcall SET_BIT
out GIFR,r18
ldi r16,INT0 ; enable int0 interrupt
rcall SET_BIT
out GICR,r18
; ==========================================================
#elif MCU_TYPE == 1
; set INT0 ATMEGA48/88/168/328 =============================
ldi r16,ISC01 ; falling edge
rcall SET_BIT
sts EICRA,r18
ldi r16,INTF0 ; clear int0 flag
rcall SET_BIT
out EIFR,r18
ldi r16,INT0 ; enable int0 interrupt
rcall SET_BIT
out EIMSK,r18
; ==========================================================
#endif
rcall LONG_WAIT_50 ; âûçîâ ïîäïðîãðàììû äëèííîãî öèêëà îæèäàíèÿ èíèöèàëèçàöèè êëàâèàòóðû
rcall LONG_WAIT_50 ; âûçîâ ïîäïðîãðàììû äëèííîãî öèêëà îæèäàíèÿ èíèöèàëèçàöèè êëàâèàòóðû
rcall LONG_WAIT_50 ; âûçîâ ïîäïðîãðàììû äëèííîãî öèêëà îæèäàíèÿ èíèöèàëèçàöèè êëàâèàòóðû
SET ; 1 -> T for fast bit set in interrupt
// Init constants
ldi XH,0x02 ; set XH for SRAM 0x200 addresses manipulation
ldi r16,0x80
mov CONST80,r16
ldi r16,0x7F
mov CONST7F,r16
ldi r16,0x10 ; 16 -> r16
KBD_RESET_LOOP: // öèêë 16 ïîïûòîê ñäåëàòü ñáðîñ êëàâèàòóðû
rcall LONG_WAIT_15 ; âûçîâ ïîäïðîãðàììû äëèííîãî öèêëà îæèäàíèÿ
mov KBD_BYTE,CONSTFF ; 0xFF->KBD_BYTE // Keyboard Command RESET
rcall KBD_SEND ; îòïðàâèòü êîìàíäó ñáðîñà (0xFF)
brcc INIT_KBD ; åñëè ñáðîñèëàñü òî ïåðåõîäèì íà èíèöèàëèçàöèþ
dec r16 ; r16--
brne KBD_RESET_LOOP ; if r16 != 0 jmp KBD_RESET_LOOP
rjmp ENDLESS_LOOP ; if failed to init keyboard fall to endless loop
INIT_KBD:
rcall SMALL_WAIT
rcall KBD_READ ; âûçîâ ïîäïðîãðàììû ÷òåíèÿ ñ êëàâèàòóðû
brcc KBD_MAIN ; if(C=0) jmp KBD_MAIN
;---- Áåñêîíå÷íûé öèêë, åñëè íå èíèöèàëèçèðîâàëîñü -----------------------
ENDLESS_LOOP:
rjmp ENDLESS_LOOP
;-------------------------------------------------------------------------
// Îáðàáîò÷èê êëàâèàòóðû
///-----------------------------------------------------------------------
KBD_MAIN: //íà÷àëî
// set scan code 2
ldi KBD_BYTE,0xF0
rcall KBD_SEND
ldi KBD_BYTE,2
rcall KBD_SEND
// enable scan
ldi KBD_BYTE,0xF4
rcall KBD_SEND
KBD_MAIN_R:
// init indicators
ldi KBD_IND,3 ; 3 = Scroll lock + num lock
rcall KBD_SEND_INDICATORS
K_REINIT:
; î÷èñòêà è çàïîëíåíèå SRAM
//ldi XH,0x02 ; load SRAM address 0x200 (keyboard buffer)
clr XL
; î÷èñòêà êëàâèàòóðíîãî áóôåðà
CLEAR_BYTE:
st X+,CONST00 ; fill byte with 0 and increase X
sbrs XL,0x03 ; ïîêà XL ìåíüøå 8 öèêë
rjmp CLEAR_BYTE
; çàïîëíåíèå ïàìÿòè ïîðòà FE (0x7F,...,0xFE) çíà÷åíèÿìè 0xFF
ldi ZH,0x01 ; load SRAM address 0x100
clr ZL
CLEAR_BYTE_FE:
st Z+,CONST00 ; fill byte 255 and increase X
tst ZL ; repeat while X < 0x200
brne CLEAR_BYTE_FE
clr KBD_STATE
clr KBD_BYTE_PREV
clr KBD_E0_FLAG
ldi YH,0x01 ; port FE table at 0x17F,...,0x1FE
sei ; 1->I ðàçðåøèòü ïðåðûâàíèÿ
NEW_KBD_LOOP:
;------ ÷òåíèå áàéòà îò êëàâèàòóðû -------------------------------------
rcall KBD_READ0 ; read byte from keyboard
brcs K_REINIT ; if parity error do reinit SRAM tables
;-----------------------------------------------------------------------
cpi KBD_BYTE,0xF0 ; check for prefix #F0
brne NOT_F0
ori KBD_STATE,0x02 ; set bit 1, indicates that prefix #F0 set
rjmp NEW_KBD_LOOP
NOT_F0:
cpi KBD_BYTE,0xE0 ; check for prefix #E0
brne NOT_E0
mov KBD_E0_FLAG,CONST80 ; set flag indicates prefix #E0 and repeat
rjmp NEW_KBD_LOOP
NOT_E0:
cpi KBD_BYTE,0xE1 ; check for E1 prefix (e.g. for "Pause" key)
brne NOT_PAUSE
; if pause pressed - skip 7 bytes (scan code 8 bytes!) --------
ldi r18,0x07
PAUSE_KEY_SKIP:
rcall KBD_READ0
dec r18
brne PAUSE_KEY_SKIP
rjmp NEW_KBD_LOOP
; -------------------------------------------------------------
NOT_PAUSE:
cpi KBD_BYTE,0x83 ; F7 keycode has bit 7 set... so replace it with keycode not defined in PS/2 scancode set 2
brne NOT_83
ldi KBD_BYTE,0x08 ; replace 0x83 with 0x08 (not defined code) to not affect bit 7
NOT_83:
or KBD_BYTE,KBD_E0_FLAG ; add E0 flag to bit 7 of key code
clr KBD_E0_FLAG ; clear E0 prefix flag
sbrc KBD_STATE,0x01 ; check KBD_STATE bit 1, if set then used prefix #F0
rjmp F0_SET ; jump to F0 keys set
; HERE IS Press key scan codes processing --------------------------------------------------------------------------
; skip repeatable codes
cp KBD_BYTE_PREV,KBD_BYTE ; if KBD_BYTE = previous value repeat loop
breq NEW_KBD_LOOP
mov KBD_BYTE_PREV,KBD_BYTE
cpi KBD_BYTE,0x07 ; check F12 pressed
brne CHECK_F11
; Push BTN1
sbi DDRC,0x01 ; set BTN1 - output LOW
rjmp PROCESS_KBD_BUFFER
CHECK_F11:
cpi KBD_BYTE,0x78 ; check F11 pressed
brne CHECK_RESET
; Push BTN2
sbi DDRC,0x02 ; set BTN2 - output LOW
rjmp NEW_KBD_LOOP
CHECK_RESET:
cpi KBD_BYTE,0xFC ; #E0, 0x7C print screen pressed second 2 bytes process RESET button
brne CHECK_SHIFTS
; reset button press -------------------------------------
sbi DDRC,0x00 ; RESET - output LOW
rjmp UPDATE_KEY_BUFFER
; /reset button press ------------------------------------
CHECK_SHIFTS: ; check SYMBOL SHIFT key pressed (Left and right CTRL keys)
cpi KBD_BYTE,0x94 ; check RIGHT CTRL pressed
breq SET_SYMSHIFT_FLAG
cpi KBD_BYTE,0x14 ; check LEFT CTRL pressed
breq SET_SYMSHIFT_FLAG
cpi KBD_BYTE,0x59 ; check RIGHT SHIFT pressed
breq SET_CAPSSHIFT_FLAG
cpi KBD_BYTE,0x12 ; check LEFT SHIFT pressed
breq SET_CAPSSHIFT_FLAG
rjmp CHECK_NUMLOCK
SET_CAPSSHIFT_FLAG:
ori KBD_STATE,0x20 ; Set Caps Shift Flag Bit 5
rjmp UPDATE_KEY_BUFFER
SET_SYMSHIFT_FLAG:
ori KBD_STATE,0x10 ; Set Symbol Shift Flag Bit 4
rjmp UPDATE_KEY_BUFFER
CHECK_NUMLOCK:
cpi KBD_BYTE,0x77 ; check NUM_LOCK
brne CHECK_CAPSLOCK
ldi XL,0x02
eor KBD_IND,XL ; XOR with indicator value for NumLock
rcall KBD_SEND_INDICATORS
rjmp K_REINIT ; reinit keyboard keytables after numlock key pressed
CHECK_CAPSLOCK:
cpi KBD_BYTE,0x58 ; check Caps Lock
brne CHECK_SCROLLOCK
ldi XL,0x04
eor KBD_IND,XL ; XOR with indicator value for CapsLock
rcall KBD_SEND_INDICATORS
ldi KBD_BYTE,0x58 ; kestore key value
rjmp UPDATE_KEY_BUFFER
CHECK_SCROLLOCK:
cpi KBD_BYTE,0x7E ; check Scroll Lock
brne UPDATE_KEY_BUFFER
ldi XL,0x01
eor KBD_IND,XL ; XOR with indicator value for ScrollLock
rcall KBD_SEND_INDICATORS
rjmp K_REINIT ; reinit keyboard keytables after Scrolllock key pressed
; Process pressed key -----------------------------------------------------------------------
UPDATE_KEY_BUFFER:
//ldi XH,0x02 ; keybuffer for key sequencies 0x200
ldi XL,0x00
; try to add key to end of buffer
KP_LOOP:
ld r18,X+ ; read value from buffer
cp r18,KBD_BYTE ; check with scan code
breq RELOOP ; if key already in buffer - go to next "read key" loop cycle
tst r18 ; check current value in buffer
brne KP_BUF_NOTZERO ; jump if not zero (repeat if not end of buffer)
st -X,KBD_BYTE ; store byte where zero value was found
rjmp PROCESS_KBD_BUFFER
KP_BUF_NOTZERO:
sbrs XL,0x03 ; if XL < 8 repeat buffer loop, or exit from loop if buffer overflow
rjmp KP_LOOP
RELOOP:
rjmp NEW_KBD_LOOP
; process F0 prefixes, #E0 also may be set as 7 bit of KBD_BYTE
; F0 prefixe set when key release, so we need to remove key from the buffer
; HERE IS Release key scan codes processing ---------------------------------------------------------------------------
F0_SET:
clr KBD_BYTE_PREV ; clear previous key value
andi KBD_STATE,0xFD ; clear F0 prefix flag
cpi KBD_BYTE,0xFC ; #E0, 0x7C print screen released second 2 bytes process RESET button
brne CHECK_F12_OFF
; reset button release -------------------------------------
ldi r18,0x03
LOOP_R:
rcall KBD_READ0
dec r18
brne LOOP_R
andi KBD_IND,0x03 ; NUM_LOCK / SCROLL_LOCK
mov KBD_BYTE,KBD_IND
rcall KBD_SEND_INDICATORS
cbi DDRC,0x00 ; RESET inactive, HI-Z mode
rjmp PROCESS_KBD_BUFFER
; /reset button release ------------------------------------
CHECK_F12_OFF:
cpi KBD_BYTE,0x07 ; check F12 button released
brne CHECK_F11_OFF
; Release BTN1
cbi DDRC,0x01 ; set BTN1 pin inactive, HI-Z mode
rjmp NEW_KBD_LOOP
CHECK_F11_OFF:
cpi KBD_BYTE,0x78 ; check F11 button released
brne CHECK_SHIFTS_OFF
; Release BTN2
cbi DDRC,0x02 ; set BTN2 pin inactive, HI-Z mode
rjmp NEW_KBD_LOOP
CHECK_SHIFTS_OFF:
// CTRL check
cpi KBD_BYTE,0x94 ; right ctrl released
breq K_REINIT2
cpi KBD_BYTE,0x14 ; left ctrl released
breq K_REINIT2
// SHIFT check
cpi KBD_BYTE,0x59 ; right shift released
breq K_REINIT2
cpi KBD_BYTE,0x12 ; left shift released
breq K_REINIT2
; Process released key -----------------------------------------------------------------------
UPDATE_KEYBUFFER_OFF:
//ldi XH,0x02 ; keybuffer for key sequencies 0x200
ldi XL,0x00
KR_LOOP:
ld r18,X+ ; read value from buffer
cp r18,KBD_BYTE ; check with scan code
breq KEY_FOUND0 ; jump if key found
sbrs XL,0x03 ; if XL >= 8 key not found in a buffer, jump to reinit keyboard
rjmp KR_LOOP ; check next value in a buffer
rjmp K_REINIT
; Key found in a buffer
KEY_FOUND0:
sbrs XL,0x03
rjmp NOT_BUF_END
st -X,Const00 ; set zero value at the end of the buffer
rjmp PROCESS_KBD_BUFFER
NOT_BUF_END:
// áåðåì ñëåäóþùåå çíà÷åíèå èç áóôåðà è ñäâèãàåì åãî íàçàä
ld r18,X
st -X,r18
subi XL,0xFE ; XL += 2,
rjmp KEY_FOUND0
PROCESS_KBD_BUFFER: ; îáðàáîòêà áóôåðà êëàâèàòóðû
////////////////////////////////////////////////////////////////////////////////////////////////////
//ldi XH,0x02 ; 0x208 -> X, àäðåñà ðÿäîâ êëàâèàòóðû ZX ïîðòà FE
ldi XL,0x08
L018B: // loop çàïîëíÿåì çíà÷åíèÿ äëÿ ðÿäîâ (äàííûå äëÿ KA8,..KA15) çíà÷åíèåì 0xFF
st X+,CONSTFF ; 0xFF -> [0x208+]
sbrs XL,0x04 ; ïîêà íå ñòàíåò ðàâíî 0x210 ïîâòîðÿåì ò.å. ïîêà XL < 16
rjmp L018B
andi KBD_STATE,0xF7 ; clear bit 3
ldi XL,0x00 ; 0x200 -> X
// ------------------------------------------------
L0192: //loop
ld r18,X+
tst r18 ; åñëè íóëåâîå çíà÷åíèå â áóôåðå, òî íà ñëåäóþùóþ èòåðàöèþ
breq L019C
; â r18 çíà÷åíèå êëàâèøè èç áóôåðà
//KEYTABLE ////////////////////////////////////////
// âûáîðêà çíà÷åíèÿ èç KEYTABLE'S
ldi ZH,high(KEYTABLE*2)
ldi ZL,low(KEYTABLE*2)
add ZL,r18
brcc L019A ; åñëè ñìåùåíèå áîëüøå 255 óâåëè÷èâàåì ZH
inc ZH
L019A:
lpm ; [Z] -> R0 âûáðàëè çíà÷åíèå äëÿ êëàâèøè èç KEYTABLE'S
rcall CHECK_ALT_KEY ; ïðîâåðêà áèòîâ àëòüòåðíàòèâíîé òàáëèöû â êîäå êëàâèøè
L019C:
sbrs XL,0x03
rjmp L0192 ; åñëè XL < 8 öèêë
// ------------------------------------------------
sbrc KBD_STATE,0x03 ; åñëè áèò 3 óñòàíîâëåí íå ïðîâåðÿåì ñîñòîÿíèÿ SymbolShift, CapsShift, ò.ê. óæå ïðîâåðåíî â CHECK_ALT_KEY
rjmp L01A4
// check symbolshift key released flag
sbrc KBD_STATE,0x00 ; return if bit 0 is not set (reset SymbolShift flag)
andi KBD_STATE,0xEE ; ñáðîñ SymbolShift è Release SymbolShift ôëàãîâ (0 è 4 áèòû)
// check capsshift key released flag
sbrc KBD_STATE,0x02 ; return if bit 2 is not set (reset CapsShift flag)
andi KBD_STATE,0xDB ; ñáðîñ CapsShift è Release CapsShift ôëàãîâ (2 è 5 áèòû)
sbrc KBD_STATE,0x04 ; ïðîâåðêà SymbolShift
rjmp SS_BIT_PROCESS
sbrc KBD_STATE,0x05 ; ïðîâåðêà CapsShift
rjmp CS_BIT_PROCESS
K_REINIT2:
rjmp K_REINIT
SS_BIT_PROCESS:
rcall SET_SS_BIT
sbrc KBD_STATE,0x05 ; ïðîâåðêà CapsShift ///////
rjmp CS_BIT_PROCESS ///////
rjmp L01A4
CS_BIT_PROCESS:
rcall SET_CS_BIT
L01A4:
rcall FILL_PORT_FE
andi KBD_STATE,0x7F ; clear bit 7
RELOOP2:
rjmp NEW_KBD_LOOP
//////////Êîíåö îáðàáîò÷èêà êëàâèàòóðû
///////// Âñÿêèå ïîäïðîãðàììû
; --- Çàïîëíåíèå àäðåñîâ ïîðòà #FE äàííûìè î íàæàòûõ êëàâèøàõ
FILL_PORT_FE:
ldi XL,0x08
clr ZH
ldi ZL,0x08
L01AA:
ld r18,X+ ; [X++]->r18
com r18 ; invert value for DDRB work
st Z+,r18 ; r18->[Z++] ïîìåùàåì çíà÷åíèÿ íåïîñðåäñòâåííî â ðåãèñòðîâóþ ïàìÿòü ðåãèñòðîâ KA08_ROW-KA15_ROW
cpi XL,0x10
brne L01AA ; loop ïîêà XL!=0x10
ldi ZH,0x01
mov ZL,CONSTFF
clr r18
st Z,r18 ; 0xFF -> [0x1FF]
CALC_ROW_VALUE:
// âû÷èñëåíèå àäðåñà ïîðòà FE (ò.å. ãäå â ïàìÿòè íàõîäÿòñÿ áàéòû äëÿ KA8,KA9,...,KA15)
dec ZL
clr r18
sbrs ZL,0x00
or r18,KA08_ROW
sbrs ZL,0x01
or r18,KA09_ROW
sbrs ZL,0x02
or r18,KA10_ROW
sbrs ZL,0x03
or r18,KA11_ROW
sbrs ZL,0x04
or r18,KA12_ROW
sbrs ZL,0x05
or r18,KA13_ROW
sbrs ZL,0x06
or r18,KA14_ROW
sbrs ZL,0x07
or r18,KA15_ROW
st Z,r18
tst ZL
brne CALC_ROW_VALUE ; ïîêà XL áîëüøå 0
ret
;----------------------------------------------------
CHECK_ALT_KEY:
tst r0
brne L0222
; åñëè êëàâèøà ñ íóëåâûì çíà÷åíèåì íåò ïðèçíàêà îòïóñêàíèÿ Caps/Symbol Shift òî âûõîäèì
sbrc KBD_STATE,0x00
rjmp L0222
sbrc KBD_STATE,0x02
rjmp L0222
ret
L0222:
sbrs r0,0x07
rjmp NO_ALT
sbrc r0,0x06
rjmp USE_ALT_KEYTABLE
NO_ALT:
// check symbolshift key released flag
sbrc KBD_STATE,0x00 ; return if bit 0 is not set (reset SymbolShift flag)
andi KBD_STATE,0xEE ; ñáðîñ SymbolShift è Release SymbolShift ôëàãîâ (0 è 4 áèòû)
// check capsshift key released flag
sbrc KBD_STATE,0x02 ; return if bit 2 is not set (reset CapsShift flag)
andi KBD_STATE,0xDB ; ñáðîñ CapsShift è Release CapsShift ôëàãîâ (2 è 5 áèòû)
sbrc KBD_STATE,0x04
rcall SET_SS_BIT
sbrc KBD_STATE,0x05
rcall SET_CS_BIT
PROCESS_KEYCODE:
ori KBD_STATE,0x08
sbrc r0,0x06
rcall SET_SS_BIT
sbrc r0,0x07
rcall SET_CS_BIT
mov r18,r0
andi r18,0x07 ; remove shift bits from keycode
mov r1,r18 ; move data bits value to r1
ldi r18,0xFE ; Set default bits value for bit 0
L023B: // check bit loop
dec r1
breq L0240 ; break loop if r1=0
sec
rol r18 ; move to next bit and set bit 0
rjmp L023B
L0240: // find value in keybuffer 0x200 using address bits
ldi ZH,0x02
mov ZL,r0
lsl ZL
swap ZL
andi ZL,0x07
subi ZL,0xF8
L0246:
ld r1,Z
and r1,r18
st Z,r1
ret
L0247:
ld r1,Z
or r1,r18
st Z,r1
ret
;----------------------------------------------------
SET_CS_BIT:
ldi ZH,0x02
ldi ZL,0x08 ; KA08
ldi r18,0xFE
rjmp L0246
SET_SS_BIT:
ldi ZH,0x02
ldi ZL,0x0F ; KA15
ldi r18,0xFD
rjmp L0246
RESET_CS_BIT:
ldi ZH,0x02
ldi ZL,0x08 ; KA08
ldi r18,1
rjmp L0247
RESET_SS_BIT:
ldi ZH,0x02
ldi ZL,0x0F ; KA15
ldi r18,2
rjmp L0247
SET_E_MODE: ; Ïåðåêëþ÷åíèå â ðåæèì E
sbrc KBD_STATE,0x07 ; skip if already set E mode
ret
mov r3,XL
rcall SET_CS_BIT
rcall SET_SS_BIT
rcall FILL_PORT_FE
rcall LONG_WAIT
rcall LONG_WAIT
rcall LONG_WAIT
rcall LONG_WAIT
rcall RESET_CS_BIT
rcall RESET_SS_BIT
rcall FILL_PORT_FE
mov XL,r3
ori KBD_STATE,0x80
ret
;----------------------------------------------------
USE_ALT_KEYTABLE:
mov r18,r0
andi r18,0x1F ; clear alternate bits and get alternate key number in table
lsl r18 ; r18 = r18 * 2
sbrc r0,0x05 ; check ALT2 table bit
rjmp USE_ALT2
ldi ZH,high(KEYTABLE_ALT*2)
ldi ZL,low(KEYTABLE_ALT*2)
add ZL,r18
brcc GET_ALT_KEYS
inc ZH ; if ZL overflow -> increase ZH
GET_ALT_KEYS:
sbrs KBD_STATE,0x05 // ïðîâåðêà CapsSHIFT
rjmp NO_CAPSSHIFT
// âûáîðêà âòîðîãî çíà÷åíèÿ èç òàáëèöû KEYTABLE_ALT
inc ZL
lpm ; [Z] -> r0, âûáîðêà âòîðîãî çíà÷åíèÿ (ñ CapsShift)
rcall RESET_CS_BIT
sbrs r0,0x07 ; check EXT MODE bit
rjmp NO_E1
and r0,CONST7F
rcall SET_E_MODE
NO_E1:
rjmp PROCESS_KEYCODE // îáðàáîòêà, åñëè íå íàæàò CapsShift
NO_CAPSSHIFT:
// âûáîðêà ïåðâîãî çíà÷åíèÿ èç òàáëèöû KEYTABLE_ALT
lpm ; [Z] -> r0, âûáîðêà ïåðâîãî çíà÷åíèÿ (áåç CapsShift)
sbrs r0,0x07 ; check EXT MODE bit
rjmp NO_E2
and r0,CONST7F
rcall SET_E_MODE
NO_E2:
rjmp PROCESS_KEYCODE // îáðàáîòêà
USE_ALT2:
ldi ZH,high(KEYTABLE_ALT2*2)
ldi ZL,low(KEYTABLE_ALT2*2)
add ZL,r18
brcc GET_ALT2_KEYS
inc ZH ; if ZL overflow -> increase ZH
GET_ALT2_KEYS:
sbrs KBD_IND,0x01 // ïðîâåðêà NumLock
rjmp NO_NUMLOCK
// âûáîðêà âòîðîãî çíà÷åíèÿ èç òàáëèöû KEYTABLE_ALT2
inc ZL
lpm ; [Z] -> r0, âûáîðêà âòîðîãî çíà÷åíèÿ (ñ NumLock)
rjmp PROCESS_KEYCODE // îáðàáîòêà, åñëè íå íàæàò CapsShift
NO_NUMLOCK:
// âûáîðêà ïåðâîãî çíà÷åíèÿ èç òàáëèöû KEYTABLE_ALT
lpm ; [Z] -> r0, âûáîðêà ïåðâîãî çíà÷åíèÿ (áåç NumLock)
rjmp PROCESS_KEYCODE // îáðàáîòêà
;----------------------------------------------------
// Set keyboard staus indicators
KBD_SEND_INDICATORS:
ldi KBD_BYTE,0xED ; keyboard command Set status indicators
rcall KBD_SEND ; subroutine send command to keyboard
mov KBD_BYTE,KBD_IND ; indicatoes value
/////---------------------------------------------------------------------------------------
///// Çàïèñü áàéòà â êëàâèàòóðó
/////---------------------------------------------------------------------------------------
KBD_SEND:
rcall KBD_SEND_BYTE
rcall KBD_READ0
brcs PARITY_ERROR
cpi KBD_BYTE,0xFA ; ïðîâåðêà êîððåêòíîñòè êîäà îòâåòà êëàâèàòóðû âûñòàâëåíèå ôëàãà äëÿ äàëüíåéøåé îáðàáîòêè ãäå òðåáóåòñÿ
PARITY_ERROR:
ret
;-------------------------------------------------------------------------------------------
KBD_SEND_BYTE:
sbi DDRC,0x05 ; set CLK pin as output (=0)
rcall WAIT_LOOP ; Wait 60-100ms
sbi DDRC,0x04 ; 1->DDC.4 DATA (=0)
rcall WAIT_LOOP2 ; 5ms
cbi DDRC,0x05 ; set CLK pin as input (=1)
rcall SMALL_WAIT
// íà÷èíàåòñÿ òàêòèðîâàíèå CLK îò êëàâèàòóðû
rcall WAIT_CLK0
rcall SMALL_WAIT
// öèêë îòïðàâêè 8 áèò äàííûõ -------------------------------
ldi KBD_LOOP_CNT,0x08
clr PARITY
rjmp L02A5
READ_LOOP:
rcall WAIT_CLK0
L02A5:
ror KBD_BYTE ; KBD_BYTE>> (ñäâèã âïðàâî, âûäâèíóòûé áèò ïîìåùàåòñÿ â C)
brcs SEND_1 ; åñëè C=1
// Îòïðàâêà áèòà = 0
sbi DDRC,0x04 ; 1->DDRC.4 (â ðåæèì çàïèñè, íà ïèíå 0, ò.ê. PortC.4 = 0)
rjmp L02AB
SEND_1: // Îòïðàâêà áèòà = 1
cbi DDRC,0x04 ; 0->DDRC.4 (â ðåæèì ÷òåíèÿ) âðîäå êàê îòïðàâëÿåòñÿ 1
inc PARITY ; âû÷èñëåíèå áèòà ÷åòíîñòè
L02AB:
rcall WAIT_CLK1
dec KBD_LOOP_CNT
brne READ_LOOP
// êîíåö öèêëà îòïðàâêè ---------------------------------------
// îòïðàâêà áèòà ÷åòíîñòè
rcall WAIT_CLK0
cbi DDRC,0x04
sbrc PARITY,0x00
sbi DDRC,0x04
rcall WAIT_CLK1
// ñòîïîâûé áèò
rcall WAIT_CLK0
cbi DDRC,0x04
rcall WAIT_CLK1
// ACK
rcall WAIT_CLK0
rcall WAIT_CLK1
ret
/////---------------------------------------------------------------------------------------
//READ FROM KEYBOARD -----------------------------------------------------------------
KBD_READ0:
rcall SMALL_WAIT
KBD_READ:
cbi DDRC,0x05 ; CLK íà ÷òåíèå
//öèêë îæèäàíèÿ ïîêà íà DATA ïèíå íå ñòàíåò 0 (ò.å. íà÷àëî ïðèåìà äàííûõ îò êëàâèàòóðû)
DATA_1_LOOP:
sbic PinC,0x04
rjmp DATA_1_LOOP ; Loop if DATA KBD PIN=1
KBD_READ1:
rcall SMALL_WAIT
// ÷èòàåì ñòàðòîâûé áèò
rcall WAIT_CLK0 ; ïîñëå ýòîãî CLK=0 è C=0
rcall WAIT_CLK1 ; ïîñëå ýòîãî CLK=1 è C=0
//öèêë ÷òåíèÿ 8 áèò äàííûõ------------------------------------
ldi KBD_LOOP_CNT,0x08
clr PARITY
KBD_DATA_LOOP:
rcall WAIT_CLK0
// read bit to carry flag
clc ; clear Carry flag
sbis PinC,0x04 ; if DATA pin = 1 skip jmp
rjmp KBD_DATA_BIT
inc PARITY ; if bit is set - increase parity
sec ; set Carry flag
KBD_DATA_BIT:
ror KBD_BYTE ; >KBD_BYTE>> (rotate through Carry)
rcall WAIT_CLK1 ; æäåì ïîêà CLK íå ñòàíåò ðàâíî 1
dec KBD_LOOP_CNT ; KBD_LOOP_CNT--
brne KBD_DATA_LOOP
//êîíåö öèêëà ÷òåíèÿ-------------------------------------------
// ÷òåíèå áèòà ÷åòíîñòè
rcall WAIT_CLK0
sbic PinC,0x04 ; if DATA pin = 0 skip inc
inc PARITY ; ðàñ÷åò áèòà ÷åòíîñòè
rcall WAIT_CLK1
// ÷òåíèå ñòîï áèòà
rcall WAIT_CLK0
rcall WAIT_CLK1
// ïðîâåðêà áèòà ÷åòíîñòè
sbrs PARITY,0x00
rjmp READ_ERROR ; îøèáêà åñëè áèò íå óñòàíîâëåí
clc ; 0 -> C
sbi DDRC,0x05 ; 1->CLK
ret
READ_ERROR:
clr KBD_BYTE ; ^KBD_BYTE
sec ; 1->C
sbi DDRC,0x05 ; CLK to output
ret
;----------------------------------------------------------------------------------------
; Ïîäïðîãðàììû îæèäàíèÿ ñìåíû óðîâíÿ CLK
;
; Ïðîâåðêà ïåðåïîëíåíèÿ òàéìåðà è CLK: öèêë ïîêà òàéìåð íå ïåðåïîëíèòñÿ èëè CLK íå ñòàíåò ðàâíî 1
; Åñëè òàéìåð ïåðåïîëíèëñÿ, çíà÷èò òàéìàóò è áèò íå ïðèíÿò
WAIT_CLK1:
sbis PinC,0x05 ; CLK=1 ïðîïóñêàåì jmp
rjmp WAIT_CLK1 ; loop
ret
; Ïðîâåðêà ïåðåïîëíåíèÿ òàéìåðà è CLK: öèêë ïîêà òàéìåð íå ïåðåïîëíèòñÿ èëè CLK íå ñòàíåò ðàâíî 0
WAIT_CLK0:
sbic PinC,0x05 ; CLK=0 ïðîïóñêàåì jmp
rjmp WAIT_CLK0
ret
;----------------------------------------------------------------------------------------
; in value - bit number in r16, out value in r18
SET_BIT:
ldi r18,0x01
SET_BIT_LOOP:
tst r16
breq SET_BIT_END
lsl r18
dec r16
rjmp SET_BIT_LOOP
SET_BIT_END:
ret
; Ïîäïðîãðàììû òàéìèíãîâ
// çàäåðæêà 50 öèêëîâ LONG_WAIT
LONG_WAIT_50:
ldi KBD_LOOP_CNT,0x32
rjmp L02FD
// çàäåðæêà 15 öèêëîâ LONG_WAIT
LONG_WAIT_15:
ldi KBD_LOOP_CNT,0x0F
L02FD:
rcall LONG_WAIT
dec KBD_LOOP_CNT
brne L02FD
ret
// çàäåðæêà 100 öèêëîâ WAIT_LOOP
LONG_WAIT:
ldi r18,0x64
mov r1,r18
L0308:
rcall WAIT_LOOP
dec r1
brne L0308
ret
// Öèêë îæèäàíèÿ CLK Low ïðè çàïèñè
WAIT_LOOP:
ldi r18,TIMING_COEFF*10
L0310:
nop
nop
nop
nop
nop
dec r18
brne L0310
ret
// Öèêë îæèäàíèÿ Data Low ïðè çàïèñè
WAIT_LOOP2:
ldi r18,TIMING_COEFF
L0311:
nop
dec r18
brne L0311
ret
// êîðîòêàÿ çàäåðæêà
SMALL_WAIT:
nop
ret
;----------------------------------------------------------------------------------------------------------
; Òàáëèöû ðàñêëàäêè êëàâèàòóðû äëÿ ðàáîòû â ðåæèìå Scan Code 2
;----------------------------------------------------------------------------------------------------------
; Îñíîâíàÿ òàáëèöà ñîñòîèò èç äâóõ ïîëîâèí, ïåðâàÿ ñîîòâåòñòâóåò êëàâèøàì, êîòîðûå ïðè íàæàòèè âûäàþò
; îäíîáàéòíûé ñêàí-êîä, âòîðàÿ ïîëîâèíà êëàâèøàì, êîòîðûå ïðè íàæàòèè âûäàþò äîïîëíèòåëüíî ïðåôèêñ 0xE0.
; Â ýòîé òàáëèöå êàæäîìó ñêàí-êîäó IBM-êëàâèàòóðû ñîîòâåòñòâóåò îäèí áàéò, êîòîðûé ñîäåðæèò èíôîðìàöèþ
; î íîìåðå êîëîíêè è íîìåðå ñòðîêè, â êîòîðîé áóäåò èìèòèðîâàòñÿ çàìûêàíèå êîíòàêòà êëàâèàòóðû Ñïåêòðóìà.