1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-12-24 14:38:05 +11:00

Make the shell a userspace app

That's my mega-commit you've all been waiting for.

The code for the shell share more routines with userspace apps than with kernel
units, because, well, its behavior is that of a userspace app, not a device
driver.

This created a weird situation with libraries and jump tables. Some routine
belonging to the `kernel/` directory felt weird there.

And then comes `apps/basic`, which will likely share even more code with the
shell. I was seeing myself creating huge jump tables to reuse code from the
shell. It didn't feel right.

Moreover, we'll probably want basic-like apps to optionnally replace the shell.

So here I am with this huge change in the project structure. I didn't test all
recipes on hardware yet, I will do later. I might have broken some...

But now, the structure feels better and the line between what belongs to
`kernel` and what belongs to `apps` feels clearer.
This commit is contained in:
Virgil Dupras 2019-11-15 15:37:49 -05:00
parent cdd0b64570
commit 019d05f64c
57 changed files with 535 additions and 361 deletions

71
CODE.md Normal file
View File

@ -0,0 +1,71 @@
## Code conventions
The code in this project follow certain project-wide conventions, which are
described here. Kernel code and userspace code follow additional conventions
which are described in `kernel/README.md` and `apps/README.md`.
## Defines
Each unit can have its own constants, but some constant are made to be defined
externally. We already have some of those external definitions in platform
includes, but we can have more defines than this.
Many units have a "DEFINES" section listing the constant it expects to be
defined. Make sure that you have these constants defined before you include the
file.
## Variable management
Each unit can define variables. These variables are defined as addresses in
RAM. We know where RAM start from the `RAMSTART` constant in platform includes,
but because those parts are made to be glued together in no pre-defined order,
we need a system to align variables from different modules in RAM.
This is why each unit that has variable expect a `<PREFIX>_RAMSTART`
constant to be defined and, in turn, defines a `<PREFIX>_RAMEND` constant to
carry to the following unit.
Thus, code that glue parts together could look like:
MOD1_RAMSTART .equ RAMSTART
#include "mod1.asm"
MOD2_RAMSTART .equ MOD1_RAMEND
#include "mod2.asm"
## Stack management
Keeping the stack "balanced" is a big challenge when writing assembler code.
Those push and pop need to correspond, otherwise we end up with completely
broken code.
The usual "push/pop" at the beginning and end of a routine is rather easy to
manage, nothing special about them.
The problem is for the "inner" push and pop, which are often necessary in
routines handling more data at once. In those cases, we walk on eggshells.
A naive approach could be to indent the code between those push/pop, but indent
level would quickly become too big to fit in 80 chars.
I've tried ASCII art in some places, where comments next to push/pop have "|"
indicating the scope of the push/pop. It's nice, but it makes code complicated
to edit, especially when dense comments are involved. The pipes have to go
through them.
Of course, one could add descriptions next to each push/pop describing what is
being pushed, and I do it in some places, but it doesn't help much in easily
tracking down stack levels.
So, what I've started doing is to accompany each "non-routine" (at the
beginning and end of a routine) push/pop with "--> lvl X" and "<-- lvl X"
comments. Example:
push af ; --> lvl 1
inc a
push af ; --> lvl 2
inc a
pop af ; <-- lvl 2
pop af ; <-- lvl 1
I think that this should do the trick, so I'll do this consistently from now on.
[zasm]: ../apps/zasm/README.md

View File

@ -31,6 +31,8 @@ A userspace application can expect the `SP` pointer to be properly set. If it
moves it, it should take care of returning it where it was before returning
because otherwise, it will break the kernel.
## Memory management
Apps in Collapse OS are design to be ROM-compatible, that is, they don't write
to addresses that are part of the code's address space.
@ -38,3 +40,24 @@ By default, apps set their RAM to begin at the end of the binary because in
most cases, these apps will be ran from RAM. If they're ran from ROM, make sure
to set `USER_RAMSTART` properly in your `user.h` to ensure that the RAM is
placed properly.
Applications that are ran as a shell (the "shell" app, of course, but also,
possibly, "basic" and others to come) need a manual override to their main
`RAMSTART` constant: You don't want them to run in the same RAM region as your
other userspace apps because if you do, as soon as you launch an app with your
shell, its memory is going to be overwritten!
What you'll do then is that you'll reserve some space in your memory layout for
the shell and add a special constant in your `user.h`, which will override the
basic one (remember, in zasm, the first `.equ` for a given constant takes
precedence).
For example, if you want a "basic" shell and that you reserve space right
after your kernel RAM for it, then your `user.h` would contain
`.equ BAS_RAMSTART KERNEL_RAMEND`.
You can also include your shell's code directly in the kernel by copying
relevant parts of the app's glue unit in your kernel's glue unit. This is often
simpler and more efficient. However, if your shell is a big program, it might
run into zasm's limits. In that case, you'd have to assemble your shell
separately.

View File

@ -5,7 +5,6 @@
; strncmp
;
.inc "user.h"
.inc "err.h"
jp basStart

View File

@ -26,6 +26,8 @@
; ******
.inc "err.h"
.inc "fs.h"
.inc "blkdev.h"
jp edMain
.inc "core.asm"

View File

