Subversion Repositories KoE_projects

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

; контроллер PS2 клавиатуры/мыши для ZX-Spectrum
; by KingOfEvil, год 2oo7 от р.х.
;
; Тактовая частота микроконтроллера 8 МГц
; Назначение выводов микроконтроллера:
;
;  PS2: PA4 - CLK
;       PA3 - DATA
;
;  PB7..PB0 - данные
;
;  PA0 - если 0, то подключить клавиатуру к PS2 интерфейсу
;        если 1, то подключена мышь
;  PA1 - сброс регистров в ПЛИС       
;  PA2 - строб для приема информации с PB7..PB0 (прием по переднему фронту
;        в сдедующей последовательности: клавиатура, мышь X, мышь Y, мышь кн.
;        Через PB7..PB0 будет передано 8 байтов, которые нужно принимать в ПЛИС
;        последовательно с каждым фронтом импульса на PA2)


; область векторов прерываний

        jmp start0 ;<0>  Начальный пуск программы
        nop        ;<1>  Сторожевой таймер
        jmp sterr  ;<2>  выход за границу стека
        jmp sc_m   ;<3>  Таймер A
        nop        ;<4>  не используется
        nop        ;<5>  не используется
        jmp sc_key ;<6>  Порт A
        nop        ;<7>  Порт B
        nop        ;<8>  не используется
        nop        ;<9>  не используется
        nop        ;<10> не используется
        nop        ;<11> не используется
        nop        ;<12> не используется
        nop        ;<13> не используется
        nop        ;<14> не используется
        rst        ;<15> Завершение записи в флэш


start0: ldr #a,0   ; Сегмент A - рабочие регистры портов
        ldr #b,18h ; Сегмент B - регистры конфигурации портов
        ldr #c,64  ; Сегмент С - переменные
        ldr #d,80  ; Сегмент D - переменные

        movl %b1,00111011b ; Установка конфигурации порта A
        movl %b1,00000110b
        movl %b1,00011111b
        movl %b1,00000000b
        movl %b1,00000000b
        movl %b1,00000000b ; прерывание по отрицательному перепаду уровня
                                                                  
        jmp rest

start:  ldr #a,0   ; Сегмент A - рабочие регистры портов
        ldr #b,18h ; Сегмент B - регистры конфигурации портов
        ldr #c,64  ; Сегмент С - переменные
        ldr #d,80  ; Сегмент D - переменные

        jsr init           ; инициализируем порты
        jsr keyini         ; инициализируем матрицу ZX-клавиш
        jsr mousini        ; инициализируем мышку
        jsr timer          ; инициализируем прерывания от таймера

        ;movl %d0,0
        jsr rdflsh

main:   bttl %d5,0001b
        jnz clm
       
        jmp main          ; и есчо разок ...

clm:    cmpl %d4,255
        jz main            ; если мышь не была расползнана при инициализации
        movl %a4,0         ; тормозим счетчик и запрещаем прерывания от него
        jsr wait           ; ожидаем готовность мыши
        movl %c3,11101011b ; код команды запроса состояния
        jsr wr_sc          ; засылаем в мышь
        jsr more           ; принимаем ответ
        cmpl %c3,11111010b ; все о.к. ?
        jnz exi            ; видимо, нет
        jsr more           ; ну а если все о.к., то принимаем еще 3 байта
        ldr #b,72
        mov %b7,%c3 ; zz
        jsr more
        jsr mashtb      
        ldr #b,72
        add %b5,%c3 ; xx

        jsr more
        
        jsr mashtb
        ldr #b,72
        add %b6,%c3 ; yy
        
        bish %b7,1111b    ; обрабатываем данные о нажатых кнопках мыши
        bicl %b7,1000b
        btgl %b7,1111b
                 
        bicl %d5,0001b    ; clear mouse interruption bit
        
        jsr vyvod         ; закачиваем данные в ПЛИС


        movl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5
        movl %a5,2         ; 


