fix: use conventional memory address
fix: readme link to itself
Merge branch 'readme'
10biForthOS = 10b(2) i(nstructions) Forth OS is a very primitive Forth with only two instructions:
It is heavily inspired by Frank Sergeant 3-Instruction Forth. [1]
Here is the full OS code in 46 bytes of 8086 assembly opcodes:
50b8 8e00 31d8 e8ff 0017 003c 0575 00ea
5000 3c00 7401 eb02 e8ee 0005 0588 eb47
b8e6 0200 d231 14cd e480 7580 c3f4
When loaded after the boot, 10biForthOS listen on the serial port for instructions (a keyboard version is also provided).
The 1
instuction should be followed by an assembly opcode to be compiled into a fixed memory location.
The 0
instruction launch the compiled program.
And that's it!
On a host computer you can then send commands to 10biForthOS.
As examples a subleq-eForth [2] or even sectorc [3] can be used to code in eForth or C.
Boot the machine (here qemu)
$ ./boot &
The OS is waiting input on the serial port.
Send the hello world example on the serial port:
$ ./send examples/hello-world.asm
00000000 B85000 mov ax,0x50
00000003 8EC0 mov es,ax
00000005 30FF xor bh,bh
... ...
00000028 726C jc 0x96
0000002A 64210D and [fs:di],cx
0000002D 00 db 0x00
Send a 0
$ ./send 0
Enjoy!
Test the keyboard:
$ ./send examples/echo-kbd.asm
00000000 E81200 call 0x15
00000003 3C0D cmp al,0xd
00000005 741A jz 0x21
... ...
00000026 B00A mov al,0xa
00000028 E8EFFF call 0x1a
0000002B EBD3 jmp short 0x0
Send a 0
$ ./send 0
Ok the keyboard is up:
Then send the subleq-eForth [2] example to start programming in Forth:
$ ./send examples/subleq-eForth/subleq-eForth.asm
00000000 30E4 xor ah,ah
00000002 B002 mov al,0x2
00000004 CD10 int 0x10
... ...
00004FAC 94 xchg ax,sp
00004FAD 0B39 or di,[bx+di]
00004FAF 04 db 0x04
Send a 0
$ ./send 0
Write your code in Forth!!
Then send the fat ( :-) ) sectorc [3] example to program in C:
./send examples/sectorc/sectorc.s
00000000 680030 push word 0x3000
00000003 1F pop ds
00000004 680020 push word 0x2000
... ...
000001E5 009EC099 add [bp-0x6640],bl
000001E9 009DC000 add [di+0xc0],bl
000001ED 00 db 0x00
Send a 0
$ ./send 0
Write your code in C!!!
$ ./cat_sectorc hello.c | ./to-serial
or (you have to reset the machine for now)
$ ./cat_sectorc sinwave.c | ./to-serial
Send a 0
$ ./send 0
Shutdown the machine:
$ ./send examples/shutdown.asm
00000000 B80010 mov ax,0x1000
00000003 8ED0 mov ss,ax
00000005 BC00F0 mov sp,0xf000
... ...
0000000B BB0100 mov bx,0x1
0000000E B90300 mov cx,0x3
00000011 CD15 int 0x15
Send a 0
$ ./send 0
The machine shutdown.
Pseudocode description:
bits 16
cpu 8086
[org 0x7c00] ; boot load address
EXECUTE equ 0x0050 ; address where code should be compiled / executed
;;;--------------------
;;; Init
;;;--------------------
init:
mov ax,EXECUTE
mov ds,ax
xor di,di
;;;--------------------
;;; Interpreter loop
;;;--------------------
loop:
call getchar
cmp al,0
jne .skip
jmp EXECUTE:0x0
.skip:
cmp al,1
je compile
jmp loop
;;;--------------------
;;; Compile
;;;--------------------
compile:
call getchar
mov byte [di],al
inc di
jmp loop
;;;--------------------
;;; Utils
;;;--------------------
getchar: ; get a char in al from serial (bios function)
mov ax,0x0200
xor dx,dx
int 0x14
and ah,0x80 ; check for failure and clear ah as a side-effect
jne getchar ; failed, try again
ret
Boot the machine (here qemu)
$ ./boot &
The OS is waiting input from the keyboard.
Type the hello world example with the keyboard (1 [opcode] 1 [opcode] ...).
transl
type it for you:
$ ./transl ../examples/hello-world.asm
00000000 B85000 mov ax,0x50
00000003 8EC0 mov es,ax
00000005 30FF xor bh,bh
... ...
00000028 726C jc 0x96
0000002A 64210D and [fs:di],cx
0000002D 00 db 0x00
1B815010018E1C01301FF1BD11F1001B41131B310A1B010118B10E12C1001B610B1B210A1CD1101EA10017C10010014816516C16C16F12C12015716F17216C16412110D100104104
Type a 0 with the keyboard and tada:
Is this a Forth?
It seems to be: it has an outer interpreter which understand assembly opcodes and an inner interpreter: the standard machine code.
You can load/redefine code at will.
Even if it lacks stacks, dictionnary, defining words, etc. It has the simplicity and hacky feeling of Forth.
Is this an OS?
Once booted you can interract with the screen, the keyboard, the file system and so on.
Once the Forth interpreter or the C compiler are loaded, you can program in Forth or C.
Doesn't it look like an OS?
Why?
Why not? More seriously. It's quit pleasant to be able to write an OS with so little code and be able to extend it while it is running.
[1] https://pygmy.utoh.org/3ins4th.html
[2] https://github.com/pbrochard/subleq-eForthOS
[3] https://github.com/xorvoid/sectorc