1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-12-04 19:58:05 +11:00

recipes/rc2014/ps2: drive a shell with ps/2 kbd!

This commit is contained in:
Virgil Dupras 2019-06-29 14:25:18 -04:00
parent 3cdb25bfda
commit e44ebb08b2
6 changed files with 154 additions and 16 deletions

81
kernel/kbd.asm Normal file
View File

@ -0,0 +1,81 @@
; kbd - implement GetC for PS/2 keyboard
;
; Status: Work in progress. See recipes/rc2014/ps2
;
; *** Defines ***
; The port of the device where we read scan codes. See recipe rc2014/ps2.
; KBD_PORT
; *** Variables ***
.equ KBD_SKIP_NEXT KBD_RAMSTART
.equ KBD_RAMEND KBD_SKIP_NEXT+1
kbdInit:
xor a
ld (KBD_SKIP_NEXT), a
ret
kbdGetC:
in a, (KBD_PORT)
or a ; cp 0
ret z
; scan code not zero, maybe we have something.
; Do we need to skip it?
push af ; <|
ld a, (KBD_SKIP_NEXT) ;|
or a ; |
jr nz, .skip ; |
pop af ; <|
cp 0x80
jr nc, .outOfBounds
; No need to skip, code within bounds, we have something! Let's see if
; there's a ASCII code associated to it.
push hl ; <|
ld hl, kbdScanCodes ; |
call addHL ; |
ld a, (hl) ; |
pop hl ; <|
or a ; cp 0
jp z, unsetZ ; no code. Keep A at 0, but unset Z
; We have something!
cp a ; ensure Z
ret
.outOfBounds:
; A scan code over 0x80 is out of bounds. Ignore.
; If F0 (break code) or E0 (extended code), we also skip the next code
cp 0xf0
jr z, .skipNext
cp 0xe0
jr z, .skipNext
xor a
jp unsetZ
.skipNext:
ld (KBD_SKIP_NEXT), a
xor a
jp unsetZ
.skip:
pop af ; equilibrate stack
xor a
ld (KBD_SKIP_NEXT), a
jp unsetZ
; A list of the value associated with the 0x80 possible scan codes of the set
; 2 of the PS/2 keyboard specs. 0 means no value. That value is a character than
; can be read in a GetC routine. No make code in the PS/2 set 2 reaches 0x80.
kbdScanCodes:
; 0x00 1 2 3 4 5 6 7 8 9 a b c d e f
.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,'`', 0
; 0x10 9 = TAB
.db 0, 0, 0, 0, 0,'Q','1', 0, 0, 0,'Z','S','A','W','2', 0
; 0x20 32 = SPACE
.db 0,'C','X','D','E','4','3', 0, 0, 32,'V','F','T','R','5', 0
; 0x30
.db 0,'N','B','H','G','Y','6', 0, 0, 0,'M','J','U','7','8', 0
; 0x40 59 = ;
.db 0,',','K','I','O','0','9', 0, 0,'.','/','L', 59,'P','-', 0
; 0x50 13 = RETURN 39 = '
.db 0, 0, 39, 0,'[','=', 0, 0, 0, 0, 13,']', 0,'\', 0, 0
; 0x60 8 = BKSP
.db 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0
; 0x70 27 = ESC
.db 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0

2
recipes/.gitignore vendored
View File

@ -1,2 +1,4 @@
*.bin *.bin
*.cfs *.cfs
*.hex
*.obj

View File

@ -1,7 +1,9 @@
PROGNAME = ps2ctl PROGNAME = ps2ctl
AVRDUDEMCU ?= t45 AVRDUDEMCU ?= t45
AVRDUDEARGS ?= -c usbtiny -P usb AVRDUDEARGS ?= -c usbtiny -P usb
TARGETS = $(PROGNAME).hex TARGETS = $(PROGNAME).hex os.bin
ZASM = ../../../tools/zasm.sh
KERNEL = ../../../kernel
# Rules # Rules
@ -14,9 +16,10 @@ send: $(PROGNAME).hex
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$< avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$<
$(PROGNAME).hex: $(PROGNAME).asm $(PROGNAME).hex: $(PROGNAME).asm
$(TARGETS):
avra -o $@ $< avra -o $@ $<
clean: os.bin: glue.asm
rm -f $(TARGETS) *.eep.hex *.obj $(ZASM) $(KERNEL) < $< > $@
clean:
rm -f $(TARGETS) *.eep.hex *.obj os.bin

