WIP PS/2 keyboard driver

This commit is contained in:
Daniele Verducci su MatissePenguin 2021-02-03 21:31:13 +01:00
parent 51780e5606
commit 2366408679
4 changed files with 178 additions and 85 deletions

View File

@ -20,32 +20,53 @@
; behave strangely (will drop next pressed key). This is not a problem, as the computer, once completed, will ; behave strangely (will drop next pressed key). This is not a problem, as the computer, once completed, will
; have a 60% keyboard, without any of the unusable keys. ; have a 60% keyboard, without any of the unusable keys.
include "ps2_keyboard_scancodeset2.asm" ; PS/2 Scan Codeset 2 mappings include 'ps2_keyboard_scancodeset2.asm' ; PS/2 Scan Codeset 2 mappings
; config (IO port 1) ; config (IO port 1)
PS2KEYB_CLEAR_REG: EQU IO_1 PS2KEYB_CLEAR_REG: EQU IO_2
PS2KEYB_DATA_REG: EQU IO_1 + 1 PS2KEYB_DATA_REG: EQU IO_2 + 1
PS2KEYB_TRANSMISSION_DURATION: EQU 86 ;@ 100khz ; The time needed for the keyboard to transmit all the 11 bits of data, in CPU clock cycles
PS2KEYB_BREAK: EQU 0xF0 - %10000000 ; The MSB is dropped: see NOTE on intro above PS2KEYB_BREAK: EQU 0xF0 - %10000000 ; The MSB is dropped: see NOTE on intro above
; Reads a single character. 0s are ignored (can be used with keyboard). ; Reads a single character and returns an ascii code when a valid key is pressed. Blocking.
; Doesn't check DATA_AVAILABLE register of parallel port, because a 0 byte
; is ignored anyway (it represents the ASCII NUL control char).
; @return A The read character ; @return A The read character
PS2Keyb_readc: PS2Keyb_readc:
in a, (PS2KEYB_DATA_REG) ; reads a character in a, (PS2KEYB_DATA_REG) ; reads a character
add a, 0 add a, 0
jp z, Term_readc ; if char is 0 (NULL), user didn't press any key: wait for character jp z, Term_readc ; if char is 0 (NULL), user didn't press any key: wait for character
; check if code is a Break Code (0xF0). If it is, discard next key as it is a released key ; we found something, allow the keyboard to complete data transmission
ld b, a ; save a ld a, PS2KEYB_TRANSMISSION_DURATION/5 ; every cycle is 5 CPU cycles
cp 0xF0 ; compare a with Break Code ps2keyb_readc_waitloop:
jp z, ps2keyb_readc_discard sub 1
jr nz, ps2keyb_readc_waitloop
; data transmission should now be complete.
; check if code is a Break Code. If it is, discard next key as it is a released key
ld c, a ; save a
cp PS2KEYB_BREAK ; compare a with Break Code
jp z, ps2keyb_readc_discard ; if it is a Break Code, jump to discarder routine
; we read a valid character: clean key registers ; we read a valid character: clean key registers
in a, PS2KEYB_CLEAR_REG in a, PS2KEYB_CLEAR_REG
; TODO: Interpretare keycode con lo scan code set ; now we will convert keycode in c to ASCII code
;ld a, b ; restore a ld hl, PS2KEYB_SCANCODESET_ASCII_MAP ; load start of codeset to ascii map
ld b, 0 ; reset b, as we are going to do a sum with bc (where c contains the read scancode)
add hl, bc ; add scancode value to map start addr (we are using it as offset)
ld a, (hl) ; load the corresponding ascii code in a for return
ret ; returns in the a register ret ; returns in the a register
ps2keyb_readc_discard: ps2keyb_readc_discard:
; waits for next non-0 keycode and discards it ; clean key registers
; TODO in a, PS2KEYB_CLEAR_REG
ps2keyb_readc_discard_waitfordata:
; wait for next non-0 keycode and discards it (it is the code of the released key)
in a, (PS2KEYB_DATA_REG) ; reads a character
add a, 0
jp z, ps2keyb_readc_discard_waitfordata ; if char is 0 (NULL), wait
; we found something, allow the keyboard to complete data transmission
ld a, PS2KEYB_TRANSMISSION_DURATION/5 ; every cycle is 5 CPU cycles
ps2keyb_readc_discard_waitloop:
sub 1
jr nz, ps2keyb_readc_discard_waitloop
; data transmission should now be complete, throw away key code
in a, PS2KEYB_CLEAR_REG
jp PS2Keyb_readc ; go back and wait for another keycode jp PS2Keyb_readc ; go back and wait for another keycode

View File

