mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 22:20:55 +11:00
Compare commits
4 Commits
585e9f3b6e
...
aad8efeff7
Author | SHA1 | Date | |
---|---|---|---|
|
aad8efeff7 | ||
|
b7d4860acf | ||
|
7761cebb0a | ||
|
9602f9b983 |
@ -103,3 +103,23 @@ stored where specified. For example, `input x` stores the result of the
|
|||||||
evaluation in variable `x`. Before the variable name, a quoted string literal
|
evaluation in variable `x`. Before the variable name, a quoted string literal
|
||||||
can be specified. In that case, that string will be printed as-is just before
|
can be specified. In that case, that string will be printed as-is just before
|
||||||
the prompt.
|
the prompt.
|
||||||
|
|
||||||
|
**peek/deek**: Put the value at specified memory address into specified
|
||||||
|
variable. peek is for a single byte, deek is for a word (little endian). For
|
||||||
|
example, `peek 42 a` puts the byte value contained in memory address 0x002a
|
||||||
|
into variable `a`. `deek 42 a` does the same as peek, but also puts the value
|
||||||
|
of 0x002b into `a`'s MSB.
|
||||||
|
|
||||||
|
**poke/doke**: Put the value of specified expression into specified memory
|
||||||
|
address. For example, `poke 42 0x102+0x40` puts `0x42` in memory address
|
||||||
|
0x2a (MSB is ignored) and `doke 42 0x102+0x40` does the same as poke, but also
|
||||||
|
puts `0x01` in memory address 0x2b.
|
||||||
|
|
||||||
|
**in**: Same thing as `peek`, but for a I/O port. `in 42 a` generates an input
|
||||||
|
I/O on port 42 and stores the byte result in `a`.
|
||||||
|
|
||||||
|
**out**: Same thing as `poke`, but for a I/O port. `out 42 1+2` generates an
|
||||||
|
output I/O on port 42 with value 3.
|
||||||
|
|
||||||
|
**sleep**: Sleep a number of "units" specified by the supplied expression. A
|
||||||
|
"unit" depends on the CPU clock speed. At 4MHz, it is roughly 8 microseconds.
|
||||||
|
@ -56,17 +56,17 @@ basCallCmd:
|
|||||||
; let's see if it's a variable assignment.
|
; let's see if it's a variable assignment.
|
||||||
call varTryAssign
|
call varTryAssign
|
||||||
ret z ; Done!
|
ret z ; Done!
|
||||||
; Second, get cmd length
|
push de ; --> lvl 1.
|
||||||
call fnWSIdx
|
ld de, SCRATCHPAD
|
||||||
cp 7
|
call rdWord
|
||||||
jp nc, unsetZ ; Too long, can't possibly fit anything.
|
; cmdname to find in (DE)
|
||||||
; A contains whitespace IDX, save it in B
|
; How lucky, we have a legitimate use of "ex (sp), hl"! We have the
|
||||||
ld b, a
|
; cmd table in the stack, which we want in HL and we have the rest of
|
||||||
ex de, hl
|
; the cmdline in (HL), which we want in the stack!
|
||||||
|
ex (sp), hl
|
||||||
inc hl \ inc hl
|
inc hl \ inc hl
|
||||||
.loop:
|
.loop:
|
||||||
ld a, b ; whitespace IDX
|
call strcmp
|
||||||
call strncmp
|
|
||||||
jr z, .found
|
jr z, .found
|
||||||
ld a, 8
|
ld a, 8
|
||||||
call addHL
|
call addHL
|
||||||
@ -74,15 +74,14 @@ basCallCmd:
|
|||||||
cp 0xff
|
cp 0xff
|
||||||
jr nz, .loop
|
jr nz, .loop
|
||||||
; not found
|
; not found
|
||||||
|
pop hl ; <-- lvl 1
|
||||||
jp unsetZ
|
jp unsetZ
|
||||||
.found:
|
.found:
|
||||||
dec hl \ dec hl
|
dec hl \ dec hl
|
||||||
call intoHL
|
call intoHL
|
||||||
push hl \ pop ix
|
push hl \ pop ix
|
||||||
; Bring back command string from DE to HL
|
; Bring back rest of the command string from the stack
|
||||||
ex de, hl
|
pop hl ; <-- lvl 1
|
||||||
ld a, b ; cmd's length
|
|
||||||
call addHL
|
|
||||||
call rdSep
|
call rdSep
|
||||||
jp (ix)
|
jp (ix)
|
||||||
|
|
||||||
@ -267,6 +266,89 @@ basINPUT:
|
|||||||
cp a ; ensure Z
|
cp a ; ensure Z
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
basPEEK:
|
||||||
|
call basDEEK
|
||||||
|
ret nz
|
||||||
|
ld d, 0
|
||||||
|
call varAssign
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
||||||
|
|
||||||
|
basPOKE:
|
||||||
|
call rdExpr
|
||||||
|
ret nz
|
||||||
|
; peek address in IX. Save it for later
|
||||||
|
push ix ; --> lvl 1
|
||||||
|
call rdSep
|
||||||
|
call rdExpr
|
||||||
|
push ix \ pop hl
|
||||||
|
pop ix ; <-- lvl 1
|
||||||
|
ret nz
|
||||||
|
; Poke!
|
||||||
|
ld (ix), l
|
||||||
|
ret
|
||||||
|
|
||||||
|
basDEEK:
|
||||||
|
call rdExpr
|
||||||
|
ret nz
|
||||||
|
; peek address in IX. Let's peek and put result in DE
|
||||||
|
ld e, (ix)
|
||||||
|
ld d, (ix+1)
|
||||||
|
call rdSep
|
||||||
|
ld a, (hl)
|
||||||
|
call varChk
|
||||||
|
ret nz ; not in variable range
|
||||||
|
; All good assign
|
||||||
|
call varAssign
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
||||||
|
|
||||||
|
basDOKE:
|
||||||
|
call basPOKE
|
||||||
|
ld (ix+1), h
|
||||||
|
ret
|
||||||
|
|
||||||
|
basOUT:
|
||||||
|
call rdExpr
|
||||||
|
ret nz
|
||||||
|
; out address in IX. Save it for later
|
||||||
|
push ix ; --> lvl 1
|
||||||
|
call rdSep
|
||||||
|
call rdExpr
|
||||||
|
push ix \ pop hl
|
||||||
|
pop bc ; <-- lvl 1
|
||||||
|
ret nz
|
||||||
|
; Out!
|
||||||
|
out (c), l
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
||||||
|
|
||||||
|
basIN:
|
||||||
|
call rdExpr
|
||||||
|
ret nz
|
||||||
|
push ix \ pop bc
|
||||||
|
ld d, 0
|
||||||
|
in e, (c)
|
||||||
|
call rdSep
|
||||||
|
ld a, (hl)
|
||||||
|
call varChk
|
||||||
|
ret nz ; not in variable range
|
||||||
|
; All good assign
|
||||||
|
call varAssign
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
||||||
|
|
||||||
|
basSLEEP:
|
||||||
|
call rdExpr
|
||||||
|
ret nz
|
||||||
|
push ix \ pop hl
|
||||||
|
.loop:
|
||||||
|
ld a, h ; 4T
|
||||||
|
or l ; 4T
|
||||||
|
ret z ; 5T
|
||||||
|
dec hl ; 6T
|
||||||
|
jr .loop ; 12T
|
||||||
|
|
||||||
; direct only
|
; direct only
|
||||||
basCmds1:
|
basCmds1:
|
||||||
.dw basBYE
|
.dw basBYE
|
||||||
@ -285,4 +367,18 @@ basCmds2:
|
|||||||
.db "if", 0, 0, 0, 0
|
.db "if", 0, 0, 0, 0
|
||||||
.dw basINPUT
|
.dw basINPUT
|
||||||
.db "input", 0
|
.db "input", 0
|
||||||
|
.dw basPEEK
|
||||||
|
.db "peek", 0, 0
|
||||||
|
.dw basPOKE
|
||||||
|
.db "poke", 0, 0
|
||||||
|
.dw basDEEK
|
||||||
|
.db "deek", 0, 0
|
||||||
|
.dw basDOKE
|
||||||
|
.db "doke", 0, 0
|
||||||
|
.dw basOUT
|
||||||
|
.db "out", 0, 0, 0
|
||||||
|
.dw basIN
|
||||||
|
.db "in", 0, 0, 0, 0
|
||||||
|
.dw basSLEEP
|
||||||
|
.db "sleep", 0
|
||||||
.db 0xff, 0xff, 0xff ; end of table
|
.db 0xff, 0xff, 0xff ; end of table
|
||||||
|
@ -32,30 +32,6 @@ rdSep:
|
|||||||
inc a ; unset Z
|
inc a ; unset Z
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Find the first whitespace in (HL) and returns its index in A
|
|
||||||
; Sets Z if whitespace is found, unset if end of string was found.
|
|
||||||
; In the case where no whitespace was found, A returns the length of the string.
|
|
||||||
fnWSIdx:
|
|
||||||
push hl
|
|
||||||
push bc
|
|
||||||
ld b, 0
|
|
||||||
.loop:
|
|
||||||
ld a, (hl)
|
|
||||||
call isSep
|
|
||||||
jr z, .found
|
|
||||||
or a
|
|
||||||
jr z, .eos
|
|
||||||
inc hl
|
|
||||||
inc b
|
|
||||||
jr .loop
|
|
||||||
.eos:
|
|
||||||
inc a ; unset Z
|
|
||||||
.found: ; Z already set from isSep
|
|
||||||
ld a, b
|
|
||||||
pop bc
|
|
||||||
pop hl
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Advance HL to the next separator or to the end of string.
|
; Advance HL to the next separator or to the end of string.
|
||||||
toSep:
|
toSep:
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
@ -85,3 +61,15 @@ rdWord:
|
|||||||
pop de
|
pop de
|
||||||
pop af
|
pop af
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; Read word from HL in SCRATCHPAD and then intepret that word as an expression.
|
||||||
|
; Put the result in IX.
|
||||||
|
; Z for success.
|
||||||
|
rdExpr:
|
||||||
|
ld de, SCRATCHPAD
|
||||||
|
call rdWord
|
||||||
|
push hl
|
||||||
|
ex de, hl
|
||||||
|
call parseExpr
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
@ -27,6 +27,7 @@ are other recipes related to the RC2014:
|
|||||||
* [Accessing a MicroSD card](sdcard/README.md)
|
* [Accessing a MicroSD card](sdcard/README.md)
|
||||||
* [Assembling binaries](zasm/README.md)
|
* [Assembling binaries](zasm/README.md)
|
||||||
* [Interfacing a PS/2 keyboard](ps2/README.md)
|
* [Interfacing a PS/2 keyboard](ps2/README.md)
|
||||||
|
* [Replace shell by a BASIC interpreter](basic/README.md)
|
||||||
|
|
||||||
## Recipe
|
## Recipe
|
||||||
|
|
||||||
|
10
recipes/rc2014/basic/Makefile
Normal file
10
recipes/rc2014/basic/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
TARGET = os.bin
|
||||||
|
ZASM = ../../../tools/zasm.sh
|
||||||
|
KERNEL = ../../../kernel
|
||||||
|
APPS = ../../../apps
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(TARGET)
|
||||||
|
$(TARGET): glue.asm
|
||||||
|
$(ZASM) $(KERNEL) $(APPS) < $< > $@
|
||||||
|
|
46
recipes/rc2014/basic/README.md
Normal file
46
recipes/rc2014/basic/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# BASIC as a shell
|
||||||
|
|
||||||
|
This recipe demonstrate the replacement of the usual shell with the BASIC
|
||||||
|
interpreter supplied in Collapse OS. To make things fun, we play with I/Os
|
||||||
|
using RC2014's Digital I/O module.
|
||||||
|
|
||||||
|
## Gathering parts
|
||||||
|
|
||||||
|
* Same parts as in the base recipe
|
||||||
|
* (Optional) RC2014's Digital I/O module
|
||||||
|
|
||||||
|
The Digital I/O module is only used in the example BASIC code. If you don't
|
||||||
|
have the module, just use BASIC in another fashion.
|
||||||
|
|
||||||
|
## Build the image
|
||||||
|
|
||||||
|
As usual, building `os.bin` is a matter of running `make`. Then, you can get
|
||||||
|
that image to your EEPROM like you did in the base recipe.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Upon boot, you'll directy be in a BASIC prompt. See documentation in
|
||||||
|
`apps/basic/README.md` for details.
|
||||||
|
|
||||||
|
For now, let's have some fun with the Digital I/O module. Type this:
|
||||||
|
|
||||||
|
```
|
||||||
|
> a=0
|
||||||
|
> 10 out 0 a
|
||||||
|
> 20 sleep 0xffff
|
||||||
|
> 30 a=a+1
|
||||||
|
> 40 goto 10
|
||||||
|
> run
|
||||||
|
```
|
||||||
|
|
||||||
|
You now have your Digital I/O lights doing a pretty dance, forever.
|
||||||
|
|
||||||
|
## Looking at the glue code
|
||||||
|
|
||||||
|
If you look at the glue code, you'll see that it's very similar to the one in
|
||||||
|
the base recipe, except that the shell includes have been replaced by the basic
|
||||||
|
includes. Those includes have been copy/pasted from `apps/basic/glue.asm` and
|
||||||
|
`USER_RAMSTART` has been replaced with `STDIO_RAMEND` so that BASIC's memory
|
||||||
|
gets placed properly (that is, right after the kernel's memory).
|
||||||
|
|
||||||
|
Simple, isn't it?
|
56
recipes/rc2014/basic/glue.asm
Normal file
56
recipes/rc2014/basic/glue.asm
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
.equ RAMSTART 0x8000
|
||||||
|
.equ RAMEND 0xffff
|
||||||
|
.equ ACIA_CTL 0x80 ; Control and status. RS off.
|
||||||
|
.equ ACIA_IO 0x81 ; Transmit. RS on.
|
||||||
|
.equ DIGIT_IO 0x00 ; digital I/O's port
|
||||||
|
|
||||||
|
jp init
|
||||||
|
|
||||||
|
; interrupt hook
|
||||||
|
.fill 0x38-$
|
||||||
|
jp aciaInt
|
||||||
|
|
||||||
|
.inc "err.h"
|
||||||
|
.inc "ascii.h"
|
||||||
|
.inc "core.asm"
|
||||||
|
.inc "str.asm"
|
||||||
|
.equ ACIA_RAMSTART RAMSTART
|
||||||
|
.inc "acia.asm"
|
||||||
|
|
||||||
|
.equ STDIO_RAMSTART ACIA_RAMEND
|
||||||
|
.equ STDIO_GETC aciaGetC
|
||||||
|
.equ STDIO_PUTC aciaPutC
|
||||||
|
.inc "stdio.asm"
|
||||||
|
|
||||||
|
; *** BASIC ***
|
||||||
|
|
||||||
|
; RAM space used in different routines for short term processing.
|
||||||
|
.equ SCRATCHPAD_SIZE 0x20
|
||||||
|
.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
|
||||||
|
; setup stack
|
||||||
|
ld sp, RAMEND
|
||||||
|
im 1
|
||||||
|
|
||||||
|
call aciaInit
|
||||||
|
ei
|
||||||
|
jp basStart
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user