exi:    movl %a4,00000011b; запускаем счетчик и разрешаем прерывания от него
        jmp main

mashtb: mov %d1,d0      ; грузим в d1 коэффициент замедления мышки
        cmpl %d1,0
        jz vjopu
        cmpl %c3,0
        jz vjopu        

        cmpl %c3,128
        js msh1 ; если меньше 128
        movl %d2,10000000b;

msh0:   shr %c3
        shra %d2
        dec %d1
        jnz msh0

        shl %d2         ; нужно установить столько старших разрядов, сколько
                        ; сдвигов было проделано (иначе стрелка будет 
                        ; дергаться из-за того, что вместо уменьшения координат
                        ; произойдет их увеличение). В d2 теперь как раз и будет
                        ; установлено нужное количество старших разрядов.

        or %c3,%d2
        
        rts

msh1:   mov %d1,%d0
msh2:   shr %c3
        dec %d1
        jnz msh2
        
        cmpl %c3,0
        jnz vjopu
        movl %c3,1

vjopu:  rts


vyvod:                     ; закачка данных в ПЛИС
        bicl %a1,0010b     ; сбрасываем регистры в ПЛИС
        nop
        nop
        bisl %a1,0010b     ; снимаем сигнал сброса
        ldr #b,72   
        mov %a2,%b0        ; понеслась :-)
        jsr strobe
        mov %a2,%b1
        jsr strobe
        mov %a2,%b2
        jsr strobe
        mov %a2,%b3
        jsr strobe
        mov %a2,%b4
        jsr strobe
        or %b5,%d4
        mov %a2,%b5
        jsr strobe
        or %b6,%d4
        mov %a2,%b6
        jsr strobe
        or %b7,%d4
        mov %a2,%b7
        jsr strobe
        movl %a2,0
        ldr #b,18h
        rts

strobe: bisl %a1,0100b ; даем строб
        nop
        nop
        bicl %a1,0100b ; снимаем строб
        rts

sc_m:   clie
        mov %c3,%a4
        bisl %d5,0001b
        stie
        rti



sc_key: clie               ; запрещаем прерывания
        mov %c3,%a1        ; снимаеи сигнал запроса прерывания                                                      +
        movl %a4,00000000b ; тормозим счетчик и запрещаем прерывания от него
        push #b
        ldr #b,18h
        movl %b1,00101011b
        movl %b1,00000111b ; разрешаем запись в PA0
        bicl %a1,0001b     ; захватываем сигнал переключения на клавиатуру
        bisl %d5,0010b     ; устанавливаем флаг прерывания от клавиатуры
       
        jsr key
        jsr vyvod

        ldr #b,18h
        movl %b1,00101011b
        movl %b1,00000110b ; запрещаем запись в PA0

        movl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5
        movl %a5,150         ; итак, получили полный коэффициент
        movl %a4,00000011b ; запускаем счетчик и разрешаем прерывания от него
        pop #b

        stie
        rti

; ****

key:    movl %c4,0
        movl %c5,0
        jsr rd_sc               ; Ура! Начинаем принимать скан-код! 
        mov %c4,%c3
        cmpl %c4,11100000b      ; принимать второй байт скан-кода?
        jz key1
        cmpl %c4,11100001b
        jz key1
        jmp conttt
key1:   bisl %c5,0010b          ; устанавливаем флажок               
        jsr more
        mov %c4,%c3    

conttt: cmpl %c4,7              ; если нажата кнопка f12, то даем reset
        jz rest
        cmpl %c4,078h
        jnz conttz
        jsr nmi
conttz: cmpl %c4,0              ; если была ошибка, то считаем, что был
                                ; принят код отжатия. Понимаю, что лажа, но
                                ; почему-то в 99% случаев ошибки происходят
                                ; именно при приеме кода отжатия. Уж не знаю,
                                ; почему. Спишем на ламерство изобретателей
                                ; PS2 интерфейса (ну не признавать же свою
                                ; криворукость ;-) )
        jz podgon
        cmpl %c4,11110000b      ; это был код отжатой клавиши?
        jz podgon
        cmpl %c4,11110001b
        jz podgon
        jmp contt0