@ -0,0 +1,137 @@
; PS/2 Keycode Mode 2 to ASCII mapping table
;
; Keycodes 0 to 83
.db PS2KEYB_SCANCODESET_ASCII_MAP: .db 0 ; (Unused)
.db 0 ; F9
.db 0 ; (Control key)
.db 0 ; F5
.db 0 ; F3
.db 0 ; F1
.db 0 ; F2
.db 0 ; F12
.db 0 ; (Control key)
.db 0 ; F10
.db 0 ; F8
.db 0 ; F6
.db 0 ; F4
.db 9 ; TAB
.db 96 ; `
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; L ALT
.db 0 ; L SHFT
.db 0 ; (Control key)
.db 0 ; L CTRL
.db 1 ; Q
.db 2 ; 1
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 3 ; Z
.db 4 ; S
.db 65 ; A
.db 66 ; W
.db 67 ; 2
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 68 ; C
.db 69 ; X
.db 70 ; D
.db 71 ; E
.db 72 ; 4
.db 73 ; 3
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 32 ; SPACE
.db 33 ; V
.db 34 ; F
.db 35 ; T
.db 36 ; R
.db 37 ; 5
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 38 ; N
.db 39 ; B
.db 40 ; H
.db 41 ; G
.db 42 ; Y
.db 43 ; 6
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 44 ; M
.db 45 ; J
.db 46 ; U
.db 47 ; 7
.db 48 ; 8
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 44 ; ,
.db 45 ; K
.db 46 ; I
.db 47 ; O
.db 48 ; 0
.db 49 ; 9
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 46 ; .
.db 47 ; /
.db 48 ; L
.db 59 ; ;
.db 60 ; P
.db 45 ; -
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 39 ; '
.db 0 ; (Unused)
.db 91 ; [
.db 61 ; =
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; CAPS
.db 0 ; R SHFT
.db 10 ; ENTER
.db 93 ; ]
.db 0 ; (Unused)
.db 92 ; \
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 8 ; BKSP
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 9 ; KP 1
.db 0 ; (Unused)
.db 10 ; KP 4 -- NOTE: shadowed by break code (see the NOTE in ps2_keyboard.asm)
.db 11 ; KP 7
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 0 ; (Unused)
.db 48 ; KP 0
.db 46 ; KP .
.db 47 ; KP 2
.db 48 ; KP 5
.db 49 ; KP 6
.db 50 ; KP 8
.db 27 ; ESC
.db 0 ; NUM
.db 0 ; F11
.db 43 ; KP +
.db 44 ; KP 3
; The following codes are unrecognized by PAT80, as it uses only 7 bits (see the NOTE in ps2_keyboard.asm)
; .db 45 ; KP -
; .db 42 ; KP *
; .db 43 ; KP 9
; .db 0 ; SCROLL
; .db 0 ; (Control key)
; .db 0 ; (Control key)
; .db 0 ; (Control key)
; .db 0 ; (Control key)
; .db 0 ; F7

View File

@ -10,9 +10,9 @@ jp Sysinit ; Startup vector: DO NOT MOVE! Must be the first instruction
; DRIVERS VAR SPACE: 0x9000 - 0x9FFF (4kb) ; DRIVERS VAR SPACE: 0x9000 - 0x9FFF (4kb)
; APPLICATION VAR SPACE: 0xA000 - 0xFFFF (24kb) ; APPLICATION VAR SPACE: 0xA000 - 0xFFFF (24kb)
; I/O MAP ; I/O MAP
; I/O 0 (0x00 - 0x1F) Parallel terminal (uses addr 0x00 only) ; I/O 0 (0x00 - 0x1F) Parallel terminal (uses addr 0x00 and 0x01)
; I/O 1 (0x20 - 0x3F) Sound card (uses addr 0x20 only) ; I/O 1 (0x20 - 0x3F) Sound card (uses addr 0x20 only)
; I/O 2 (0x40 - 0x5F) ; I/O 2 (0x40 - 0x5F) PS2 Keyboard (uses 0x40 and 0x41)
; I/O 3 (0x60 - 0x7F) ; I/O 3 (0x60 - 0x7F)
; I/O 4 (0x80 - 0x9F) ; I/O 4 (0x80 - 0x9F)
; I/O 5 (0xA0 - 0xBF) ; I/O 5 (0xA0 - 0xBF)
@ -56,7 +56,8 @@ Sys_Printc:
; Reads a single character ; Reads a single character
; @return A The read character ; @return A The read character
Sys_Readc: Sys_Readc:
jp Term_readc ;jp Term_readc
jp PS2Keyb_readc
; Reads a line ; Reads a line
; @return BC The pointer to a null-terminated read string ; @return BC The pointer to a null-terminated read string
@ -91,6 +92,7 @@ IO_7: EQU 0xE0
;include 'drivers/hd44780.asm' ;include 'drivers/hd44780.asm'
;include 'drivers/keyboard.asm' ;include 'drivers/keyboard.asm'
include 'drivers/ps2_keyboard.asm'
include 'drivers/arduino_terminal.asm' include 'drivers/arduino_terminal.asm'
include 'drivers/sn76489.asm' include 'drivers/sn76489.asm'
include 'monitor.asm' include 'monitor.asm'

View File

@ -1,67 +0,0 @@
#include <TVout.h>
#include <TVoutfonts/fontALL.h>
TVout TV;
// Pins
#define RS 5
#define EN 4
const byte DATA [] = {A5, A4, A3, A2, 13, 12, 11, 10};
bool clkState = false;
void setup() {
Serial.begin(57600);
Serial.println("PAL debugger");
// Init comm pins
pinMode(EN, INPUT);
pinMode(RS, INPUT);
for(int pin = 0; pin < 8; pin++) {
pinMode(DATA[pin], INPUT);
}
// Init VGA
TV.begin(PAL,120,96);
TV.select_font(font4x6);
TV.println("TV init");
}
void loop() {
bool newClkState = digitalRead(EN);
if (newClkState == false && clkState == true) {
// Falling edge: read data from bus
onClk();
}
clkState = newClkState;
}
void onClk() {
bool isCommand = digitalRead(RS);
if (isCommand) {
//onCommandReceived();
onDataReceived();
} else {
onDataReceived();
}
}
void onCommandReceived() {
}
void onDataReceived() {
char ch = readByte();
TV.print(ch);
Serial.println(ch);
}
byte readByte() {
unsigned int data = 0;
for(int pin=0; pin < 8; pin++) {
byte b = digitalRead(DATA[pin]) ? 1 : 0;
data = (data << 1) + b; // Shifta di 1 e aggiunge il bit corrente. Serve per ricostruire il numero da binario
}
return data;
}