@ -5,62 +5,6 @@
; *** Code ***
; Parse the hex char at A and extract it's 0-15 numerical value. Put the result
; in A.
;
; On success, the carry flag is reset. On error, it is set.
parseHex:
; First, let's see if we have an easy 0-9 case
add a, 0xc6 ; maps '0'-'9' onto 0xf6-0xff
sub 0xf6 ; maps to 0-9 and carries if not a digit
ret nc
and 0xdf ; converts lowercase to uppercase
add a, 0xe9 ; map 0x11-x017 onto 0xFA - 0xFF
sub 0xfa ; map onto 0-6
ret c
; we have an A-F digit
add a, 10 ; C is clear, map back to 0xA-0xF
ret
; Parses 2 characters of the string pointed to by HL and returns the numerical
; value in A. If the second character is a "special" character (<0x21) we don't
; error out: the result will be the one from the first char only.
; HL is set to point to the last char of the pair.
;
; On success, the carry flag is reset. On error, it is set.
parseHexPair:
push bc
ld a, (hl)
call parseHex
jr c, .end ; error? goto end, keeping the C flag on
rla \ rla \ rla \ rla ; let's push this in MSB
ld b, a
inc hl
ld a, (hl)
cp 0x21
jr c, .single ; special char? single digit
call parseHex
jr c, .end ; error?
or b ; join left-shifted + new. we're done!
; C flag was set on parseHex and is necessarily clear at this point
jr .end
.single:
; If we have a single digit, our result is already stored in B, but
; we have to right-shift it back.
ld a, b
and 0xf0
rra \ rra \ rra \ rra
dec hl
.end:
pop bc
ret
; Parse arguments at (HL) with specifiers at (DE) into (IX).
;
; Args specifiers are a series of flag for each arg:
@ -161,3 +105,4 @@ parseArgs:
pop de
pop bc
ret

View File

@ -1,5 +1,61 @@
; *** Code ***
; Parse the hex char at A and extract it's 0-15 numerical value. Put the result
; in A.
;
; On success, the carry flag is reset. On error, it is set.
parseHex:
; First, let's see if we have an easy 0-9 case
add a, 0xc6 ; maps '0'-'9' onto 0xf6-0xff
sub 0xf6 ; maps to 0-9 and carries if not a digit
ret nc
and 0xdf ; converts lowercase to uppercase
add a, 0xe9 ; map 0x11-x017 onto 0xFA - 0xFF
sub 0xfa ; map onto 0-6
ret c
; we have an A-F digit
add a, 10 ; C is clear, map back to 0xA-0xF
ret
; Parses 2 characters of the string pointed to by HL and returns the numerical
; value in A. If the second character is a "special" character (<0x21) we don't
; error out: the result will be the one from the first char only.
; HL is set to point to the last char of the pair.
;
; On success, the carry flag is reset. On error, it is set.
parseHexPair:
push bc
ld a, (hl)
call parseHex
jr c, .end ; error? goto end, keeping the C flag on
rla \ rla \ rla \ rla ; let's push this in MSB
ld b, a
inc hl
ld a, (hl)
cp 0x21
jr c, .single ; special char? single digit
call parseHex
jr c, .end ; error?
or b ; join left-shifted + new. we're done!
; C flag was set on parseHex and is necessarily clear at this point
jr .end
.single:
; If we have a single digit, our result is already stored in B, but
; we have to right-shift it back.
ld a, b
and 0xf0
rra \ rra \ rra \ rra
dec hl
.end:
pop bc
ret
; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
; result in A.
;

70
apps/lib/stdio.asm Normal file
View File

@ -0,0 +1,70 @@
; *** Requirements ***
; printnstr
;
; *** Variables ***
; Used to store formatted hex values just before printing it.
.equ STDIO_HEX_FMT STDIO_RAMSTART
.equ STDIO_RAMEND @+2
; *** Code ***
; Format the lower nibble of A into a hex char and stores the result in A.
fmtHex:
; The idea here is that there's 7 characters between '9' and 'A'
; in the ASCII table, and so we add 7 if the digit is >9.
; daa is designed for using Binary Coded Decimal format, where each
; nibble represents a single base 10 digit. If a nibble has a value >9,
; it adds 6 to that nibble, carrying to the next nibble and bringing the
; value back between 0-9. This gives us 6 of that 7 we needed to add, so
; then we just condtionally set the carry and add that carry, along with
; a number that maps 0 to '0'. We also need the upper nibble to be a
; set value, and have the N, C and H flags clear.
or 0xf0
daa ; now a =0x50 + the original value + 0x06 if >= 0xfa
add a, 0xa0 ; cause a carry for the values that were >=0x0a
adc a, 0x40
ret
; Formats value in A into a string hex pair. Stores it in the memory location
; that HL points to. Does *not* add a null char at the end.
fmtHexPair:
push af
; let's start with the rightmost char
inc hl
call fmtHex
ld (hl), a
; and now with the leftmost
dec hl
pop af
push af
rra \ rra \ rra \ rra
call fmtHex
ld (hl), a
pop af
ret
; Print the hex char in A
printHex:
push bc
push hl
ld hl, STDIO_HEX_FMT
call fmtHexPair
ld b, 2
call printnstr
pop hl
pop bc
ret
; Print the hex pair in HL
printHexPair:
push af
ld a, h
call printHex
ld a, l
call printHex
pop af
ret

View File

