duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 3ac7474d73020c4f6bda684475ab3350c02efa2d
parent e00ff7ad42f3d78815f7e2f164fb679a44810f2c
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Thu,  4 Aug 2022 13:58:08 -0400

Replace dusk.asm with the C VM

Diffstat:
M.build.yml | 2--
M.gitignore | 6++----
MMakefile | 31++++++-------------------------
MREADME.md | 32+++++++++++++++++++++-----------
Ddusk.asm | 925-------------------------------------------------------------------------------
Mfs/tests/asm/i386.fs | 1+
Mfs/tests/kernel.fs | 45++++++++++++++++++++++++++++++++++++++++++++-
Mfs/tests/lib/core.fs | 39---------------------------------------
Dposix/glue1.fs | 3---
Dposix/glue2.fs | 5-----
Mposix/vm.c | 30++++++++++++++++++++++--------
11 files changed, 96 insertions(+), 1023 deletions(-)

diff --git a/.build.yml b/.build.yml @@ -1,7 +1,5 @@ image: debian/stable -arch: amd64 packages: - - nasm - mtools - build-essential - qemu-system-x86 diff --git a/.gitignore b/.gitignore @@ -1,9 +1,7 @@ /dusk -/duskvm -/fatfs -/boot.fs +/memdump /fs/init.fs -/posix/tmpboot.fs +/posix/boot.fs /*.bin /*.img *.o diff --git a/Makefile b/Makefile @@ -1,35 +1,16 @@ TARGETS = dusk -BOOTFS_SRC = fs/xcomp/bootlo.fs \ - fs/drv/ramdrive.fs \ - posix/glue1.fs \ - fs/fs/fatlo.fs \ - posix/glue2.fs \ - fs/xcomp/boothi.fs -TMPBOOTFS_SRC = fs/xcomp/bootlo.fs fs/xcomp/boothi.fs +BOOTFS_SRC = fs/xcomp/bootlo.fs fs/xcomp/boothi.fs ALLSRCS = $(shell find fs) all: $(TARGETS) -dusk: dusk.asm boot.fs fatfs - nasm -f elf32 dusk.asm -o dusk.o - ld -m elf_i386 dusk.o -o $@ - fs/init.fs: posix/init.fs fs/xcomp/init.fs cat posix/init.fs fs/xcomp/init.fs > $@ -posix/tmpboot.fs: $(TMPBOOTFS_SRC) - cat $(TMPBOOTFS_SRC) > $@ - -duskvm: posix/vm.c posix/tmpboot.fs fs/init.fs - $(CC) posix/vm.c -Wall -o $@ - -boot.fs: $(BOOTFS_SRC) +posix/boot.fs: $(BOOTFS_SRC) cat $(BOOTFS_SRC) > $@ -fatfs: $(ALLSRCS) posix/init.fs - dd if=/dev/zero of=$@ bs=1M count=1 - mformat -M 512 -d 1 -i $@ :: - cat posix/init.fs fs/xcomp/init.fs > fs/init.fs - mcopy -sQ -i $@ fs/* :: +dusk: posix/vm.c posix/boot.fs fs/init.fs + $(CC) posix/vm.c -Wall -o $@ mbr.bin: dusk buildmbr.fs ./dusk < buildmbr.fs 2> $@ @@ -43,8 +24,8 @@ pc.img: mbr.bin pc.bin $(ALLSRCS) mformat -M 512 -d 1 -R 40 -i $@ :: dd if=mbr.bin of=$@ bs=1 seek=62 conv=notrunc dd if=pc.bin of=$@ bs=1 seek=512 conv=notrunc - cat fs/xcomp/pc/init.fs fs/xcomp/init.fs > fs/init.fs mcopy -sQ -i $@ fs/* :: + cat fs/xcomp/pc/init.fs fs/xcomp/init.fs | mcopy -D overwrite -i $@ - ::init.fs .PHONY: pcrun pcrun: pc.img @@ -66,4 +47,4 @@ test: dusk .PHONY: clean clean: - rm -f $(TARGETS) dusk.o fatfs fs/init.fs boot.fs *.bin *.img + rm -f $(TARGETS) dusk.o fs/init.fs posix/boot.fs memdump *.bin *.img diff --git a/README.md b/README.md @@ -168,19 +168,30 @@ Meanwhile, I'm very open to discussions, comments, debates, questions. I would even say that I'm not closed to patches, as long as you're aware of the fact that I apply double standards until liftoff. -## Build and run +## Build and run Dusk -To build Dusk OS, you need: +Dusk is designed to run on bare metal and to build itself from itself (it's +*almost* self-hosting, but not quite yet. Soon). However, it's also possible to +build Dusk from any POSIX platform using Dusk's C VM from `posix/vm.c`. + +This VM implements a Forth that can interpret the whole of Dusk's Forth code, +but this VM is CPU-agnostic and has its own simplistic bytecode. This means that +this VM cannot do fancy stuff like run native code generated by its assemblers +and compilers. That makes running Dusk from this VM less than exciting: it's +just a boring Forth. + +However, that boring Forth is enough to generate bare metal images for any of +its target platforms, so that's why it exists. To build this VM, you need: * GNU Make -* GNU binutils -* nasm -* A x86-compatible Linux kernel to run this on +* A C compiler * [mtools][6] -Run `make` and then run `./dusk`. You'll get a prompt. Documentation is lacking -for now, you'll have to look at the source to have an idea of available -vocabulary. Type `bye` to quit. +Running `make` will yield a `./dusk` binary which if opened, provides an +interactive prompt. + +Documentation is lacking for now, you'll have to look at the source to have an +idea of available vocabulary. Type `bye` to quit. There is some documentation in `/fs/doc`. @@ -191,9 +202,8 @@ and echoed twice. To avoid that, you can invoke it like this: `make run` does this for you. -### Running OpenBSD? - -You might be interested in [this thread from the mailing list][5]. +But if you really want to play with Dusk, you shouldn't play with this prompt, +but rather play with a bare metal build which can be ran under QEMU. See below. ### Building bare metal binaries diff --git a/dusk.asm b/dusk.asm @@ -1,925 +0,0 @@ -; This is a STC forth. PSP=ebp RSP=esp -BITS 32 -%define CELLSZ 4 -%define PS_SZ 0x1000 -%define RS_SZ 0x1000 -%define MEMSIZE 0xa0000 -%define SYSCALL_EXIT 1 ; int status -%define SYSCALL_READ 3 ; int fd, void *buf, size_t count -%define SYSCALL_WRITE 4 ; int fd, const void *buf, size_t count - -%macro pspush 1 ; src - sub ebp, CELLSZ - mov dword [ebp], %1 -%endmacro - -%macro pspop 1 ; dst - mov %1, dword [ebp] - add ebp, CELLSZ -%endmacro - -%macro firstword 3 ; name namelen lbl -db %1 -dd 0 -db %2 -%push dict -%$prev_word: -%3: -%endmacro - -%macro defword 3 ; name namelen lbl -db %1 -dd %$prev_word -db %2 -%pop -%push dict -%$prev_word: -%3: -%endmacro - -; If toptr=0, push the value of the dword at addr %1 to PS -; If toptr!=0 jump to that ptr -%macro sysval 1 ; lbl -mov eax,%1 -test dword [toptr], -1 -jnz to_is_set -mov eax,[eax] -pspush eax -ret -%endmacro - -; If toptr=0, jump to the address pointed at by the dword at addr %1 -; If toptr!=0 jump to that ptr -%macro sysalias 1 ; lbl -mov eax,%1 -test dword [toptr], -1 -jnz to_is_set -jmp [eax] -%endmacro - -SECTION .bss -areg: resd 1 ; A register -toptr: resd 1 ; Current "to" word pointer. 0 means none -bootptr: resd 1 -current: resd 1 -here: resd 1 -compiling: resd 1 -curword: resb 0x20 ; 1b len, then contents -inrd: resd 1 ; in< -emit: resd 1 -main: resd 1 -abort: resd 1 - resd PS_SZ -ps_top: - resd RS_SZ -rs_top: -herestart: resb MEMSIZE -heremax: -SECTION .data -bootsrc: incbin "boot.fs" -wnfstr: db " word not found" -uflwstr: db "stack underflow" -wordexpstr: db "word expected" -fatfs: incbin "fatfs" -SECTION .text - -GLOBAL _start -_start: - mov dword [bootptr], bootsrc - mov dword [here], herestart - mov dword [current], word_mainloop - mov dword [main], word_mainloop - mov dword [inrd], word_bootrd - mov dword [emit], word__emit - mov dword [abort], word__abort - jmp word_abort - -firstword 'bye', 3, word_bye - mov eax, SYSCALL_EXIT - mov ebx, 0 ; error code - int 0x80 - -defword 'byefail', 7, word_byefail - mov eax, SYSCALL_EXIT - mov ebx, 1 ; error code - int 0x80 - -defword 'noop', 4, word_noop -_ret: ; label for whenever you need to conditionally return - ret - -defword 'main', 4, word_main - sysalias main - -defword 'quit', 4, word_quit - cld - mov dword [toptr], 0 - mov esp, rs_top - jmp word_main - -defword '(abort)', 7, word__abort - mov ebp, ps_top - jmp word_quit - -defword 'abort', 5, word_abort - sysalias abort - -defword 'exit', 4, word_exit - pop eax - ret - -defword 'execute', 7, word_execute - pspop eax - jmp eax - -; Compiled by "create" -; This word is called right before data begins, which means that the address -; that interests us is right on top of RS. -defword '(cell)', 6, word_cellroutine - pop eax - pspush eax - ret - -; Compiled by "value" -; Called right before a 4b data, RS has its address now. -; If toptr=0, return that value -; If toptr!=0 jump to that ptr -defword '(val)', 5, word_valroutine - pop eax - test dword [toptr], -1 - jnz to_is_set - mov ebx, [eax] - pspush ebx - ret - -; Compiled by "alias" -; Called right before a 4b word pointer, RS has its address now. -; If toptr=0, return jump to where it's pointing. -; If toptr!=0 jump to that ptr -defword '(alias)', 7, word_aliasroutine - pop eax - test dword [toptr], -1 - jnz to_is_set - jmp [eax] - -; Compiled by "does" -; When called, RS points to the address of the word following "does>" -; After that 4b pointer, data begins, so we want to push its address to PS. -defword '(does)', 6, word_doesroutine - pop eax - mov ebx, eax - add ebx, CELLSZ - pspush ebx - jmp [eax] - -; String literal. What follows it is a byte with the length of the string. -; What we do here is to push the address of that string to PS, and then read -; that length byte, then skip that many bytes and jump there. -defword '(s)', 3, word_strlit - pop esi ; addr of str - pspush esi - xor eax, eax - lodsb ; len - add esi, eax ; ret to PC right after str - jmp esi - -defword '(br)', 4, word_brroutine - pop eax - jmp dword [eax] - -defword '(?br)', 5, word_condbrroutine - pspop eax - or eax, eax - jz word_brroutine - pop eax - add eax, CELLSZ - jmp eax - -defword '(next)', 6, word_nextroutine - dec dword [esp+CELLSZ] - jnz word_brroutine - pop eax - pop ebx - add eax, CELLSZ - jmp eax - -defword 'boot<', 5, word_bootrd - mov esi, [bootptr] - xor eax,eax - mov al, [esi] - inc dword [bootptr] - pspush eax - ret - -defword '(emit)', 6, word__emit - mov eax, SYSCALL_WRITE - mov ebx, 1 ; stdout - mov ecx, ebp ; buffer: top of PS, little endian - mov edx, 1 ; len - int 0x80 - pspop eax - ret - -defword 'emit', 4, word_emit - sysalias emit - -defword 'stderr', 6, word_stderr - mov eax, SYSCALL_WRITE - mov ebx, 2 ; stderr - mov ecx, ebp ; buffer: top of PS, little endian - mov edx, 1 ; len - int 0x80 - pspop eax - ret - -defword 'key', 3, word_key - pspush 0 - mov eax, SYSCALL_READ - mov ebx, 0 ; stdin - mov ecx, ebp ; buffer - mov edx, 1 ; len - int 0x80 - ret - -defword 'drop', 4, word_drop - add ebp, CELLSZ - ret - -defword 'dup', 3, word_dup - mov eax, [ebp] - sub ebp, CELLSZ - mov [ebp], eax - ret - -defword '?dup', 4, word_conddup - test dword [ebp], -1 - jnz word_dup - ret - -defword 'swap', 4, word_swap - mov eax, [ebp] - mov ebx, [ebp+CELLSZ] - mov [ebp], ebx - mov [ebp+CELLSZ], eax - ret - -defword 'over', 4, word_over - mov eax, [ebp+CELLSZ] - sub ebp, CELLSZ - mov [ebp], eax - ret - -defword 'rot', 3, word_rot - mov eax, [ebp] - mov ebx, [ebp+CELLSZ] - mov ecx, [ebp+CELLSZ*2] - mov [ebp], ecx - mov [ebp+CELLSZ], eax - mov [ebp+CELLSZ*2], ebx - ret - -defword 'nip', 3, word_nip - pspop eax - mov [ebp], eax - ret - -defword 'tuck', 4, word_tuck - mov eax, [ebp] - mov ebx, [ebp+CELLSZ] - mov [ebp], ebx - mov [ebp+CELLSZ], eax - pspush eax - ret - -defword 'rot>', 4, word_rotr - mov eax, [ebp] - mov ebx, [ebp+CELLSZ] - mov ecx, [ebp+CELLSZ*2] - mov [ebp], ebx - mov [ebp+CELLSZ], ecx - mov [ebp+CELLSZ*2], eax - ret - -; Warning: RS routines are all called, which means that we have to work from -; the second item from the top rather than the first. - -defword 'r>', 2, word_rs2ps - pop eax - sub ebp, CELLSZ - pop dword [ebp] - jmp eax - -defword '>r', 2, word_ps2rs - pspop eax - xchg eax, [esp] - jmp eax - -defword 'r@', 2, word_rsget - mov eax, [esp+CELLSZ] - pspush eax - ret - -defword 'r~', 2, word_rsdrop - pop eax - add esp, CELLSZ - jmp eax - -defword 'scnt', 4, word_scnt - mov eax, ps_top - sub eax, ebp - shr ax, 2 ; div by 4, preserve neg - pspush eax - ret - -defword 'rcnt', 4, word_rcnt - mov eax, rs_top - sub eax, esp - shr ax, 2 ; div by 4, preserve neg - dec ax ; ignore this call - pspush eax - ret - -defword '>A', 2, word_Aset - pspop eax - mov [areg], eax - ret - -defword 'A>', 2, word_Aget - mov eax, [areg] - pspush eax - ret - -defword 'Ac@', 3, word_Acfetch - mov eax, 0 - mov esi, [areg] - mov al, [esi] - pspush eax - ret - -defword 'Ac!', 3, word_Acstore - pspop eax - mov esi, [areg] - mov [esi], al - ret - -defword 'A+', 2, word_Ainc - inc dword [areg] - ret - -defword 'A-', 2, word_Adec - dec dword [areg] - ret - -defword 'A>r', 3, word_A2rs - pop eax - push dword [areg] - jmp eax - -defword 'r>A', 3, word_rs2A - pop eax - pop dword [areg] - jmp eax - -to_is_set: ; eax=cell addr - pspush eax - mov ebx, [toptr] - mov dword [toptr], 0 - jmp ebx - -defword '[to]', 4, word_set_toptr - pspop eax - mov [toptr], eax - ret - -defword 'to?', 3, word_get_toptr - mov eax, [toptr] - pspush eax - mov dword [toptr], 0 - ret - -defword '1+', 2, word_inc - inc dword [ebp] - ret - -defword '1-', 2, word_dec - dec dword [ebp] - ret - -defword 'c@', 2, word_cfetch - mov esi, [ebp] - mov eax, 0 - mov al, [esi] - mov [ebp], eax - ret - -defword 'c!', 2, word_cstore - pspop eax - pspop ebx - mov [eax], bl - ret - -defword 'c,', 2, word_cwrite - pspop eax -_cwrite: ; al=c - mov esi, [here] - mov [esi], al - inc dword [here] - ret - -defword 'w@', 2, word_wfetch - mov esi, [ebp] - mov eax, 0 - mov ax, [esi] - mov [ebp], eax - ret - -defword 'w!', 2, word_wstore - pspop eax - pspop ebx - mov [eax], bx - ret - -defword '@', 1, word_fetch - mov esi, [ebp] - mov eax, [esi] - mov [ebp], eax - ret - -defword '!', 1, word_store - pspop eax - pspop ebx - mov [eax], ebx - ret - -defword '+!', 2, word_addstore - pspop eax - pspop ebx - add [eax], ebx - ret - -defword ',', 1, word_write - pspop eax -_write: ; eax=n - mov esi, [here] - mov [esi], eax - add dword [here], CELLSZ - ret - -defword '+', 1, word_add - pspop eax - add [ebp], eax - ret - -defword '-', 1, word_sub - pspop eax - sub [ebp], eax - ret - -defword '*', 1, word_mul - pspop eax - mov ebx, [ebp] - mul ebx - mov [ebp], eax - ret - -; ( a b -- r q ) -defword '/mod', 4, word_divmod - mov eax, [ebp+4] - mov ebx, [ebp] - xor edx, edx - div ebx - mov [ebp+4], edx ; remainder - mov [ebp], eax ; quotient - ret - -defword 'and', 3, word_and - pspop eax - and [ebp], eax - ret - -defword 'or', 2, word_or - pspop eax - or [ebp], eax - ret - -defword 'xor', 3, word_xor - pspop eax - xor [ebp], eax - ret - -defword 'bool', 4, word_bool - mov eax, [ebp] - mov dword [ebp], 0 - test eax, eax - setnz byte [ebp] - ret - -defword 'not', 3, word_not - mov eax, [ebp] - mov dword [ebp], 0 - test eax, eax - setz byte [ebp] - ret - -defword '<', 1, word_lt - pspop eax - sub [ebp], eax - mov dword [ebp], 0 - setc byte [ebp] - ret - -defword '<<c', 3, word_shlc - pspush 0 - shl dword [ebp+CELLSZ], 1 - setc byte [ebp] - ret - -defword '>>c', 3, word_shrc - pspush 0 - shr dword [ebp+CELLSZ], 1 - setc byte [ebp] - ret - -; ( n u -- n ) -defword 'lshift', 6, word_lshift - pspop ecx - shl dword [ebp], cl - ret - -defword 'rshift', 6, word_rshift - pspop ecx - shr dword [ebp], cl - ret - -litncode: - pspush 0 -litncode_end: -defword 'litn', 4, word_litn - mov esi, litncode ; src - mov ecx, litncode_end-litncode-CELLSZ ; len_of_code-len-of-imm - call _movewrite - jmp word_write - -defword 'execute,', 8, word_executewrite - mov al, 0xe8 ; call opcode - call _cwrite - pspop eax ; absolute addr - sub eax, [here] ; displacement - sub eax, 4 ; ... from *after* call/jmp op - jmp _write - -defword 'exit,', 5, word_exitwrite - mov al, 0xc3 ; ret opcode - jmp _cwrite - -defword 'current', 7, word_current - sysval current - -defword 'here', 4, word_here - sysval here - -defword 'heremax', 7, word_heremax - pspush heremax - ret - -defword 'fatfs(', 6, word_fatfsaddr - pspush fatfs - ret - -defword 'compiling', 9, word_compiling - sysval compiling - -; where "word" feeds itself -defword 'in<', 3, word_inrd - sysalias inrd - -; ( src dst u -- ) -defword 'move', 4, word_move - pspop ecx - pspop edi - pspop esi - test ecx, ecx - jz _ret - rep movsb - ret - -; ( a u -- ) -defword 'move,', 5, word_movewrite - pspop ecx - pspop esi - test ecx, ecx - jz _ret -_movewrite: ; esi=a ecx=u - mov edi, [here] - add dword [here], ecx - rep movsb - ret - -; ( a u -- ) -defword 'rtype', 5, word_rtype - pspop ecx - pspop esi -_rtype_loop: - xor eax, eax - mov al, [esi] - pspush eax - push esi - push ecx - call word_emit - pop ecx - pop esi - inc esi - dec ecx - jnz _rtype_loop - ret - -; ( -- ) -defword '(wnf)', 5, word_wnf - mov esi, curword+1 - xor ecx, ecx - mov cl, [curword] - call _rtype_loop - mov ecx, 15 - mov esi, wnfstr -_errmsg: - call _rtype_loop - jmp word_abort - -defword 'stack?', 6, word_stackcond - cmp ebp, ps_top - jna _ret - mov ecx, 15 - mov esi, uflwstr - jmp _errmsg - -; ( -- str ) -defword 'curword', 7, word_curword - pspush curword - ret - -; ( -- str-or-0 ) -defword 'maybeword', 9, word_maybeword - ; save toptr so that it doesn't mess [inrd], which could be calling a word - ; with to semantics - push dword [toptr] - mov dword [toptr], 0 -_word_loop1: - call [inrd] ; ( -- c ) - pspop eax - test eax, eax - js _word_eof - cmp eax, 0x21 ; is ws? - jc _word_loop1 - mov ebx, curword+1 -_word_loop2: - mov [ebx], al - inc ebx - push ebx - call [inrd] ; ( -- c ) - pop ebx - pspop eax - test eax, eax - js _word_stoploop2 ; EOF, but we just treat is as a WS - cmp eax, 0x21 ; is ws? - jnc _word_loop2 -_word_stoploop2: - pop dword [toptr] - sub ebx, curword+1 - mov [curword], bl - pspush curword - ret -_word_eof: - pop dword [toptr] - pspush 0 - ret - -; ( -- str-or-0 ) -defword 'word', 4, word_word - call word_maybeword - test dword [ebp], -1 - jnz _ret - mov ecx, 13 - mov esi, wordexpstr - jmp _errmsg - -; ( str -- n? f ) esi=sa ecx=sl -_parse_c: - cmp ecx, 3 - jnz _parse_no - cmp byte [esi+2], "'" - jnz _parse_no - xor eax, eax - mov al, [esi+1] - mov [ebp], eax - pspush 1 - ret - -; ( str -- n? f ) esi=sa ecx=sl -_parse_h: - cmp ecx, 2 - jc _parse_no - inc esi ; skip $ - dec ecx - xor eax, eax ; res - xor ebx, ebx -_parse_h_loop: - mov bl, [esi] - or bl, 0x20 - sub bl, '0' - jc _parse_no - cmp bl, 10 - jc _parse_h_ok ; ebx=n - sub bl, 'a'-'0' - jc _parse_no - add bl, 10 ; ebx=n - cmp bl, 16 - jnc _parse_no -_parse_h_ok: ; ebx=n - shl eax, 4 ; res*16 - add eax, ebx - inc esi - dec ecx - jnz _parse_h_loop - mov [ebp], eax - pspush 1 - ret -__h_no: - mov dword [ebp], 0 - ret - -; ( str -- n? f ) esi=sa ecx=sl -_parse_ud: - test ecx, ecx - jz _parse_no - xor eax, eax ; res -_parse_ud_loop: - mov ebx, 10 - mul ebx ; res*10 - mov bl, [esi] - sub bl, '0' - jc _parse_no - cmp bl, 10 ; ebx=n - jnc _parse_no - add eax, ebx - inc esi - dec ecx - jnz _parse_ud_loop - mov [ebp], eax - pspush 1 - ret - -; ( str -- n? f ) -defword 'parse', 5, word_parse - mov esi, [ebp] - xor ecx, ecx - mov cl, [esi] - inc esi - cmp byte [esi], "'" - jz _parse_c - cmp byte [esi], '$' - jz _parse_h - cmp byte [esi], '-' - jnz _parse_ud - inc esi - dec ecx - call _parse_ud - test dword [ebp], -1 - jz _parse_no - neg dword [ebp+CELLSZ] - ret -_parse_no: - mov dword [ebp], 0 - ret - -; ( a1 a2 u -- f ) -defword '[]=', 3, word_rangeeq - pspop ecx - pspop edi - pspop esi - xor eax, eax - repz cmpsb - setz al - pspush eax - ret - -; ( str -- word-or-0 ) -defword 'find', 4, word_find - mov esi, [ebp] - xor ecx, ecx - mov cl, [esi] - inc dword [ebp] - mov edx, [current] -_find_loop: - mov edi, edx - dec edi - mov al, [edi] - and al, 0x3f ; 3f instead of 7f? we reserve space for another flag. - cmp al, cl - jnz _find_skip1 - ; same length - sub edi, 4 - sub edi, ecx - mov esi, [ebp] - repz cmpsb - jnz _find_skip2 - ; same contents - mov [ebp], edx - ret -_find_skip2: - mov cl, al -_find_skip1: - sub edx, 5 - mov edx, [edx] - test edx, edx - jnz _find_loop - ; not found - mov dword [ebp], 0 - ret - -; ( -- w ) -defword "'", 1, word_apos - call word_word - call word_find - test dword [ebp], -1 - jz word_wnf - ret - -; : entry ( str -- ) -; c@+ tuck move, ( len ) current , c, here to current ; -defword 'entry', 5, word_entry - pspop esi - xor ecx, ecx - mov cl, [esi] - inc esi - mov edx, ecx ; save len - call _movewrite - mov eax, [current] - call _write - mov eax, edx - call _cwrite - mov eax, [here] - mov [current], eax - ret - -; : xtcomp 1 to compiling begin -; word parse if litn else curword find if -; dup immediate? if execute else call, then -; else (wnf) then then -; compiling not until -; exit, ; -defword 'xtcomp', 6, word_xtcomp - mov dword [compiling], 1 -_xtcomp_loop: - call word_word - call word_parse - pspop eax - test eax, eax - jz _xtcomp_notlit - ; is literal - call word_litn - jmp _xtcomp_loop -_xtcomp_notlit: - pspush curword - call word_find - test dword [ebp], -1 - jz word_wnf - ; word found - mov eax, [ebp] ; w - dec eax - test byte [eax], 0x80 - jnz _xtcomp_imm - call word_executewrite - jmp _xtcomp_loop -_xtcomp_imm: - call word_execute - test dword [compiling], -1 - jnz _xtcomp_loop - jmp word_exitwrite - -defword ':', 1, word_docol - call word_word - call word_entry - jmp word_xtcomp - -defword ';', 0x81, word_compstop - mov dword [compiling], 0 - ret - -; ( str -- ) -defword 'runword', 7, word_runword - call word_parse - pspop eax - test eax, eax - jnz _ret ; is a literal - ; not a literal - pspush curword - call word_find - test dword [ebp], -1 - jz word_wnf - call word_execute - jmp word_stackcond - -defword 'mainloop', 8, word_mainloop - call word_word - call word_runword - jmp word_mainloop diff --git a/fs/tests/asm/i386.fs b/fs/tests/asm/i386.fs @@ -1,4 +1,5 @@ ?f<< /tests/harness.fs +ARCH S" i386" s= not [if] ." Skipping i386 assembler tests" nl> \s [then] ?f<< /asm/i386.fs testbegin \ Tests for asm/i386.fs diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -24,8 +24,51 @@ chain foo myfoo 42 foo 43 #eq fooinit 42 foo 86 #eq \ (42+1)*2 -testend \ [if]..then 1 [if] 42 42 #eq [then] 0 [if] abort [then] + +\ does words +: incer doer , does> @ 1+ ; +41 incer foo +101 incer bar + +foo 42 #eq +bar 102 #eq + +\ case +: foo ( n ) case + 1 of = 111 endof + 42 of > 222 endof + 333 + endcase ; + +here .x +current .x +' foo .x +1 foo 111 #eq +2 foo 222 #eq +3 foo 222 #eq +42 foo 333 #eq + +\ while..repeat +: foo begin dup 9 20 =><= not while dup 3 5 =><= not while 1+ repeat + 100 + else 200 + then ; + +1 foo 103 #eq +10 foo 210 #eq +6 foo 209 #eq +20 foo 220 #eq + +\ prevword +: bar ; +: baz ; +' baz prevword ' bar #eq + +\ autoloading +floaded # + +0 ( file doesn't exist ) floaded? not # +S" /tests/harness.fs" findpath floaded? # +testend diff --git a/fs/tests/lib/core.fs b/fs/tests/lib/core.fs @@ -13,43 +13,4 @@ $1234 capture .x S" 00001234" #s= 42 1024 * 1024 * capture .sz S" 42MB" #s= -1 capture .sz S" 3GB" #s= -\ does words -: incer doer , does> @ 1+ ; -41 incer foo -101 incer bar - -foo 42 #eq -bar 102 #eq - -\ case -: foo ( n ) case - 1 of = 111 endof - 42 of > 222 endof - 333 - endcase ; - -1 foo 111 #eq -2 foo 222 #eq -3 foo 222 #eq -42 foo 333 #eq - -\ while..repeat -: foo begin dup 9 20 =><= not while dup 3 5 =><= not while 1+ repeat - 100 + else 200 + then ; - -1 foo 103 #eq -10 foo 210 #eq -6 foo 209 #eq -20 foo 220 #eq - -\ prevword -: bar ; -: baz ; -' baz prevword ' bar #eq - -\ autoloading -floaded # - -0 ( file doesn't exist ) floaded? not # -S" /tests/harness.fs" findpath floaded? # testend diff --git a/posix/glue1.fs b/posix/glue1.fs @@ -1,3 +0,0 @@ -\ Glue code between the storage driver and the FS handler -fatfs( to ramdrv( -RAMDrive value fatdrv diff --git a/posix/glue2.fs b/posix/glue2.fs @@ -1,5 +0,0 @@ -\ Glue code that goes between the filesystem part and boothi -alias fatopenlo fopen -alias fatchild fchild -0 S" drv" fchild S" ramdrive.fs" fchild floaded, -0 S" fs" fchild S" fatlo.fs" fchild floaded, diff --git a/posix/vm.c b/posix/vm.c @@ -326,7 +326,7 @@ static void RSGET() { // op: 22 static void RDROP() { // op: 23 dword a = rpop(); - ppop(); + rpop(); rpush(a); } @@ -363,11 +363,15 @@ static void ADEC() { // op: 2b } static void A2RS() { // op: 2c + dword a = rpop(); rpush(vm.areg); + rpush(a); } static void RS2A() { // op: 2d + dword a = rpop(); vm.areg = rpop(); + rpush(a); } static void TOSET() { // op: 2e @@ -587,7 +591,7 @@ static void PARSE() { // op: 53 dword s = ppop(); byte len = gb(s++); dword n = 0; - dword neg = 0; + byte neg = 0; byte c; if (!len) goto err; switch (gb(s)) { @@ -611,7 +615,7 @@ static void PARSE() { // op: 53 } break; case '-': - neg = 0x80000000; + neg = 1; s++; len--; if (!len) goto err; default: // decimal @@ -621,7 +625,7 @@ static void PARSE() { // op: 53 n *= 10; n += c; } - n |= neg; + if (neg) n *= -1; } ppush(n); ppush(1); return; @@ -811,9 +815,11 @@ static void FREADBUF () { // op: 5f static void FCLOSE () { // op: 60 dword hdl = ppop(); int fd = getfiledesc(hdl); - close(fd); - sd(hdl+20, 0); - sd(hdl+24, 0); + if (fd) { + close(fd); + sd(hdl+20, 0); + sd(hdl+24, 0); + } } #define OPCNT 0x61 @@ -918,6 +924,8 @@ static void buildsysdict() { sysval("current", CURRENT); sysval("compiling", COMPILING); sysconst("heremax", HEREMAX); + sysconst("curword", CURWORD); + entry("mainloop"); sd(MAINLOOP, here()); callwr(find("word")); callwr(find("runword")); @@ -928,7 +936,7 @@ static void buildsysdict() { // Interpret loop int main() { strcpy(fsids[0], "fs"); // Set FS root path - bootfp = fopen("posix/tmpboot.fs", "r"); + bootfp = fopen("posix/boot.fs", "r"); if (!bootfp) { printf("Can't open boot file.\n"); return 1; @@ -937,5 +945,11 @@ int main() { vm.PC = find("(abort)"); while (vm.PC < MEMSZ) oprun1(); fclose(bootfp); + if (vm.PC > MEMSZ) { + fprintf(stderr, "Dumping memory to memdump.\n"); + FILE *fp = fopen("memdump", "w"); + fwrite(vm.mem, MEMSZ, 1, fp); + fclose(fp); + } return MEMSZ - vm.PC; }