
PAGE_0:		    	equ	82h	    ; порт 0 окна = addr 0000h
PAGE_1:			    equ	0A2h	; порт 1 окна = 4000h
PAGE_2:	    		equ	0C2h	; порт 2 окна = 8000h
PAGE_3:			    equ	0E2h	; порт 3 окна = 0c000h

SIO_CONTROL_A:   EQU 19h
SIO_DATA_REG_A:  EQU 18h
SIO_CONTROL_B:   EQU 1Bh
SIO_DATA_REG_B:  EQU 1Ah
CTC_CH0:         equ 10h
CTC_CH1:         equ 11h
CTC_CH2:         equ 12h
CTC_CH3:         equ 13h

RGMOD		equ 0c9h

; ....

    ; Запомним текущий видео-режим
    LD      C, DSS.GetVMod
    RST     10h
    LD      HL, GetVMod_Error_Message
    ;JR      C, PutError
    LD      C, A
    LD      (.Current_VMod), BC

    ; Запрос памяти

    ; сохраним текущие значения страниц
    IN      A, (PAGE_1)
    LD      (SavePage1), A
    IN      A, (PAGE_3)
    LD      (SavePage3), A

    ; Настройка прерываний CTC и SIO
    LD      HL, IM2_Empty     : LD (0FDFFh), HL
    
    LD      (0FD10h), hl
    LD      (0FD12h), hl
    LD      (0FD14h), hl
    LD      (0FD16h), hl
    LD      (0FD18h), hl
    LD      (0FD1Ah), hl
    LD      (0FD1Ch), hl
    LD      (0FD1Eh), hl
    
    LD      HL, IM2_VShandler : LD (0FD06h), HL
    
    LD      A, I
    LD      (.SaveInterrupt), A
    LD      A, 0FDh
    DI
    LD      I, A
    IM      2
    
.Sync:
    EI
    HALT
    DI
    IN      A, (SIO_CONTROL_A)
    BIT     0, A              ; 0-bit, байт пришел ?
    JR      Z, .EndSync             ; да, это прерывание от клавиатуры
    CALL    Keyboard.PS2_Scan
    JR      .Sync
.EndSync:

    LD      B, 5
.loopSync:
    DJNZ    .loopSync

    ; Настройка CTC
    LD      A, 057h : OUT (CTC_CH2), A
    LD      A, 112  : OUT (CTC_CH2), A
    LD      A, 0d7h : OUT (CTC_CH3), A
    LD      A, 160  : OUT (CTC_CH3), A
    LD      A, 0    : OUT (CTC_CH0), A
    
    ; Настройка SIO
    LD      A, 1   : OUT (SIO_CONTROL_A), A
    LD      A, 18h : OUT (SIO_CONTROL_A), A
    LD      A, 2   : OUT (SIO_CONTROL_B), A
    LD      A, 10h : OUT (SIO_CONTROL_B), A

    LD      HL, IM2_Keyhandler
    LD      (0FDFFh), HL    
 
    LD      (0FD10h), hl
    LD      (0FD12h), hl
    LD      (0FD14h), hl
    LD      (0FD16h), hl
    LD      (0FD18h), hl
    LD      (0FD1Ah), hl
    LD      (0FD1Ch), hl
    LD      (0FD1Eh), hl


Loop:
; основаной цикл
; ................

    LD      A, (Keyboard.KeyFlags)
    BIT     7, A
    JR      NZ, .Key_ESC


    JP      Loop

.Key_ESC: ; Выход

    DI
    ; Восстановим прерывания и CTC
    LD      A, 057h : OUT (CTC_CH3), A
    LD      A, 160  : OUT (CTC_CH3), A
    
    ; Восстановим SIO
    LD      A, 1   : OUT (SIO_CONTROL_A), A
    LD      A, 0   : OUT (SIO_CONTROL_A), A
    LD      A, 2   : OUT (SIO_CONTROL_B), A
    LD      A, 10h : OUT (SIO_CONTROL_B), A
    
.SaveInterrupt+*: LD A, 0
    LD      I, A
    IM      1
    EI

    CALL    Keyboard.PS2_Clear_Buf
    
    ; Восстанавливаем страницы памяти 
    LD      A,(SavePage1)
    OUT     (PAGE_1), A
    LD      A,(SavePage3)
    OUT     (PAGE_3), A
    
    ; Освободим память запрошенную память
    
    ; возвращаем текстовый режим
.Current_VMod+*: LD BC, 0
    LD      A, C
    LD      C, DSS.SetVMod
    RST     10h
    
