Blame | Last modification | View Log | Download | RSS feed
; контроллер 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> Таймер Anop ;<4> не используетсяnop ;<5> не используетсяjmp sc_key ;<6> Порт Anop ;<7> Порт Bnop ;<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 ; Установка конфигурации порта Amovl %b1,00000110bmovl %b1,00011111bmovl %b1,00000000bmovl %b1,00000000bmovl %b1,00000000b ; прерывание по отрицательному перепаду уровняjmp reststart: 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,0jsr rdflshmain: bttl %d5,0001bjnz clmjmp main ; и есчо разок ...clm: cmpl %d4,255jz main ; если мышь не была расползнана при инициализацииmovl %a4,0 ; тормозим счетчик и запрещаем прерывания от негоjsr wait ; ожидаем готовность мышиmovl %c3,11101011b ; код команды запроса состоянияjsr wr_sc ; засылаем в мышьjsr more ; принимаем ответcmpl %c3,11111010b ; все о.к. ?jnz exi ; видимо, нетjsr more ; ну а если все о.к., то принимаем еще 3 байтаldr #b,72mov %b7,%c3 ; zzjsr morejsr mashtbldr #b,72add %b5,%c3 ; xxjsr morejsr mashtbldr #b,72add %b6,%c3 ; yybish %b7,1111b ; обрабатываем данные о нажатых кнопках мышиbicl %b7,1000bbtgl %b7,1111bbicl %d5,0001b ; clear mouse interruption bitjsr vyvod ; закачиваем данные в ПЛИСmovl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5movl %a5,2 ;exi: movl %a4,00000011b; запускаем счетчик и разрешаем прерывания от негоjmp mainmashtb: mov %d1,d0 ; грузим в d1 коэффициент замедления мышкиcmpl %d1,0jz vjopucmpl %c3,0jz vjopucmpl %c3,128js msh1 ; если меньше 128movl %d2,10000000b;msh0: shr %c3shra %d2dec %d1jnz msh0shl %d2 ; нужно установить столько старших разрядов, сколько; сдвигов было проделано (иначе стрелка будет; дергаться из-за того, что вместо уменьшения координат; произойдет их увеличение). В d2 теперь как раз и будет; установлено нужное количество старших разрядов.or %c3,%d2rtsmsh1: mov %d1,%d0msh2: shr %c3dec %d1jnz msh2cmpl %c3,0jnz vjopumovl %c3,1vjopu: rtsvyvod: ; закачка данных в ПЛИСbicl %a1,0010b ; сбрасываем регистры в ПЛИСnopnopbisl %a1,0010b ; снимаем сигнал сбросаldr #b,72mov %a2,%b0 ; понеслась :-)jsr strobemov %a2,%b1jsr strobemov %a2,%b2jsr strobemov %a2,%b3jsr strobemov %a2,%b4jsr strobeor %b5,%d4mov %a2,%b5jsr strobeor %b6,%d4mov %a2,%b6jsr strobeor %b7,%d4mov %a2,%b7jsr strobemovl %a2,0ldr #b,18hrtsstrobe: bisl %a1,0100b ; даем стробnopnopbicl %a1,0100b ; снимаем стробrtssc_m: cliemov %c3,%a4bisl %d5,0001bstiertisc_key: clie ; запрещаем прерыванияmov %c3,%a1 ; снимаеи сигнал запроса прерывания +movl %a4,00000000b ; тормозим счетчик и запрещаем прерывания от негоpush #bldr #b,18hmovl %b1,00101011bmovl %b1,00000111b ; разрешаем запись в PA0bicl %a1,0001b ; захватываем сигнал переключения на клавиатуруbisl %d5,0010b ; устанавливаем флаг прерывания от клавиатурыjsr keyjsr vyvodldr #b,18hmovl %b1,00101011bmovl %b1,00000110b ; запрещаем запись в PA0movl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5movl %a5,150 ; итак, получили полный коэффициентmovl %a4,00000011b ; запускаем счетчик и разрешаем прерывания от негоpop #bstierti; ****key: movl %c4,0movl %c5,0jsr rd_sc ; Ура! Начинаем принимать скан-код!mov %c4,%c3cmpl %c4,11100000b ; принимать второй байт скан-кода?jz key1cmpl %c4,11100001bjz key1jmp contttkey1: bisl %c5,0010b ; устанавливаем флажокjsr moremov %c4,%c3conttt: cmpl %c4,7 ; если нажата кнопка f12, то даем resetjz restcmpl %c4,078hjnz conttzjsr nmiconttz: cmpl %c4,0 ; если была ошибка, то считаем, что был; принят код отжатия. Понимаю, что лажа, но; почему-то в 99% случаев ошибки происходят; именно при приеме кода отжатия. Уж не знаю,; почему. Спишем на ламерство изобретателей; PS2 интерфейса (ну не признавать же свою; криворукость ;-) )jz podgoncmpl %c4,11110000b ; это был код отжатой клавиши?jz podgoncmpl %c4,11110001bjz podgonjmp contt0podgon: bisl %c5,0001b ; устанавливаем флажокjsr more ; принимаем еще один скан-код - код отжатойmov %c4,%c3 ; клавишиcontt0: bttl %c5,0010bjz conttacontt1: cmpl %c4,00010001b ; правый alt = левый alt = symbol shiftjz contt2ex5: cmpl %c4,74hjnz ex6jsr shiftmovl %c4,3ehex6: cmpl %c4,6bhjnz ex7jsr shiftmovl %c4,2ehex7: cmpl %c4,75h ; upjnz ex8jsr shiftmovl %c4,3dhex8: cmpl %c4,72h ; downjnz ex9jsr shiftmovl %c4,36hex9: cmpl %c4,71h ; backspace = deljnz contt2jsr backspjmp contt2contta: cmpl %c4,66h ; это клавиша backspace?jnz conttdjsr backsp ; если да, то ставим в соответсвие caps+0conttd: cmpl %c4,59h ; правый shift = левый shift = caps shiftjnz conttwmovl %c4,12hconttw: cmpl %c4,0dh ; TAB = EDIT = caps + 0jnz contejsr shiftmovl %c4,16hconte: cmpl %c4,58h ; Caps lock = caps + 2jnz conte1jsr shiftmovl %c4,1ehconte1: cmpl %c4,049h ; точкаjnz conte2jsr sshiftmovl %c4,03ahconte2: cmpl %c4,041h ; запятаяjnz conte3jsr sshiftmovl %c4,031hconte3: cmpl %c4,055h ; =jnz conte4jsr sshiftmovl %c4,004bhconte4: cmpl %c4,04eh ; -jnz conte5jsr sshiftmovl %c4,03bhconte5: cmpl %c4,6jnz conte6bttl %c5,0001bjnz conte6inc %d0 ; f2 - увеличения коэффициента замедления мышкиconte6: cmpl %c4,4jnz conte7bttl %c5,0001bjnz conte7dec %d0 ; f3 - уменьшение коэффициента замедления мышкиcmpl %d0,255jnz conte7movl %d0,0conte7: cmpl %c4,5jnz contt2jsr wrflsh ; - f1 - сохранение коэффициента замедления во flash - памятьcontt2: mdal %c1,scodemdah %c2,scode ; Грузим в регистр косвенной адресации адресmtpr #6,%c1 ; таблицы скан-кодов в памяти командmtpr #7,%c2 ; (вся хрень с автоинкрементом, доступ через d7)ccd: movl %c1,72cyck0: movl %c6,8 ; 8 битmovl %c2,11111110b ; стартовое значениеcyck1: mov %c3,d7 ; берем скан-код из таблицыcmp %c3,%c4 ; совпал с прочитанным?jz skey ; если совпал то идем на skeysst 0001b ; устанавливаем флаг crlc %c2 ; смотрим следующий вариантdec %c6jnz cyck1inc %c1cmpl %c1,77 ; проверили все 5 наборов по 8 клавишjnz cyck0movl %c4,0rtsppodgon:jsr keyinijmp podgonskey: mtpr #4,%c1movl %c1,01000000bmtpr #5,%c1bttl %c5,0001bjnz reskeyand %d6,%c2 ; фиксируем нажатие клавишиmovl %c4,0rtsreskey: not %c2or %d6,%c2 ; фиксируем отжатие клавишиmovl %c4,0rts ; Усёmore: movl %c0,222 ; будем ждать (3*45+3)*222 командwt0: movl %c1,45 ; если за это время не поступит новый байтwt1: mov %c2,%a1 ; данных, то выходим по ошибкеbtth %c2,0001b;jz wt2dec %c1jnz wt1dec %c0jnz wt0;rtswt2: jsr rd_scrtsbacksp: jsr shift ; del = shift+0 обрабатываем shiftmovl %c4,45h ; подсовываем скан-код нуляrtsshift: ldr #b,72bttl %c5,0001bjnz rshiftbicl %b0,0001b ; фиксируем нажатие клавишиldr #b,18hrtsrshift: bisl %b0,0001b ; фиксируем отжатие клавишиldr #b,18hrtssshift: ldr #b,72bttl %c5,0001bjnz rsshiftbich %b1,1000b ; фиксируем нажатие клавишиldr #b,18hrtsrsshift:bish %b1,1000b ; фиксируем отжатие клавишиldr #b,18hrtsnmi: bicl %a1,0010b ; даем сигнал сбросаmovl %a2,1 ; даем data0 = 1 (теперь на выходе nmi ПЛИС; появится 0)nopnopnopnopmovl %a2,0 ; убираем 1 на data0bisl %a1,0010b ; снимаем сигнал сбросаrts; **************************************************************rd_sc: ; Процедура чтения байта скан-кодаmovl %c3,0 ; Будем читать в c3. Начальное значение 0mov %c1,%a1bttl %c1,1000b ; проверяем стартовый бит; jnz error ; если не 0, то кладем на этот байт скан-кода, да и на весь; скан-кодmovl %c2,8 ; будем читать 8 битscan1: jsr waitjsr wait1 ; идем на процедуру ожидания следующего тактаshr %c3mov %c1,%a1bttl %c1,1000bjz scan2bish %c3,1000b ; если data=1, то ставим эту 1 в c3scan2: dec %c2jnz scan1jsr wait ; Байт скан-кода вроде бы прочитали, теперь надо принять бит; четности и затем стоповый бит.jsr wait1; На бит четности сразу же кладем, ибо нафиг он не нуженjsr waitjsr wait1mov %c1,a1bttl %c1,1000b ; Проверяем стоповый бит; jz error ; если он =0, то кладем на этот скан-код. Видимо, была ошибкаjsr wait ; ждем прихода в исходное состояниеrts; ******************************************************************wr_sc: ; Процедура передачи байта скан-кода; Чтобы перейти в режим передачи данных, нужно удерживать 0 на линии; clk не менее 60 мкс. На всякий случай будем держать 0 80 мкс.; 80 это 320 команд (640 тактов) при F=8 МГцmovl %b1,00101011b ; будем писать в подрегистр типа вывода порта Amovl %b1,00011110bbicl %a1,1000bbich %a1,0001b ; выдаем 0 в clk и datamovl %c0,64 ; Ждем 64*5=320 командrepl: nopnopnopdec %c0jnz repl;bish %a1,0001b ; снимаем 0 clkmovl %b1,00101011b ; будем писать в подрегистр типа вывода порта Amovl %b1,00001110b ; переводим clk на чтениеbicl %a1,1000bmovl %c0,0 ; это будет счетчик единичных битов для формирования; бита четностиw1: movl %c7,255 ; ждем 0, т.е. начала тактирования процессаw2: btth %a1,0001bjz e1nopnopnopnopnopdec %c7jnz w2e1:; передачи данных девайсомmovl %c2,8 ; будем передавать 8 битwr_0: ; передаем битwr1: shr %c3jc wr2bicl %a1,1000bjmp wr3wr2: bisl %a1,1000binc %c0 ; добавляем 1 к счетчикуwr3: btth %a1,0001b ; ждем 1 на clkjz wr3;; ожидаем защелкивания бита данных девайсом и его; готовности к приему следующего бита (0 на clk)movl %c7,255ww2: btth %a1,0001bjz ee1nopnopnopnopnopdec %c7jnz ww2ee1: dec %c2jnz wr_0; Байт скан-кода вроде бы передали, теперь надо передать бит; четности и затем принять стоповый бит. Мля, ну какие же; ламеры придумали этот ps2 интерфейс :-Emovl %c3,0shr %c0 ; Значение бита четности берем из 0-го разряда %c0jnc bcnz ; Если бит четности =0bisl %c3,1 ; если бит четности =1bcnz: ; передаемshr %c3jc wrr2bicl %a1,1000bjmp wrr3wrr2: bisl %a1,1000binc %c0 ; добавляем 1 к счетчикуwrr3: ; ждем 1btth %a1,0001bjz wrr3;; ожидаем защелкивания бита данных девайсом и его; готовности к приему следующего битаmovl %c7,255 ; ждем 0wwa1: btth %a1,0001bjz eexnopnopnopnopnopdec %c7jnz wwa1eex: movl %b1,00101011b ; будем писать в подрегистр типа вывода порта Amovl %b1,00000110b ; переводим data на чтениеit: ; ждем 1btth %a1,0001bjz it;jsr wait1 ; ожидаем приход стопового битаmovl %c7,255 ; ждем 0awa1: btth %a1,0001bjz wexnopnopnopnopnopdec %c7jnz awa1wex: mov %c1,%a1bttl %c1,1000b ; проверяем стоповый бит; только непонятно, зачем ;)ht: ; ждем 1btth %a1,0001bjz ht;rtserror: movl %c3,0wait: mov %c1,%a1 ; ждем 1btth %c1,0001bjz wait;rtswait1: movl %c7,255 ; ждем 0wai1: mov %c1,%a1btth %c1,0001bjz exit1nopnopnopnopnopdec %c7jnz wai1jmp errorexit1: rts; ********************wrflsh: ldr #b,56 ; адрес регистра управления блока ЭСППЗУ данныхmovl %b1,0 ; адрес ячейки = 0 (используем только один байт)mov %b7,%d0movl %b0,00000001bwrf1: bttl %b0,0001bjnz wrf1 ; ждем, пока происходит записьldr #b,18hrts; ********************rdflsh: ldr #b,56 ; адрес регистра управления блока ЭСППЗУ данныхmovl %b1,0 ; адрес ячейки = 0 (используем только один байт)movl %b0,00000010brdf1: bttl %b0,0010bjnz rdf1 ; ждем, пока происходит чтениеmov %d0,%b7ldr #b,18hrts; ********************init: movl %b1,00111011b ; Установка конфигурации порта Amovl %b1,00000110bmovl %b1,00011111bmovl %b1,00000000bmovl %b1,00000000bmovl %b1,00000001b ; прерывание по отрицательному перепаду уровня; на линии clk_key для опроса клавиатурыstiemovl %b2,00011011b ; Установка конфигурации порта Bmovl %b2,11111111bmovl %b2,11111111bmovl %b2,0movl %b2,0movl %b2,0bisl %a1,0010b ; выдаем 1 на линию сброса регистров в ПЛИСbicl %a1,0100b ; выдаем 0 на линию strobemovl %d5,0 ; флажок (потом пригодится)rtskeyini: ; инициализация матрицы клавиатурыldr #b,72 ; весь буфер из 5-и байтов заполняемmovl %b0,11111111b ; значениями 255movl %b1,11111111bmovl %b2,11111111bmovl %b3,11111111bmovl %b4,11111111bldr #b,18hjsr vyvodrts; здесь надо бы отключать клавиатуру - потом поправлюmousini:movl %d4,0ldr #b,72movl %b5,125movl %b6,125movl %b7,255ldr #b,18hjsr wait ; мышь подключили. Теперь ожидаем ее готовность; Теперь нужно передать в мышь команду запроса; ее состояния (здесь неудобно использовать; потоковый режим, хотя, в принципе, можно)movl %c3,11110000b ; код команды перехода в Remote modejsr wr_scjsr more ; принимаем код подтвержденияcmpl %c3,11111010bjnz mousoff ; errormovl %c3,11110011bjsr wr_scjsr moremovl %c3,40jsr wr_scjsr morertsmousoff:movl %d4,255rtstimer: ; мышку будем опрашивать по прерываниям от таймераmovl %a4,00010010b ; подключаем регистр конфигурации к адресу 5movl %a5,01001110b ; задаем коэффициент деления тактовой частоты 1/128movl %a4,00000010b ; подключаем регистр интервала (low) к адресу 5movl %a5,113movl %a4,00000110b ; подключаем регистр интервала (hi) к адресу 5movl %a5,2 ; итак, получили полный коэффициент; деления 128*(2?4?*256+113)=80000, прерывания от; таймера будут идти с частотой Fтакт/80000=100 Гцmovl %a4,00000011b ; пускаем таймер на счетstie ; разрешаем прерыванияrtsrest: bicl %a1,0010bnopnopbisl %a1,0100bmovl %c3,255trmz0: movl %c4,255trmz1: movl %c5,30trmz2: dec %c5jnz trmz2dec %c4jnz trmz1dec %c3jnz trmz0bicl %a1,0100bnopnopbisl %a1,0010brstjmp startsterr: rstjmp startscode: .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;