podgon: bisl %c5,0001b          ; устанавливаем флажок
        jsr more                ; принимаем еще один скан-код - код отжатой 
        mov %c4,%c3             ; клавиши 

contt0: bttl %c5,0010b
        jz contta

contt1: cmpl %c4,00010001b ; правый alt = левый alt = symbol shift
        jz contt2

ex5:    cmpl %c4,74h
        jnz ex6
        jsr shift
        movl %c4,3eh

ex6:    cmpl %c4,6bh
        jnz ex7
        jsr shift
        movl %c4,2eh

ex7:    cmpl %c4,75h       ; up
        jnz ex8
        jsr shift
        movl %c4,3dh
        
ex8:    cmpl %c4,72h       ; down
        jnz ex9
        jsr shift
        movl %c4,36h

ex9:    cmpl %c4,71h       ; backspace = del
        jnz contt2
        jsr backsp 
        jmp contt2

contta: cmpl %c4,66h            ; это клавиша backspace?
        jnz conttd
        jsr backsp              ; если да, то ставим в соответсвие caps+0

conttd: cmpl %c4,59h            ; правый shift = левый shift = caps shift
        jnz conttw
        movl %c4,12h

conttw: cmpl %c4,0dh            ; TAB = EDIT = caps + 0
        jnz conte
        jsr shift
        movl %c4,16h

conte:  cmpl %c4,58h            ; Caps lock = caps + 2
        jnz conte1
        jsr shift
        movl %c4,1eh

conte1: cmpl %c4,049h ; точка
        jnz conte2
        jsr sshift
        movl %c4,03ah

conte2: cmpl %c4,041h ; запятая
        jnz conte3
        jsr sshift
        movl %c4,031h

conte3: cmpl %c4,055h  ; =
        jnz conte4
        jsr sshift
        movl %c4,004bh

conte4: cmpl %c4,04eh  ; -
        jnz conte5
        jsr sshift
        movl %c4,03bh

conte5: cmpl %c4,6
        jnz conte6
        bttl %c5,0001b
        jnz conte6
        inc %d0   ; f2 - увеличения коэффициента замедления мышки
        
conte6: cmpl %c4,4
        jnz conte7
        bttl %c5,0001b
        jnz conte7
        dec %d0 ; f3 - уменьшение коэффициента замедления мышки
        cmpl %d0,255
        jnz conte7
        movl %d0,0

conte7: cmpl %c4,5
        jnz contt2
        jsr wrflsh ; - f1 - сохранение коэффициента замедления во flash - память

contt2: mdal %c1,scode
        mdah %c2,scode      ; Грузим в регистр косвенной адресации адрес
        mtpr #6,%c1         ; таблицы скан-кодов в памяти команд
        mtpr #7,%c2         ; (вся хрень с автоинкрементом, доступ через d7) 
                
ccd:    movl %c1,72
cyck0:  movl %c6,8         ; 8 бит
        movl %c2,11111110b ; стартовое значение
cyck1:  mov %c3,d7         ; берем скан-код из таблицы
        cmp %c3,%c4        ; совпал с прочитанным?
        jz skey            ; если совпал то идем на skey
        sst 0001b          ; устанавливаем флаг c
        rlc %c2            ; смотрим следующий вариант
        dec %c6
        jnz cyck1
        inc %c1
        cmpl %c1,77        ; проверили все 5 наборов по 8 клавиш
        jnz cyck0
        movl %c4,0
        rts

ppodgon:jsr keyini
        jmp podgon

         
skey:   mtpr #4,%c1
        movl %c1,01000000b
        mtpr #5,%c1
        bttl %c5,0001b
        jnz reskey 
        and %d6,%c2        ; фиксируем нажатие клавиши
        movl %c4,0
        rts
