1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 22:10:56 +11:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Virgil Dupras
105acedab8 basic: improve README
markdown formatting was broken. Also, don't mark it as WIP.
2019-12-01 20:15:45 -05:00
Virgil Dupras
10864afa96 recipes/ti84: use the BASIC shell 2019-12-01 20:11:13 -05:00
6 changed files with 73 additions and 47 deletions

View File

@ -1,16 +1,11 @@
# basic # basic
**Work in progress, not finished.** This is a BASIC interpreter which has been written from scratch for Collapse OS.
This is a BASIC interpreter which is being written from scratch for Collapse OS.
There are many existing z80 implementations around, some of them open source There are many existing z80 implementations around, some of them open source
and most of them good and efficient, but because a lot of that code overlaps and most of them good and efficient, but because a lot of that code overlaps
with code that has already been written for zasm, I believe that it's better to with code that has already been written for zasm, I believe that it's better to
reuse those bits of code. reuse those bits of code.
Integrating an existing BASIC to Collapse OS seemed a bigger challenge than
writing from scratch, so here I am, writing from scratch again...
## Design goal ## Design goal
The reason for including a BASIC dialect in Collapse OS is to supply some form The reason for including a BASIC dialect in Collapse OS is to supply some form
@ -98,17 +93,17 @@ with variables in it, work fine.
There are two types of commands: normal and direct-only. The latter can only There are two types of commands: normal and direct-only. The latter can only
be invoked in direct mode, not through a code listing. be invoked in direct mode, not through a code listing.
**bye**: Direct-only. Quits BASIC `bye`: Direct-only. Quits BASIC
**list**: Direct-only. Prints all lines in the code listing, prefixing them `list`: Direct-only. Prints all lines in the code listing, prefixing them
with their associated line number. with their associated line number.
**run**: Direct-only. Runs code from the listing, starting with the first one. `run`: Direct-only. Runs code from the listing, starting with the first one.
If `goto` was previously called in direct mode, we start from that line instead. 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 <what> [<what>]**: Prints the result of the specified expression, `print <what> [<what>]`: Prints the result of the specified expression,
then CR/LF. Can be given multiple arguments. In that case, all arguments are 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 printed separately with a space in between. For example, `print 12 13` prints
`12 13<cr><lf>` `12 13<cr><lf>`
@ -117,48 +112,48 @@ 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 <lineno>**: Make the next line to be executed the line number `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 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 an expression. If invoked in direct mode, `run` must be called to actually
run the line (followed by the next, and so on). run the line (followed by the next, and so on).
**if <cond> <cmd>**: If specified condition is true, execute the rest of the `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 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 2<1 print 12` does nothing. The argument for this command is a "thruth
expression". expression".
**input [<prompt>]**: Prompts the user for a numerical value and puts that `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. 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 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 will be printed before asking for input. Unlike a `print` call, there is no
CR/LF after that print. CR/LF after that print.
**peek/deek <addr>**: 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 <addr> <val>**: Put the value of specified expression into `poke/doke <addr> <val>`: Put the value of specified expression into
specified memory address. For example, `poke 42 0x102+0x40` puts `0x42` in 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 memory address 0x2a (MSB is ignored) and `doke 42 0x102+0x40` does the same
as poke, but also puts `0x01` in memory address 0x2b. as poke, but also puts `0x01` in memory address 0x2b.
**in <port>**: Same thing as `peek`, but for a I/O port. `in 42` generates an `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`. input I/O on port 42 and stores the byte result in `A`.
**out <port> <val>**: Same thing as `poke`, but for a I/O port. `out 42 1+2` `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. generates an output I/O on port 42 with value 3.
**getc**: Waits for a single character to be typed in the console and then puts `getc`: Waits for a single character to be typed in the console and then puts
that value in `A`. that value in `A`.
**putc <char>**: Puts the specified character to the console. `putc <char>`: Puts the specified character to the console.
**sleep <units>**: Sleep a number of "units" specified by the supplied `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 expression. A "unit" depends on the CPU clock speed. At 4MHz, it is roughly 8
microseconds. microseconds.
**addr <what>**: This very handy returns (in `A`), the address you query for. `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. 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
@ -168,7 +163,7 @@ Then, there's the *special stuff*. This is the list of things you can query for:
* `$`: the scratchpad. * `$`: the scratchpad.
**usr <addr>**: This calls the memory address specified as an expression `usr <addr>`: This calls the memory address specified as an expression
argument. Before doing so, it sets the registers according to a specific 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 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 `DE`, `H` in `HL` `B` in `BC` and `X` in `IX`. `IY` can't be used because
@ -191,24 +186,24 @@ 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 <blkid>**: Select the active block device. The active block device is `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 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 example, `bsel 0` selects the first configured device. `bsel 1` selects the
second. second.
A freshly selected blkdev begins with its "pointer" at 0. A freshly selected blkdev begins with its "pointer" at 0.
**seek <lsw> <msw>**: Moves the blkdev "pointer" to the specified offset. The `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 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.
It defaults to 0. 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 <val>**: Writes a byte in active blkdev at current pointer, then `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 advance the pointer by one. The value of the byte is determined by the
expression supplied as an argument. Example: `putb 42`. expression supplied as an argument. Example: `putb 42`.
@ -216,9 +211,9 @@ expression supplied as an argument. Example: `putb 42`.
`fs.asm` provides those commands: `fs.asm` provides those commands:
**fls**: prints the list of files contained in the active filesystem. `fls`: prints the list of files contained in the active filesystem.
**fopen <fhandle> <fname>**: Open file "fname" in handle "fhandle". File handles `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 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 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. here, you have to look at your glue code.
@ -229,16 +224,16 @@ handle 1 maps to blkid 2.
Once a file is opened, you can use the mapped blkid as you would with any block Once a file is opened, you can use the mapped blkid as you would with any block
device (bseek, getb, putb). device (bseek, getb, putb).
**fnew <blkcnt> <fname>**: Allocates space of "blkcnt" blocks (each block is `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. 0x100 bytes in size) for a new file names "fname". Maximum blkcnt is 0xff.
**fdel <fname>**: Mark file named "fname" as deleted. `fdel <fname>`: Mark file named "fname" as deleted.
**ldbas <fname>**: loads the content of the file specified in the argument `ldbas <fname>`: loads the content of the file specified in the argument
(as an unquoted filename) and replace the current code listing with this (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). 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 `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 `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 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 its contents at `USER_CODE` (from `user.h`) and calls that address, with HL

