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:
parent
cdd0b64570
commit
019d05f64c
71
CODE.md
Normal file
71
CODE.md
Normal 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
|
@ -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.
|
||||
|
@ -5,7 +5,6 @@
|
||||
; strncmp
|
||||
;
|
||||
.inc "user.h"
|
||||
|
||||
.inc "err.h"
|
||||
|
||||
jp basStart
|
||||
|
@ -26,6 +26,8 @@
|
||||
; ******
|
||||
|
||||
.inc "err.h"
|
||||
.inc "fs.h"
|
||||
.inc "blkdev.h"
|
||||
jp edMain
|
||||
|
||||
.inc "core.asm"
|
||||
|
@ -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
|
||||
|
@ -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
70
apps/lib/stdio.asm
Normal 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
|
||||
|
||||
|
@ -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:
|
@ -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
35
apps/shell/glue.asm
Normal 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
22
apps/shell/gluem.asm
Normal 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:
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
8
kernel/blkdev.h
Normal 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
|
||||
|
@ -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).
|
||||
|
@ -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
13
kernel/fs.h
Normal 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
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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) < $< > $@
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,4 @@
|
||||
.org 0x8700
|
||||
.equ FS_HANDLE_SIZE 8
|
||||
.equ BLOCKDEV_SIZE 8
|
||||
|
||||
; *** JUMP TABLE ***
|
||||
.equ strncmp 0x03
|
||||
|
@ -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) < $< > $@
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
2
recipes/ti84/user.h
Normal file
@ -0,0 +1,2 @@
|
||||
; RAMSTART + kernel usage + safety buffer
|
||||
.equ USER_RAMSTART 0x8040
|
1
tools/emul/.gitignore
vendored
1
tools/emul/.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
/zasm/zasm
|
||||
/runbin/runbin
|
||||
/*/*-bin.h
|
||||
/*/*.bin
|
||||
/cfsin/zasm
|
||||
/cfsin/ed
|
||||
/cfsin/basic
|
||||
|
@ -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 $< $@
|
||||
|
@ -1,4 +1,5 @@
|
||||
.inc "user.h"
|
||||
.org USER_CODE
|
||||
ld hl, sAwesome
|
||||
call printstr
|
||||
xor a ; success
|
||||
|
@ -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"
|
@ -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
|
||||
|
||||
|
@ -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.
@ -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.
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -2,7 +2,6 @@ jp test
|
||||
|
||||
.inc "core.asm"
|
||||
.inc "str.asm"
|
||||
.inc "parse.asm"
|
||||
.inc "zasm/util.asm"
|
||||
|
||||
testNum: .db 1
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user