reskey: not %c2
        or %d6,%c2         ; фиксируем отжатие клавиши
        movl %c4,0
        rts ; Усё       

more:   movl %c0,222       ; будем ждать (3*45+3)*222 команд 
wt0:    movl %c1,45       ; если за это время не поступит новый байт
wt1:    mov %c2,%a1        ; данных, то выходим по ошибке
        btth %c2,0001b;
        jz wt2
        dec %c1
        jnz wt1
        dec %c0
        jnz wt0;
        rts     
wt2:    jsr rd_sc
        rts

backsp: jsr shift       ; del = shift+0 обрабатываем shift
        movl %c4,45h    ; подсовываем скан-код нуля
        rts

shift:  ldr #b,72
        bttl %c5,0001b
        jnz rshift 
        bicl %b0,0001b       ; фиксируем нажатие клавиши
        ldr #b,18h
        rts
rshift: bisl %b0,0001b       ; фиксируем отжатие клавиши
        ldr #b,18h
        rts      

sshift: ldr #b,72
        bttl %c5,0001b
        jnz rsshift 
        bich %b1,1000b       ; фиксируем нажатие клавиши
        ldr #b,18h
        rts
rsshift:bish %b1,1000b       ; фиксируем отжатие клавиши
        ldr #b,18h
        rts      

nmi:    bicl %a1,0010b     ; даем сигнал сброса
        movl %a2,1         ; даем data0 = 1 (теперь на выходе nmi ПЛИС
                           ; появится 0)
        nop
        nop
        nop
        nop
        movl %a2,0         ; убираем 1 на data0
        bisl %a1,0010b     ; снимаем сигнал сброса
        rts             

; **************************************************************

rd_sc:  ; Процедура чтения байта скан-кода

        movl %c3,0 ; Будем читать в c3. Начальное значение 0
        mov %c1,%a1
        bttl %c1,1000b ; проверяем стартовый бит
;       jnz error ; если не 0, то кладем на этот байт скан-кода, да и на весь 
                  ; скан-код

        movl %c2,8 ; будем читать 8 бит
scan1:  jsr wait
        jsr wait1 ; идем на процедуру ожидания следующего такта   
        shr %c3
        mov %c1,%a1
        bttl %c1,1000b
        jz scan2
        bish %c3,1000b ; если data=1, то ставим эту 1 в c3
scan2:  dec %c2
        jnz scan1
        jsr wait ; Байт скан-кода вроде бы прочитали, теперь надо принять бит
                 ; четности и затем стоповый бит.
        jsr wait1; На бит четности сразу же кладем, ибо нафиг он не нужен
        
        jsr wait
        jsr wait1
        mov %c1,a1
        bttl %c1,1000b ; Проверяем стоповый бит

;       jz error ; если он =0, то кладем на этот скан-код. Видимо, была ошибка
        jsr wait ; ждем прихода в исходное состояние
        rts        

; ******************************************************************

wr_sc:  ; Процедура передачи байта скан-кода
        ; Чтобы перейти в режим передачи данных, нужно удерживать 0 на линии
        ; clk не менее 60 мкс. На всякий случай будем держать 0 80 мкс.
        ; 80 это 320 команд (640 тактов) при F=8 МГц

        movl %b1,00101011b ; будем писать в подрегистр типа вывода порта A
        movl %b1,00011110b
        bicl %a1,1000b
        bich %a1,0001b     ; выдаем 0 в clk и data

        movl %c0,64 ; Ждем 64*5=320 команд 
repl:   nop        
        nop
        nop
        dec %c0
        jnz repl;
        
        bish %a1,0001b ; снимаем 0 clk
        movl %b1,00101011b ; будем писать в подрегистр типа вывода порта A
        movl %b1,00001110b ; переводим clk на чтение
        bicl %a1,1000b
        movl %c0,0 ; это будет счетчик единичных битов для формирования
                   ; бита четности
                
