recipes/rc2014/ps2: drive a shell with ps/2 kbd!
This commit is contained in:
parent
3cdb25bfda
commit
e44ebb08b2
81
kernel/kbd.asm
Normal file
81
kernel/kbd.asm
Normal 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
2
recipes/.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
*.bin
|
||||
*.cfs
|
||||
*.hex
|
||||
*.obj
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
42
recipes/rc2014/ps2/glue.asm
Normal file
42
recipes/rc2014/ps2/glue.asm
Normal 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
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user