├── COPYING ├── Darwin.mk ├── Linux.mk ├── Makefile ├── README ├── dict.asm ├── event.asm ├── f ├── firth.asm ├── image.asm ├── net.asm ├── system.asm ├── term.asm ├── tools.asm └── vm.asm /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, David J. Goehrig 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | Neither the name of the Firth nor the names of its contributors may be 15 | used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 | OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Darwin.mk: -------------------------------------------------------------------------------- 1 | 2 | syscall.asm: /usr/include/sys/syscall.h 3 | cat /usr/include/sys/syscall.h | grep -v "old " | grep "^#define" | sed 's%#define%\%define%' | sed 's%SYS_%%' | sed 's%$$% + 0x2000000%' | tail -n +3 > syscall.asm 4 | 5 | firth.o : firth.asm syscall.asm 6 | yasm -f macho64 firth.asm -D Darwin 7 | 8 | firth : firth.o 9 | ld -o firth -e open_image -macosx_version_min 10.7 -pagezero_size 0x100000000 firth.o 10 | -------------------------------------------------------------------------------- /Linux.mk: -------------------------------------------------------------------------------- 1 | 2 | SYSCALLS = cat /usr/include/asm/unistd_64.h | grep -v "old " | grep "^#define" | sed 's%#define%\%define%' | sed 's%__NR_%%' | tail -n +2 3 | 4 | ASM = yasm -f elf64 5 | 6 | LD = ld -o firth -e open_image 7 | 8 | 9 | syscall.asm: /usr/include/asm/unistd_64.h 10 | cat /usr/include/asm/unistd_64.h | grep "__NR_" | sed 's%.* __NR_%%g' | grep -v '#define' | grep -v SYSCALL | grep -v ifndef | grep -v endif | grep -v '\*' | awk '{ print "%define", $$1, $$2 }' > syscall.asm 11 | 12 | firth.o : firth.asm syscall.asm 13 | yasm -f elf64 firth.asm -D Linux 14 | 15 | firth : firth.o 16 | ld -o firth -e open_image firth.o 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | ARCH = $(shell uname) 3 | 4 | all : firth image syscall.asm 5 | 6 | # This routine is use to generate the base file, edited by hand later 7 | dict.asm: 8 | grep def image.asm | awk "{ printf \"dict %s,'%s'\\n\", \$$2, \$$2 }" > dict.asm 9 | 10 | include $(ARCH).mk 11 | 12 | image.bin : image.asm syscall.asm vm.asm term.asm tools.asm dict.asm 13 | yasm -m amd64 -f bin -o image.bin image.asm -D $(ARCH) 14 | 15 | image : image.bin 16 | dd if=/dev/zero of=image bs=1048576 count=1 17 | dd if=image.bin of=image bs=1048576 conv=notrunc count=1 18 | 19 | .PHONY: clean 20 | clean: 21 | rm firth image *.o *.bin syscall.asm 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Firth 2 | ----- 3 | 4 | Firth is an experimental evolution of Forth geared around the following concepts: 5 | 6 | * 2 stack w/ registers architecture on a modern 64bit x86_64 CPU 7 | * direct low level system interface, not requiring any C code 8 | * object oriented memory usage with message passing via registers 9 | * one process per object threaded model 10 | * message passing as flow control 11 | * one concurrent process per processor core (vcpu) 12 | * just in time compilation for everything (no interpreter) 13 | * prototypal inheritance with deep copy semantics 14 | * virtual machine as the base object 15 | * persistent system images 16 | 17 | The goal of Firth is to build a modern Forth that adopts a Erlang meets Self 18 | process/object model. While initially targeting 64bit x86_64, it should be 19 | retargetable with minimal effort to other processors, such as ARM. 20 | 21 | 22 | Building 23 | -------- 24 | 25 | To build: 26 | 27 | make 28 | 29 | This will produce a firth binary and a image file. 30 | 31 | 32 | Running 33 | ------- 34 | 35 | To run: 36 | 37 | ./f 38 | 39 | This will run firth on the image file in a raw tty. 40 | 41 | 42 | Contributing 43 | ------------ 44 | 45 | Firth is being released under a BSD 3-clause license. See the COPYING file for details. If you would like to contribute back to Firth, 46 | feel free to send an email to dave at dloh.org 47 | 48 | FIN 49 | 50 | -------------------------------------------------------------------------------- /dict.asm: -------------------------------------------------------------------------------- 1 | ; create a dictionary entry (in data) 2 | dict boot,'boot' 3 | dict arg1,'#1' 4 | dict arg2,'#2' 5 | dict arg3,'#3' 6 | dict arg4,'#4' 7 | dict arg5,'#5' 8 | dict arg6,'#6' 9 | dict os,'os' 10 | dict rpush,'>r' 11 | dict rpop,'r>' 12 | dict dupe,'.' 13 | dict nip,';;' 14 | dict drop,';' 15 | dict stack,'$' 16 | dict free, 'fp' 17 | dict compile,',' 18 | dict alloc,'#' 19 | dict fetch,'@' 20 | dict fetchplus,'@+' 21 | dict store,'!' 22 | dict storeplus,'!+' 23 | dict source,'$' 24 | dict dest,'%' 25 | dict deststore,'%!' 26 | dict sourcefetch,'$@' 27 | dict addition,'+' 28 | dict subtract,'-' 29 | dict multiply,'*' 30 | dict divide,'/' 31 | dict negate,'neg' 32 | dict andb,'&' 33 | dict orb,'|' 34 | dict xorb,'^' 35 | dict notb,'~' 36 | dict shiftl,'<<' 37 | dict shiftr,'>>' 38 | dict equals,'=' 39 | dict zero,'0=' 40 | dict less,'<' 41 | dict more,'>' 42 | dict if,'?' 43 | dict invoke,'->' 44 | dict continue,'<-' 45 | dict forever,'halt' 46 | dict create,'create' 47 | -------------------------------------------------------------------------------- /event.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; event.asm 3 | ; © 2013 David J Goehrig 4 | ; 5 | ; only doing kevent64 for now 6 | ; 7 | ; struct kevent64_s { 8 | ; uint64_t ident; /* identifier for this event */ 9 | ; int16_t filter; /* filter for event */ 10 | ; uint16_t flags; /* general flags */ 11 | ; uint32_t fflags; /* filter-specific flags */ 12 | ; int64_t data; /* filter-specific data */ 13 | ; uint64_t udata; /* opaque user data identifier */ 14 | ; uint64_t ext[2]; /* filter-specific extensions */ 15 | ; }; 16 | 17 | -------------------------------------------------------------------------------- /f: -------------------------------------------------------------------------------- 1 | clear 2 | STTY=$(stty -g) 3 | stty raw -echo 4 | ./firth 5 | stty "$STTY" 6 | -------------------------------------------------------------------------------- /firth.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; firth.asm - boot loader for a firth image 3 | ; 4 | ; © 2012,2013 David J Goehrig 5 | ; 6 | 7 | BITS 64 8 | 9 | section .text ; starts 0x100000000 10 | 11 | image_start equ 0x100003000 ; image loaded 3 pages higher 12 | 13 | %include "syscall.asm" 14 | 15 | global open_image 16 | 17 | open_image: 18 | mov rax, open ; 0x2000005 open 19 | mov rdi, qword image ; "image" 20 | mov rsi, 0x2 ; RDWR 21 | syscall 22 | mov r8, rax ; fd 23 | mov r15, rax ; fd copy 24 | 25 | find_size: 26 | mov rax, fstat ; 0x20000bd fstat 27 | mov rdi, r15 ; file descriptor 28 | mov rsi, qword stats ; buffer address 29 | syscall 30 | mov r13, qword image_size ; size of image file 31 | mov r14, [r13] ; save image size 32 | 33 | map_image: 34 | mov rax, mmap ; 0x20000c5 mmap 35 | mov rdi, image_start ; image addr 36 | mov rsi, r14 ; file size 37 | mov rdx, 0x7 ; READ0x1|WRITE0x2|EXEC0x4 38 | %ifdef Darwin 39 | mov r10, 0x111 ; NO_EXTEND0x100|SHARED0x01|FILE0x00| 0x10 FIXED 0x111 40 | %else 41 | mov r10, 0x011 ; Linux SHARED0x01|FILE0x00| 0x10 FIXED 0x11 42 | %endif 43 | ; mov r8, fd 44 | mov r9,0 ; offset 0 45 | syscall 46 | mov r13,rax ; image address 47 | 48 | boot: 49 | test r13,r13 ; test image mmap result (0 means we failed) 50 | jnz works 51 | 52 | fail: 53 | mov rax, write ; 0x2000004 write 54 | mov rdi, 2 ; stderr 55 | mov rsi, qword error ; string 56 | mov rdx, 23 ; length 57 | syscall 58 | mov rax, exit ; 0x2000001 exit 59 | syscall 60 | 61 | works: 62 | jmp r13 ; jump to image 63 | 64 | section .data ; 0x100001000 65 | 66 | error: db "failed to load image!",0xa,0xd 67 | image: db "image", 0,90,90 68 | stats: dq 0,0, ; starts at 0x40 from start of data segment 69 | dq 0,0, 70 | dq 0,0, 71 | %ifdef Darwin 72 | dq 0,0, ; linux is 24 sooner 73 | dq 0 74 | %endif 75 | image_size: dq 0, ; 0x100001088 76 | dq 0,0,0,0,0,0,0,0,0,0,0,0,0 ; 77 | 78 | -------------------------------------------------------------------------------- /image.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; image.asm 3 | ;; 4 | ;; © 2012,2013 David J. Goehrig 5 | ;; 6 | 7 | BITS 64 8 | ORG 0 9 | 10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 11 | ;; Include core macro files 12 | %include "vm.asm" 13 | %include "system.asm" 14 | %include "net.asm" 15 | 16 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 17 | ;; Initialize VM 18 | vm 19 | 20 | 21 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 22 | ;; Define core words... 23 | 24 | definition boot 25 | nop 26 | nop 27 | nop 28 | .loop: jmp .loop 29 | end boot 30 | 31 | ;; Operating System Interface 32 | def arg1 33 | def arg2 34 | def arg3 35 | def arg4 36 | def arg5 37 | def arg6 38 | def os 39 | 40 | ;; Stack Functions 41 | 42 | def rpush 43 | def rpop 44 | def dupe 45 | def nip 46 | def drop 47 | def stack 48 | 49 | ;; Memory Functions 50 | 51 | def free 52 | def compile 53 | def alloc 54 | def fetch 55 | def fetchplus 56 | def store 57 | def storeplus 58 | def source 59 | def dest 60 | def deststore 61 | def sourcefetch 62 | 63 | ; math routines 64 | 65 | def addition 66 | def subtract 67 | def multiply 68 | def divide 69 | def negate 70 | 71 | ; logic routines 72 | def andb 73 | def orb 74 | def xorb 75 | def notb 76 | def shiftl 77 | def shiftr 78 | 79 | ; test / control 80 | def equals 81 | def zero 82 | def less 83 | def more 84 | def if 85 | def invoke 86 | def continue 87 | def forever 88 | 89 | ; dictionary 90 | def create 91 | 92 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 93 | ;; Constants, Variables, and Values 94 | 95 | ;dictionary_last: dq word_create ;; last word in dict.asm 96 | ;dictionary_free: dq dictionary_end 97 | 98 | 99 | 100 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 101 | ;; The dictionary 102 | 103 | dictionary: 104 | ;; %include "dict.asm" 105 | dictionary_end: dq 0 106 | -------------------------------------------------------------------------------- /net.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; net.asm 3 | ;; 4 | ;; © 2013 David J. Goehrig 5 | ;; 6 | 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | ;; tcp selects a SOCK_STREAM 9 | 10 | %macro tcp 0 11 | literal 1 12 | arg2 13 | %endmacro 14 | 15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 16 | ;; udp selects a SOCK_DGRAM 17 | 18 | %macro udp 0 19 | literal 2 20 | arg2 21 | %endmacro 22 | 23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 24 | ;; creates a socket and leave fd on top of stack 25 | 26 | %macro create_socket 0 27 | literal 2 ; PF_INET 28 | arg1 29 | literal socket ; socket syscall 30 | os ; fd on tos 31 | %endmacro 32 | 33 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 34 | ;; flags the socket address as reuseable, use before socket_bind 35 | 36 | %macro reuse_addr 0 37 | jmp .skip ; give us an int to work with inline 38 | .flag: dd 1 39 | .skip: literal 4 ; sizeof .flag 40 | arg5 41 | data .flag ; 42 | arg4 43 | literal 4 ; SO_REUSEADDR 44 | arg3 45 | literal 0xffff ; SOL_SOCKET 46 | arg2 47 | arg1 ; fd off of tos 48 | literal setsockopt ; setsockopt syscall 49 | os 50 | %endmacro ; tos 0 if successful 51 | 52 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 53 | ;; binds a socket to a given address, assumes IPv4 54 | 55 | %macro bind_socket 0 56 | literal 16 ; sizeof sockaddr 57 | arg3 58 | arg2 ; sockaddr tos 59 | arg1 ; fd nos 60 | literal bind 61 | os 62 | %endmacro ; tos 0 if successful 63 | 64 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 65 | ;; activates a inbound socket connection on the bound port, 255 connections max 66 | 67 | %macro listen_socket 0 68 | literal 255 ; backlog 69 | arg2 70 | arg1 ; fd on tos 71 | literal listen 72 | os 73 | %endmacro 74 | 75 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 76 | ;; connects the socket to the remote address 77 | 78 | %macro connect_socket 0 79 | literal 16 ; sizeof sockaddr 80 | arg3 81 | arg2 ; sockaddr tos 82 | arg1 ; fd nos 83 | literal connect 84 | os 85 | %endmacro 86 | 87 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 88 | ;; sends data to a socket, use for udp 89 | 90 | %macro send_to_socket 0 91 | literal 16 92 | arg6 93 | arg5 ; sockaddr tos 94 | literal 0 95 | arg4 ; no flags 96 | arg3 ; length 97 | arg2 ; buffer 98 | arg1 ; fd 99 | literal sendto 100 | os 101 | %endmacro 102 | 103 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 104 | ;; receive data from a socket, use for udp 105 | 106 | %macro recv_from_socket 0 107 | jmp .skip 108 | literal 0 ; null addrlen 109 | arg6 110 | literal 0 ; null addr 111 | arg5 112 | literal 0 ; no flags 113 | arg4 114 | arg3 ; length tos 115 | arg2 ; buffer nos 116 | arg1 ; fd 117 | literal recvfrom 118 | os 119 | %endmacro 120 | 121 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 122 | ;; sends data to a bound socket, currently doesn't support OOB 123 | 124 | %macro send_socket 0 125 | literal 0 126 | arg4 127 | arg3 ; length tos 128 | arg2 ; buffer nos 129 | arg1 ; fd 130 | literal send 131 | os 132 | %endmacro 133 | 134 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 135 | ;; receives data from a bound socket, currently doesn't support OOB 136 | 137 | %macro recv_socket 0 138 | literal 0 139 | arg4 140 | arg3 ; length tos 141 | arg2 ; buffer nos 142 | arg1 ; fd 143 | literal recv 144 | os 145 | %endmacro 146 | 147 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 148 | ;; write data to a socket (or fd) 149 | 150 | %macro write_socket 0 151 | arg3 ; length tos 152 | arg2 ; buffer nos 153 | arg1 ; fd 154 | literal write 155 | os 156 | %endmacro 157 | 158 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 159 | ;; read data from a socket (or fd) 160 | 161 | %macro read_socket 0 162 | arg3 ; length tos 163 | arg2 ; buffer nos 164 | arg1 ; fd 165 | literal read 166 | os 167 | %endmacro 168 | 169 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 170 | ;; shutdown methods shutdown ro, wo, or r/w 171 | 172 | %macro _shutdown 0 173 | arg1 ; fd 174 | literal shutdown 175 | os 176 | %endmacro 177 | 178 | %macro shutdown_read_socket 0 179 | literal 0 180 | arg2 181 | _shutdown 182 | %endmacro 183 | 184 | %macro shutdown_write_socket 0 185 | literal 1 186 | arg2 187 | _shutdown 188 | %endmacro 189 | 190 | %macro shutdown_socket 0 191 | literal 2 192 | arg2 193 | _shutdown 194 | %endmacro 195 | -------------------------------------------------------------------------------- /system.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; System Macros for Mac OS X 3 | ;; 4 | ;; © 2012 David J Goehrig 5 | ;; 6 | 7 | %include "syscall.asm" 8 | 9 | ; displays the counted string on the top of the stack 10 | ; len str -- len 11 | %macro show 0 12 | arg2 13 | arg3 14 | literal 1 15 | arg1 16 | literal write 17 | os 18 | %endmacro 19 | 20 | ; displays a counted string ( addr -- written ) 21 | %macro cshow 0 22 | dupe 23 | fetchraw 24 | andnum 0xff ; low byte 25 | arg3 ; count 26 | addnum 1 27 | arg2 ; addr + 1 28 | literal 1 29 | arg1 30 | literal write 31 | os 32 | %endmacro 33 | 34 | ; key -- 35 | %macro type 0 36 | dupe ; key -- key key 37 | stack ; nos address key -- key stack 38 | arg2 ; key stack -- key 39 | literal 1 ; key -- key stdout 40 | arg1 ; key -- key 41 | literal 1 ; key -- key 1 byte 42 | arg3 ; key 1 -- key 43 | literal write ; key -- key write 44 | os ; key -- key count 45 | drop ; key -- key 46 | drop 47 | %endmacro 48 | 49 | ; -- 50 | %macro quit 0 51 | literal 0 52 | arg1 53 | literal exit ; 0x2000001 exit 54 | os 55 | %endmacro 56 | 57 | ; -- key 58 | %macro key 0 59 | stack ; nos pointer 60 | arg2 61 | literal 1 62 | arg3 ; read 1 byte 63 | literal 0 ; stdin 64 | arg1 65 | literal read 66 | os 67 | drop 68 | %endmacro 69 | 70 | -------------------------------------------------------------------------------- /term.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Terminal Code 3 | ;; 4 | ;; © 2012 David J Goehrig 5 | ;; 6 | 7 | 8 | call clear 9 | call term 10 | ; we never get here 11 | 12 | %include "tools.asm" 13 | 14 | ; this is the key input display loop 15 | term: 16 | key 17 | dupe 18 | type 19 | call test_quit 20 | call test_retn 21 | call test_backspace 22 | call test_plain 23 | call test_red 24 | call test_green 25 | jmp term ; will return 26 | 27 | test_quit: 28 | literal 17 ; ctrl-q 29 | equals 30 | method done 31 | if 32 | ret 33 | 34 | done: 35 | quit 36 | ret 37 | 38 | test_retn: 39 | literal 13 40 | equals 41 | method linefeed 42 | if 43 | ret 44 | 45 | linefeed: 46 | literal 10 47 | type 48 | ret 49 | 50 | test_backspace: 51 | literal 127 ; delete key 52 | equals 53 | method backspace 54 | if 55 | ret 56 | 57 | backspace: 58 | literal 8 59 | type 60 | literal 32 61 | type 62 | literal 8 63 | type 64 | ret 65 | 66 | nl: 67 | literal 0xa 68 | type 69 | ret 70 | 71 | eol: 72 | literal 0xd 73 | type 74 | literal 0xa 75 | type 76 | ret 77 | 78 | space: 79 | literal 0x20 80 | type 81 | ret 82 | 83 | clear: 84 | literal 27 85 | type 86 | literal 99 87 | type 88 | ret 89 | 90 | test_green; 91 | literal 7 92 | equals 93 | method green_text 94 | if 95 | ret 96 | 97 | green_text: 98 | data green_str 99 | cshow 100 | ret 101 | 102 | test_red: 103 | literal 18 104 | equals 105 | method red_text 106 | if 107 | ret 108 | 109 | red_text: 110 | data red_str 111 | cshow 112 | ret 113 | 114 | test_plain: 115 | literal 16 116 | equals 117 | method plain_text 118 | if 119 | ret 120 | 121 | plain_text: 122 | data plain_str 123 | cshow 124 | ret 125 | 126 | ; ANSI color codes and jazz 127 | align 8 128 | terminal_data: 129 | done_str: db "done",0,0,0,0 130 | align 8 131 | plain_str: db 8,27,"[0;0;0m" 132 | align 8 133 | red_str: db 10,27,"[0;31;40m" 134 | align 8 135 | green_str: db 10,27,"[0;32;40m" 136 | align 8 137 | yellow_str: db 27,"[0;33;40m" 138 | align 8 139 | blue_str: db 27,"[0;34;40m" 140 | align 8 141 | magenta_str: db 27,"[0;35;40m" 142 | align 8 143 | cyan_str: db 27,"[0;36;40m" 144 | align 8 145 | white_str: db 27,"[0;37;40m" 146 | align 8 147 | position_str: db 27,"[6n" 148 | -------------------------------------------------------------------------------- /tools.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; tools.asm 3 | ;; 4 | ;; © 2012,2013 David J Göhrig 5 | ;; 6 | 7 | octal: 8 | dupe ; a -- a a 9 | shiftrnum 3 ; a a -- a a/8 10 | dupe ; a -- a a/8 a/8 11 | shiftrnum 3 ; a -- a a/8 a/16 12 | andnum 7 ; 13 | addnum 48 ; 14 | type ; a/16&7 15 | andnum 7 ; 16 | addnum 48 ; 17 | type ; a/8&7 18 | andnum 7 ; 19 | addnum 48 ; 20 | type ; a&7 21 | ret 22 | 23 | hexen: 24 | dupe 25 | shiftrnum 4 ; a - a a/16 26 | andnum 15 ; a - a a/16&15 27 | literal 9 ; a - a a/16&15 9 28 | more ; a - a a/16&15 flag 29 | method first_digit ; a - a a/16&15 flag digit 30 | if ; a - a a/16&15 31 | hexen_cont: 32 | addnum 48 ; "a"-10 33 | type 34 | andnum 15 35 | literal 9 36 | more 37 | method second_digit 38 | if 39 | addnum 48 40 | type 41 | ret 42 | 43 | first_digit: 44 | addnum 39 45 | method hexen_cont 46 | invoke 47 | 48 | second_digit: 49 | addnum 87 50 | type 51 | ret 52 | 53 | dump: 54 | dupe 55 | rpush ; byte 0 56 | dupe 57 | shiftrnum 8 58 | rpush ; byte 1 59 | dupe 60 | shiftrnum 16 61 | rpush ; byte 2 62 | dupe 63 | shiftrnum 24 64 | rpush ; byte 3 65 | dupe 66 | shiftrnum 32 67 | rpush ; byte 4 68 | dupe 69 | shiftrnum 40 70 | rpush ; byte 5 71 | dupe 72 | shiftrnum 48 73 | rpush ; byte 6 74 | shiftrnum 56 75 | call hexen ; byte 7 76 | rpop 77 | call hexen ; byte 6 78 | rpop 79 | call hexen ; byte 5 80 | rpop 81 | call hexen ; byte 4 82 | rpop 83 | call hexen ; byte 3 84 | rpop 85 | call hexen ; byte 2 86 | rpop 87 | call hexen ; byte 1 88 | rpop 89 | call hexen ; byte 0 90 | ret 91 | 92 | -------------------------------------------------------------------------------- /vm.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; VMMacros 3 | ;; 4 | ;; © 2012 David J Goehrig 5 | ;; 6 | 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | ; Register Allocation 9 | ; 10 | ; rax top of stack / return value 11 | ; rdx misc data, arg3 / 2nd return 12 | ; rcx count 13 | ; rbx context pointer ( preserved ) 14 | ; rbp data stack pointer ( preserved ) 15 | ; rsp return stack pointer ( preserved ) 16 | ; rdi -- syscalls arg1 17 | ; rsi -- syscalls arg2 18 | ; r8 -- syscalls arg5 19 | ; r9 -- syscalls arg6 20 | ; r10 -- syscalls arg4 21 | ; r11 -- temp 22 | ; r12 free address location ( preserved ) 23 | ; r13 image location ( preserved ) 24 | ; r14 image size / fetch pointer ( preserved ) 25 | ; r15 file handle / store pointer ( preserved ) 26 | 27 | ; register machine 28 | %define ip rip ; instruction pointer 29 | %define cp rbx ; context pointer 30 | %define fp r12 ; free pointer 31 | %define bp r13 ; base pointer 32 | %define dp rbp ; data stack pointer 33 | %define rp rsp ; return stack pointer 34 | %define tos rax ; top of data stack 35 | %define nos rbp*8+rbx ; next on data stack 36 | %define src r14 ; source address register 37 | %define dst r15 ; destination address register 38 | %define tmp1 r10 ; temporary register 39 | %define tmp2 r11 ; temporary register 40 | 41 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 42 | ;; Define bits of the dictionary 43 | 44 | ; define a word (in code) 45 | 46 | %macro definition 1 ; word 47 | def_%1: 48 | %endmacro 49 | 50 | ; end a definition (in code) 51 | %macro end 1 ; word 52 | end_%1: 53 | ret 54 | %endmacro 55 | 56 | %macro def 1 ; word 57 | definition %1 58 | %1 59 | end %1 60 | %endmacro 61 | 62 | ; create a dictionary entry (in data) 63 | %macro dict 2 ; word 64 | %strlen _len %2 65 | align 8 66 | word_%1: 67 | dq def_%1 ; definition address 68 | dq end_%1 - def_%1 ; definition length 69 | dq _len ; word length 70 | db %2 ; word 71 | align 8, db 0 72 | %endmacro 73 | 74 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 75 | ;; VM Image Definition 76 | %macro vm 0 77 | _vm: 78 | jmp _init 79 | nop ; allocating some extra space for future 80 | nop 81 | nop 82 | nop 83 | nop 84 | nop 85 | ; VM header 86 | image_addr: dq 0 ; 0x 87 | image_size: dq 0 88 | image_fd: dq 0 89 | _init: 90 | mov [bp + image_addr], r13 ; Save addr 91 | mov [bp + image_size], r14 ; Save size 92 | mov [bp + image_fd], r15 ; Save file handle 93 | mov tos, 0x1000 94 | spawn ; create a new context 95 | save 96 | literal 0x01deadbeef 97 | literal 0x02deadbeef 98 | literal 0x03deadbeef 99 | literal 0x04deadbeef 100 | literal 0x05cafebabe 101 | literal 0x06cafebabe 102 | literal 0x07cafebabe 103 | literal 0x08cafebabe 104 | literal 0x09feedface 105 | %endmacro 106 | 107 | ;; Defines a machine state relative to a context poitner 108 | dstack equ 0 ; data stack 109 | res_ip equ 8*8 ; saved instruction pointer 110 | res_cp equ 8*9 ; context pointer 111 | res_fp equ 8*10 ; free poitner 112 | res_bp equ 8*11 ; base memory pointer 113 | res_dp equ 8*12 ; data stack pointer 114 | res_rp equ 8*13 ; return stack pointer 115 | res_tos equ 8*14 ; top of data stack 116 | res_src equ 8*15 ; memory source address pointer 117 | res_dst equ 8*16 ; memory destination address pointer 118 | rstack equ 8*17 ; 119 | 120 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 121 | ;; Context macros 122 | 123 | ;; Saves the machine's context so that it may safely exit 124 | %macro save 0 125 | lea tmp1, [bp + .endstop] 126 | mov [cp + res_ip], tmp1 ; this is past the data stack 127 | mov [cp + res_cp], cp ; at the bottom or the return stack 128 | mov [cp + res_fp], fp 129 | mov [cp + res_bp], bp 130 | mov [cp + res_dp], dp 131 | mov [cp + res_rp], rp 132 | mov [cp + res_tos], tos 133 | mov [cp + res_src], src 134 | mov [cp + res_dst], dst 135 | .endstop: nop 136 | %endmacro 137 | 138 | ;; Resume loads the previously save register state into the machine registers 139 | %macro resume 0 140 | mov bp, [cp + res_bp] 141 | mov dst, [cp + res_dst] 142 | mov src, [cp + res_src] 143 | mov tos, [cp + res_tos] 144 | mov rp, [cp + res_rp] 145 | mov dp, [cp + res_dp] 146 | mov fp, [cp + res_fp] 147 | mov tmp1, [cp + res_ip] 148 | push tmp1 ; we restore the instruction pointer by returning to it 149 | ret 150 | %endmacro 151 | 152 | ;; Switch swaps one context pointer for another 153 | %macro switch 0 154 | mov [cp+64],dp ; base pointer 155 | mov [cp+72],rp ; return pointer 156 | mov cp,tos ; switch contexts 157 | mov dp,[cp+64] ; load stack 158 | mov rp,[cp+72] ; load return 159 | %endmacro 160 | 161 | ;; Creates initializes a new context at a given address, 8 pages 32k 162 | %macro spawn 0 163 | lea cp,[bp + tos*8] ; load the context pointer in the top of the stack 164 | lea rp,[cp + 0x0ff8] ; loads the return stack pointer 165 | lea fp,[cp + 0x1000] ; free page memory above return stack 166 | xor dp,dp ; data stack pointer is 0, aka cp + 0 167 | xor tos,tos ; clear the rest of the pointers etc 168 | xor src,src 169 | xor dst,dst 170 | %endmacro 171 | 172 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 173 | ;; System Functions Interface 174 | 175 | ;; loads OS C ABI arg1 176 | %macro arg1 0 177 | mov rdi,tos 178 | drop 179 | %endmacro 180 | 181 | ;; loads OS C ABI arg2 182 | %macro arg2 0 183 | mov rsi,tos 184 | drop 185 | %endmacro 186 | 187 | ;; loads OS C ABI arg3 188 | %macro arg3 0 189 | mov rdx,tos 190 | drop 191 | %endmacro 192 | 193 | ;; loads OS C ABI arg4 194 | %macro arg4 0 195 | mov r10,tos 196 | drop 197 | %endmacro 198 | 199 | ;; loads OS C ABI arg5 200 | %macro arg5 0 201 | mov r8,tos 202 | drop 203 | %endmacro 204 | 205 | ;; loads OS C ABI arg6 206 | %macro arg6 0 207 | mov r9,tos 208 | drop 209 | %endmacro 210 | 211 | ;; Makes an operating system call 212 | %macro os 0 213 | syscall 214 | %endmacro 215 | 216 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 217 | ;; Stack functions 218 | 219 | ;; moves the top of the data stack to the top of the return stack 220 | %macro rpush 0 221 | push tos 222 | drop 223 | %endmacro 224 | 225 | ;; move top of the return stack to the top of the data stack 226 | %macro rpop 0 227 | dupe 228 | pop tos 229 | %endmacro 230 | 231 | ;; places tos in nos and pushes rest of the stack down 232 | %macro dupe 0 233 | add dp,1 234 | and dp,7 235 | mov [nos],tos 236 | %endmacro 237 | 238 | ;; drops the next on the data stack 239 | %macro nip 0 240 | add dp,-1 241 | and dp,7 242 | %endmacro 243 | 244 | ;; removes top of the stack fetches the next on stack 245 | %macro drop 0 246 | mov tos,[nos] 247 | nip 248 | %endmacro 249 | 250 | ;; places the address of the next on the stack into the top of the stack 251 | %macro stack 0 252 | lea tos,[nos] 253 | %endmacro 254 | 255 | ;; Places a literal value in tos 256 | %macro literal 1 257 | dupe 258 | mov tos, %1 259 | %endmacro 260 | 261 | ;; Places the address of a code point in tos 262 | %macro method 1 263 | dupe 264 | lea tos,[bp+%1] 265 | %endmacro 266 | 267 | ;; Locates literal data pointer 268 | %macro data 1 269 | dupe 270 | lea tos,[bp+%1] 271 | %endmacro 272 | 273 | 274 | ;; places the address of a static region of memory on the stack 275 | %macro offset 1 276 | dupe 277 | lea tos,[%1] ; load it as if zero based addr 278 | shr tos,3 ; divide by 8 to get cell addr 279 | %endmacro 280 | 281 | ;; places the address of a given memory cell into tos, cells start addressing from 0 282 | %macro cell 1 283 | dupe 284 | lea tos, [bp + %1*8] 285 | %endmacro 286 | 287 | ; Memory macros 288 | 289 | %macro free 0 290 | xchg tos,fp ; swaps the free pointer with tos 291 | %endmacro 292 | 293 | %macro compile 0 294 | mov [fp],tos ; copies tos to the next free address 295 | drop ; drops the tos 296 | lea fp,[fp+8] ; advances the free pointer 297 | %endmacro 298 | 299 | %macro alloc 0 300 | mov tmp1,fp ; squirrel away free address 301 | lea fp,[fp + tos*8] ; update free pointer allocating tos cells 302 | mov tos,tmp1 ; return address we alloc'd 303 | %endmacro 304 | 305 | %macro allocnum 1 306 | mov tos,fp ; return the free address 307 | lea fp,[fp + %1*8] ; update by fixed num cells 308 | %endmacro 309 | 310 | %macro fetchraw 0 311 | mov tos,[tos] ; absolute addressing 312 | %endmacro 313 | 314 | %macro fetchaddr 1 ; fetch an address 315 | dupe 316 | mov tos,[bp + %1*8] ; cell based addressing 317 | %endmacro 318 | 319 | %macro fetch 0 ; fetch address in tos 320 | mov tos,[bp + tos*8] ; 321 | %endmacro 322 | 323 | ; -- cell 324 | %macro fetchplus 0 325 | dupe 326 | mov tos,[bp + src*8] ; fetch from src register 327 | add src,1 ; increment src register 328 | %endmacro 329 | 330 | %macro source 0 ; swaps the src and top of stack 331 | xchg src,tos 332 | %endmacro 333 | 334 | %macro storeaddr 1 ; store tos to an address 335 | mov [bp + %1*8],tos 336 | drop 337 | %endmacro 338 | 339 | %macro store 0 ; store nos to address in tos 340 | mov tmp1,[nos] 341 | mov [bp + tos*8],tmp1 ; store to a cell address 342 | nip 343 | drop ; remove two elements from stack 344 | %endmacro 345 | 346 | %macro storeplus 0 347 | mov [bp+ dst*8],tos ; store top of stack to memory address 348 | add dst,1 ; increment meory addr 349 | drop 350 | %endmacro 351 | 352 | %macro dest 0 353 | xchg dst,tos ; swap destination and top of stack 354 | %endmacro 355 | 356 | %macro deststore 0 357 | dupe 358 | mov [dst],tos 359 | %endmacro 360 | 361 | %macro sourcefetch 0 362 | mov tos,[src] 363 | drop 364 | %endmacro 365 | 366 | ; Math macros 367 | %macro addition 0 368 | add tos,[nos] 369 | nip 370 | %endmacro 371 | 372 | %macro addnum 1 373 | add tos, %1 374 | %endmacro 375 | 376 | %macro subtract 0 377 | sub tos,[nos] 378 | nip 379 | %endmacro 380 | 381 | %macro subnum 1 382 | sub tos,%1 383 | %endmacro 384 | 385 | %macro multiply 0 386 | imul tos,[nos] 387 | nip 388 | %endmacro 389 | 390 | %macro mulnum 1 391 | imul tos,%1 392 | %endmacro 393 | 394 | %macro divide 0 395 | xor rdx,rdx 396 | mov tmp1,[nos] 397 | idiv tos,tmp1 398 | nip 399 | %endmacro 400 | 401 | %macro divnum 1 402 | xor rdx,rdx 403 | mov tmp1,%1 404 | idiv tos,tmp1 405 | %endmacro 406 | 407 | %macro negate 0 ; twos compliment negation 408 | neg tos 409 | %endmacro 410 | 411 | ; Logic Macros 412 | 413 | %macro andb 0 ; binary and tos and nos 414 | and tos,[nos] 415 | nip 416 | %endmacro 417 | 418 | %macro andnum 1 ; binary and tos with literal 419 | and tos,%1 420 | %endmacro 421 | 422 | %macro orb 0 ; binary or tos with nos 423 | or tos,[nos] 424 | nip 425 | %endmacro 426 | 427 | %macro ornum 1 ; binary or tos with literal 428 | or tos,%1 429 | %endmacro 430 | 431 | %macro xorb 0 ; binary xor tos with now 432 | xor tos,[nos] 433 | nip 434 | %endmacro 435 | 436 | %macro xornum 1 ; binary xor tos with literal 437 | xor tos,%1 438 | %endmacro 439 | 440 | %macro notb 0 ; ones compliment negation 441 | not tos 442 | %endmacro 443 | 444 | %macro shiftl 0 ; shift left 1 445 | mov rcx,[nos] 446 | shl tos,cl 447 | nip 448 | %endmacro 449 | 450 | %macro shiftlnum 1 ; shift left num 451 | shl tos,%1 452 | %endmacro 453 | 454 | %macro shiftr 0 ; shift right 1 455 | mov rcx,[nos] 456 | shr tos,cl 457 | nip 458 | %endmacro 459 | 460 | %macro shiftrnum 1 ; shift right num 461 | shr tos,%1 462 | %endmacro 463 | 464 | ;; test / flow control 465 | ; b a -- b 0|b 466 | %macro equals 0 467 | cmp rax,[nos] 468 | je .econt 469 | xor rax,rax 470 | .econt: nop 471 | %endmacro 472 | 473 | %macro zero 0 474 | dupe 475 | test rax,rax 476 | jnz .zcont 477 | not rax ; rax is not zero 478 | jmp .zdone 479 | .zcont: xor rax,rax ; rax is 0 480 | .zdone: nop 481 | %endmacro 482 | 483 | ; b a -- b 0|a 484 | %macro less 0 485 | cmp [nos],rax 486 | jl .lcont 487 | xor rax,rax 488 | .lcont: nop 489 | %endmacro 490 | 491 | ; b a -- b 0|a 492 | %macro more 0 493 | cmp [nos],rax 494 | jg .gcont 495 | xor rax,rax 496 | .gcont: nop 497 | %endmacro 498 | 499 | ; x addr -- x --> addr 500 | %macro if 0 501 | rpush 502 | test rax,rax ; if it is zero we don't jump 503 | jz .ifcnt 504 | drop 505 | ret 506 | .ifcnt: pop tos ; discard return address on return stack 507 | drop 508 | %endmacro 509 | 510 | %macro invoke 0 511 | rpush 512 | ret 513 | %endmacro 514 | 515 | %macro continue 0 516 | test rax,rax 517 | jz .cntcnt 518 | drop 519 | ret 520 | .cntcnt: drop 521 | %endmacro 522 | 523 | %macro forever 0 524 | jmp $$ 525 | %endmacro 526 | 527 | 528 | --------------------------------------------------------------------------------