View File

@ -36,16 +36,15 @@ address selection + `IORQ` + `RO`
## Using the PS/2 interface ## Using the PS/2 interface
As of now, the interface is incomplete and can only be queried through the After having built and flashed the `glue.asm` supplied with this recipe, you end
shell's `iord`. I've set my device up for addr `8` (that is, I wired `A3` up with a shell driven by the PS/2 keyboard (but it still outputs to ACIA).
through the inverter, the rest through diodes, and hooked this pudding to `OE`).
When doing `iord 8` in the shell, I get the scan code of the last key I pressed, You will see, by typing on the keyboard, that it kinda works, but in a very
unless the 595 was "busy" with another code. For example, if I press `A`, my basic and glitchy way. You will get double letters sometimes, and at some point,
next `iord 8` will yield `1C` (the "make" code for "A" in the PS/2 protocol). communications are likely to become "corrupted" (you reliably get the wrong
letters). That's because parity checks, timeouts and reset procedures aren't
implemented yet.
Doing a second `iord 8` right after a first will yield `0`, indicating that the But still, it kinda works!
device properly detect the first reading attempt and properly flushes the value
from the 595.
[avra]: https://github.com/hsoft/avra [avra]: https://github.com/hsoft/avra

View File

@ -0,0 +1,42 @@
.equ RAMSTART 0x8000
.equ RAMEND 0xffff
.equ ACIA_CTL 0x80 ; Control and status. RS off.
.equ ACIA_IO 0x81 ; Transmit. RS on.
.equ KBD_PORT 0x08
jp init
; interrupt hook
.fill 0x38-$
jp aciaInt
#include "err.h"
#include "core.asm"
#include "parse.asm"
.equ ACIA_RAMSTART RAMSTART
#include "acia.asm"
.equ KBD_RAMSTART ACIA_RAMEND
#include "kbd.asm"
.equ STDIO_RAMSTART KBD_RAMEND
#include "stdio.asm"
.equ SHELL_RAMSTART STDIO_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 0
#include "shell.asm"
init:
di
; setup stack
ld hl, RAMEND
ld sp, hl
im 1
call aciaInit
ld hl, kbdGetC
ld de, aciaPutC
call stdioInit
call shellInit
ei
jp shellLoop

View File

@ -233,16 +233,27 @@ sendTo595Loop:
dec r16 dec r16
brne sendTo595Loop ; not zero yet? loop brne sendTo595Loop ; not zero yet? loop
; toggle RCLK ; We're finished sending our data to the 595 and we're ready to go back
sbi PORTB, RCLK ; to business as usual. However, timing is important here. The z80 is
cbi PORTB, RCLK ; very fast and constantly hammers our 595 with polls. While this
; routine was running, it was getting zeroes, which is fine, but as soon
; as we trigger RCLK, the z80 is going to fetch that value. What we want
; to do is to enable back the interrupts as soon as RCLK is triggered
; so that the z80 doesn't have enough time to poll twice. If it did, we
; would return a double character. This is why RCLK triggering is the
; last operation.
; release PS/2 ; release PS/2
cbi DDRB, DATA cbi DDRB, DATA
; Set R2 to "595 is busy" ; Set R2 to "595 is busy"
inc r2 inc r2
; toggle RCLK
sbi PORTB, RCLK
cbi PORTB, RCLK
sei sei
rjmp loop rjmp loop
; Check that Y is within bounds, reset to SRAM_START if not. ; Check that Y is within bounds, reset to SRAM_START if not.