w1:     movl %c7,255   ; ждем 0, т.е. начала тактирования процесса
w2:     btth %a1,0001b
        jz e1
        nop
        nop
        nop
        nop
        nop
        dec %c7
        jnz w2
e1:
                   ; передачи данных девайсом
        movl %c2,8 ; будем передавать 8 бит
wr_0:              ; передаем бит

wr1:    shr %c3
        jc wr2
        bicl %a1,1000b
        jmp wr3

wr2:    bisl %a1,1000b
        inc %c0         ; добавляем 1 к счетчику
wr3:    btth %a1,0001b  ; ждем 1 на clk
        jz wr3;

         ; ожидаем защелкивания бита данных девайсом и его
         ; готовности к приему следующего бита (0 на clk)

        movl %c7,255
ww2:    btth %a1,0001b
        jz ee1
        nop
        nop
        nop
        nop
        nop
        dec %c7
        jnz ww2

ee1:    dec %c2
        jnz wr_0 
        
                 ; Байт скан-кода вроде бы передали, теперь надо передать бит
                 ; четности и затем принять стоповый бит. Мля, ну какие же
                 ; ламеры придумали этот ps2 интерфейс :-E

        movl %c3,0
        shr %c0  ; Значение бита четности берем из 0-го разряда %c0
        jnc bcnz ; Если бит четности =0
        bisl %c3,1 ; если бит четности =1

bcnz:   ; передаем 

        shr %c3
        jc wrr2
        bicl %a1,1000b
        jmp wrr3

wrr2:   bisl %a1,1000b
        inc %c0   ; добавляем 1 к счетчику

wrr3:   ; ждем 1
        btth %a1,0001b
        jz wrr3;

        ; ожидаем защелкивания бита данных девайсом и его
        ; готовности к приему следующего бита

        movl %c7,255   ; ждем 0
wwa1:   btth %a1,0001b
        jz eex
        nop
        nop
        nop
        nop
        nop
        dec %c7
        jnz wwa1

eex:    movl %b1,00101011b ; будем писать в подрегистр типа вывода порта A
        movl %b1,00000110b ; переводим data на чтение
        
it:     ; ждем 1
        btth %a1,0001b
        jz it;
        
        jsr wait1 ; ожидаем приход стопового бита


        movl %c7,255   ; ждем 0
awa1:   btth %a1,0001b
        jz wex
        nop
        nop
        nop
        nop
        nop
        dec %c7
        jnz awa1

wex:    mov %c1,%a1
        bttl %c1,1000b ; проверяем стоповый бит
                       ; только непонятно, зачем ;)

ht:     ; ждем 1
        btth %a1,0001b
        jz ht;
        rts        

error:  movl %c3,0

wait:   mov %c1,%a1    ; ждем 1
        btth %c1,0001b
        jz wait;
        rts
wait1:  movl %c7,255   ; ждем 0
wai1:   mov %c1,%a1
        btth %c1,0001b
        jz exit1
        nop
        nop
        nop
        nop
        nop
        dec %c7
        jnz wai1
        jmp error
exit1:  rts

; ********************

wrflsh: ldr #b,56  ; адрес регистра управления блока ЭСППЗУ данных
        movl %b1,0 ; адрес ячейки = 0 (используем только один байт)
        mov %b7,%d0
        movl %b0,00000001b
wrf1:   bttl %b0,0001b
        jnz wrf1 ; ждем, пока происходит запись
        ldr #b,18h
        rts

; ********************

rdflsh: ldr #b,56  ; адрес регистра управления блока ЭСППЗУ данных
        movl %b1,0 ; адрес ячейки = 0 (используем только один байт)
        movl %b0,00000010b
rdf1:   bttl %b0,0010b
        jnz rdf1 ; ждем, пока происходит чтение
        mov %d0,%b7
        ldr #b,18h
        rts

