From 019d05f64c34dce9190b1aa3a624d614307bce3e Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Fri, 15 Nov 2019 15:37:49 -0500 Subject: [PATCH] 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. --- CODE.md | 71 ++++++++++++++++++++++ apps/README.md | 23 +++++++ apps/basic/glue.asm | 1 - apps/ed/glue.asm | 2 + kernel/parse.asm => apps/lib/args.asm | 57 +---------------- apps/lib/parse.asm | 56 +++++++++++++++++ apps/lib/stdio.asm | 70 +++++++++++++++++++++ doc/shell.md => apps/shell/README.md | 0 kernel/blockdev_cmds.asm => apps/shell/blkdev.asm | 11 ++-- kernel/fs_cmds.asm => apps/shell/fs.asm | 48 ++++----------- apps/shell/glue.asm | 35 +++++++++++ apps/shell/gluem.asm | 22 +++++++ kernel/shell.asm => apps/shell/main.asm | 0 {kernel => apps/shell}/pgm.asm | 16 +---- apps/zasm/glue.asm | 8 +-- doc/README.md | 2 +- kernel/README.md | 69 ++------------------- kernel/blkdev.h | 8 +++ kernel/blockdev.asm | 16 ++--- kernel/fs.asm | 59 +++++++++++++----- kernel/fs.h | 13 ++++ kernel/stdio.asm | 27 +------- kernel/str.asm | 39 ------------ recipes/rc2014/Makefile | 3 +- recipes/rc2014/eeprom/glue.asm | 11 +++- recipes/rc2014/glue.asm | 8 ++- recipes/rc2014/ps2/Makefile | 3 +- recipes/rc2014/ps2/glue.asm | 8 ++- recipes/rc2014/sdcard/Makefile | 3 +- recipes/rc2014/sdcard/glue.asm | 16 +++-- recipes/rc2014/zasm/Makefile | 2 +- recipes/rc2014/zasm/glue.asm | 16 +++-- recipes/rc2014/zasm/user.h | 2 - recipes/sms/Makefile | 3 +- recipes/sms/glue.asm | 8 ++- recipes/sms/kbd/Makefile | 3 +- recipes/sms/kbd/glue.asm | 8 ++- recipes/sms/romasm/Makefile | 2 +- recipes/sms/romasm/glue.asm | 16 +++-- recipes/sms/romasm/user.h | 2 - recipes/ti84/Makefile | 3 +- recipes/ti84/glue.asm | 8 ++- recipes/ti84/user.h | 2 + tools/emul/.gitignore | 1 + tools/emul/Makefile | 11 +++- tools/emul/cfsin/hello.asm | 1 + tools/emul/shell/{shell_.asm => glue.asm} | 61 +++++++++---------- tools/emul/shell/user.h | 21 +++++-- tools/emul/zasm/glue.asm | 10 ++- tools/emul/zasm/kernel.bin | Bin 1512 -> 1368 bytes tools/emul/zasm/user.h | 3 - tools/emul/zasm/zasm.bin | Bin 4733 -> 4874 bytes tools/tests/unit/test_expr.asm | 1 - tools/tests/unit/test_parse.asm | 4 +- tools/tests/unit/test_parse_z.asm | 1 - tools/tests/unit/test_util_z.asm | 1 - tools/tests/unit/test_z_instr.asm | 1 - 57 files changed, 535 insertions(+), 361 deletions(-) create mode 100644 CODE.md rename kernel/parse.asm => apps/lib/args.asm (66%) create mode 100644 apps/lib/stdio.asm rename doc/shell.md => apps/shell/README.md (100%) rename kernel/blockdev_cmds.asm => apps/shell/blkdev.asm (94%) rename kernel/fs_cmds.asm => apps/shell/fs.asm (66%) create mode 100644 apps/shell/glue.asm create mode 100644 apps/shell/gluem.asm rename kernel/shell.asm => apps/shell/main.asm (100%) rename {kernel => apps/shell}/pgm.asm (81%) create mode 100644 kernel/blkdev.h create mode 100644 kernel/fs.h create mode 100644 recipes/ti84/user.h rename tools/emul/shell/{shell_.asm => glue.asm} (71%) diff --git a/CODE.md b/CODE.md new file mode 100644 index 0000000..950d80a --- /dev/null +++ b/CODE.md @@ -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 `_RAMSTART` +constant to be defined and, in turn, defines a `_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 diff --git a/apps/README.md b/apps/README.md index 5f62c10..e7d9382 100644 --- a/apps/README.md +++ b/apps/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. diff --git a/apps/basic/glue.asm b/apps/basic/glue.asm index c418393..aa180c3 100644 --- a/apps/basic/glue.asm +++ b/apps/basic/glue.asm @@ -5,7 +5,6 @@ ; strncmp ; .inc "user.h" - .inc "err.h" jp basStart diff --git a/apps/ed/glue.asm b/apps/ed/glue.asm index 847802d..03760f0 100644 --- a/apps/ed/glue.asm +++ b/apps/ed/glue.asm @@ -26,6 +26,8 @@ ; ****** .inc "err.h" +.inc "fs.h" +.inc "blkdev.h" jp edMain .inc "core.asm" diff --git a/kernel/parse.asm b/apps/lib/args.asm similarity index 66% rename from kernel/parse.asm rename to apps/lib/args.asm index 8f7397b..86bcbe7 100644 --- a/kernel/parse.asm +++ b/apps/lib/args.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 + diff --git a/apps/lib/parse.asm b/apps/lib/parse.asm index 7907faa..683f3ba 100644 --- a/apps/lib/parse.asm +++ b/apps/lib/parse.asm @@ -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. ; diff --git a/apps/lib/stdio.asm b/apps/lib/stdio.asm new file mode 100644 index 0000000..5423212 --- /dev/null +++ b/apps/lib/stdio.asm @@ -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 + + diff --git a/doc/shell.md b/apps/shell/README.md similarity index 100% rename from doc/shell.md rename to apps/shell/README.md diff --git a/kernel/blockdev_cmds.asm b/apps/shell/blkdev.asm similarity index 94% rename from kernel/blockdev_cmds.asm rename to apps/shell/blkdev.asm index 534f3f2..acb0700 100644 --- a/kernel/blockdev_cmds.asm +++ b/apps/shell/blkdev.asm @@ -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: diff --git a/kernel/fs_cmds.asm b/apps/shell/fs.asm similarity index 66% rename from kernel/fs_cmds.asm rename to apps/shell/fs.asm index 7cf63a8..c47a734 100644 --- a/kernel/fs_cmds.asm +++ b/apps/shell/fs.asm @@ -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 diff --git a/apps/shell/glue.asm b/apps/shell/glue.asm new file mode 100644 index 0000000..4fe7e20 --- /dev/null +++ b/apps/shell/glue.asm @@ -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: diff --git a/apps/shell/gluem.asm b/apps/shell/gluem.asm new file mode 100644 index 0000000..11f1df1 --- /dev/null +++ b/apps/shell/gluem.asm @@ -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: + diff --git a/kernel/shell.asm b/apps/shell/main.asm similarity index 100% rename from kernel/shell.asm rename to apps/shell/main.asm diff --git a/kernel/pgm.asm b/apps/shell/pgm.asm similarity index 81% rename from kernel/pgm.asm rename to apps/shell/pgm.asm index da50bd1..bc3bfe3 100644 --- a/kernel/pgm.asm +++ b/apps/shell/pgm.asm @@ -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 diff --git a/apps/zasm/glue.asm b/apps/zasm/glue.asm index e067ea8..4dcd46c 100644 --- a/apps/zasm/glue.asm +++ b/apps/zasm/glue.asm @@ -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 diff --git a/doc/README.md b/doc/README.md index 67c33ee..9bbd03f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -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) diff --git a/kernel/README.md b/kernel/README.md index d32f474..797ea25 100644 --- a/kernel/README.md +++ b/kernel/README.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 `_RAMSTART` -constant to be defined and, in turn, defines a `_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/`). diff --git a/kernel/blkdev.h b/kernel/blkdev.h new file mode 100644 index 0000000..dc62062 --- /dev/null +++ b/kernel/blkdev.h @@ -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 + diff --git a/kernel/blockdev.asm b/kernel/blockdev.asm index ec98ae8..b62cf12 100644 --- a/kernel/blockdev.asm +++ b/kernel/blockdev.asm @@ -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). diff --git a/kernel/fs.asm b/kernel/fs.asm index 030ab55..aba1fad 100644 --- a/kernel/fs.asm +++ b/kernel/fs.asm @@ -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 diff --git a/kernel/fs.h b/kernel/fs.h new file mode 100644 index 0000000..68df440 --- /dev/null +++ b/kernel/fs.h @@ -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 diff --git a/kernel/stdio.asm b/kernel/stdio.asm index a352b75..c8d55fb 100644 --- a/kernel/stdio.asm +++ b/kernel/stdio.asm @@ -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. diff --git a/kernel/str.asm b/kernel/str.asm index f943b82..968497f 100644 --- a/kernel/str.asm +++ b/kernel/str.asm @@ -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: diff --git a/recipes/rc2014/Makefile b/recipes/rc2014/Makefile index c9a9feb..0c9ad10 100644 --- a/recipes/rc2014/Makefile +++ b/recipes/rc2014/Makefile @@ -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) < $< > $@ diff --git a/recipes/rc2014/eeprom/glue.asm b/recipes/rc2014/eeprom/glue.asm index cab4ffb..628d3a4 100644 --- a/recipes/rc2014/eeprom/glue.asm +++ b/recipes/rc2014/eeprom/glue.asm @@ -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 diff --git a/recipes/rc2014/glue.asm b/recipes/rc2014/glue.asm index d011768..f1735ae 100644 --- a/recipes/rc2014/glue.asm +++ b/recipes/rc2014/glue.asm @@ -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 diff --git a/recipes/rc2014/ps2/Makefile b/recipes/rc2014/ps2/Makefile index 1106e67..983db19 100644 --- a/recipes/rc2014/ps2/Makefile +++ b/recipes/rc2014/ps2/Makefile @@ -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 diff --git a/recipes/rc2014/ps2/glue.asm b/recipes/rc2014/ps2/glue.asm index 926c43b..f4da6fe 100644 --- a/recipes/rc2014/ps2/glue.asm +++ b/recipes/rc2014/ps2/glue.asm @@ -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 diff --git a/recipes/rc2014/sdcard/Makefile b/recipes/rc2014/sdcard/Makefile index 00db76c..61c963b 100644 --- a/recipes/rc2014/sdcard/Makefile +++ b/recipes/rc2014/sdcard/Makefile @@ -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 diff --git a/recipes/rc2014/sdcard/glue.asm b/recipes/rc2014/sdcard/glue.asm index 65041ff..da117d4 100644 --- a/recipes/rc2014/sdcard/glue.asm +++ b/recipes/rc2014/sdcard/glue.asm @@ -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 diff --git a/recipes/rc2014/zasm/Makefile b/recipes/rc2014/zasm/Makefile index f5f1942..cd29d6d 100644 --- a/recipes/rc2014/zasm/Makefile +++ b/recipes/rc2014/zasm/Makefile @@ -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 diff --git a/recipes/rc2014/zasm/glue.asm b/recipes/rc2014/zasm/glue.asm index 60941de..cdc33a0 100644 --- a/recipes/rc2014/zasm/glue.asm +++ b/recipes/rc2014/zasm/glue.asm @@ -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 diff --git a/recipes/rc2014/zasm/user.h b/recipes/rc2014/zasm/user.h index da80eed..0ef18f9 100644 --- a/recipes/rc2014/zasm/user.h +++ b/recipes/rc2014/zasm/user.h @@ -1,6 +1,4 @@ .org 0x8700 -.equ FS_HANDLE_SIZE 8 -.equ BLOCKDEV_SIZE 8 ; *** JUMP TABLE *** .equ strncmp 0x03 diff --git a/recipes/sms/Makefile b/recipes/sms/Makefile index 9a6e9e4..6e7bbe1 100644 --- a/recipes/sms/Makefile +++ b/recipes/sms/Makefile @@ -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) < $< > $@ diff --git a/recipes/sms/glue.asm b/recipes/sms/glue.asm index d15f13a..65fa766 100644 --- a/recipes/sms/glue.asm +++ b/recipes/sms/glue.asm @@ -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 diff --git a/recipes/sms/kbd/Makefile b/recipes/sms/kbd/Makefile index 831e37f..64a8b63 100644 --- a/recipes/sms/kbd/Makefile +++ b/recipes/sms/kbd/Makefile @@ -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 diff --git a/recipes/sms/kbd/glue.asm b/recipes/sms/kbd/glue.asm index 73ba6fe..ad283b3 100644 --- a/recipes/sms/kbd/glue.asm +++ b/recipes/sms/kbd/glue.asm @@ -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 diff --git a/recipes/sms/romasm/Makefile b/recipes/sms/romasm/Makefile index b1e46df..606a85a 100644 --- a/recipes/sms/romasm/Makefile +++ b/recipes/sms/romasm/Makefile @@ -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 diff --git a/recipes/sms/romasm/glue.asm b/recipes/sms/romasm/glue.asm index ef2178c..c0e45a2 100644 --- a/recipes/sms/romasm/glue.asm +++ b/recipes/sms/romasm/glue.asm @@ -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 diff --git a/recipes/sms/romasm/user.h b/recipes/sms/romasm/user.h index 83d4a46..1883e0f 100644 --- a/recipes/sms/romasm/user.h +++ b/recipes/sms/romasm/user.h @@ -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 diff --git a/recipes/ti84/Makefile b/recipes/ti84/Makefile index b1338a0..f98b262 100644 --- a/recipes/ti84/Makefile +++ b/recipes/ti84/Makefile @@ -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) diff --git a/recipes/ti84/glue.asm b/recipes/ti84/glue.asm index 54af26b..2f91c1d 100644 --- a/recipes/ti84/glue.asm +++ b/recipes/ti84/glue.asm @@ -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 diff --git a/recipes/ti84/user.h b/recipes/ti84/user.h new file mode 100644 index 0000000..d48c053 --- /dev/null +++ b/recipes/ti84/user.h @@ -0,0 +1,2 @@ +; RAMSTART + kernel usage + safety buffer +.equ USER_RAMSTART 0x8040 diff --git a/tools/emul/.gitignore b/tools/emul/.gitignore index d4bb0a3..63baf15 100644 --- a/tools/emul/.gitignore +++ b/tools/emul/.gitignore @@ -2,6 +2,7 @@ /zasm/zasm /runbin/runbin /*/*-bin.h +/*/*.bin /cfsin/zasm /cfsin/ed /cfsin/basic diff --git a/tools/emul/Makefile b/tools/emul/Makefile index affef32..e5c3b33 100644 --- a/tools/emul/Makefile +++ b/tools/emul/Makefile @@ -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 $< $@ diff --git a/tools/emul/cfsin/hello.asm b/tools/emul/cfsin/hello.asm index e9a99d0..b225fb7 100644 --- a/tools/emul/cfsin/hello.asm +++ b/tools/emul/cfsin/hello.asm @@ -1,4 +1,5 @@ .inc "user.h" +.org USER_CODE ld hl, sAwesome call printstr xor a ; success diff --git a/tools/emul/shell/shell_.asm b/tools/emul/shell/glue.asm similarity index 71% rename from tools/emul/shell/shell_.asm rename to tools/emul/shell/glue.asm index 84da006..c74df59 100644 --- a/tools/emul/shell/shell_.asm +++ b/tools/emul/shell/glue.asm @@ -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" diff --git a/tools/emul/shell/user.h b/tools/emul/shell/user.h index 4bba572..2fb0145 100644 --- a/tools/emul/shell/user.h +++ b/tools/emul/shell/user.h @@ -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 + diff --git a/tools/emul/zasm/glue.asm b/tools/emul/zasm/glue.asm index f436838..d7eeb0c 100644 --- a/tools/emul/zasm/glue.asm +++ b/tools/emul/zasm/glue.asm @@ -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" diff --git a/tools/emul/zasm/kernel.bin b/tools/emul/zasm/kernel.bin index 760660fa17e7240625cdbf9b8d62c81868534084..82dbbf709266298a523cb7021d6e6a7e06ebaac5 100644 GIT binary patch literal 1368 zcmY*ZUuYaf82@Hx_i{;XdzVzb1hu;^=y0hfIZ~qguq+CVh|*%^D2OROSVTfe|9NVY z7!d5MNPYE55Pdm)s7HP1-MJoi9!9zzE7C9zOIe|$C!Fm?0=nlndl#)N%zpFzzM1*H z-}jsGJGy@v{4c?OAN(uehv1i~{}c6J*8Oqf7m2??e4_cL*86al95~tK;X`n8GT`Bo zUET`#mUtGnxQuV%|CWq+T49&g%_1Z}2bvg*wme zVs2j^*5x$}IBf8$tmv|0$Vx_5MmR$EPlve?O_jBz%d#;zhd*pA!!kT+%ov{G&w)Q} z^y2jz%ZO>iE^H%Ft$1D8xgG3C&)ti*JB9-SR@TcL6myX5WfRF5+n;>E#*-}DhbU6= zTeX4#P5y3jklmct-K<(^szF(WAD=&R9I6)cGKa(&;No+=5r@6bYqMUlleo&X z!tZ$8d!+?0$~zvJ!i9Kt(Bz>CA9ttFD=q`e;yQL0a|%#hF2$7cmox-|h&zs#Kq?kC z)Sqe&+Nq|7_E3MRKNZx_pDJi*r_GFe&LK}$zMRUkkB9A21W88HI71PR7;NM-_i1~dbR8L zJY+;sJrDe@)$i}P8onUn3WycmfqvoPgCfS!mq?)R8Rw~f9oGVl-J{B=eE literal 1512 zcmY*Z|7#pY6rb6hy<8GwFS(+d_@%op*zqDZP12H_VOd%*wg>@>F-1ryh4_;N+nm=g zx%flzcl`r|{9q~h>H3q`rqH`%x!56$=5kytje{&@10kg3tQU#so^Li6t$W<;oA-Hd z=FMk5Z{3XM-bF4)?oH&bA=gLlMeJs<+fCeWh#S+~R_rcfcNM!-aTgT#p;EuuhYwHH zSoI||)m>)QNo#zo%(nO`w8ez~1l~`C$Nb#(haTIyVqNZ)Za#+i=Lq~_^Y6`EA;7HU zr>)puUXhi??8fNaJ=&h5sukPiDWns-@pZn)c6W|0&Hw1Iy2Zam>E2rX2t3lPL3VYt z=Yi20AgWpM*zfr=tQ1^$6x>)@GuYD7+V0B6uS=V2e?D4jW2HI1hK62w8JE}jYV3CsB<|w(6c;BhsTzuXjG(-n8Es6+($!4Au28` zYx#`P3Q-+_VH~z%KY`h%xA){IS^k)+SsjlE&np*Mz3Q9aD*%>8ZNlG0vArVCV6R-0 zh!1q}DHM-;mUUoeyW-(bh7{_)jZKU=RlFMTC`{z=MJx%f@&$!Yqq3(zZu(cHU-%&+ zEMbMH@btwd{#%$=f_y^*^8d&eWq7z`ha#5*qE@j%{trk-qjFJ04${(pIQ`x^lrLhPx_t2pkpI`jnv8>pI6-h zQu33-PL94l3O9=|ARzjA)rj%|VyJn&l`pG2t3n^h=I|qidD7t@5wBR#4;@TD3#SOg zp_qnT9L`(^37cot&XW#S(e|CJIqXDUgIYj?aJcFipHPiAeLkZa9sD#gcA-Uq!YeN%J$HH-3T4f&}5^ zWf}j4P?D9Q5XaAuJamP$00iiv}3rzLTt|CVOXYaG4* zMW1opn3zDb6`ZNyb(Ev~2dSVutB^dqQBh|rYNn#DtGU8DVD;xchE}V9uLj5Y2XC^) A^Z)<= diff --git a/tools/emul/zasm/user.h b/tools/emul/zasm/user.h index 318ba72..8c80238 100644 --- a/tools/emul/zasm/user.h +++ b/tools/emul/zasm/user.h @@ -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 diff --git a/tools/emul/zasm/zasm.bin b/tools/emul/zasm/zasm.bin index c312b97443525980f80a6a992e0a29d4ae1a43c6..3298a4247f118c4c97d3afd6b7b79ebd845cafeb 100644 GIT binary patch delta 2393 zcmY*beQaCR6@PxVUmSnMFCop#SACyfnp~U`4Yw38fZKIyYx^Z}8${%KmgeU$;984;|W|xtIS*!5?kG)DX%G$6M5F#%- z_cg0FOL_O)bAIP{?#H?3WV7dIy=>*}Irc>4(xvx5f9Lu~mp*;}tE-pX+H!#?@n~lo z{EkQkQ;fRk-1C~?n!0`~2*3U%Rka_=F4qj*DC(1pK55e@ST~Y{I?dhw*41pjvcET1lWrK>19B?vVn20nsgZI!f5FlE(I;V0&1v*H@S3PKMa= z#N2ZU_T|Lf+Yhp*5^96({@4+jG%=N8axkQn(8I(?;$6Dfp^#1n`Am1&2xCPGVWqB- zv0RL)MkFPImB_t{E;0a8^R`{HsT}rg=!P!36ta`i>)OVm7VcFjmmStO~Z zrKFKrStiX)Sr?lX(#phautZ9Sm7=u~ky+HJ9oDy-0>EZT0)sg6L{btq>WkWKSTE1e zAlR|~7*;kkN>>q>1M;D`LHZamEyK62xqXcJP_YZ!SraFG0WkG61P%t1~iupDy|dpz(NQ4>JZI*j(kMuaHG_=m|) zhfp&lJ>eKhGPB6xpB7mE6kycTjv$xHRVxQG>MtC@-p!-CZqKx}0nf(Ts?EU&UXed0 z*v0l^8#WiSy#6wF{{8f@`ko^+Ix$o^6gR!t3#{bHA=qhPK`WReQlZ~;McI@jC7TTr1?u+kvhHwXP z0Sz@ArUv&QOhC^H2P9xBV98718SbeW>gHd1)a;Mi zdHp-n|fk8yBI9p)Cg6>An6h&rz|bh5S^s?qod)-$61+$q4Y?%XBxih70-BX5k^ z#vd3zKmMEX_r^EJg|tDJ+6ym-%qQ@DqdR1ggVZ{9+8XOR8zhnTp#*G__qa? zC>U@-z*!jo%r;WSA1&6km{Z_lEdm>BhL>qoJN$@ITc&X^e?hSwVAfxwlg@3PHt~X@ z8>{P&78LST28!C(jKqv)$6PJr{q`ZvQgUsub0FVrajte zI-*UcGs+4bv=6mPX~AW+H;(|0vpUcT$2_B5rw|4F(^a`5;2bhVhwY6}1;S37?Ao!y#U3?=$=CiuEcxQMkQ<=}k1{O5h>A=Kgq0>Pz6oB){2)^VdnmCPc3^Mq}4oE1O;eBdJT;;9F6 zy4am3e~sftT5K66#%hDzc^*2iml@od=b_<(5X?tH`N*tNjEMP2L5b|l6Ei`yj2O)k zS%!uP9H(^P>po<0dqV^xbh}shX delta 2221 zcmZ8ieQaA-6@Pw?UmSnMFKN=(q>k_NYmz&ssWvYnR#x7+KiWP&+fCLk{s>)p6_m2C ztZFMKt}=Uw4Ym1Mq3tY4?S!$)esvh+QiXs{yR6_KY z^W3aL{B!TQ=lss^oO3_UePiJ6KDP42+w3X*5u3=qs_0MIV(iC?{=RLLeOJ-1+8&W} zD(PY>H)3NUt%MGeT`KN3#U739W004+%8fAAq!8BX2B~IcrW%p72-YGGX{N{kNI%N< z7gw^_yJa>^(W#L^#;hA#OGbD=v$*Ww9tvxOQA2*s2!pgsMUK#bCfI>A?AL@2aw8^q zMTQCO(?Abk128g!TCE6`Fk@u{6DU`_YEw6SUpLH*Nm|Ju#Y-v?n6fE$Xrz~sZIGfx zhqZ-fAz^08ug8Y<>l6TZTnf>0@404=WAw zFe83Pg|Tk9ybOJ;TB=fSmAb0*q(M~uS$nW}C`MGJEZkWoC6&Cc;($1!agWmw9-xDG zWJV$Y_<@RjbU$|aZ$f57LbA zYaplltM|Q)`;_GpK0xMAs(3ej470*U(?T8T z)Kx-)lN5Gx_XHPb6F80)Sk6BF_V*7XdaO#52A!_b7YzD*mCjaa z-dL@1vaf}IXM))DS6c>0W|UHOwFVo_Fnn#ilN03@@~(p8vV+(a|KG`q0s&r2pfAbC zgeb@OlH@;e{boxS`&vT3(-P!XvenAvw7%C795^@8zdg5mH~4LBtlL@`!6UvhA=t(F zi7lIxS>5~*c6@3k^wW;e@aOT$VTF3Ihj0wJ8i$(wi$;MSlL|xB8D&exlF_(!wsEac zCqGQ+A36l@tpsWlXEd|Gl3NMA=2&yxieqPU8P|Wt1$y3!2@d%#+z#{i_G#=fr(4W# zILKM0(yQO(g5sMA?6uHuCeRS@Kw1|ysjzJp?4PwC-6EQzqt?JtNaYl{5yzpiiyHYn zj(flb&{m2^EWK+C7NBQ^LlVR(V97(^DLqZC&%8Y0gq`YWydK6%{h!Tu-2 zOIiW4(o3xeY<>D?tx~eAq8=Xj)8ps}>5C&T94#8-ff+O-d4B#$%13$r)NvY!x_HkC zIuy0@6Hn#ILrLtDIoRJGdJo-}JA_uk{W9h3Wo=LE=UqQ#3rW4#eWW#!?9DSMp?}l; zZT3b|-*g{GKTZbn)7CiaM!x~MIl5=jS~B3y!>E7NGiN)aU-x9$t)xEc4cSiXQ{IWl z@Z`nG4<>Ivu zwgtjk2jdGC!7f+_xpyb5MKkwF_@z(6{}Zkm40)h*)JpcKh}#L#1*tSc?3fPzpQ%6( zlpCuxiF5kwyknBsV(ZIwqxM}sFbQW#_9(Rxv%YTrmAKR8My;EXBr>B=d$gCfMBAw& z$_hQCor!iyX~9__9wzFR(xA{^Z}0WS)8*9%KKe)PP$`M($(~SA(!i#=78()D#i9wJxMYmSUOY|Y+` z9Jc1ZOyyhY2Kh^xv@yuBFe7a&)s5`}v^&>=w21YhzpZ#VUEY9GgT_Gqoi3YupnF+! zqrNfv_~vm4@`YlV?1?p(WvzVn-r}>1&!OP+!3+0HaX3Q;vZffhKaFN816ldNqG5em zV9ICU%d%v!KafXv=#Bp*Zqj&OS?2Mw1^U=X4Gk7mJ0q{zuj@z14S2Bpd zd&+h<#R{MRK5+R3FBU(5=z$y&8Qf;|Muw4DV=R#4;S23x#`JbCFOkQq&eA zVlGn9B7HeB93uxa;?J|>k_tZ?aF|)NOZ=6!UVvpY{y-MAm8Vsk&2i+J^A|3nbEhv{ zU{0L*+Kba)Z_4_yjzIBRjNHkVXDNk-vkjj)a**eygbmoeGx1q!TjQrFyVf;D?buIg zRpz0o<}2sM^OfJGtcwhftCK*@gUv$WdUui&Q^KBRm7s2txpz8OK7-f=qj{4TVqy5# cgE<*l*+WH^1MENfT`U~T!Jltc0qP~=zv(2Fd;kCd diff --git a/tools/tests/unit/test_expr.asm b/tools/tests/unit/test_expr.asm index b470610..c9e0f04 100644 --- a/tools/tests/unit/test_expr.asm +++ b/tools/tests/unit/test_expr.asm @@ -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" diff --git a/tools/tests/unit/test_parse.asm b/tools/tests/unit/test_parse.asm index 13b6bca..70d500c 100644 --- a/tools/tests/unit/test_parse.asm +++ b/tools/tests/unit/test_parse.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 diff --git a/tools/tests/unit/test_parse_z.asm b/tools/tests/unit/test_parse_z.asm index 402cfdf..285ba5f 100644 --- a/tools/tests/unit/test_parse_z.asm +++ b/tools/tests/unit/test_parse_z.asm @@ -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" diff --git a/tools/tests/unit/test_util_z.asm b/tools/tests/unit/test_util_z.asm index e2cb9b4..d48cfc9 100644 --- a/tools/tests/unit/test_util_z.asm +++ b/tools/tests/unit/test_util_z.asm @@ -2,7 +2,6 @@ jp test .inc "core.asm" .inc "str.asm" -.inc "parse.asm" .inc "zasm/util.asm" testNum: .db 1 diff --git a/tools/tests/unit/test_z_instr.asm b/tools/tests/unit/test_z_instr.asm index f049d44..70166d5 100644 --- a/tools/tests/unit/test_z_instr.asm +++ b/tools/tests/unit/test_z_instr.asm @@ -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"