From e44ebb08b20732e625dc3198fb26a4f9c3216511 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sat, 29 Jun 2019 14:25:18 -0400 Subject: [PATCH] recipes/rc2014/ps2: drive a shell with ps/2 kbd! --- kernel/kbd.asm | 81 +++++++++++++++++++++++++++++++++++ recipes/.gitignore | 2 + recipes/rc2014/ps2/Makefile | 11 +++-- recipes/rc2014/ps2/README.md | 17 ++++---- recipes/rc2014/ps2/glue.asm | 42 ++++++++++++++++++ recipes/rc2014/ps2/ps2ctl.asm | 17 ++++++-- 6 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 kernel/kbd.asm create mode 100644 recipes/rc2014/ps2/glue.asm diff --git a/kernel/kbd.asm b/kernel/kbd.asm new file mode 100644 index 0000000..d0b2c15 --- /dev/null +++ b/kernel/kbd.asm @@ -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 diff --git a/recipes/.gitignore b/recipes/.gitignore index 9452281..91337ae 100644 --- a/recipes/.gitignore +++ b/recipes/.gitignore @@ -1,2 +1,4 @@ *.bin *.cfs +*.hex +*.obj diff --git a/recipes/rc2014/ps2/Makefile b/recipes/rc2014/ps2/Makefile index e9513f9..1106e67 100644 --- a/recipes/rc2014/ps2/Makefile +++ b/recipes/rc2014/ps2/Makefile @@ -1,7 +1,9 @@ PROGNAME = ps2ctl AVRDUDEMCU ?= t45 AVRDUDEARGS ?= -c usbtiny -P usb -TARGETS = $(PROGNAME).hex +TARGETS = $(PROGNAME).hex os.bin +ZASM = ../../../tools/zasm.sh +KERNEL = ../../../kernel # Rules @@ -14,9 +16,10 @@ send: $(PROGNAME).hex avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$< $(PROGNAME).hex: $(PROGNAME).asm -$(TARGETS): avra -o $@ $< -clean: - rm -f $(TARGETS) *.eep.hex *.obj +os.bin: glue.asm + $(ZASM) $(KERNEL) < $< > $@ +clean: + rm -f $(TARGETS) *.eep.hex *.obj os.bin diff --git a/recipes/rc2014/ps2/README.md b/recipes/rc2014/ps2/README.md index e64ba2d..002a97e 100644 --- a/recipes/rc2014/ps2/README.md +++ b/recipes/rc2014/ps2/README.md @@ -36,16 +36,15 @@ address selection + `IORQ` + `RO` ## Using the PS/2 interface -As of now, the interface is incomplete and can only be queried through the -shell's `iord`. I've set my device up for addr `8` (that is, I wired `A3` -through the inverter, the rest through diodes, and hooked this pudding to `OE`). +After having built and flashed the `glue.asm` supplied with this recipe, you end +up with a shell driven by the PS/2 keyboard (but it still outputs to ACIA). -When doing `iord 8` in the shell, I get the scan code of the last key I pressed, -unless the 595 was "busy" with another code. For example, if I press `A`, my -next `iord 8` will yield `1C` (the "make" code for "A" in the PS/2 protocol). +You will see, by typing on the keyboard, that it kinda works, but in a very +basic and glitchy way. You will get double letters sometimes, and at some point, +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 -device properly detect the first reading attempt and properly flushes the value -from the 595. +But still, it kinda works! [avra]: https://github.com/hsoft/avra diff --git a/recipes/rc2014/ps2/glue.asm b/recipes/rc2014/ps2/glue.asm new file mode 100644 index 0000000..c19e57d --- /dev/null +++ b/recipes/rc2014/ps2/glue.asm @@ -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 diff --git a/recipes/rc2014/ps2/ps2ctl.asm b/recipes/rc2014/ps2/ps2ctl.asm index 352fb6e..2fcf732 100644 --- a/recipes/rc2014/ps2/ps2ctl.asm +++ b/recipes/rc2014/ps2/ps2ctl.asm @@ -233,16 +233,27 @@ sendTo595Loop: dec r16 brne sendTo595Loop ; not zero yet? loop - ; toggle RCLK - sbi PORTB, RCLK - cbi PORTB, RCLK + ; We're finished sending our data to the 595 and we're ready to go back + ; to business as usual. However, timing is important here. The z80 is + ; 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 cbi DDRB, DATA ; Set R2 to "595 is busy" inc r2 + + ; toggle RCLK + sbi PORTB, RCLK + cbi PORTB, RCLK sei + rjmp loop ; Check that Y is within bounds, reset to SRAM_START if not.