View File

@ -1,5 +1,9 @@
# shell # shell
**This shell is currently being replaced with the
[BASIC shell](../basic/README.md). While it's still used in many places, it's
being phased out.**
The shell is a text interface giving you access to commands to control your The shell is a text interface giving you access to commands to control your
machine. It is not built to be user friendly, but to minimize binary space and machine. It is not built to be user friendly, but to minimize binary space and
maximize code simplicity. maximize code simplicity.

View File

@ -8,6 +8,7 @@
## User guide ## User guide
* [The shell](../apps/shell/README.md) * [The shell](../apps/shell/README.md)
* [The BASIC shell](../apps/basic/README.md)
* [Load code in RAM and run it](load-run-code.md) * [Load code in RAM and run it](load-run-code.md)
* [Using block devices](blockdev.md) * [Using block devices](blockdev.md)
* [Using the filesystem](fs.md) * [Using the filesystem](fs.md)

View File

@ -51,6 +51,7 @@ init:
call aciaInit call aciaInit
ei ei
call basInit
jp basStart jp basStart

View File

@ -10,7 +10,7 @@ There is, however, a built-in USB controller that might prove very handy.
## Recipe ## Recipe
This recipe gets the Collapse OS shell to run on the TI-84+, using its LCD This recipe gets the Collapse OS BASIC shell to run on the TI-84+, using its LCD
screen as output and its builtin keyboard as input. screen as output and its builtin keyboard as input.
## Gathering parts ## Gathering parts
@ -66,9 +66,19 @@ Press "1" to continue.
When this is done, you can press the ON button to see Collapse OS' prompt! When this is done, you can press the ON button to see Collapse OS' prompt!
## Validation errors
Sometimes, when uploading an upgrade file to your calculator, you'll get a
validation error. You can always try again, but in my own experience, some
specific binaries will simply always be refused by the calculator. Adding
random `nop` or reordering lines (when it makes sense, of course) should fix
the problem.
I'm not sure whether it's a bug with the calculator or with `mktiupgrade`.
## Usage ## Usage
The shell works like a normal shell, but with very tight screen space. The shell works like a normal BASIC shell, but with very tight screen space.
When pressing a "normal" key, it spits the symbol associated to it depending When pressing a "normal" key, it spits the symbol associated to it depending
on the current mode. In normal mode, it spits the digit/symbol. In Alpha mode, on the current mode. In normal mode, it spits the digit/symbol. In Alpha mode,

View File

@ -37,19 +37,31 @@
.equ STDIO_PUTC lcdPutC .equ STDIO_PUTC lcdPutC
.inc "stdio.asm" .inc "stdio.asm"
; *** Shell *** ; *** BASIC ***
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART STDIO_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 0
.inc "shell/main.asm"
; 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"
.out BAS_RAMEND
boot: boot:
di di
ld hl, RAMEND ld sp, RAMEND
ld sp, hl
im 1 im 1
; enable ON key interrupt ; enable ON key interrupt
@ -67,12 +79,15 @@ boot:
halt halt
main: main:
; Fun fact: if I place this line just above basStart like I would
; normally do, my TI-84+ refuses to validate the binary. But placed
; here, validation works fine.
call basInit
call kbdInit call kbdInit
call lcdInit call lcdInit
xor a xor a
call lcdSetCol call lcdSetCol
call shellInit jp basStart
jp shellLoop
handleInterrupt: handleInterrupt:
di di