.Exit:
.ExitCode+*: LD B, 0
    LD      C, DSS.Exit
    RST     10h
    JR      $

UpdateMechanics:
    LD      A, (Keyboard.KeyFlags)
    OR      A
    RET     Z
    BIT     3, A
    JR      NZ, .Key_UP
    BIT     2, A
    JR      NZ, .Key_DOWN
    RET
    
.Key_DOWN:
; ...
.Key_UP:
; ...
    RET


IM2_Empty:
    EI
    RETI

IM2_Keyhandler:
    PUSH    AF, BC, DE, HL
    EXX
    EX      AF, AF
    PUSH    AF, BC, DE, HL, IX, IY
    IN      A, (SIO_CONTROL_A)
    BIT     0, A              ; 0-bit, байт пришел ?
    CALL    NZ, Keyboard.PS2_Scan           ; да, это прерывание от клавиатуры
.SkipClearKeyFlags:    
    POP     IY, IX, HL, DE, BC, AF
    EX      AF, AF
    EXX
    POP     HL, DE, BC, AF
    EI
    RETI

IM2_VShandler:
    PUSH    AF, BC, DE, HL
    EXX
    EX      AF, AF
    PUSH    AF, BC, DE, HL, IX, IY

.NeedChangePage+*: LD A, 0 ; 1 - нужно переключить экран
    OR      A
    JR      Z, .skip

.NumberScreen+*: LD B, 0 ; 0/1 - номер экрана, который в данный момент выводится
    ; Переключаем экран
	IN		A, (RGMOD)
	AND		0feh
    OR      B
    XOR     1
	OUT		(RGMOD), A
    AND     1
    LD      (.NumberScreen), A

    XOR     A
    LD      (.NeedChangePage), A
.skip:
    CALL    UpdateMechanics ; Возможно нужно перенести из прерывания

; Расчет FPS
; ..........

    POP     IY, IX, HL, DE, BC, AF
    EX      AF, AF
    EXX
    POP     HL, DE, BC, AF
    EI
    RETI

; очистка буфера клавиатуры
; Портит регистры AF
Keyboard.PS2_Clear_Buf:
    IN      a, (SIO_CONTROL_A)
    BIT     0, a
    RET     Z
	IN      A, (SIO_DATA_REG_A)
    JR      PS2_Clear_Buf

; Из PS/2 возвращает в Keyboard.KeyFlags нажатые клавиши:
; бит кнопка
;  0 - RIGHT
;  1 - LEFT
;  2 - DOWN
;  3 - UP
;  4 - SPACE
;  5 - none
;  6 - ENTER
;  7 - ESC
; Портит регистры AF, BC, DE, HL
Keyboard.PS2_Scan:
    LD      HL, .KeyStatus
    LD      DE, 0c686h ; D - код команды SET 0, (HL) / E - код команды RES 0, (HL)
.Loop
    IN      a, (SIO_CONTROL_A)
    BIT     0, a
    RET     Z
	IN      A, (SIO_DATA_REG_A)
	CP	    0E0h
	JR      NZ, .kh1
	SET     7, (HL) ; // двойной сканкод
    JR      .Loop
    
.kh1:	
    CP      0F0h
	JR      NZ, .kh2
	SET     6, (HL) ; // отпускание клавиши
    JR      .Loop
    
.kh2:	
    BIT     7, A ; автоповтор?
	JR      Z, .kh3
	LD      (HL), 0
    JR      .Loop
    
.kh3:
    LD      B, 8
	BIT     6, (HL)
    LD      C, D ; С - код команды SET 0, (HL)
	JR      Z, .KeyPress
.KeyRelease:
    LD      C, E ; С - код команды RES 0, (HL)
.KeyPress:
	LD      (HL), 0
    PUSH    HL
    INC     HL
.KeyPressLoop:
    CP      (HL)
    JR      Z, .SetKey
    INC     HL
    DJNZ    .KeyPressLoop
    POP     HL
    JR      .Loop
.SetKey:
    LD      A, B
    DEC     A
    CPL
    RLA
    RLA
    RLA
    AND     00111000b
    OR      C
    LD      (.CodeSet + 1), A ; Изменяем команду по .CodeSet
    POP     HL
    DEC     HL
.CodeSet: SET 0, (HL)
    INC     HL
    JR      .Loop
    
.KeyFlags:  DB 0
.KeyStatus: DB 0
.KeysArray: DB 74h,  6bh,  72h,  75h,  29h,  00h,  5ah,  76h

Keyboard.KeyFlags: EQU .KeyFlags
    
SavePage1: DB 0
SavePage3: DB 0