@ -1,16 +1,17 @@
; *** REQUIREMENTS ***
; blockdev
; stdio
; blkSelPtr
; blkSel
; blkSeek
; blkTell
blkBselCmd:
.db "bsel", 0b001, 0, 0
ld a, (hl) ; argument supplied
cp BLOCKDEV_COUNT
jr nc, .error ; if selection >= device count, error
push de
ld de, BLOCKDEV_SEL
call blkSelPtr
call blkSel
pop de
jr nz, .error
xor a
ret
.error:

View File

@ -6,25 +6,16 @@ fsOnCmd:
; Lists filenames in currently active FS
flsCmd:
.db "fls", 0, 0, 0, 0
call fsIsOn
jr nz, .error
call fsBegin
jr nz, .error
.loop:
call fsIsDeleted
jr z, .skip
ld hl, FS_META+FS_META_FNAME_OFFSET
call printstr
call printcrlf
.skip:
call fsNext
jr z, .loop ; Z set? fsNext was successful
xor a
jr .end
.error:
ld iy, .iter
call fsIter
ret z
ld a, FS_ERR_NO_FS
.end:
ret
.iter:
ld a, FS_META_FNAME_OFFSET
call addHL
call printstr
jp printcrlf
; Takes one byte block number to allocate as well we one string arg filename
; and allocates a new file in the current fs.
@ -43,21 +34,16 @@ fnewCmd:
fdelCmd:
.db "fdel", 0b1001, 0b001, 0
push hl
push de
call intoHL ; HL now holds the string we look for
call fsFindFN
jr nz, .notfound
; Found! delete
xor a
; Set filename to zero to flag it as deleted
ld (FS_META+FS_META_FNAME_OFFSET), a
call fsWriteMeta
; a already to 0, our result.
jr .end
call fsDel
jr z, .end
; weird error, continue to error condition
.notfound:
ld a, FS_ERR_NOT_FOUND
.end:
pop de
pop hl
ret
@ -70,16 +56,8 @@ fopnCmd:
push hl
push de
ld a, (hl) ; file handle index
ld de, FS_HANDLES
or a ; cp 0
jr z, .noInc ; DE already point to correct handle
ld b, a
.loop:
ld a, FS_HANDLE_SIZE
call addDE
djnz .loop
.noInc:
; DE now stores pointer to file handle
call fsHandle
; DE now points to file handle
inc hl
call intoHL ; HL now holds the string we look for
call fsFindFN

35
apps/shell/glue.asm Normal file
View File

@ -0,0 +1,35 @@
; This repesents a full-featured shell, that is, a shell that includes all
; options it has to offer. For a minimal shell, use "gluem.asm"
.inc "user.h"
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
jp init
.inc "core.asm"
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.equ SHELL_RAMSTART USER_RAMSTART
.equ SHELL_EXTRA_CMD_COUNT 9
.inc "shell/main.asm"
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.dw fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd
.equ STDIO_RAMSTART SHELL_RAMEND
.inc "lib/stdio.asm"
.inc "shell/blkdev.asm"
.inc "shell/fs.asm"
.equ PGM_RAMSTART STDIO_RAMEND
.equ PGM_CODEADDR USER_CODE
.inc "shell/pgm.asm"
init:
call shellInit
ld hl, pgmShellHook
ld (SHELL_CMDHOOK), hl
jp shellLoop
USER_RAMSTART:

22
apps/shell/gluem.asm Normal file
View File

@ -0,0 +1,22 @@
; This repesents a minimal shell, that is, the smallest shell our configuration
; options allow. For a full-featured shell, see "glue.asm"
.inc "user.h"
.inc "err.h"
.inc "ascii.h"
jp init
.inc "core.asm"
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART USER_RAMSTART
.equ SHELL_EXTRA_CMD_COUNT 0
.inc "shell/main.asm"
init:
call shellInit
jp shellLoop
USER_RAMSTART:

View File

@ -21,8 +21,6 @@
; Routine suitable to plug into SHELL_CMDHOOK. HL points to the full cmdline.
; which has been processed to replace the first ' ' with a null char.
pgmShellHook:
call fsIsOn
jr nz, .noFile
; (HL) is suitable for a direct fsFindFN call
call fsFindFN
jr nz, .noFile
@ -31,17 +29,11 @@ pgmShellHook:
call findchar
inc hl ; beginning of args
; Alright, ready to run!
jp pgmRun
jp .run
.noFile:
ld a, SHELL_ERR_IO_ERROR
ret
; Loads code in file that FS_PTR is currently pointing at and place it in
; PGM_CODEADDR. Then, jump to PGM_CODEADDR. We expect HL to point to unparsed
; arguments being given to the program.
pgmRun:
call fsIsValid
jr nz, .ioError
.run:
push hl ; unparsed args
ld ix, PGM_HANDLE
call fsOpen
@ -57,7 +49,3 @@ pgmRun:
pop hl ; recall args
; ready to jump!
jp PGM_CODEADDR
.ioError:
ld a, SHELL_ERR_IO_ERROR
ret

View File

