Compare commits
4 Commits
7d28637740
...
b5683f447b
Author | SHA1 | Date | |
---|---|---|---|
|
b5683f447b | ||
|
b06cf09754 | ||
|
e9e3bd80f6 | ||
|
223cb94466 |
2
blk/414
2
blk/414
@ -10,6 +10,6 @@
|
|||||||
DUP 0x7f > IF DROP (key) EXIT THEN
|
DUP 0x7f > IF DROP (key) EXIT THEN
|
||||||
DUP _shift? IF DROP 1 PS2_SHIFT C! (key) EXIT THEN
|
DUP _shift? IF DROP 1 PS2_SHIFT C! (key) EXIT THEN
|
||||||
( ah, finally, we have a gentle run-of-the-mill KC )
|
( ah, finally, we have a gentle run-of-the-mill KC )
|
||||||
PS2_CODES PS2_SHIFT @ IF 0x80 + THEN + C@
|
PS2_CODES PS2_SHIFT C@ IF 0x80 + THEN + C@
|
||||||
DUP NOT IF DROP (key) THEN ;
|
DUP NOT IF DROP (key) THEN ;
|
||||||
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
PROGNAME = ps2ctl
|
|
||||||
AVRDUDEMCU ?= t45
|
|
||||||
AVRDUDEARGS ?= -c usbtiny -P usb
|
|
||||||
TARGETS = $(PROGNAME).hex os.bin
|
|
||||||
BASEDIR = ../../..
|
|
||||||
ZASM = $(BASEDIR)/emul/zasm/zasm
|
|
||||||
KERNEL = $(BASEDIR)/kernel
|
|
||||||
APPS = $(BASEDIR)/apps
|
|
||||||
|
|
||||||
# Rules
|
|
||||||
|
|
||||||
.PHONY: send all clean
|
|
||||||
|
|
||||||
all: $(TARGETS)
|
|
||||||
@echo Done!
|
|
||||||
|
|
||||||
send: $(PROGNAME).hex
|
|
||||||
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).hex
|
|
||||||
|
|
||||||
$(PROGNAME).hex: $(PROGNAME).asm
|
|
||||||
avra -o $@ $(PROGNAME).asm
|
|
||||||
|
|
||||||
os.bin: glue.asm
|
|
||||||
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(TARGETS) *.eep.hex *.obj os.bin
|
|
@ -61,10 +61,23 @@ probably have gone the flip-flop way. Seems more solid.
|
|||||||
|
|
||||||
## Using the PS/2 interface
|
## Using the PS/2 interface
|
||||||
|
|
||||||
After having built and flashed the `glue.asm` supplied with this recipe, you end
|
To use this interface, you have to build a new Collapse OS binary. We'll use
|
||||||
up with a shell driven by the PS/2 keyboard (but it still outputs to ACIA).
|
the xcomp unit from the base recipe and modify it.
|
||||||
|
|
||||||
There are still a few glitches, especially at initialization or at connect and
|
First, we need a `(ps2kc)` routine. In this case, it's easy, it's
|
||||||
disconnect, but it otherwise works rather well!
|
`: (ps2kc) 8 PC@ ;`. Add this after ACIA loading. Then, we can load PS/2
|
||||||
|
subsystem. You add `411 414 LOADR`. Then, at initialization, you add `PS2$`
|
||||||
|
after `ACIA$`. You also need to define `PS2_MEM` at the top. You can probably
|
||||||
|
use `RAMSTART + 0x7a`.
|
||||||
|
|
||||||
|
Rebuild, reflash, should work. For debugging purposes, you might not want to
|
||||||
|
go straight to plugging PS/2 `(key)` into the system. What I did myself was
|
||||||
|
to load the PS/2 subsystem *before* ACIA (which overrides with its own `(key)`)
|
||||||
|
and added a dummy word in between to access PS/2's key.
|
||||||
|
|
||||||
|
Also (and this is a TODO: investigate), I had a problem where the break key I
|
||||||
|
got from `(ps2kc)` was 0x70 instead of 0xf0 which had the effect of duplicating
|
||||||
|
all my keystrokes. I added a 0x70 -> 0xf0 replacement in my version of
|
||||||
|
`(ps2kc)`. Does the trick (at the cost of a non-functional numpad 0).
|
||||||
|
|
||||||
[avra]: https://github.com/hsoft/avra
|
[avra]: https://github.com/hsoft/avra
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
.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
|
|
||||||
|
|
||||||
.inc "err.h"
|
|
||||||
.inc "ascii.h"
|
|
||||||
.inc "core.asm"
|
|
||||||
.inc "str.asm"
|
|
||||||
.equ ACIA_RAMSTART RAMSTART
|
|
||||||
.inc "acia.asm"
|
|
||||||
|
|
||||||
.equ KBD_RAMSTART ACIA_RAMEND
|
|
||||||
.inc "kbd.asm"
|
|
||||||
|
|
||||||
.equ STDIO_RAMSTART KBD_RAMEND
|
|
||||||
.equ STDIO_GETC kbdGetC
|
|
||||||
.equ STDIO_PUTC aciaPutC
|
|
||||||
.inc "stdio.asm"
|
|
||||||
|
|
||||||
; *** BASIC ***
|
|
||||||
|
|
||||||
; RAM space used in different routines for short term processing.
|
|
||||||
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
|
|
||||||
.equ SCRATCHPAD STDIO_RAMEND
|
|
||||||
.inc "lib/util.asm"
|
|
||||||
.inc "lib/ari.asm"
|
|
||||||
.inc "lib/parse.asm"
|
|
||||||
.inc "lib/fmt.asm"
|
|
||||||
.equ EXPR_PARSE parseLiteralOrVar
|
|
||||||
.inc "lib/expr.asm"
|
|
||||||
.inc "basic/util.asm"
|
|
||||||
.inc "basic/parse.asm"
|
|
||||||
.inc "basic/tok.asm"
|
|
||||||
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
|
|
||||||
.inc "basic/var.asm"
|
|
||||||
.equ BUF_RAMSTART VAR_RAMEND
|
|
||||||
.inc "basic/buf.asm"
|
|
||||||
.equ BAS_RAMSTART BUF_RAMEND
|
|
||||||
.inc "basic/main.asm"
|
|
||||||
|
|
||||||
init:
|
|
||||||
di
|
|
||||||
ld sp, RAMEND
|
|
||||||
im 1
|
|
||||||
|
|
||||||
call aciaInit
|
|
||||||
call kbdInit
|
|
||||||
call basInit
|
|
||||||
ei
|
|
||||||
jp basStart
|
|
||||||
|
|
||||||
KBD_FETCHKC:
|
|
||||||
in a, (KBD_PORT)
|
|
||||||
ret
|
|
||||||
|
|
@ -18,7 +18,6 @@ This recipe is for installing a minimal Collapse OS system on the SMS. There
|
|||||||
are other recipes related to the SMS:
|
are other recipes related to the SMS:
|
||||||
|
|
||||||
* [Interfacing a PS/2 keyboard](kbd/README.md)
|
* [Interfacing a PS/2 keyboard](kbd/README.md)
|
||||||
* [zasm and ed from ROM](romasm/README.md)
|
|
||||||
|
|
||||||
## Gathering parts
|
## Gathering parts
|
||||||
|
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
; 8K of onboard RAM
|
|
||||||
.equ RAMSTART 0xc000
|
|
||||||
; Memory register at the end of RAM. Must not overwrite
|
|
||||||
.equ RAMEND 0xfdd0
|
|
||||||
|
|
||||||
jp init
|
|
||||||
|
|
||||||
.fill 0x66-$
|
|
||||||
retn
|
|
||||||
|
|
||||||
.inc "err.h"
|
|
||||||
.inc "ascii.h"
|
|
||||||
.inc "core.asm"
|
|
||||||
.inc "str.asm"
|
|
||||||
|
|
||||||
.equ PAD_RAMSTART RAMSTART
|
|
||||||
.inc "sms/pad.asm"
|
|
||||||
|
|
||||||
.inc "sms/vdp.asm"
|
|
||||||
.equ GRID_RAMSTART PAD_RAMEND
|
|
||||||
.equ GRID_COLS VDP_COLS
|
|
||||||
.equ GRID_ROWS VDP_ROWS
|
|
||||||
.equ GRID_SETCELL vdpSetCell
|
|
||||||
.equ GRID_GETC padGetC
|
|
||||||
.inc "grid.asm"
|
|
||||||
|
|
||||||
.equ STDIO_RAMSTART GRID_RAMEND
|
|
||||||
.equ STDIO_GETC gridGetC
|
|
||||||
.equ STDIO_PUTC gridPutC
|
|
||||||
.inc "stdio.asm"
|
|
||||||
|
|
||||||
; *** BASIC ***
|
|
||||||
|
|
||||||
; RAM space used in different routines for short term processing.
|
|
||||||
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
|
|
||||||
.equ SCRATCHPAD STDIO_RAMEND
|
|
||||||
.inc "lib/util.asm"
|
|
||||||
.inc "lib/ari.asm"
|
|
||||||
.inc "lib/parse.asm"
|
|
||||||
.inc "lib/fmt.asm"
|
|
||||||
.equ EXPR_PARSE parseLiteralOrVar
|
|
||||||
.inc "lib/expr.asm"
|
|
||||||
.inc "basic/util.asm"
|
|
||||||
.inc "basic/parse.asm"
|
|
||||||
.inc "basic/tok.asm"
|
|
||||||
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
|
|
||||||
.inc "basic/var.asm"
|
|
||||||
.equ BUF_RAMSTART VAR_RAMEND
|
|
||||||
.inc "basic/buf.asm"
|
|
||||||
.equ BAS_RAMSTART BUF_RAMEND
|
|
||||||
.inc "basic/main.asm"
|
|
||||||
|
|
||||||
init:
|
|
||||||
di
|
|
||||||
im 1
|
|
||||||
|
|
||||||
ld sp, RAMEND
|
|
||||||
|
|
||||||
call gridInit
|
|
||||||
call padInit
|
|
||||||
call vdpInit
|
|
||||||
call basInit
|
|
||||||
jp basStart
|
|
||||||
|
|
||||||
FNT_DATA:
|
|
||||||
.bin "fnt/7x7.bin"
|
|
||||||
|
|
||||||
.fill 0x7ff0-$
|
|
||||||
.db "TMR SEGA", 0x00, 0x00, 0xfb, 0x68, 0x00, 0x00, 0x00, 0x4c
|
|
@ -1,22 +0,0 @@
|
|||||||
PROGNAME = ps2ctl
|
|
||||||
AVRDUDEMCU ?= t45
|
|
||||||
AVRDUDEARGS ?= -c usbtiny -P usb
|
|
||||||
TARGETS = $(PROGNAME).bin
|
|
||||||
BASEDIR = ../../..
|
|
||||||
EDIR = $(BASEDIR)/emul
|
|
||||||
|
|
||||||
# Rules
|
|
||||||
|
|
||||||
.PHONY: send all clean
|
|
||||||
|
|
||||||
all: $(TARGETS)
|
|
||||||
@echo Done!
|
|
||||||
|
|
||||||
send: $(PROGNAME).bin
|
|
||||||
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).bin
|
|
||||||
|
|
||||||
$(PROGNAME).bin: $(PROGNAME).fs
|
|
||||||
cd $(EDIR) && ./avra.sh < ../recipes/sms/kbd/$(PROGNAME).fs > ../recipes/sms/kbd/$@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(TARGETS)
|
|
@ -100,16 +100,16 @@ The code expects a SR-latch that works like a 4043, that is, S and R are
|
|||||||
triggered high, S makes Q high, R makes Q low. R is hooked to PB4. S is hooked
|
triggered high, S makes Q high, R makes Q low. R is hooked to PB4. S is hooked
|
||||||
to TH (and also the A/B on the '157). Q is hooked to PB0 and TL.
|
to TH (and also the A/B on the '157). Q is hooked to PB0 and TL.
|
||||||
|
|
||||||
## Usage
|
## Building the binary
|
||||||
|
|
||||||
The code in this recipe is set up to listen to the keyboard on port B, leaving
|
We start with the base recipe and add a few things:
|
||||||
port A to drive, for example, an Everdrive with a D-pad. Unlike the generic
|
|
||||||
SMS recipe, this kernel has no character selection mechanism. It acts like a
|
|
||||||
regular shell, taking input from the keyboard.
|
|
||||||
|
|
||||||
`kernel/sms/kbd.asm` also has a FetchKC implementation for port A if you prefer.
|
1. at the top: `RAMSTART 0x72 + CONSTANT PS2_MEM`
|
||||||
Just hook it on. I've tried it, it works.
|
2. After VDP load: `641 LOAD : (ps2kc) (ps2kcB) ;` (that binds us to port B)
|
||||||
|
3. Right after: `411 414 LOADR` (that gives us `(key)`)
|
||||||
|
4. After `VDP$`: `PS2$`.
|
||||||
|
|
||||||
Did you get there? Feels pretty cool huh?
|
Rebuild, send to SMS, then run with your keyboard interface plugged to PortB.
|
||||||
|
It should mostly work. There are still a few glitches to iron out...
|
||||||
|
|
||||||
[rc2014-ps2]: ../../rc2014/ps2
|
[rc2014-ps2]: ../../rc2014/ps2
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
; 8K of onboard RAM
|
|
||||||
.equ RAMSTART 0xc000
|
|
||||||
; Memory register at the end of RAM. Must not overwrite
|
|
||||||
.equ RAMEND 0xddd0
|
|
||||||
|
|
||||||
jp init
|
|
||||||
|
|
||||||
.fill 0x66-$
|
|
||||||
retn
|
|
||||||
|
|
||||||
.inc "err.h"
|
|
||||||
.inc "ascii.h"
|
|
||||||
.inc "core.asm"
|
|
||||||
.inc "str.asm"
|
|
||||||
|
|
||||||
.inc "sms/kbd.asm"
|
|
||||||
.equ KBD_RAMSTART RAMSTART
|
|
||||||
.equ KBD_FETCHKC smskbdFetchKCB
|
|
||||||
.inc "kbd.asm"
|
|
||||||
|
|
||||||
.inc "sms/vdp.asm"
|
|
||||||
.equ GRID_RAMSTART KBD_RAMEND
|
|
||||||
.equ GRID_COLS VDP_COLS
|
|
||||||
.equ GRID_ROWS VDP_ROWS
|
|
||||||
.equ GRID_SETCELL vdpSetCell
|
|
||||||
.equ GRID_GETC kbdGetC
|
|
||||||
.inc "grid.asm"
|
|
||||||
|
|
||||||
.equ STDIO_RAMSTART GRID_RAMEND
|
|
||||||
.equ STDIO_GETC gridGetC
|
|
||||||
.equ STDIO_PUTC gridPutC
|
|
||||||
.inc "stdio.asm"
|
|
||||||
|
|
||||||
; *** BASIC ***
|
|
||||||
|
|
||||||
; RAM space used in different routines for short term processing.
|
|
||||||
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
|
|
||||||
.equ SCRATCHPAD STDIO_RAMEND
|
|
||||||
.inc "lib/util.asm"
|
|
||||||
.inc "lib/ari.asm"
|
|
||||||
.inc "lib/parse.asm"
|
|
||||||
.inc "lib/fmt.asm"
|
|
||||||
.equ EXPR_PARSE parseLiteralOrVar
|
|
||||||
.inc "lib/expr.asm"
|
|
||||||
.inc "basic/util.asm"
|
|
||||||
.inc "basic/parse.asm"
|
|
||||||
.inc "basic/tok.asm"
|
|
||||||
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
|
|
||||||
.inc "basic/var.asm"
|
|
||||||
.equ BUF_RAMSTART VAR_RAMEND
|
|
||||||
.inc "basic/buf.asm"
|
|
||||||
.equ BAS_RAMSTART BUF_RAMEND
|
|
||||||
.inc "basic/main.asm"
|
|
||||||
|
|
||||||
init:
|
|
||||||
di
|
|
||||||
im 1
|
|
||||||
|
|
||||||
ld sp, RAMEND
|
|
||||||
|
|
||||||
; Initialize the keyboard latch by "dummy reading" once. This ensures
|
|
||||||
; that the adapter knows it can fill its '164.
|
|
||||||
; Port B TH output, high
|
|
||||||
ld a, 0b11110111
|
|
||||||
out (0x3f), a
|
|
||||||
nop
|
|
||||||
; Port A/B reset
|
|
||||||
ld a, 0xff
|
|
||||||
out (0x3f), a
|
|
||||||
|
|
||||||
call kbdInit
|
|
||||||
call gridInit
|
|
||||||
call vdpInit
|
|
||||||
call basInit
|
|
||||||
jp basStart
|
|
||||||
|
|
||||||
FNT_DATA:
|
|
||||||
.bin "fnt/7x7.bin"
|
|
||||||
|
|
||||||
.fill 0x7ff0-$
|
|
||||||
.db "TMR SEGA", 0x00, 0x00, 0xfb, 0x68, 0x00, 0x00, 0x00, 0x4c
|
|
||||||
|
|
@ -1,348 +0,0 @@
|
|||||||
; Receives keystrokes from PS/2 keyboard and send them to the '164. On the PS/2
|
|
||||||
; side, it works the same way as the controller in the rc2014/ps2 recipe.
|
|
||||||
; However, in this case, what we have on the other side isn't a z80 bus, it's
|
|
||||||
; the one of the two controller ports of the SMS through a DB9 connector.
|
|
||||||
|
|
||||||
; The PS/2 related code is copied from rc2014/ps2 without much change. The only
|
|
||||||
; differences are that it pushes its data to a '164 instead of a '595 and that
|
|
||||||
; it synchronizes with the SMS with a SR latch, so we don't need PCINT. We can
|
|
||||||
; also afford to run at 1MHz instead of 8.
|
|
||||||
|
|
||||||
; *** Register Usage ***
|
|
||||||
;
|
|
||||||
; GPIOR0 flags:
|
|
||||||
; 0 - when set, indicates that the DATA pin was high when we received a
|
|
||||||
; bit through INT0. When we receive a bit, we set flag T to indicate
|
|
||||||
; it.
|
|
||||||
;
|
|
||||||
; R16: tmp stuff
|
|
||||||
; R17: recv buffer. Whenever we receive a bit, we push it in there.
|
|
||||||
; R18: recv step:
|
|
||||||
; - 0: idle
|
|
||||||
; - 1: receiving data
|
|
||||||
; - 2: awaiting parity bit
|
|
||||||
; - 3: awaiting stop bit
|
|
||||||
; R19: Register used for parity computations and tmp value in some other places
|
|
||||||
; R20: data being sent to the '164
|
|
||||||
; Y: pointer to the memory location where the next scan code from ps/2 will be
|
|
||||||
; written.
|
|
||||||
; Z: pointer to the next scan code to push to the 595
|
|
||||||
;
|
|
||||||
|
|
||||||
.inc "avr.h"
|
|
||||||
.inc "tn254585.h"
|
|
||||||
.inc "tn45.h"
|
|
||||||
|
|
||||||
; *** Constants ***
|
|
||||||
.equ CLK 2 ; Port B
|
|
||||||
.equ DATA 1 ; Port B
|
|
||||||
.equ CP 3 ; Port B
|
|
||||||
; SR-Latch's Q pin
|
|
||||||
.equ LQ 0 ; Port B
|
|
||||||
; SR-Latch's R pin
|
|
||||||
.equ LR 4 ; Port B
|
|
||||||
|
|
||||||
; init value for TCNT0 so that overflow occurs in 100us
|
|
||||||
.equ TIMER_INITVAL 0x100-100
|
|
||||||
|
|
||||||
; *** Code ***
|
|
||||||
|
|
||||||
rjmp main
|
|
||||||
rjmp hdlINT0
|
|
||||||
|
|
||||||
; Read DATA and set GPIOR0/0 if high. Then, set flag T.
|
|
||||||
; no SREG fiddling because no SREG-modifying instruction
|
|
||||||
hdlINT0:
|
|
||||||
sbic PINB, DATA ; DATA clear? skip next
|
|
||||||
sbi GPIOR0, 0
|
|
||||||
set
|
|
||||||
reti
|
|
||||||
|
|
||||||
main:
|
|
||||||
ldi r16, RAMEND&0xff
|
|
||||||
out SPL, r16
|
|
||||||
ldi r16, RAMEND}8
|
|
||||||
out SPH, r16
|
|
||||||
|
|
||||||
; init variables
|
|
||||||
clr r18
|
|
||||||
out GPIOR0, r18
|
|
||||||
|
|
||||||
; Setup int0
|
|
||||||
; INT0, falling edge
|
|
||||||
ldi r16, 0x02 ; ISC01
|
|
||||||
out MCUCR, r16
|
|
||||||
; Enable INT0
|
|
||||||
ldi r16, 0x40 ; INT0
|
|
||||||
out GIMSK, r16
|
|
||||||
|
|
||||||
; Setup buffer
|
|
||||||
clr YH
|
|
||||||
ldi YL, SRAM_START&0xff
|
|
||||||
clr ZH
|
|
||||||
ldi ZL, SRAM_START&0xff
|
|
||||||
|
|
||||||
; Setup timer. We use the timer to clear up "processbit" registers after
|
|
||||||
; 100us without a clock. This allows us to start the next frame in a
|
|
||||||
; fresh state. at 1MHZ, no prescaling is necessary. Each TCNT0 tick is
|
|
||||||
; already 1us long.
|
|
||||||
ldi r16, 0x01 ; CS00 - no prescaler
|
|
||||||
out TCCR0B, r16
|
|
||||||
|
|
||||||
; init DDRB
|
|
||||||
sbi DDRB, CP
|
|
||||||
cbi PORTB, LR
|
|
||||||
sbi DDRB, LR
|
|
||||||
|
|
||||||
sei
|
|
||||||
|
|
||||||
loop:
|
|
||||||
brts processbit ; flag T set? we have a bit to process
|
|
||||||
cp YL, ZL ; if YL == ZL, buffer is empty
|
|
||||||
brne sendTo164 ; YL != ZL? our buffer has data
|
|
||||||
|
|
||||||
; nothing to do. Before looping, let's check if our communication timer
|
|
||||||
; overflowed.
|
|
||||||
in r16, TIFR
|
|
||||||
sbrc r16, 1 ; TOV0
|
|
||||||
rjmp processbitReset ; Timer0 overflow? reset processbit
|
|
||||||
|
|
||||||
; Nothing to do for real.
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
; Process the data bit received in INT0 handler.
|
|
||||||
processbit:
|
|
||||||
in r19, GPIOR0 ; backup GPIOR0 before we reset T
|
|
||||||
andi r19, 0x1 ; only keep the first flag
|
|
||||||
cbi GPIOR0, 0
|
|
||||||
clt ; ready to receive another bit
|
|
||||||
|
|
||||||
; We've received a bit. reset timer
|
|
||||||
rcall resetTimer
|
|
||||||
|
|
||||||
; Which step are we at?
|
|
||||||
tst r18
|
|
||||||
breq processbits0
|
|
||||||
cpi r18, 1
|
|
||||||
breq processbits1
|
|
||||||
cpi r18, 2
|
|
||||||
breq processbits2
|
|
||||||
; step 3: stop bit
|
|
||||||
clr r18 ; happens in all cases
|
|
||||||
; DATA has to be set
|
|
||||||
tst r19 ; Was DATA set?
|
|
||||||
breq loop ; not set? error, don't push to buffer
|
|
||||||
; push r17 to the buffer
|
|
||||||
st Y+, r17
|
|
||||||
rcall checkBoundsY
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
processbits0:
|
|
||||||
; step 0 - start bit
|
|
||||||
; DATA has to be cleared
|
|
||||||
tst r19 ; Was DATA set?
|
|
||||||
brne loop ; Set? error. no need to do anything. keep r18
|
|
||||||
; as-is.
|
|
||||||
; DATA is cleared. prepare r17 and r18 for step 1
|
|
||||||
inc r18
|
|
||||||
ldi r17, 0x80
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
processbits1:
|
|
||||||
; step 1 - receive bit
|
|
||||||
; We're about to rotate the carry flag into r17. Let's set it first
|
|
||||||
; depending on whether DATA is set.
|
|
||||||
clc
|
|
||||||
sbrc r19, 0 ; skip if DATA cleared.
|
|
||||||
sec
|
|
||||||
; Carry flag is set
|
|
||||||
ror r17
|
|
||||||
; Good. now, are we finished rotating? If carry flag is set, it means
|
|
||||||
; that we've rotated in 8 bits.
|
|
||||||
brcc loop ; we haven't finished yet
|
|
||||||
; We're finished, go to step 2
|
|
||||||
inc r18
|
|
||||||
rjmp loop
|
|
||||||
processbits2:
|
|
||||||
; step 2 - parity bit
|
|
||||||
mov r1, r19
|
|
||||||
mov r19, r17
|
|
||||||
rcall checkParity ; --> r16
|
|
||||||
cp r1, r16
|
|
||||||
brne processbitError ; r1 != r16? wrong parity
|
|
||||||
inc r18
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
processbitError:
|
|
||||||
clr r18
|
|
||||||
ldi r19, 0xfe
|
|
||||||
rcall sendToPS2
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
processbitReset:
|
|
||||||
clr r18
|
|
||||||
rcall resetTimer
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
; Send the value of r20 to the '164
|
|
||||||
sendTo164:
|
|
||||||
sbis PINB, LQ ; LQ is set? we can send the next byte
|
|
||||||
rjmp loop ; Even if we have something in the buffer, we
|
|
||||||
; can't: the SMS hasn't read our previous
|
|
||||||
; buffer yet.
|
|
||||||
; We disable any interrupt handling during this routine. Whatever it
|
|
||||||
; is, it has no meaning to us at this point in time and processing it
|
|
||||||
; might mess things up.
|
|
||||||
cli
|
|
||||||
sbi DDRB, DATA
|
|
||||||
|
|
||||||
ld r20, Z+
|
|
||||||
rcall checkBoundsZ
|
|
||||||
ldi r16, 8
|
|
||||||
|
|
||||||
sendTo164Loop:
|
|
||||||
cbi PORTB, DATA
|
|
||||||
sbrc r20, 7 ; if leftmost bit isn't cleared, set DATA high
|
|
||||||
sbi PORTB, DATA
|
|
||||||
; toggle CP
|
|
||||||
cbi PORTB, CP
|
|
||||||
lsl r20
|
|
||||||
sbi PORTB, CP
|
|
||||||
dec r16
|
|
||||||
brne sendTo164Loop ; not zero yet? loop
|
|
||||||
|
|
||||||
; release PS/2
|
|
||||||
cbi DDRB, DATA
|
|
||||||
sei
|
|
||||||
|
|
||||||
; Reset the latch to indicate that the next number is ready
|
|
||||||
sbi PORTB, LR
|
|
||||||
cbi PORTB, LR
|
|
||||||
rjmp loop
|
|
||||||
|
|
||||||
resetTimer:
|
|
||||||
ldi r16, TIMER_INITVAL
|
|
||||||
out TCNT0, r16
|
|
||||||
ldi r16, 0x02 ; TOV0
|
|
||||||
out TIFR, r16
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Send the value of r19 to the PS/2 keyboard
|
|
||||||
sendToPS2:
|
|
||||||
cli
|
|
||||||
|
|
||||||
; First, indicate our request to send by holding both Clock low for
|
|
||||||
; 100us, then pull Data low
|
|
||||||
; lines low for 100us.
|
|
||||||
cbi PORTB, CLK
|
|
||||||
sbi DDRB, CLK
|
|
||||||
rcall resetTimer
|
|
||||||
|
|
||||||
; Wait until the timer overflows
|
|
||||||
in r16, TIFR
|
|
||||||
sbrs r16, 1 ; TOV0
|
|
||||||
rjmp $-4
|
|
||||||
; Good, 100us passed.
|
|
||||||
|
|
||||||
; Pull Data low, that's our start bit.
|
|
||||||
cbi PORTB, DATA
|
|
||||||
sbi DDRB, DATA
|
|
||||||
|
|
||||||
; Now, let's release the clock. At the next raising edge, we'll be
|
|
||||||
; expected to have set up our first bit (LSB). We set up when CLK is
|
|
||||||
; low.
|
|
||||||
cbi DDRB, CLK ; Should be starting high now.
|
|
||||||
|
|
||||||
; We will do the next loop 8 times
|
|
||||||
ldi r16, 8
|
|
||||||
; Let's remember initial r19 for parity
|
|
||||||
mov r1, r19
|
|
||||||
|
|
||||||
sendToPS2Loop:
|
|
||||||
; Wait for CLK to go low
|
|
||||||
sbic PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; set up DATA
|
|
||||||
cbi PORTB, DATA
|
|
||||||
sbrc r19, 0 ; skip if LSB is clear
|
|
||||||
sbi PORTB, DATA
|
|
||||||
lsr r19
|
|
||||||
|
|
||||||
; Wait for CLK to go high
|
|
||||||
sbis PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
dec r16
|
|
||||||
brne sendToPS2Loop ; not zero? loop
|
|
||||||
|
|
||||||
; Data was sent, CLK is high. Let's send parity
|
|
||||||
mov r19, r1 ; recall saved value
|
|
||||||
rcall checkParity ; --> r16
|
|
||||||
|
|
||||||
; Wait for CLK to go low
|
|
||||||
sbic PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; set parity bit
|
|
||||||
cbi PORTB, DATA
|
|
||||||
sbrc r16, 0 ; parity bit in r16
|
|
||||||
sbi PORTB, DATA
|
|
||||||
|
|
||||||
; Wait for CLK to go high
|
|
||||||
sbis PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; Wait for CLK to go low
|
|
||||||
sbic PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; We can now release the DATA line
|
|
||||||
cbi DDRB, DATA
|
|
||||||
|
|
||||||
; Wait for DATA to go low. That's our ACK
|
|
||||||
sbic PINB, DATA
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; Wait for CLK to go low
|
|
||||||
sbic PINB, CLK
|
|
||||||
rjmp $-2
|
|
||||||
|
|
||||||
; We're finished! Enable INT0, reset timer, everything back to normal!
|
|
||||||
rcall resetTimer
|
|
||||||
clt ; also, make sure T isn't mistakely set.
|
|
||||||
sei
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Check that Y is within bounds, reset to SRAM_START if not.
|
|
||||||
checkBoundsY:
|
|
||||||
tst YL
|
|
||||||
breq $+4
|
|
||||||
ret ; not zero, nothing to do
|
|
||||||
; YL is zero. Reset Y
|
|
||||||
clr YH
|
|
||||||
ldi YL, SRAM_START&0xff
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Check that Z is within bounds, reset to SRAM_START if not.
|
|
||||||
checkBoundsZ:
|
|
||||||
tst ZL
|
|
||||||
breq $+4
|
|
||||||
ret ; not zero, nothing to do
|
|
||||||
; ZL is zero. Reset Z
|
|
||||||
clr ZH
|
|
||||||
ldi ZL, SRAM_START&0xff
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Counts the number of 1s in r19 and set r16 to 1 if there's an even number of
|
|
||||||
; 1s, 0 if they're odd.
|
|
||||||
checkParity:
|
|
||||||
ldi r16, 1
|
|
||||||
lsr r19
|
|
||||||
brcc $+4 ; Carry unset? skip next
|
|
||||||
inc r16 ; Carry set? We had a 1
|
|
||||||
tst r19 ; is r19 zero yet?
|
|
||||||
brne checkParity+2 ; no? loop and skip first LDI
|
|
||||||
andi r16, 0x1 ; Sets Z accordingly
|
|
||||||
ret
|
|
||||||
|
|
1
recipes/sms/romasm/.gitignore
vendored
1
recipes/sms/romasm/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
user.h
|
|
@ -1,21 +0,0 @@
|
|||||||
BASEDIR = ../../..
|
|
||||||
ZASM = $(BASEDIR)/emul/zasm/zasm
|
|
||||||
KERNEL = $(BASEDIR)/kernel
|
|
||||||
APPS = $(BASEDIR)/apps
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
all: os.sms
|
|
||||||
|
|
||||||
# -o value synced with offset in glue.asm
|
|
||||||
ed.bin: $(APPS)/ed/glue.asm
|
|
||||||
$(ZASM) -o 1f $(KERNEL) $(APPS) user.h < $(APPS)/ed/glue.asm > $@
|
|
||||||
|
|
||||||
# -o value synced with offset in glue.asm
|
|
||||||
zasm.bin: $(APPS)/zasm/glue.asm
|
|
||||||
$(ZASM) -o 24 $(KERNEL) $(APPS) user.h < $(APPS)/zasm/glue.asm > $@
|
|
||||||
|
|
||||||
os.sms: glue.asm ed.bin zasm.bin
|
|
||||||
$(ZASM) $(KERNEL) $(APPS) ed.bin zasm.bin < glue.asm > $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f os.sms ed.bin zasm.bin
|
|
@ -1,61 +0,0 @@
|
|||||||
# zasm and ed from ROM
|
|
||||||
|
|
||||||
SMS' RAM is much tighter than in the RC2014, which makes the idea of loading
|
|
||||||
apps like zasm and ed in memory before using it a bit wasteful. In this recipe,
|
|
||||||
we'll include zasm and ed code directly in the kernel and expose them as shell
|
|
||||||
commands.
|
|
||||||
|
|
||||||
Moreover, we'll carve ourselves a little 1K memory map to put a filesystem in
|
|
||||||
there. This will give us a nice little system that can edit small source files
|
|
||||||
compile them and run them.
|
|
||||||
|
|
||||||
## Gathering parts
|
|
||||||
|
|
||||||
* A SMS that can run Collapse OS.
|
|
||||||
* A [PS/2 keyboard adapter](../kbd/README.md)
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
There's nothing special with building this recipe. Like the base recipe, run
|
|
||||||
`make` then copy `os.sms` to your destination medium.
|
|
||||||
|
|
||||||
If you look at the makefile, however, you'll see that we use a new trick here:
|
|
||||||
we embed "apps" binaries directly in our ROM so that we don't have to load them
|
|
||||||
in memory.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Alright, here's what we'll do: we'll author a source file, assemble it and run
|
|
||||||
it, *all* on your SMS! Commands:
|
|
||||||
|
|
||||||
Collapse OS
|
|
||||||
> fnew 1 src
|
|
||||||
> ed src
|
|
||||||
: 1i
|
|
||||||
.org 0xc200
|
|
||||||
: 1a
|
|
||||||
ld hl, sFoo
|
|
||||||
: 2a
|
|
||||||
call 0x3f
|
|
||||||
: 3a
|
|
||||||
xor a
|
|
||||||
: 4a
|
|
||||||
ret
|
|
||||||
: 5a
|
|
||||||
sFoo: .db "foo", 0
|
|
||||||
: w
|
|
||||||
> fnew 1 dest
|
|
||||||
> fopn 0 src
|
|
||||||
> fopn 1 dest
|
|
||||||
> zasm 1 2
|
|
||||||
First pass
|
|
||||||
Second pass
|
|
||||||
> dest
|
|
||||||
foo>
|
|
||||||
|
|
||||||
Awesome right? Some precisions:
|
|
||||||
|
|
||||||
* Our glue code specifies a `USER_RAMSTART` of `0xc200`. This is where
|
|
||||||
`dest` is loaded by the `pgm` shell hook.
|
|
||||||
* `0x3f` is the offset of `printstr` in the jump table of our glue code.
|
|
||||||
* `xor a` is for the command to report as successful to the shell.
|
|
@ -1,187 +0,0 @@
|
|||||||
; TODO: This recipe has not been tested since its conversion to the BASIC shell.
|
|
||||||
; My PS/2 adapter has been acting up and probably has a loose wire. I need to
|
|
||||||
; fix it beore I can test this recipe on real hardware.
|
|
||||||
; But theoretically, it works...
|
|
||||||
|
|
||||||
; 8K of onboard RAM
|
|
||||||
.equ RAMSTART 0xc000
|
|
||||||
.equ USER_CODE 0xd500
|
|
||||||
; Memory register at the end of RAM. Must not overwrite
|
|
||||||
.equ RAMEND 0xddd0
|
|
||||||
|
|
||||||
jp init
|
|
||||||
|
|
||||||
; *** JUMP TABLE ***
|
|
||||||
jp strncmp
|
|
||||||
jp upcase
|
|
||||||
jp findchar
|
|
||||||
jp parseHex
|
|
||||||
jp blkSel
|
|
||||||
jp blkSet
|
|
||||||
jp fsFindFN
|
|
||||||
jp fsOpen
|
|
||||||
jp fsGetB
|
|
||||||
jp fsPutB
|
|
||||||
jp fsSetSize
|
|
||||||
jp printstr
|
|
||||||
jp _blkGetB
|
|
||||||
jp _blkPutB
|
|
||||||
jp _blkSeek
|
|
||||||
jp _blkTell
|
|
||||||
jp printcrlf
|
|
||||||
jp stdioPutC
|
|
||||||
jp stdioReadLine
|
|
||||||
|
|
||||||
.fill 0x66-$
|
|
||||||
retn
|
|
||||||
|
|
||||||
.inc "err.h"
|
|
||||||
.inc "ascii.h"
|
|
||||||
.inc "blkdev.h"
|
|
||||||
.inc "fs.h"
|
|
||||||
.inc "core.asm"
|
|
||||||
.inc "str.asm"
|
|
||||||
|
|
||||||
.inc "sms/kbd.asm"
|
|
||||||
.equ KBD_RAMSTART RAMSTART
|
|
||||||
.equ KBD_FETCHKC smskbdFetchKCB
|
|
||||||
.inc "kbd.asm"
|
|
||||||
|
|
||||||
.inc "sms/vdp.asm"
|
|
||||||
.equ GRID_RAMSTART KBD_RAMEND
|
|
||||||
.equ GRID_COLS VDP_COLS
|
|
||||||
.equ GRID_ROWS VDP_ROWS
|
|
||||||
.equ GRID_SETCELL vdpSetCell
|
|
||||||
.equ GRID_GETC kbdGetC
|
|
||||||
.inc "grid.asm"
|
|
||||||
|
|
||||||
.equ STDIO_RAMSTART GRID_RAMEND
|
|
||||||
.equ STDIO_GETC gridGetC
|
|
||||||
.equ STDIO_PUTC gridPutC
|
|
||||||
.inc "stdio.asm"
|
|
||||||
|
|
||||||
.equ MMAP_START 0xd700
|
|
||||||
; 0x180 is to leave some space for the stack
|
|
||||||
.equ MMAP_LEN RAMEND-MMAP_START-0x180
|
|
||||||
.inc "mmap.asm"
|
|
||||||
|
|
||||||
.equ BLOCKDEV_RAMSTART STDIO_RAMEND
|
|
||||||
.equ BLOCKDEV_COUNT 3
|
|
||||||
.inc "blockdev.asm"
|
|
||||||
; List of devices
|
|
||||||
.dw mmapGetB, mmapPutB
|
|
||||||
.dw f0GetB, f0PutB
|
|
||||||
.dw f1GetB, f1PutB
|
|
||||||
|
|
||||||
|
|
||||||
.equ FS_RAMSTART BLOCKDEV_RAMEND
|
|
||||||
.equ FS_HANDLE_COUNT 2
|
|
||||||
.inc "fs.asm"
|
|
||||||
|
|
||||||
; *** BASIC ***
|
|
||||||
|
|
||||||
; RAM space used in different routines for short term processing.
|
|
||||||
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
|
|
||||||
.equ SCRATCHPAD FS_RAMEND
|
|
||||||
.inc "lib/util.asm"
|
|
||||||
.inc "lib/ari.asm"
|
|
||||||
.inc "lib/parse.asm"
|
|
||||||
.inc "lib/fmt.asm"
|
|
||||||
.equ EXPR_PARSE parseLiteralOrVar
|
|
||||||
.inc "lib/expr.asm"
|
|
||||||
.inc "basic/util.asm"
|
|
||||||
.inc "basic/parse.asm"
|
|
||||||
.inc "basic/tok.asm"
|
|
||||||
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
|
|
||||||
.inc "basic/var.asm"
|
|
||||||
.equ BUF_RAMSTART VAR_RAMEND
|
|
||||||
.inc "basic/buf.asm"
|
|
||||||
.equ BFS_RAMSTART BUF_RAMEND
|
|
||||||
.inc "basic/fs.asm"
|
|
||||||
.inc "basic/blk.asm"
|
|
||||||
.equ BAS_RAMSTART BFS_RAMEND
|
|
||||||
.inc "basic/main.asm"
|
|
||||||
|
|
||||||
; USER_CODE is set according to this output below.
|
|
||||||
.out BAS_RAMEND
|
|
||||||
|
|
||||||
init:
|
|
||||||
di
|
|
||||||
im 1
|
|
||||||
|
|
||||||
ld sp, RAMEND
|
|
||||||
|
|
||||||
; init a FS in mmap
|
|
||||||
ld hl, MMAP_START
|
|
||||||
ld a, 'C'
|
|
||||||
ld (hl), a
|
|
||||||
inc hl
|
|
||||||
ld a, 'F'
|
|
||||||
ld (hl), a
|
|
||||||
inc hl
|
|
||||||
ld a, 'S'
|
|
||||||
ld (hl), a
|
|
||||||
|
|
||||||
call fsInit
|
|
||||||
xor a
|
|
||||||
ld de, BLOCKDEV_SEL
|
|
||||||
call blkSel
|
|
||||||
call fsOn
|
|
||||||
|
|
||||||
call kbdInit
|
|
||||||
call gridInit
|
|
||||||
call vdpInit
|
|
||||||
|
|
||||||
call basInit
|
|
||||||
ld hl, basFindCmdExtra
|
|
||||||
ld (BAS_FINDHOOK), hl
|
|
||||||
jp basStart
|
|
||||||
|
|
||||||
basFindCmdExtra:
|
|
||||||
ld hl, basFSCmds
|
|
||||||
call basFindCmd
|
|
||||||
ret z
|
|
||||||
ld hl, basBLKCmds
|
|
||||||
call basFindCmd
|
|
||||||
ret z
|
|
||||||
ld hl, .mycmds
|
|
||||||
call basFindCmd
|
|
||||||
ret z
|
|
||||||
jp basPgmHook
|
|
||||||
.mycmds:
|
|
||||||
.db "ed", 0
|
|
||||||
.dw 0x1f00
|
|
||||||
.db "zasm", 0
|
|
||||||
.dw 0x2400
|
|
||||||
.db 0xff
|
|
||||||
|
|
||||||
f0GetB:
|
|
||||||
ld ix, FS_HANDLES
|
|
||||||
jp fsGetB
|
|
||||||
|
|
||||||
f0PutB:
|
|
||||||
ld ix, FS_HANDLES
|
|
||||||
jp fsPutB
|
|
||||||
|
|
||||||
f1GetB:
|
|
||||||
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
|
||||||
jp fsGetB
|
|
||||||
|
|
||||||
f1PutB:
|
|
||||||
ld ix, FS_HANDLES+FS_HANDLE_SIZE
|
|
||||||
jp fsPutB
|
|
||||||
|
|
||||||
; last time I checked, PC at this point was 0x128f. Let's give us a nice margin
|
|
||||||
; for the start of ed.
|
|
||||||
.fill 0x1f00-$
|
|
||||||
.bin "ed.bin"
|
|
||||||
|
|
||||||
; Last check: 0x23b0
|
|
||||||
.fill 0x2400-$
|
|
||||||
.bin "zasm.bin"
|
|
||||||
|
|
||||||
FNT_DATA:
|
|
||||||
.bin "fnt/7x7.bin"
|
|
||||||
|
|
||||||
.fill 0x7ff0-$
|
|
||||||
.db "TMR SEGA", 0x00, 0x00, 0xfb, 0x68, 0x00, 0x00, 0x00, 0x4c
|
|
@ -1,32 +0,0 @@
|
|||||||
.equ USER_CODE 0xc200
|
|
||||||
; Make ed fit in SMS's memory
|
|
||||||
.equ ED_BUF_MAXLINES 0x100
|
|
||||||
.equ ED_BUF_PADMAXLEN 0x800
|
|
||||||
|
|
||||||
; Make zasm fit in SMS's memory
|
|
||||||
.equ ZASM_REG_MAXCNT 0x80
|
|
||||||
.equ ZASM_LREG_MAXCNT 0x10
|
|
||||||
.equ ZASM_REG_BUFSZ 0x800
|
|
||||||
.equ ZASM_LREG_BUFSZ 0x100
|
|
||||||
|
|
||||||
; *** JUMP TABLE ***
|
|
||||||
.equ strncmp 0x03
|
|
||||||
.equ upcase @+3
|
|
||||||
.equ findchar @+3
|
|
||||||
.equ parseHex @+3
|
|
||||||
.equ blkSel @+3
|
|
||||||
.equ blkSet @+3
|
|
||||||
.equ fsFindFN @+3
|
|
||||||
.equ fsOpen @+3
|
|
||||||
.equ fsGetB @+3
|
|
||||||
.equ fsPutB @+3
|
|
||||||
.equ fsSetSize @+3
|
|
||||||
.equ printstr @+3
|
|
||||||
.equ _blkGetB @+3
|
|
||||||
.equ _blkPutB @+3
|
|
||||||
.equ _blkSeek @+3
|
|
||||||
.equ _blkTell @+3
|
|
||||||
.equ printcrlf @+3
|
|
||||||
.equ stdioPutC @+3
|
|
||||||
.equ stdioReadLine @+3
|
|
||||||
|
|
@ -44,7 +44,7 @@ int main(int argc, char **argv)
|
|||||||
set_blocking(fd, 1);
|
set_blocking(fd, 1);
|
||||||
char s[0x40];
|
char s[0x40];
|
||||||
sprintf(s,
|
sprintf(s,
|
||||||
": _ 0x%04x 0x%04x DO KEY DUP .x I A! LOOP ; _",
|
": _ 0x%04x 0x%04x DO KEY DUP .x I C! LOOP ; _",
|
||||||
memptr+bytecount, memptr);
|
memptr+bytecount, memptr);
|
||||||
sendcmd(fd, s);
|
sendcmd(fd, s);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user