1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 18:20:55 +11:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Virgil Dupras
fc23a7c4a1 basic: do registers-to-vars transfer after pgm hook call 2019-11-25 23:16:15 -05:00
Virgil Dupras
264e72e0fd basic: add fnew and fdel commands 2019-11-25 22:49:24 -05:00
Virgil Dupras
817088f794 fs: fix broken "ensure Z" in fsIter 2019-11-25 22:32:55 -05:00
Virgil Dupras
7c893dada1 basic: can now execute user apps!
Shell replacement sequence beginning in 3, 2, 1...
2019-11-25 22:05:10 -05:00
Virgil Dupras
b29073b01d basic: add fopen command 2019-11-25 21:41:37 -05:00
6 changed files with 156 additions and 48 deletions

View File

@ -108,50 +108,53 @@ If `goto` was previously called in direct mode, we start from that line instead.
**clear**: Direct-only. Clears the current code listing.
**print**: Prints the result of the specified expression, then CR/LF. Can be
given multiple arguments. In that case, all arguments are printed separately
with a space in between. For example, `print 12 13` prints `12 13<cr><lf>`
**print <what> [<what>]**: Prints the result of the specified expression,
then CR/LF. Can be given multiple arguments. In that case, all arguments are
printed separately with a space in between. For example, `print 12 13` prints
`12 13<cr><lf>`
Unlike anywhere else, the `print` command can take a string inside a double
quote. That string will be printed as-is. For example, `print "foo" 40+2` will
print `foo 42`.
**goto**: Make the next line to be executed the line number specified as an
argument. Errors out if line doesn't exist. Argument can be an expression. If
invoked in direct mode, `run` must be called to actually run the line (followed
by the next, and so on).
**goto <lineno>**: Make the next line to be executed the line number
specified as an argument. Errors out if line doesn't exist. Argument can be
an expression. If invoked in direct mode, `run` must be called to actually
run the line (followed by the next, and so on).
**if**: If specified condition is true, execute the rest of the line. Otherwise,
do nothing. For example, `if 2>1 print 12` prints `12` and `if 2<1 print 12`
does nothing. The argument for this command is a "thruth expression".
**if <cond> <cmd>**: If specified condition is true, execute the rest of the
line. Otherwise, do nothing. For example, `if 2>1 print 12` prints `12` and `if
2<1 print 12` does nothing. The argument for this command is a "thruth
expression".
**input**: Prompts the user for a numerical value and puts that value in `A`.
The prompted value is evaluated as an expression and then stored. The command
takes an optional string literal parameter. If present, that string will be
printed before asking for input. Unlike a `print` call, there is no CR/LF after
that print.
**input [<prompt>]**: Prompts the user for a numerical value and puts that
value in `A`. The prompted value is evaluated as an expression and then stored.
The command takes an optional string literal parameter. If present, that string
will be printed before asking for input. Unlike a `print` call, there is no
CR/LF after that print.
**peek/deek**: Put the value at specified memory address into `A`. peek is for
**peek/deek <addr>**: Put the value at specified memory address into `A`. peek is for
a single byte, deek is for a word (little endian). For example, `peek 42` puts
the byte value contained in memory address 0x002a into variable `A`. `deek 42`
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.
**poke/doke <addr> <val>**: 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` generates an input
I/O on port 42 and stores the byte result in `A`.
**in <port>**: Same thing as `peek`, but for a I/O port. `in 42` 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.
**out <port> <val>**: 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.
**sleep <units>**: 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.
**addr**: This very handy returns (in `A`), the address you query for. You can
query for two types of things: commands or special stuff.
**addr <what>**: This very handy returns (in `A`), the address you query for.
You can query for two types of things: commands or special stuff.
If you query for a command, type the name of the command as an argument. The
address of the associated routine will be returned.
@ -160,12 +163,12 @@ Then, there's the *special stuff*. This is the list of things you can query for:
* `$`: the scratchpad.
**usr**: This calls the memory address specified as an expression argument.
Before doing so, it sets the registers according to a specific logic: Variable
`A`'s LSB goes in register `A`, variable `D` goes in register `DE`, `H` in `HL`
`B` in `BC` and `X` in `IX`. `IY` can't be used because it's used for the jump.
Then, after the call, the value of the registers are put back into the
variables following the same logic.
**usr <addr>**: This calls the memory address specified as an expression
argument. Before doing so, it sets the registers according to a specific
logic: Variable `A`'s LSB goes in register `A`, variable `D` goes in register
`DE`, `H` in `HL` `B` in `BC` and `X` in `IX`. `IY` can't be used because
it's used for the jump. Then, after the call, the value of the registers are
put back into the variables following the same logic.
Let's say, for example, that you want to use the kernel's `printstr` to print
the contents of the scratchpad. First, you would call `addr $` to put the
@ -183,14 +186,15 @@ Here's the documentation for them.
Block devices commands. Block devices are configured during kernel
initialization and are referred to by numbers.
**bsel**: Select the active block device. The active block device is the target
of all commands below. You select it by specifying its number. For example,
`bsel 0` selects the first configured device. `bsel 1` selects the second.
**bsel <blkid>**: Select the active block device. The active block device is
the target of all commands below. You select it by specifying its number. For
example, `bsel 0` selects the first configured device. `bsel 1` selects the
second.
A freshly selected blkdev begins with its "pointer" at 0.
**seek**: Moves the blkdev "pointer" to the specified offset. The first
argument is the offset's least significant half (blkdev supports 32-bit
**seek <lsw> <msw>**: Moves the blkdev "pointer" to the specified offset. The
first argument is the offset's least significant half (blkdev supports 32-bit
addressing). Is is interpreted as an unsigned integer.
The second argument is optional and is the most significant half of the address.
@ -199,9 +203,9 @@ It defaults to 0.
**getb**: Read a byte in active blkdev at current pointer, then advance the
pointer by one. Read byte goes in `A`.
**putb**: Writes a byte in active blkdev at current pointer, then advance the
pointer by one. The value of the byte is determined by the expression supplied
as an argument. Example: `putb 42`.
**putb <val>**: Writes a byte in active blkdev at current pointer, then
advance the pointer by one. The value of the byte is determined by the
expression supplied as an argument. Example: `putb 42`.
### fs
@ -209,6 +213,35 @@ as an argument. Example: `putb 42`.
**fls**: prints the list of files contained in the active filesystem.
**ldbas**: loads the content of the file specified in the argument (as an
unquoted filename) and replace the current code listing with this contents. Any
line not starting with a number is ignored (not an error).
**fopen <fhandle> <fname>**: Open file "fname" in handle "fhandle". File handles
are specified in kernel glue code and are in limited number. The kernel glue
code also maps to blkids through the glue code. So to know what you're doing
here, you have to look at your glue code.
In the emulated code, there are two file handles. Handle 0 maps to blkid 1 and
handle 1 maps to blkid 2.
Once a file is opened, you can use the mapped blkid as you would with any block
device (bseek, getb, putb).
**fnew <blkcnt> <fname>**: Allocates space of "blkcnt" blocks (each block is
0x100 bytes in size) for a new file names "fname". Maximum blkcnt is 0xff.
**fdel <fname>**: Mark file named "fname" as deleted.
**ldbas <fname>**: loads the content of the file specified in the argument
(as an unquoted filename) and replace the current code listing with this
contents. Any line not starting with a number is ignored (not an error).
**basPgmHook**: That is not a command, but a routine to hook into
`BAS_FINDHOOK`. If you do, whenever a command name isn't found, the filesystem
is iterated to see if it finds a file with the same name. If it does, it loads
its contents at `USER_CODE` (from `user.h`) and calls that address, with HL
pointing to the the remaining args in the command line.
The user code called this way follows the *usr* convention for output, that is,
it converts all registers at the end of the call and stores them in appropriate
variables. If `A` is nonzero, an error is considered to have occurred.
It doesn't do var-to-register transfers on input, however. Only HL is passed
through (with the contents of the command line).

View File

@ -4,6 +4,7 @@
.equ BFS_FILE_HDL BFS_RAMSTART
.equ BFS_RAMEND @+FS_HANDLE_SIZE
; Lists filenames in currently active FS
basFLS:
ld iy, .iter
jp fsIter
@ -61,9 +62,79 @@ basLDBAS:
ret
basFOPEN:
call rdExpr ; file handle index
ret nz
push ix \ pop de
ld a, e
call fsHandle
; DE now points to file handle
call rdSep
; HL now holds the string we look for
call fsFindFN
ret nz ; not found
; Found!
; FS_PTR points to the file we want to open
push de \ pop ix ; IX now points to the file handle.
jp fsOpen
; Takes one byte block number to allocate as well we one string arg filename
; and allocates a new file in the current fs.
basFNEW:
call rdExpr ; file block count
ret nz
call rdSep ; HL now points to filename
push ix \ pop de
ld a, e
jp fsAlloc
; Deletes filename with specified name
basFDEL:
call fsFindFN
ret nz
; Found! delete
jp fsDel
basPgmHook:
; Cmd to find is in (DE)
ex de, hl
; (HL) is suitable for a direct fsFindFN call
call fsFindFN
ret nz
; We have a file! Let's load it in memory
ld ix, BFS_FILE_HDL
call fsOpen
ld hl, 0 ; addr that we read in file handle
ld de, USER_CODE ; addr in mem we write to
.loop:
call fsGetB ; we use Z at end of loop
ld (de), a ; Z preserved
inc hl ; Z preserved in 16-bit
inc de ; Z preserved in 16-bit
jr z, .loop
; Ready to jump. Return .call in IX and basCallCmd will take care
; of setting (HL) to the arg string. .call then takes care of wrapping
; the USER_CODE call.
ld ix, .call
cp a ; ensure Z
ret
.call:
ld iy, USER_CODE
call callIY
call basR2Var
or a ; Z set only if A is zero
ret
basFSCmds:
.dw basFLS
.db "fls", 0, 0, 0
.dw basLDBAS
.db "ldbas", 0
.dw basFOPEN
.db "fopen", 0
.dw basFNEW
.db "fnew", 0, 0
.dw basFDEL
.db "fdel", 0, 0
.db 0xff, 0xff, 0xff ; end of table

View File

@ -415,6 +415,7 @@ basUSR:
; and finally, A
ld a, (VAR_TBL)
call callIY
basR2Var: ; Just send reg to vars. Used in basPgmHook
; Same dance, opposite way
ld (VAR_TBL), a
ld (VAR_TBL+46), ix

View File

@ -555,7 +555,7 @@ fsIter:
call nz, callIY
call fsNext
jr z, .loop ; Z set? fsNext was successful
or a ; ensure Z
cp a ; ensure Z
ret
; Delete currently active file

View File

@ -3,6 +3,7 @@
.inc "err.h"
.inc "ascii.h"
.equ RAMSTART 0x4000
.equ USER_CODE 0x4200
.equ STDIO_PORT 0x00
.equ FS_DATA_PORT 0x01
.equ FS_ADDR_PORT 0x02
@ -109,7 +110,9 @@ basFindCmdExtra:
call basFindCmd
ret z
ld hl, basBLKCmds
jp basFindCmd
call basFindCmd
ret z
jp basPgmHook
emulGetC:
; Blocks until a char is returned

View File

@ -1,5 +1,5 @@
.equ SHELL_RAMSTART 0x4100
.equ USER_CODE 0x4200
.equ USER_CODE 0x4200 ; in sync with glue.asm
; *** JUMP TABLE ***
.equ strncmp 0x03