@ -21,14 +21,11 @@
; strncmp
; upcase
; findchar
; parseHex
; parseHexPair
; blkSel
; blkSet
; fsFindFN
; fsOpen
; fsGetB
; parseArgs
; _blkGetB
; _blkPutB
; _blkSeek
@ -64,17 +61,20 @@
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
jp zasmMain
.inc "core.asm"
.inc "zasm/const.asm"
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "zasm/util.asm"
.equ IO_RAMSTART USER_RAMSTART
.inc "zasm/io.asm"
.equ TOK_RAMSTART IO_RAMEND
.inc "zasm/tok.asm"
.inc "lib/parse.asm"
.equ INS_RAMSTART TOK_RAMEND
.inc "zasm/instr.asm"
.equ DIREC_RAMSTART INS_RAMEND

View File

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

View File

@ -8,67 +8,10 @@ yourself.
This code is designed to be assembled by Collapse OS' own [zasm][zasm].
## Defines
## Scope
Each part can have its own constants, but some constant are made to be defined
externally. We already have some of those external definitions in platform
includes, but we can have more defines than this.
Each part has a "DEFINES" section listing the constant it expects to be defined.
Make sure that you have these constants defined before you include the file.
## Variable management
Each part can define variables. These variables are defined as addresses in
RAM. We know where RAM start from the `RAMSTART` constant in platform includes,
but because those parts are made to be glued together in no pre-defined order,
we need a system to align variables from different modules in RAM.
This is why each part that has variable expect a `<PARTNAME>_RAMSTART`
constant to be defined and, in turn, defines a `<PARTNAME>_RAMEND` constant to
carry to the following part.
Thus, code that glue parts together could look like:
MOD1_RAMSTART .equ RAMSTART
#include "mod1.asm"
MOD2_RAMSTART .equ MOD1_RAMEND
#include "mod2.asm"
## Stack management
Keeping the stack "balanced" is a big challenge when writing assembler code.
Those push and pop need to correspond, otherwise we end up with completely
broken code.
The usual "push/pop" at the beginning and end of a routine is rather easy to
manage, nothing special about them.
The problem is for the "inner" push and pop, which are often necessary in
routines handling more data at once. In those cases, we walk on eggshells.
A naive approach could be to indent the code between those push/pop, but indent
level would quickly become too big to fit in 80 chars.
I've tried ASCII art in some places, where comments next to push/pop have "|"
indicating the scope of the push/pop. It's nice, but it makes code complicated
to edit, especially when dense comments are involved. The pipes have to go
through them.
Of course, one could add descriptions next to each push/pop describing what is
being pushed, and I do it in some places, but it doesn't help much in easily
tracking down stack levels.
So, what I've started doing is to accompany each "non-routine" (at the
beginning and end of a routine) push/pop with "--> lvl X" and "<-- lvl X"
comments. Example:
push af ; --> lvl 1
inc a
push af ; --> lvl 2
inc a
pop af ; <-- lvl 2
pop af ; <-- lvl 1
I think that this should do the trick, so I'll do this consistently from now on.
[zasm]: ../apps/zasm/README.md
Units in the `kernel/` folder is about device driver, abstractions over them
as well as the file system. Although a typical kernel boots to a shell, the
code for that shell is not considered part of the kernel code (even if, most of
the time, it's assembled in the same binary). Shells are considered userspace
applications (which live in `apps/`).

8
kernel/blkdev.h Normal file
View File

@ -0,0 +1,8 @@
.equ BLOCKDEV_SEEK_ABSOLUTE 0
.equ BLOCKDEV_SEEK_FORWARD 1
.equ BLOCKDEV_SEEK_BACKWARD 2
.equ BLOCKDEV_SEEK_BEGINNING 3
.equ BLOCKDEV_SEEK_END 4
.equ BLOCKDEV_SIZE 8

View File

@ -37,13 +37,6 @@
; BLOCKDEV_COUNT: The number of devices we manage.
; *** CONSTS ***
.equ BLOCKDEV_SEEK_ABSOLUTE 0
.equ BLOCKDEV_SEEK_FORWARD 1
.equ BLOCKDEV_SEEK_BACKWARD 2
.equ BLOCKDEV_SEEK_BEGINNING 3
.equ BLOCKDEV_SEEK_END 4
.equ BLOCKDEV_SIZE 8
; *** VARIABLES ***
; Pointer to the selected block device. A block device is a 8 bytes block of
; memory with pointers to GetB, PutB, and a 32-bit counter, in that order.
@ -51,9 +44,17 @@
.equ BLOCKDEV_RAMEND @+BLOCKDEV_SIZE
; *** CODE ***
; Put the pointer to the "regular" blkdev selection in DE
blkSelPtr:
ld de, BLOCKDEV_SEL
; Select block index specified in A and place them in routine pointers at (DE).
; For example, for a "regular" blkSel, you will want to set DE to BLOCKDEV_SEL.
; Sets Z on success, reset on error.
; If A >= BLOCKDEV_COUNT, it's an error.
blkSel:
cp BLOCKDEV_COUNT
jp nc, unsetZ ; if selection >= device count, error
push af
push de
push hl
@ -73,6 +74,7 @@ blkSel:
pop hl
pop de
pop af
cp a ; ensure Z
ret
; Setup blkdev handle in (DE) using routines at (HL).

View File

@ -76,21 +76,7 @@
; *** DEFINES ***
; Number of handles we want to support
; FS_HANDLE_COUNT
; *** CONSTS ***
.equ FS_MAX_NAME_SIZE 0x1a
.equ FS_BLOCKSIZE 0x100
.equ FS_METASIZE 0x20
.equ FS_META_ALLOC_OFFSET 3
.equ FS_META_FSIZE_OFFSET 4
.equ FS_META_FNAME_OFFSET 6
; Size in bytes of a FS handle:
; * 4 bytes for starting offset of the FS block
; * 2 bytes for file size
.equ FS_HANDLE_SIZE 6
.equ FS_ERR_NO_FS 0x5
.equ FS_ERR_NOT_FOUND 0x6
;
; *** VARIABLES ***
; A copy of BLOCKDEV_SEL when the FS was mounted. 0 if no FS is mounted.
.equ FS_BLK FS_RAMSTART
@ -552,3 +538,46 @@ fsIsOn:
pop de
pop hl
ret
; Iterate over files in active file system and, for each file, call (IY) with
; the file's metadata currently placed. HL is set to FS_META.
; Sets Z on success, unset on error.
; There are no error condition happening midway. If you get an error, then (IY)
; was never called.
fsIter:
call fsIsOn
ret nz
call fsBegin
ret nz
.loop:
call fsIsDeleted
ld hl, FS_META
call nz, callIY
call fsNext
jr z, .loop ; Z set? fsNext was successful
or a ; ensure Z
ret
; Delete currently active file
; Sets Z on success, unset on error.
fsDel:
call fsIsValid
ret nz
xor a
; Set filename to zero to flag it as deleted
ld (FS_META+FS_META_FNAME_OFFSET), a
jp fsWriteMeta
; Given a handle index in A, set DE to point to the proper handle.
fsHandle:
ld de, FS_HANDLES
or a ; cp 0
ret z ; DE already point to correct handle
push bc
ld b, a
.loop:
ld a, FS_HANDLE_SIZE
call addDE
djnz .loop
pop bc
ret

13
kernel/fs.h Normal file
View File

@ -0,0 +1,13 @@
.equ FS_MAX_NAME_SIZE 0x1a
.equ FS_BLOCKSIZE 0x100
.equ FS_METASIZE 0x20
.equ FS_META_ALLOC_OFFSET 3
.equ FS_META_FSIZE_OFFSET 4
.equ FS_META_FNAME_OFFSET 6
; Size in bytes of a FS handle:
; * 4 bytes for starting offset of the FS block
; * 2 bytes for file size
.equ FS_HANDLE_SIZE 6
.equ FS_ERR_NO_FS 0x5
.equ FS_ERR_NOT_FOUND 0x6

View File

@ -30,12 +30,9 @@
.equ STDIO_BUFSIZE 0x20
; *** Variables ***
; Used to store formatted hex values just before printing it.
.equ STDIO_HEX_FMT STDIO_RAMSTART
; Line buffer. We read types chars into this buffer until return is pressed
; This buffer is null-terminated.
.equ STDIO_BUF @+2
.equ STDIO_BUF STDIO_RAMSTART
; Index where the next char will go in stdioGetC.
.equ STDIO_RAMEND @+STDIO_BUFSIZE
@ -88,28 +85,6 @@ printcrlf:
pop af
ret
; Print the hex char in A
printHex:
push bc
push hl
ld hl, STDIO_HEX_FMT
call fmtHexPair
ld b, 2
call printnstr
pop hl
pop bc
ret
; Print the hex pair in HL
printHexPair:
push af
ld a, h
call printHex
ld a, l
call printHex
pop af
ret
; Repeatedly calls stdioGetC until a whole line was read, that is, when CR or
; LF is read or if the buffer is full. Sets HL to the beginning of the read
; line, which is null-terminated.

View File

@ -42,45 +42,6 @@ findchar:
ret
; Format the lower nibble of A into a hex char and stores the result in A.
fmtHex:
; The idea here is that there's 7 characters between '9' and 'A'
; in the ASCII table, and so we add 7 if the digit is >9.
; daa is designed for using Binary Coded Decimal format, where each
; nibble represents a single base 10 digit. If a nibble has a value >9,
; it adds 6 to that nibble, carrying to the next nibble and bringing the
; value back between 0-9. This gives us 6 of that 7 we needed to add, so
; then we just condtionally set the carry and add that carry, along with
; a number that maps 0 to '0'. We also need the upper nibble to be a
; set value, and have the N, C and H flags clear.
or 0xf0
daa ; now a =0x50 + the original value + 0x06 if >= 0xfa
add a, 0xa0 ; cause a carry for the values that were >=0x0a
adc a, 0x40
ret
; Formats value in A into a string hex pair. Stores it in the memory location
; that HL points to. Does *not* add a null char at the end.
fmtHexPair:
push af
; let's start with the rightmost char
inc hl
call fmtHex
ld (hl), a
; and now with the leftmost
dec hl
pop af
push af
rra \ rra \ rra \ rra
call fmtHex
ld (hl), a
pop af
ret
; Compares strings pointed to by HL and DE up to A count of characters. If
; equal, Z is set. If not equal, Z is reset.
strncmp:

View File

@ -1,8 +1,9 @@
TARGET = os.bin
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@

View File

@ -13,9 +13,9 @@ jp aciaInt
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
@ -36,14 +36,19 @@ jp aciaInt
.equ AT28W_RAMSTART STDIO_RAMEND
.inc "at28w/main.asm"
; *** Shell ***
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART AT28W_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 5
.inc "shell.asm"
.inc "shell/main.asm"
; Extra cmds
.dw a28wCmd
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.inc "blockdev_cmds.asm"
.inc "shell/blkdev.asm"
init:
di

View File

@ -15,7 +15,6 @@ jp aciaInt
.inc "ascii.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
@ -24,9 +23,14 @@ jp aciaInt
.equ STDIO_PUTC aciaPutC
.inc "stdio.asm"
; *** Shell ***
.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.asm"
.inc "shell/main.asm"
init:
di

View File

@ -4,6 +4,7 @@ AVRDUDEARGS ?= -c usbtiny -P usb
TARGETS = $(PROGNAME).hex os.bin
ZASM = ../../../tools/zasm.sh
KERNEL = ../../../kernel
APPS = ../../../apps
# Rules
@ -19,7 +20,7 @@ $(PROGNAME).hex: $(PROGNAME).asm
avra -o $@ $<
os.bin: glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
clean:
rm -f $(TARGETS) *.eep.hex *.obj os.bin

View File

@ -10,7 +10,6 @@ jp init
.inc "ascii.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
@ -22,9 +21,14 @@ jp init
.equ STDIO_PUTC aciaPutC
.inc "stdio.asm"
; *** Shell ***
.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.asm"
.inc "shell/main.asm"
init:
di

View File

@ -2,6 +2,7 @@ TARGETS = os.bin cfsin/helo
TOOLS = ../../../tools
ZASM = $(TOOLS)/zasm.sh
KERNEL = ../../../kernel
APPS = ../../../apps
CFSPACK = $(TOOLS)/cfspack/cfspack
.PHONY: all
@ -9,7 +10,7 @@ all: $(TARGETS) sdcard.cfs
os.bin: glue.asm
cfsin/helo: helo.asm
$(TARGETS):
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
$(CFSPACK):
make -C $(TOOLS)/cfspack

View File

@ -22,9 +22,10 @@ jp aciaInt
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
.equ BLOCKDEV_RAMSTART ACIA_RAMEND
@ -44,18 +45,23 @@ jp aciaInt
.equ FS_HANDLE_COUNT 1
.inc "fs.asm"
; *** Shell ***
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART FS_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 11
.inc "shell.asm"
.inc "shell/main.asm"
.dw sdcInitializeCmd, sdcFlushCmd
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.dw fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd
.inc "blockdev_cmds.asm"
.inc "fs_cmds.asm"
.inc "shell/blkdev.asm"
.inc "shell/fs.asm"
.equ PGM_RAMSTART SHELL_RAMEND
.inc "pgm.asm"
.inc "shell/pgm.asm"
.equ SDC_RAMSTART PGM_RAMEND
.equ SDC_PORT_CSHIGH 6

View File

@ -10,7 +10,7 @@ CFSPACK = $(TOOLS)/cfspack/cfspack
all: os.bin sdcard.cfs
os.bin: glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
$(CFSPACK):
make -C $(TOOLS)/cfspack

View File

@ -41,9 +41,10 @@ jp aciaInt
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
.equ BLOCKDEV_RAMSTART ACIA_RAMEND
@ -68,18 +69,23 @@ jp aciaInt
.equ FS_HANDLE_COUNT 2
.inc "fs.asm"
; *** Shell ***
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART FS_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 11
.inc "shell.asm"
.inc "shell/main.asm"
.dw sdcInitializeCmd, sdcFlushCmd
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.dw fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd
.inc "fs_cmds.asm"
.inc "blockdev_cmds.asm"
.inc "shell/fs.asm"
.inc "shell/blkdev.asm"
.equ PGM_RAMSTART SHELL_RAMEND
.inc "pgm.asm"
.inc "shell/pgm.asm"
.equ SDC_RAMSTART PGM_RAMEND
.equ SDC_PORT_CSHIGH 6

View File

@ -1,6 +1,4 @@
.org 0x8700
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8
; *** JUMP TABLE ***
.equ strncmp 0x03

View File

@ -1,8 +1,9 @@
TARGET = os.sms
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@

View File

@ -12,7 +12,6 @@
.inc "ascii.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.equ PAD_RAMSTART RAMSTART
.inc "sms/pad.asm"
@ -25,9 +24,14 @@
.equ STDIO_PUTC vdpPutC
.inc "stdio.asm"
; *** Shell ***
.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.asm"
.inc "shell/main.asm"
init:
di

View File

@ -4,6 +4,7 @@ AVRDUDEARGS ?= -c usbtiny -P usb
TARGETS = $(PROGNAME).hex os.sms
ZASM = ../../../tools/zasm.sh
KERNEL = ../../../kernel
APPS = ../../../apps
# Rules
@ -19,7 +20,7 @@ $(PROGNAME).hex: $(PROGNAME).asm
avra -o $@ $<
os.sms: glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
clean:
rm -f $(TARGETS) *.eep.hex *.obj os.bin

View File

@ -12,7 +12,6 @@
.inc "ascii.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "sms/kbd.asm"
.equ KBD_RAMSTART RAMSTART
@ -27,9 +26,14 @@
.equ STDIO_PUTC vdpPutC
.inc "stdio.asm"
; *** Shell ***
.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.asm"
.inc "shell/main.asm"
init:
di

View File

@ -14,7 +14,7 @@ zasm.bin: $(APPS)/zasm/glue.asm
$(ZASM) -o 1d $(KERNEL) $(APPS) user.h < $< > $@
os.sms: glue.asm ed.bin zasm.bin
$(ZASM) $(KERNEL) ed.bin zasm.bin < $< > $@
$(ZASM) $(KERNEL) $(APPS) ed.bin zasm.bin < $< > $@
clean:
rm -f os.sms ed.bin zasm.bin

View File

@ -34,9 +34,10 @@
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "sms/kbd.asm"
.equ KBD_RAMSTART RAMSTART
@ -69,18 +70,23 @@
.equ FS_HANDLE_COUNT 2
.inc "fs.asm"
; *** Shell ***
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
.inc "lib/stdio.asm"
.equ SHELL_RAMSTART FS_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 10
.inc "shell.asm"
.inc "shell/main.asm"
.dw edCmd, zasmCmd, fnewCmd, fdelCmd, fopnCmd, flsCmd, blkBselCmd
.dw blkSeekCmd, blkLoadCmd, blkSaveCmd
.inc "blockdev_cmds.asm"
.inc "fs_cmds.asm"
.inc "shell/blkdev.asm"
.inc "shell/fs.asm"
.equ PGM_RAMSTART SHELL_RAMEND
.equ PGM_CODEADDR USER_RAMSTART
.inc "pgm.asm"
.inc "shell/pgm.asm"
.out PGM_RAMEND

View File

@ -1,6 +1,4 @@
.equ USER_RAMSTART 0xc200
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8
; Make ed fit in SMS's memory
.equ ED_BUF_MAXLINES 0x100
.equ ED_BUF_PADMAXLEN 0x800

View File

@ -1,12 +1,13 @@
TARGET = os.rom
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
MKTIUPGRADE = mktiupgrade
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
truncate -s 1M $@
os.8xu: $(TARGET)

View File

@ -37,10 +37,14 @@
.equ STDIO_PUTC lcdPutC
.inc "stdio.asm"
.inc "parse.asm"
; *** Shell ***
.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.asm"
.inc "shell/main.asm"
boot:
di

2
recipes/ti84/user.h Normal file
View File

@ -0,0 +1,2 @@
; RAMSTART + kernel usage + safety buffer
.equ USER_RAMSTART 0x8040

View File

@ -2,6 +2,7 @@
/zasm/zasm
/runbin/runbin
/*/*-bin.h
/*/*.bin
/cfsin/zasm
/cfsin/ed
/cfsin/basic

View File

@ -10,8 +10,12 @@ CFSIN_CONTENTS = $(SHELLAPPS) cfsin/user.h
.PHONY: all
all: $(TARGETS) $(CFSIN_CONTENTS)
shell/kernel-bin.h: shell/shell_.asm $(ZASMBIN)
$(ZASMSH) $(KERNEL) < $< | ./bin2c.sh KERNEL | tee $@ > /dev/null
# -o in sync with SHELL_CODE in shell/glue.asm
shell/shell.bin: $(APPS)/shell/glue.asm $(ZASMBIN)
$(ZASMSH) -o 07 $(KERNEL) shell/user.h $(APPS) < $< | tee $@ > /dev/null
shell/kernel-bin.h: shell/glue.asm shell/shell.bin $(ZASMBIN)
$(ZASMSH) $(KERNEL) shell/shell.bin < $< | ./bin2c.sh KERNEL | tee $@ > /dev/null
zasm/kernel-bin.h: zasm/kernel.bin
./bin2c.sh KERNEL < $< | tee $@ > /dev/null
@ -32,8 +36,9 @@ libz80/libz80.o: libz80/z80.c
$(CFSPACK):
$(MAKE) -C ../cfspack
# -o in sync with USER_CODE in shell/user.h
$(SHELLAPPS): $(ZASMBIN)
$(ZASMSH) $(KERNEL) $(APPS) shell/user.h < $(APPS)/$(notdir $@)/glue.asm > $@
$(ZASMSH) -o 42 $(KERNEL) $(APPS) shell/user.h < $(APPS)/$(notdir $@)/glue.asm > $@
cfsin/user.h: shell/user.h
cp $< $@

View File

@ -1,4 +1,5 @@
.inc "user.h"
.org USER_CODE
ld hl, sAwesome
call printstr
xor a ; success

View File

@ -1,9 +1,17 @@
; named shell_.asm to avoid infinite include loop.
; Last check:
; Kernel size: 0x619
; Kernel RAM usage: 0x66
; Shell size: 0x411
; Shell RAM usage: 0x11
.inc "blkdev.h"
.inc "fs.h"
.inc "err.h"
.inc "ascii.h"
.equ RAMSTART 0x4000
; kernel ram is well under 0x100 bytes. We're giving us 0x200 bytes so that we
; never worry about the stack.
.equ KERNEL_RAMEND 0x4200
.equ USERCODE KERNEL_RAMEND
; 0x100 - 0x66 gives us a nice space for the stack.
.equ KERNEL_RAMEND 0x4100
.equ SHELL_CODE 0x0700
.equ STDIO_PORT 0x00
.equ FS_DATA_PORT 0x01
.equ FS_ADDR_PORT 0x02
@ -14,30 +22,36 @@
jp strncmp
jp upcase
jp findchar
jp parseHex
jp parseHexPair
jp blkSelPtr
jp blkSel
jp blkSet
jp blkSeek
jp blkTell
jp blkGetB
jp blkPutB
jp fsFindFN
jp fsOpen
jp fsGetB
jp fsPutB
jp fsSetSize
jp parseArgs
jp fsOn
jp fsIter
jp fsAlloc
jp fsDel
jp fsHandle
jp printstr
jp printnstr
jp _blkGetB
jp _blkPutB
jp _blkSeek
jp _blkTell
jp printcrlf
jp stdioGetC
jp stdioPutC
jp stdioReadLine
.inc "core.asm"
.inc "str.asm"
.inc "err.h"
.inc "ascii.h"
.inc "parse.asm"
.equ BLOCKDEV_RAMSTART RAMSTART
.equ BLOCKDEV_COUNT 4
@ -61,35 +75,16 @@
.equ FS_HANDLE_COUNT 2
.inc "fs.asm"
.equ SHELL_RAMSTART FS_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 9
.inc "shell.asm"
.dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.dw fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd
.inc "blockdev_cmds.asm"
.inc "fs_cmds.asm"
.equ PGM_RAMSTART SHELL_RAMEND
.equ PGM_CODEADDR USERCODE
.inc "pgm.asm"
;.out PGM_RAMEND
init:
di
; setup stack
ld hl, KERNEL_RAMEND
ld sp, hl
ld sp, KERNEL_RAMEND
call fsInit
ld a, 0 ; select fsdev
ld de, BLOCKDEV_SEL
call blkSel
call fsOn
call shellInit
ld hl, pgmShellHook
ld (SHELL_CMDHOOK), hl
jp shellLoop
call SHELL_CODE
emulGetC:
; Blocks until a char is returned
@ -154,3 +149,5 @@ stdinPutB:
ld ix, STDIN_HANDLE
jp fsPutB
.fill SHELL_CODE-$
.bin "shell.bin"

View File

@ -1,26 +1,35 @@
.org 0x4200 ; in sync with USERCODE in shell/shell_.asm
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8
.equ SHELL_RAMSTART 0x4100
.equ USER_CODE 0x4200
; *** JUMP TABLE ***
.equ strncmp 0x03
.equ upcase @+3
.equ findchar @+3
.equ parseHex @+3
.equ parseHexPair @+3
.equ blkSelPtr @+3
.equ blkSel @+3
.equ blkSet @+3
.equ blkSeek @+3
.equ blkTell @+3
.equ blkGetB @+3
.equ blkPutB @+3
.equ fsFindFN @+3
.equ fsOpen @+3
.equ fsGetB @+3
.equ fsPutB @+3
.equ fsSetSize @+3
.equ parseArgs @+3
.equ fsOn @+3
.equ fsIter @+3
.equ fsAlloc @+3
.equ fsDel @+3
.equ fsHandle @+3
.equ printstr @+3
.equ printnstr @+3
.equ _blkGetB @+3
.equ _blkPutB @+3
.equ _blkSeek @+3
.equ _blkTell @+3
.equ printcrlf @+3
.equ stdioGetC @+3
.equ stdioPutC @+3
.equ stdioReadLine @+3

View File

@ -6,20 +6,21 @@
.equ FS_DATA_PORT 0x02
.equ FS_SEEK_PORT 0x03
.equ STDERR_PORT 0x04
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
jp init ; 3 bytes
; *** JUMP TABLE ***
jp strncmp
jp upcase
jp findchar
jp parseHex
jp parseHexPair
jp blkSel
jp blkSet
jp fsFindFN
jp fsOpen
jp fsGetB
jp parseArgs
jp _blkGetB
jp _blkPutB
jp _blkSeek
@ -28,9 +29,6 @@ jp printstr
.inc "core.asm"
.inc "str.asm"
.inc "err.h"
.inc "ascii.h"
.inc "parse.asm"
.equ BLOCKDEV_RAMSTART RAMSTART
.equ BLOCKDEV_COUNT 3
.inc "blockdev.asm"

Binary file not shown.

View File

@ -7,14 +7,11 @@
.equ strncmp 0x03
.equ upcase @+3
.equ findchar @+3
.equ parseHex @+3
.equ parseHexPair @+3
.equ blkSel @+3
.equ blkSet @+3
.equ fsFindFN @+3
.equ fsOpen @+3
.equ fsGetB @+3
.equ parseArgs @+3
.equ _blkGetB @+3
.equ _blkPutB @+3
.equ _blkSeek @+3

Binary file not shown.

View File

@ -11,7 +11,6 @@ jp test
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "lib/util.asm"
.inc "zasm/util.asm"
.inc "zasm/const.asm"

View File

@ -1,7 +1,9 @@
jp test
.inc "core.asm"
.inc "parse.asm"
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "lib/args.asm"
zasmGetPC:
ret

View File

@ -6,7 +6,6 @@ jp test
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "lib/util.asm"
.inc "zasm/util.asm"
.inc "lib/parse.asm"

View File

@ -2,7 +2,6 @@ jp test
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "zasm/util.asm"
testNum: .db 1

View File

@ -3,7 +3,6 @@ jp runTests
.inc "err.h"
.inc "core.asm"
.inc "str.asm"
.inc "parse.asm"
.inc "zasm/const.asm"
.inc "lib/util.asm"
.inc "zasm/util.asm"