basic: add fopen command

This commit is contained in:
Virgil Dupras 2019-11-25 21:41:37 -05:00
parent a0daed6812
commit b29073b01d
2 changed files with 78 additions and 45 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. **clear**: Direct-only. Clears the current code listing.
**print**: Prints the result of the specified expression, then CR/LF. Can be **print <what> [<what>]**: Prints the result of the specified expression,
given multiple arguments. In that case, all arguments are printed separately then CR/LF. Can be given multiple arguments. In that case, all arguments are
with a space in between. For example, `print 12 13` prints `12 13<cr><lf>` 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 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 quote. That string will be printed as-is. For example, `print "foo" 40+2` will
print `foo 42`. print `foo 42`.
**goto**: Make the next line to be executed the line number specified as an **goto <lineno>**: Make the next line to be executed the line number
argument. Errors out if line doesn't exist. Argument can be an expression. If specified as an argument. Errors out if line doesn't exist. Argument can be
invoked in direct mode, `run` must be called to actually run the line (followed an expression. If invoked in direct mode, `run` must be called to actually
by the next, and so on). run the line (followed by the next, and so on).
**if**: If specified condition is true, execute the rest of the line. Otherwise, **if <cond> <cmd>**: If specified condition is true, execute the rest of the
do nothing. For example, `if 2>1 print 12` prints `12` and `if 2<1 print 12` line. Otherwise, do nothing. For example, `if 2>1 print 12` prints `12` and `if
does nothing. The argument for this command is a "thruth expression". 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`. **input [<prompt>]**: Prompts the user for a numerical value and puts that
The prompted value is evaluated as an expression and then stored. The command value in `A`. The prompted value is evaluated as an expression and then stored.
takes an optional string literal parameter. If present, that string will be The command takes an optional string literal parameter. If present, that string
printed before asking for input. Unlike a `print` call, there is no CR/LF after will be printed before asking for input. Unlike a `print` call, there is no
that print. 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 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` 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. 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 **poke/doke <addr> <val>**: Put the value of specified expression into
address. For example, `poke 42 0x102+0x40` puts `0x42` in memory address specified memory address. For example, `poke 42 0x102+0x40` puts `0x42` in
0x2a (MSB is ignored) and `doke 42 0x102+0x40` does the same as poke, but also memory address 0x2a (MSB is ignored) and `doke 42 0x102+0x40` does the same
puts `0x01` in memory address 0x2b. 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 **in <port>**: Same thing as `peek`, but for a I/O port. `in 42` generates an
I/O on port 42 and stores the byte result in `A`. 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 **out <port> <val>**: Same thing as `poke`, but for a I/O port. `out 42 1+2`
output I/O on port 42 with value 3. generates an output I/O on port 42 with value 3.
**sleep**: Sleep a number of "units" specified by the supplied expression. A **sleep <units>**: Sleep a number of "units" specified by the supplied
"unit" depends on the CPU clock speed. At 4MHz, it is roughly 8 microseconds. 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 **addr <what>**: This very handy returns (in `A`), the address you query for.
query for two types of things: commands or special stuff. 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 If you query for a command, type the name of the command as an argument. The
address of the associated routine will be returned. 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. * `$`: the scratchpad.
**usr**: This calls the memory address specified as an expression argument. **usr <addr>**: This calls the memory address specified as an expression
Before doing so, it sets the registers according to a specific logic: Variable argument. Before doing so, it sets the registers according to a specific
`A`'s LSB goes in register `A`, variable `D` goes in register `DE`, `H` in `HL` logic: Variable `A`'s LSB goes in register `A`, variable `D` goes in register
`B` in `BC` and `X` in `IX`. `IY` can't be used because it's used for the jump. `DE`, `H` in `HL` `B` in `BC` and `X` in `IX`. `IY` can't be used because
Then, after the call, the value of the registers are put back into the it's used for the jump. Then, after the call, the value of the registers are
variables following the same logic. 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 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 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 Block devices commands. Block devices are configured during kernel
initialization and are referred to by numbers. initialization and are referred to by numbers.
**bsel**: Select the active block device. The active block device is the target **bsel <blkid>**: Select the active block device. The active block device is
of all commands below. You select it by specifying its number. For example, the target of all commands below. You select it by specifying its number. For
`bsel 0` selects the first configured device. `bsel 1` selects the second. example, `bsel 0` selects the first configured device. `bsel 1` selects the
second.
A freshly selected blkdev begins with its "pointer" at 0. A freshly selected blkdev begins with its "pointer" at 0.
**seek**: Moves the blkdev "pointer" to the specified offset. The first **seek <lsw> <msw>**: Moves the blkdev "pointer" to the specified offset. The
argument is the offset's least significant half (blkdev supports 32-bit first argument is the offset's least significant half (blkdev supports 32-bit
addressing). Is is interpreted as an unsigned integer. addressing). Is is interpreted as an unsigned integer.
The second argument is optional and is the most significant half of the address. 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 **getb**: Read a byte in active blkdev at current pointer, then advance the
pointer by one. Read byte goes in `A`. pointer by one. Read byte goes in `A`.
**putb**: Writes a byte in active blkdev at current pointer, then advance the **putb <val>**: Writes a byte in active blkdev at current pointer, then
pointer by one. The value of the byte is determined by the expression supplied advance the pointer by one. The value of the byte is determined by the
as an argument. Example: `putb 42`. expression supplied as an argument. Example: `putb 42`.
### fs ### fs
@ -209,6 +213,17 @@ as an argument. Example: `putb 42`.
**fls**: prints the list of files contained in the active filesystem. **fls**: prints the list of files contained in the active filesystem.
**ldbas**: loads the content of the file specified in the argument (as an **fopen <fhandle> <fname>**: Open file "fname" in handle "fhandle". File handles
unquoted filename) and replace the current code listing with this contents. Any are specified in kernel glue code and are in limited number. The kernel glue
line not starting with a number is ignored (not an error). 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).
**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).

View File

@ -61,9 +61,27 @@ basLDBAS:
ret 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
basFSCmds: basFSCmds:
.dw basFLS .dw basFLS
.db "fls", 0, 0, 0 .db "fls", 0, 0, 0
.dw basLDBAS .dw basLDBAS
.db "ldbas", 0 .db "ldbas", 0
.dw basFOPEN
.db "fopen", 0
.db 0xff, 0xff, 0xff ; end of table .db 0xff, 0xff, 0xff ; end of table