; ********************
init:   movl %b1,00111011b ; Установка конфигурации порта A
        movl %b1,00000110b
        movl %b1,00011111b
        movl %b1,00000000b
        movl %b1,00000000b
        movl %b1,00000001b ; прерывание по отрицательному перепаду уровня
                           ; на линии clk_key  для опроса клавиатуры

        stie

        movl %b2,00011011b ; Установка конфигурации порта B
        movl %b2,11111111b
        movl %b2,11111111b
        movl %b2,0
        movl %b2,0
        movl %b2,0

        bisl %a1,0010b     ; выдаем 1 на линию сброса регистров в ПЛИС
        bicl %a1,0100b     ; выдаем 0 на линию strobe

        movl %d5,0         ; флажок (потом пригодится)
        rts

keyini:                   ; инициализация матрицы клавиатуры
        ldr #b,72         ; весь буфер из 5-и байтов заполняем
        movl %b0,11111111b ; значениями 255
        movl %b1,11111111b
        movl %b2,11111111b
        movl %b3,11111111b
        movl %b4,11111111b
        ldr #b,18h
        jsr vyvod
        rts

; здесь надо бы отключать клавиатуру - потом поправлю

mousini:movl %d4,0
        ldr #b,72
        movl %b5,125
        movl %b6,125
        movl %b7,255
        ldr #b,18h
        jsr wait           ; мышь подключили. Теперь ожидаем ее готовность
                           ; Теперь нужно передать в мышь команду запроса
                           ; ее состояния (здесь неудобно использовать
                           ; потоковый режим, хотя, в принципе, можно)
        movl %c3,11110000b ; код команды перехода в Remote mode
        jsr wr_sc
        jsr more           ; принимаем код подтверждения 
        cmpl %c3,11111010b 
        jnz mousoff       ; error 
        movl %c3,11110011b
        jsr wr_sc
        jsr more
        movl %c3,40
        jsr wr_sc
        jsr more        
        rts

mousoff:movl %d4,255
        rts

timer:                     ; мышку будем опрашивать по прерываниям от таймера
        movl %a4,00010010b ; подключаем регистр конфигурации к адресу 5     
        movl %a5,01001110b ; задаем коэффициент деления тактовой частоты 1/128
        movl %a4,00000010b ; подключаем регистр интервала (low) к адресу 5
        movl %a5,113
        movl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5
        movl %a5,2         ; итак, получили полный коэффициент
                           ; деления 128*(2?4?*256+113)=80000, прерывания от
                           ; таймера будут идти с частотой Fтакт/80000=100 Гц
        movl %a4,00000011b ; пускаем таймер на счет
        stie               ; разрешаем прерывания
        rts


rest:   bicl %a1,0010b   
        nop
        nop
        bisl %a1,0100b 
        movl %c3,255
trmz0:  movl %c4,255
trmz1:  movl %c5,30
trmz2:  dec %c5
        jnz trmz2
        dec %c4
        jnz trmz1
        dec %c3
        jnz trmz0
        bicl %a1,0100b 
        nop
        nop
        bisl %a1,0010b
        rst
        jmp start

sterr:  rst
        jmp start
           
scode:  .byte 12h,1ch,15h,16h,45h,4dh,5ah,29h
        .even; байт 0: cs,a,q,1,0,p,ent,space

        .byte 1ah,1bh,1dh,1eh,46h,44h,4bh,11h
        .even; байт 1: z,s,w,2,9,o,l,ss

        .byte 22h,23h,24h,26h,3eh,43h,42h,3ah
        .even; байт 2: x,d,e,3,8,i,k,m

        .byte 21h,2bh,2dh,25h,3dh,3ch,3bh,31h
        .even; байт 3: c,f,r,4,7,u,j,n

        .byte 2ah,34h,2ch,2eh,36h,35h,33h,32h
        .even; байт 4: v,g,t,5,6,y,h,b

.end;