code: 9ferno

Download patch

ref: 6b9b01c4efb785704a8a5bff92d11250cb284c11
parent: 0977f294bab0345ba43fbf674449fd8e996c5719
author: 9ferno <gophone2015@gmail.com>
date: Fri Oct 29 11:29:34 EDT 2021

compiling native forth interpreter

--- a/.gitignore
+++ b/.gitignore
@@ -358,3 +358,5 @@
 
 os/pc64/6.*
 os/pc64/*.i
+os/pc64/primitives.s
+os/pc64/words.s
--- a/mkfiles/mksyslib-rc
+++ b/mkfiles/mksyslib-rc
@@ -34,7 +34,7 @@
 	$YACC $YFLAGS $prereq
 
 clean-std:V:
-	rm -f *.[$OS] [$OS].out
+	rm -f *.[$OS] [$OS].out $CLEANEXTRA
 
 nuke-std:V:	clean-std
 	rm -f y.tab.? y.output y.error
--- /dev/null
+++ b/os/pc64/ff.s
@@ -1,0 +1,617 @@
+#include "mem.h"
+
+/*
+ ff kernel, amd64 9front variant
+
+ Register usage:
+
+ TOS: AX top of stack register
+ SP:  SP parameter stack pointer, grows towards lower memory (downwards)
+ RP:  BP return stack pointer, grows towards higher memory (upwards)
+ AP:  SI address pointer
+ W:   DI work register (holds CFA)
+ 	BX, CX, DX, R8-R15 temporary registers
+
+Memory map:
+
+Return stack 4096 bytes at FFSTART
+	|
+	|
+	v (grows downwards)
+Others 4096 bytes
+	system variables
+	word buffer
+	tib, text input buffer
+Parameter stack 4096 bytes at FFEND-4096
+	^ (grows upwards)
+	|
+	|
+SSTACK_END = FFEND
+*/
+
+#define SSTACK_SIZE 4096
+#define RSTACK_SIZE 4096
+#define	LAST $centry_c_boot(SB) /* last defined word, should generate this */
+#define	SSTACK_END FFEND
+
+/* putting this above the asm code as the v_dp define is needed by _main */
+/*	m_ for primitive/macro word cfa
+	mc_ for primtive/macro word constants
+	c_ for colon word cfa
+	ci_ for colon immediate word cfa
+	v_ for colon variable word cfa
+ */
+#include "primitives.s"
+
+TEXT	ffmain(SB), 1, $-4		/* _main(SB), 1, $-4 without the libc */
+	/* The last dictionary entry address is stored in dtop.
+	 * The location of dtop is stored in the variable dp.
+	 * To get the location of dtop, get the value in the parameter field
+	 * (link + name(1+2) + code field address = 24 bytes) of the dp
+	 * dictionary entry.
+	 */
+	MOVQ $mventry_dp+24(SB), BX	/* BX = dp parameter field address, which has the dtop address */
+	MOVQ (BX), BX	/* BX = *BX = dtop address */
+	MOVQ (BX), AX	/* AX = *BX = $LAST = boot word address (defined last, stored at dtop) */
+				/* if 6a allows multiple symbols per address, then 
+					the above 3 instructions would have been
+					MOVQ (($mventry_dp+24(SB))), AX */
+	/*
+	 * Could do this instead of the calculations below
+	 * LEAQ 24(AX), SI
+	 */
+	ADDQ $16, AX	/* AX += link (8 bytes) + len (1 byte) + minimum for align to 8 bytes */
+	XORQ CX, CX
+	MOVB 8(BX), CL	/* CL = length of boot name */
+	ADDQ CX, AX		/* AX += len */
+	ANDQ $~7, AX	/* AX = address of boot's code - 8 bytes */
+	LEAQ 8(AX), SI	/* SI = L257 = start of boot code = has docol address there
+					 * skipping over docol as we do not need to save the SI
+					 * could have done LEAQ 24(AX), SI
+					 */
+	MOVQ $FFEND, SP	/* setting up stack, argc + argv */
+
+/* lodsl could make this simpler. But, this is more comprehensible
+	why not JMP* (DI)?
+ */
+#define NEXT	MOVQ (SI), DI; \
+		ADDQ $8, SI; \
+		MOVQ (DI), BX; \
+		JMP* BX;
+
+	NEXT
+
+TEXT	reset(SB), 1, $-4
+	MOVQ $FFSTART, BP
+	NEXT
+
+TEXT	clear(SB), 1, $-4
+	MOVQ $FFEND, SP
+	NEXT
+
+TEXT	colon(SB), 1, $-4
+	MOVQ SI,(BP)
+	ADDQ $8, BP
+	LEAQ 8(DI), SI
+	NEXT
+
+TEXT	dodoes(SB), 1, $-4	/* ( -- a ) */
+	MOVQ SI,(BP)
+	ADDQ $8,BP
+	MOVQ 8(DI),SI
+	PUSHQ AX
+	LEAQ 16(DI), AX
+	NEXT
+
+TEXT	jump(SB), 1, $-4	/* ( -- ) */
+	MOVQ (SI),SI
+	NEXT
+
+/* ( f -- ) cjump address
+	if true, skip the address and continue
+	else, go to the address */
+TEXT	cjump(SB), 1, $-4	/* ( f -- ) */
+	MOVQ (SI), BX	/* get the next address */
+	ADDQ $8, SI	/* move esi beyond that */
+	TESTQ AX, AX
+	JNZ .l1		/* if true, move along */
+	MOVQ BX, SI	/* if false, go to the above address */
+.l1:
+	POPQ AX
+	NEXT
+
+TEXT	fetch(SB), 1, $-4	/* ( a -- n) */
+	MOVQ (AX), AX
+	NEXT
+
+/* shouldn't it be (a n -- )? */
+TEXT	store(SB), 1, $-4	/* ( n a -- ) */
+	POPQ (AX)
+	POPQ AX
+	NEXT
+
+TEXT	cfetch(SB), 1, $-4	/* ( a -- c ) */
+	XORQ BX, BX
+	MOVB (AX), BL
+	MOVQ BX, AX
+	NEXT
+
+TEXT	cstore(SB), 1, $-4	/* ( c a -- ) */
+	POPQ BX
+	MOVB BL, (AX)
+	POPQ AX
+	NEXT
+
+TEXT	terminate(SB), 1, $-4	/* ( n -- ) */
+	XORQ BX, BX
+	TESTQ AX, AX
+	JZ .l2
+	MOVQ $failtext(SB), BX
+.l2:
+	/* PUSHQ BX */
+	/* SUBQ $8, SP */	/* dummy retaddr */
+	MOVQ BX, a0+0(FP)	/* address of exit status? status = nil? */
+	MOVQ $8, RARG	/* EXITS */
+	SYSCALL		/* syscall for exit */
+
+TEXT	testfsopen(SB), 1, $-4
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	PUSHQ $0	/* OREAD */
+	PUSHQ $name(SB)
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $14, RARG	/* open */
+	SYSCALL
+	ADDQ $24, SP
+	POPQ BP
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+/* man errstr */
+TEXT	errstr(SB), 1, $-4
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	PUSHQ AX
+
+	PUSHQ $128	/* size */
+	PUSHQ $errstrbuffer(SB) /* buf */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $41, RARG	/* errstr */
+	SYSCALL
+	ADDQ $24, SP
+
+	MOVQ $-1, BX	/* -1LL (seek pos) */
+	PUSHQ BX	/* offset */
+	PUSHQ $128	/* size, could use c's strlen for the exact size */
+	PUSHQ $errstrbuffer(SB) /* buf */
+	PUSHQ $2	/* assuming that stderr = 2 */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $51, RARG	/* PWRITE */
+	SYSCALL
+	ADDQ $40, SP
+
+	POPQ AX
+	POPQ BP
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+TEXT	fsopen(SB), 1, $-4	/* ( cstr flags mode -- fd ) */
+	POPQ BX		/* flags */
+	POPQ CX		/* name */
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	PUSHQ AX
+	MOVQ $14, RARG	/* OPEN */
+	TESTQ $512, BX	/* O_CREAT? */
+	JZ .l3
+	MOVQ $22, RARG	/* CREATE */
+.l3:
+	ANDQ $0xF, BX	/* retain only OREAD, OWRITE, ORDWR */
+	PUSHQ BX
+	PUSHQ CX
+	PUSHQ $0	/* dummy retaddr */
+	SYSCALL
+	ADDQ $32, SP
+	POPQ BP
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+TEXT	fsclose(SB), 1, $-4	/* ( fd -- n ) */
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	PUSHQ AX	/* fd */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $4, RARG	/* CLOSE */
+	SYSCALL
+	ADDQ $16, SP	/* removing the pushed parameters */
+	POPQ BP
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+TEXT	fsread(SB), 1, $-4	/* ( a n fd -- n2 ) */
+	POPQ CX		/* size */
+	POPQ DX		/* buf */
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	MOVQ $-1, BX	/* -1LL (seek pos) */
+	PUSHQ BX	/* offset */
+	PUSHQ CX	/* size */
+	PUSHQ DX	/* buf */
+	PUSHQ AX	/* fd */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $50, RARG	/* PREAD */
+	SYSCALL		/* return value in AX */
+	ADDQ $40, SP
+	POPQ BP		/* restore return stack pointer */
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+TEXT	fswrite(SB), 1, $-4	/* ( a n fd -- n2 ) */
+	POPQ CX		/* size */
+	POPQ DX		/* buf */
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	MOVQ $-1, BX	/* -1LL (seek pos) */
+	PUSHQ BX	/* offset */
+	PUSHQ CX	/* size */
+	PUSHQ DX	/* buf */
+	PUSHQ AX	/* fd */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $51, RARG	/* PWRITE */
+	SYSCALL
+	ADDQ $40, SP
+	POPQ BP
+	POPQ SI
+	NEXT
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+
+TEXT	fsseek(SB), 1, $-4	/* ( pos fd -- n ) */
+	POPQ BX		/* offset */
+	PUSHQ SI	/* for some reason, the syscall is changing SI and DI */
+	PUSHQ BP
+	XORQ DX, DX	/* type 0 */
+	PUSHQ DX	/* type 0 */
+	PUSHQ BX	/* offset */
+	PUSHQ AX  	/* fd */
+	PUSHQ $0	/* dummy retaddr */
+	MOVQ $39, RARG	/* SEEK */
+	SYSCALL
+	ADDQ $32, SP	/* remove the pushed parameters */
+	POPQ BP
+	POPQ SI
+	NEXT
+
+TEXT	mmap(SB), 1, $-4	/* ( a1 -- a2 ) */
+	MOVQ $-1, AX	/* unimplemented */
+
+TEXT	variable(SB), 1, $-4	/* ( -- a ) */
+	PUSHQ AX
+	LEAQ 8(DI), AX
+	NEXT
+
+TEXT	constant(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	MOVQ 8(DI), AX
+	NEXT
+
+TEXT	literal(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	MOVQ (SI), AX
+	ADDQ $8, SI
+	NEXT
+
+TEXT	sliteral(SB), 1, $-4	/* ( -- a n ) */
+	PUSHQ AX
+	XORQ AX,AX
+	MOVB (SI), AL
+	INCQ SI
+	PUSHQ SI
+	ADDQ AX, SI
+	ADDQ $7, SI
+	ANDQ $~7, SI
+	NEXT
+
+TEXT	exitcolon(SB), 1, $-4
+	SUBQ $8, BP
+	MOVQ (BP), SI
+	NEXT  
+
+/* puts the top 2 entries of the data stack in the return stack */
+TEXT	doinit(SB), 1, $-4	/* ( hi lo -- ) */
+	MOVQ AX, (BP)
+	POPQ AX
+	MOVQ AX, 8(BP)
+	POPQ AX
+	ADDQ $16, BP
+	NEXT
+
+/* not sure if this works, needs testing to follow https://github.com/mark4th/x64
+	check the notes
+	return stack would have
+		current index
+		end index
+	(R lo hi -- )
+	increment lo
+	when hi > lo, go to the address next to doloop
+ */
+TEXT	doloop(SB), 1, $-4
+	INCQ -16(BP)
+doloop1:
+	MOVQ -16(BP), BX
+	CMPQ BX, -8(BP)
+	JGE .l4
+	MOVQ (SI), SI
+	NEXT
+.l4:
+	SUBQ $16, BP
+	ADDQ $8, SI
+	NEXT
+
+TEXT	doploop(SB), 1, $-4	/* ( n -- ) */
+	ADDQ AX, -16(BP)
+	POPQ AX
+	JMP doloop1
+
+TEXT	rfetch(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	MOVQ -8(BP), AX
+	NEXT
+
+TEXT	rpush(SB), 1, $-4	/* ( n -- ) */
+	MOVQ AX,(BP)
+	POPQ AX
+	ADDQ $8,BP
+	NEXT
+
+TEXT	rpop(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	SUBQ $8, BP
+	MOVQ (BP), AX
+	NEXT
+
+TEXT	i(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	MOVQ -16(BP), AX
+	NEXT
+
+TEXT	j(SB), 1, $-4	/* ( -- n ) */
+	PUSHQ AX
+	MOVQ -32(BP), AX
+	NEXT
+
+TEXT	plus(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	POPQ BX
+	ADDQ BX, AX
+	NEXT  
+
+TEXT	minus(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	POPQ BX
+	SUBQ AX, BX
+	MOVQ BX, AX
+	NEXT
+
+TEXT	multiply(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	POPQ BX
+	IMULQ BX
+	NEXT
+
+TEXT	slashmod(SB), 1, $-4	/* ( n1 n2 -- n3 n4 ) */
+	MOVQ AX, BX
+	MOVQ (SP), AX
+	CDQ
+	IDIVQ BX
+	MOVQ AX, (SP)
+	NEXT
+
+TEXT	uslashmod(SB), 1, $-4	/* ( u1 u2 -- u3 u4 ) */
+	MOVQ AX, BX
+	MOVQ (SP), AX
+	XORQ DX, DX
+	DIVQ BX
+	MOVQ DX, (SP)
+	NEXT
+
+TEXT	binand(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	ANDQ (SP), AX
+	ADDQ $8, SP
+	NEXT
+
+TEXT	binor(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	ORQ (SP), AX
+	ADDQ $8, SP
+	NEXT
+
+TEXT	binxor(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	XORQ (SP), AX
+	ADDQ $8, SP
+	NEXT
+
+TEXT	xswap(SB), 1, $-4	/* ( x y -- y x ) */
+	XCHGQ AX, (SP)
+	NEXT
+
+TEXT	drop(SB), 1, $-4	/* ( x -- ) */
+	POPQ AX
+	NEXT
+
+TEXT	dup(SB), 1, $-4	/* ( x -- x x ) */
+	PUSHQ AX
+	NEXT
+
+TEXT	over(SB), 1, $-4	/* ( x y -- x y x ) */
+	PUSHQ AX
+	MOVQ 8(SP), AX
+	NEXT
+
+TEXT	equal(SB), 1, $-4	/* ( x y -- f ) */
+	POPQ BX
+	CMPQ BX, AX
+	JEQ .true
+	XORQ AX, AX
+	NEXT
+TEXT	true(SB), 1, $-4
+.true:
+	MOVQ $-1, AX
+	NEXT
+	
+TEXT	greater(SB), 1, $-4	/* ( x y -- f ) */
+	POPQ BX
+	CMPQ BX, AX
+	JGT .true
+	XORQ AX, AX
+	NEXT
+
+/* if x < y then y - x > 0, no sign flag
+	intel manual says destination operand - source operand
+	but, 9front assemblers seem to work differently
+	compare x and y == CMP x, y
+ */
+TEXT	less(SB), 1, $-4	/* ( x y -- f ) */
+	POPQ BX
+	CMPQ BX, AX
+	JLT .true
+	XORQ AX, AX
+	NEXT
+
+TEXT	stackptr(SB), 1, $-4	/* ( -- a ) does not include TOS! */
+	PUSHQ AX
+	MOVQ SP, AX
+	NEXT
+
+TEXT	lshift(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	MOVQ AX, CX
+	POPQ AX
+	SHLQ CL, AX
+	NEXT
+	
+TEXT	rshift(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	MOVQ AX, CX
+	POPQ AX
+	SHRQ CL, AX
+	NEXT
+
+TEXT	rshifta(SB), 1, $-4	/* ( n1 n2 -- n ) */
+	MOVQ AX, CX
+	POPQ AX
+	SARQ CL, AX
+	NEXT
+
+TEXT	execute(SB), 1, $-4	/* ( ... a -- ... ) */
+	MOVQ AX, DI
+	POPQ AX
+	MOVQ (DI), BX
+	JMP BX
+
+TEXT	deferred(SB), 1, $-4
+	MOVQ 8(DI), DI
+	MOVQ (DI), BX
+	JMP BX
+
+TEXT	unloop(SB), 1, $-4
+	SUBQ $16, BP
+	NEXT
+
+TEXT	cmove(SB), 1, $-4	/* ( a1 a2 n -- ) */
+	MOVQ AX, CX
+	POPQ DI
+	MOVQ SI, BX
+	POPQ SI
+	REP; MOVSB
+	MOVQ BX, SI
+	POPQ AX
+	NEXT
+
+TEXT	cmoveb(SB), 1, $-4	/* ( a1 a2 n -- ) */
+	MOVQ AX, CX
+	POPQ DI
+	DECQ AX
+	ADDQ AX, DI
+	MOVQ SI, BX
+	POPQ SI
+	ADDQ AX, SI
+	STD
+	REP; MOVSB
+	CLD
+	MOVQ BX, SI
+	POPQ AX
+	NEXT
+
+TEXT	cas(SB), 1, $-4	/* ( a old new -- f ) */
+	MOVQ AX, CX	/* new */
+	POPQ AX	/* old */
+	POPQ BX	/* addr */
+	LOCK; CMPXCHGQ CX, (BX)
+	JE .true
+	XORQ AX, AX
+	/* pause -- no equivalent in 6a ? */
+	NEXT
+
+TEXT	ffend(SB), 1, $-4
+
+#include "words.s"
+
+DATA	failtext(SB)/6, $"error\z"
+GLOBL	failtext(SB), $6
+
+DATA	name(SB)/8, $"/tmp/tes"
+DATA	name+8(SB)/6, $"t.txt\z"
+GLOBL	name(SB), $14
+
+DATA	errstrbuffer(SB)/1, $0
+GLOBL	errstrbuffer(SB), $128	/* matches ERRMAX of libc.h */
+
+DATA	tibuffer(SB)/1, $0
+GLOBL	tibuffer(SB), $1024
+DATA	wordbuffer(SB)/1, $0
+GLOBL	wordbuffer(SB), $256
+/* TODO there should not be a heap limit, get rid of this */
+/*
+DATA	heap(SB)/1, $0
+GLOBL	heap(SB), $HEAP_SIZE
+*/
+
+
+DATA	dtop(SB)/8, LAST
+GLOBL	dtop(SB), $8
+/* 0's until heap allocated */
+DATA	htop(SB)/8, $0
+GLOBL	htop(SB), $8
+DATA	heapend(SB)/8, $0
+GLOBL	heapend(SB), $8
+
+	END
--- a/os/pc64/l.s
+++ b/os/pc64/l.s
@@ -125,6 +125,9 @@
 MOVB $15, BX
 MOVB BX, (AX)
 	JMP _idle1
+
+	to dumpstack
+JMP dumpstack(SB)
 */
 TEXT _warp64<>(SB), 1, $-4
 
@@ -595,7 +598,7 @@
 	RET
 
 TEXT cmpswap486(SB), 1, $-4
-TEXT cas(SB), 1, $-4
+/* TEXT cas(SB), 1, $-4 *//* ff uses this name */
 	MOVL	exp+8(FP), AX
 	MOVL	new+16(FP), BX
 	LOCK; CMPXCHGL BX, (RARG)
--- a/os/pc64/main.c
+++ b/os/pc64/main.c
@@ -25,6 +25,7 @@
 
 char bootdisk[KNAMELEN];
 
+extern void ffmain(void);	/* forth interpreter */
 /* until I sort out the mp initialization issue */
 extern void startaps(void);
 
@@ -113,9 +114,11 @@
 		"\tcpu0mach 0x%p cpu0sp 0x%p cpu0gdt 0x%p\n"
 		"\tcpu0pml4 0x%p cpu0pdp 0x%p  cpu0pd 0x%p\n"
 		"\tcpu0end 0x%p\n",
+		"\tetext 0x%p edata 0x%p end 0x%p\n",
 		(void*)KDZERO, CONFADDR,APBOOTSTRAP,
 		IDTADDR, CPU0MACH, CPU0SP, GDTADDR,
-		PML4ADDR, PDPADDR, PD0ADDR, CPU0END);
+		PML4ADDR, PDPADDR, PD0ADDR, CPU0END,
+		etext, edata, end);
 	print("Some page table entries\n");
 	ptedebug(1*MiB,"1 MiB");
 	ptedebug(2*MiB,"2 MiB");
@@ -144,6 +147,7 @@
 	screeninit();
 	print("\nInferno release built at %lud\n", kerndate);
 	showconfig();
+ffmain();
 	cpuidentify();
 	meminit0();			/* builds the memmap */
 	doc("archinit");
--- a/os/pc64/mem.h
+++ b/os/pc64/mem.h
@@ -79,17 +79,19 @@
 #define CPU0END		(KDZERO+0x12000ull)	/* CPU0MACH + (MACHSIZE = 64 KiB = 0x10 000) */
 										/* MACHSIZE includes stack size */
 #define CPU0SP		(KDZERO+0x12000ull)
+#define FFSTART		(KDZERO+0x12000ull) /* FF stacks, system variables, tib, word buffer */
+#define FFEND		(KDZERO+0x15000ull) /* 3 pages */
 /* 1 PD table has 512 entries
  * each entry maps to a 2MB page
  * 512 entries maps 1GiB and occupies 512*8 = 4096 bytes
  */
-#define PML4ADDR	(KDZERO+0x13000ull)
-#define PDPADDR		(KDZERO+0x14000ull)	/* KZERO=0 .. 512GiB */
-#define PD0ADDR		(KDZERO+0x15000ull)	/* KZERO=0 .. 1GiB */
-#define PT0ADDR		(KDZERO+0x16000ull)	/* KZERO=0 .. 2MiB */
-#define PT1ADDR		(KDZERO+0x17000ull)	/* 2MiB .. 4MiB */
-#define PT2ADDR		(KDZERO+0x18000ull)	/* 4MiB .. 6MiB */
-#define PT3ADDR		(KDZERO+0x19000ull)	/* 6MiB .. 8MiB */
+#define PML4ADDR	(KDZERO+0x15000ull)
+#define PDPADDR		(KDZERO+0x16000ull)	/* KZERO=0 .. 512GiB */
+#define PD0ADDR		(KDZERO+0x17000ull)	/* KZERO=0 .. 1GiB */
+#define PT0ADDR		(KDZERO+0x18000ull)	/* KZERO=0 .. 2MiB */
+#define PT1ADDR		(KDZERO+0x19000ull)	/* 2MiB .. 4MiB */
+#define PT2ADDR		(KDZERO+0x1a000ull)	/* 4MiB .. 6MiB */
+#define PT3ADDR		(KDZERO+0x1b000ull)	/* 6MiB .. 8MiB */
 						/* fill with page tables until KTZERO */
 
 /*
--- a/os/pc64/mkfile
+++ b/os/pc64/mkfile
@@ -24,6 +24,7 @@
 
 OBJ=\
 	l.$O\
+	ff.$O\
 	fpu.$O\
 	portclock.$O\
 	tod.$O\
@@ -88,6 +89,14 @@
 fault386.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
 main.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h rebootcode.i
 trap.$O:	$ROOT/Inferno/$OBJTYPE/include/ureg.h
+
+ff.$O:	primitives.s words.s
+primitives.s:	primitives.awk primitives-nasm.s
+	cat primitives-nasm.s | ./primitives.awk > primitives.s
+words.s:	words.awk words-nasm.s
+	cat words-nasm.s | ./words.awk > words.s
+
+CLEANEXTRA=words.s primitives.s
 
 devether.$O $ETHERS:	etherif.h ../port/netif.h
 $IP devip.$O:		../ip/ip.h
--- /dev/null
+++ b/os/pc64/primitives-nasm.s
@@ -1,0 +1,65 @@
+dict:
+  MENTRY "@", fetch, 1
+  MENTRY "!", store, 1
+  MENTRY "c@", cfetch, 2
+  MENTRY "c!", cstore, 2
+  MENTRY "testfsopen", testfsopen, 10
+  MENTRY "errstr", errstr, 6
+  MENTRY "fsread", fsread, 6
+  MENTRY "fswrite", fswrite, 7
+  MENTRY "fsseek", fsseek, 6
+  MENTRY "fsopen", fsopen, 6
+  MENTRY "fsclose", fsclose, 7
+  MENTRY "mmap", mmap, 4
+  MENTRY "halt", terminate, 4
+  MENTRY "clear", clear, 5
+  MENTRY "reset", reset, 5
+  MVENTRY "h", h, htop, 1
+  MVENTRY "dp", dp, dtop, 2
+  MENTRY "exitcolon", exitcolon, 4
+  MENTRY "(literal)", literal, 9
+  MENTRY "(sliteral)", sliteral, 10
+  MENTRY "(do)", doinit, 4
+  MENTRY "(loop)", doloop, 6
+  MENTRY "(+loop)", doploop, 7
+  MENTRY "r@", rfetch, 2
+  MENTRY "r>", rpop, 2
+  MENTRY ">r", rpush, 2
+  MENTRY "i", i, 1
+  MENTRY "j", j, 1
+  MENTRY "+", plus, 1
+  MENTRY "-", minus, 1
+  MENTRY "*", multiply, 1
+  MENTRY "(if)", cjump, 4
+  MENTRY "(else)", jump, 6
+  MENTRY "/mod", slashmod, 4
+  MENTRY "u/mod", uslashmod, 5
+  MENTRY "and", binand, 3
+  MENTRY "or", binor, 2
+  MENTRY "xor", binxor, 3
+  MENTRY "swap", xswap, 4
+  MENTRY "drop", drop, 4
+  MENTRY "dup", dup, 3
+  MENTRY "over", over, 4
+  MENTRY "=", equal, 1
+  MENTRY ">", greater, 1
+  MENTRY "<", less, 1
+  MVENTRY "tib", tib, tibuffer, 3
+  MVENTRY "wordb", wordb, wordbuffer, 5
+  MENTRY "s@", stackptr, 2
+  MENTRY "lshift", lshift, 6
+  MENTRY "rshift", rshift, 6
+  MENTRY "rshifta", rshifta, 7
+  MENTRY "execute", execute, 7
+  MENTRY "unloop", unloop, 6
+  MENTRY "cmove", cmove, 5
+  MENTRY "cmove>", cmoveb, 6
+  MENTRY "(variable)", variable, 10
+  MENTRY "(constant)", constant, 10
+  MENTRY "(:)", colon, 3
+  MENTRY "(does)", dodoes, 6
+  MVENTRY "heaptop", heaptop, heapend, 7
+  MVENTRY "_start", textbase, ffmain, 6
+  MVENTRY "_end", textend, ffend, 4
+  MENTRY "cas", cas, 3
+  MENTRY "(deferred)", deferred, 10
--- /dev/null
+++ b/os/pc64/primitives.awk
@@ -1,0 +1,96 @@
+#!/bin/awk -f
+
+# rc script to build amd64 9front forth words from words-nasm.s
+#	./words words-nassm.s
+# watch -e 'words.awk' 'head words-nasm.s | ./words.awk'
+
+BEGIN{
+	FS=",[ \t]*|[ \t]+"
+	last=""
+	nlines=0
+	addr=""
+}
+{
+	lines[++nlines]=sprintf("/* %s */\n", $0);
+}
+function writelast(typ, label, last){
+	if(last == "")
+		lines[++nlines]=sprintf("DATA	%s_%s(SB)/8, LAST\n", typ, label);
+	else
+		lines[++nlines]=sprintf("DATA	%s_%s(SB)/8, $%s\n", typ, label, last);
+}
+$2 == "MENTRY" {
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+	}
+	gsub(/"/,"", $3)
+	name = $3
+	label = $4
+	tot = 0
+	writelast("mentry", label, last)
+	last=sprintf("mentry_%s(SB)", label);
+	lines[++nlines]=sprintf("DATA	mentry_%s+8(SB)/1, $%d\n", label, length(name));
+	for(i=1; i<=length(name); i++){
+		lines[++nlines]=sprintf("DATA	mentry_%s+%d(SB)/1, $'%c'\n", label, 8+i, substr(name,i,1));
+	}
+	tot = 8+i;
+	# for alignment
+	if(tot%8 > 0)
+		tot += 8-(tot%8);
+	lines[++nlines]=sprintf("DATA	mentry_%s+%d(SB)/8, $%s(SB)\n", label, tot, label);
+	lines[++nlines]=sprintf("#define	m_%s(SB) mentry_%s+%d(SB)\n", label, label, tot);
+	tot += 8
+	addrlabel = sprintf("mentry_%s", label)
+}
+$2 == "MVENTRY" {
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+	}
+	gsub(/"/,"", $3)
+	name = $3
+	label = $4
+	tot = 0
+	writelast("mventry", label, last)
+	last=sprintf("mventry_%s(SB)", label);
+	lines[++nlines]=sprintf("DATA	mventry_%s+8(SB)/1, $%d\n", label, length(name));
+	for(i=1; i<=length(name); i++){
+		lines[++nlines]=sprintf("DATA	mventry_%s+%d(SB)/1, $'%c'\n", label, 8+i, substr(name,i,1));
+	}
+	tot = 8+i;
+	# for alignment
+	if(tot%8 > 0)
+		tot += 8-(tot%8);
+	lines[++nlines]=sprintf("DATA	mventry_%s+%d(SB)/8, $constant(SB)\n", label, tot);
+	lines[++nlines]=sprintf("#define	mc_%s(SB) mventry_%s+%d(SB)\n", label, label, tot);
+	tot += 8;
+	lines[++nlines]=sprintf("DATA	mventry_%s+%d(SB)/8, $%s(SB)\n", label, tot, $5);
+	tot += 8;
+	addrlabel = sprintf("mventry_%s", label)
+}
+$1 ~ /:$/ && $1 !~ /^dict:$/ {
+	l=$1
+	gsub(/:$/,"",l)
+	# for not printing out the labels while still developing the program
+	#	to only print the unprocessed lines
+	#lines[++nlines] = ""
+	printf("#define	%s(SB) %s+%d(SB)\n", l, addrlabel, tot);
+}
+{
+	#if(done == nlines){
+	#	print $0
+	#}
+	#for(i = done+1; i <= nlines; i++){
+	#	printf("%s", lines[i])
+	#}
+	done=nlines	
+}
+END{
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s(SB), $%d\n", addrlabel, tot);
+		lines[++nlines]=sprintf("#undef	LAST\n");
+		lines[++nlines]=sprintf("#define	LAST $%s\n", last);
+	}
+	for(i = 1; i <= nlines; i++){
+		printf("%s", lines[i])
+	}	
+}
--- a/os/pc64/trap.c
+++ b/os/pc64/trap.c
@@ -253,6 +253,8 @@
 	print("  CS %4.4zux  DS %4.4ux  ES %4.4ux  FS %4.4ux  GS %4.4ux\n",
 		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
 		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
+	print("  R8 %4.4zux  R9 %4.4ux  R10 %4.4ux  R11 %4.4ux  R12 %4.4ux\n",
+		ureg->r8, ureg->r9, ureg->r10, ureg->r11, ureg->r12);
 }
 
 void
--- /dev/null
+++ b/os/pc64/words-nasm.s
@@ -1,0 +1,1815 @@
+ CENTRY `false`, c_false, 5
+ dd m_literal
+ dd 0
+ dd m_exitcolon
+ CENTRY `true`, c_true, 4
+ dd m_literal
+ dd -1
+ dd m_exitcolon
+ CENTRY `bl`, c_bl, 2
+ dd m_literal
+ dd 32
+ dd m_exitcolon
+ VENTRY `s0`, v_s0, 2
+ VENTRY `args`, v_args, 4
+ CENTRY `on`, c_on, 2
+ dd m_literal
+ dd -1
+ dd m_xswap
+ dd m_store
+ dd m_exitcolon
+ CENTRY `off`, c_off, 3
+ dd m_literal
+ dd 0
+ dd m_xswap
+ dd m_store
+ dd m_exitcolon
+ CENTRY `>body`, c_tobody, 5
+ dd m_literal
+ dd 8
+ dd m_plus
+ dd m_exitcolon
+ CENTRY `aligned`, c_aligned, 7
+ dd m_literal
+ dd 7
+ dd m_plus
+ dd m_literal
+ dd -8
+ dd m_binand
+ dd m_exitcolon
+ CENTRY `cells`, c_cells, 5
+ dd m_literal
+ dd 3			; (index << 2) -> (index << 3)for amd64
+ dd m_lshift
+ dd m_exitcolon
+ CENTRY `cell+`, c_cellplus, 5
+ dd m_literal
+ dd 1
+ dd c_cells
+ dd m_plus
+ dd m_exitcolon
+ CENTRY `depth`, c_depth, 5
+ dd v_s0
+ dd m_fetch
+ dd m_stackptr
+ dd m_minus
+ dd m_literal
+ dd 3
+ dd m_rshift
+ dd m_literal
+ dd 1
+ dd m_minus
+ dd m_exitcolon
+ CENTRY `nip`, c_nip, 3
+ dd m_xswap
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `rot`, c_rot, 3
+ dd m_rpush
+ dd m_xswap
+ dd m_rpop
+ dd m_xswap
+ dd m_exitcolon
+ CENTRY `2drop`, c_2drop, 5
+ dd m_drop
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `2dup`, c_2dup, 4
+ dd m_over
+ dd m_over
+ dd m_exitcolon
+ CENTRY `2nip`, c_2nip, 4
+ dd c_nip
+ dd c_nip
+ dd m_exitcolon
+ CENTRY `2swap`, c_2swap, 5
+ dd c_rot
+ dd m_rpush
+ dd c_rot
+ dd m_rpop
+ dd m_exitcolon
+ CENTRY `?dup`, c_qdup, 4 ; if (tos != 0) dup ( n -- ) TODO correct stack notations
+ dd m_dup	; ( n n -- )
+ dd m_dup	; ( n n n -- )
+ dd m_literal
+ dd 0		; ( n n n 0 -- )
+ dd m_equal	; ( n n f -- )
+ dd m_cjump	; ( n n -- )
+ dd L20
+ dd m_drop	; tos == 0 ( n -- )
+L20:		; tos != 0 ( n n -- )
+ dd m_exitcolon
+ CENTRY `pick`, c_pick, 4
+ dd c_qdup
+ dd m_cjump
+ dd L22
+ dd m_literal
+ dd 1
+ dd m_plus
+ dd c_cells
+ dd m_stackptr
+ dd m_plus
+ dd m_fetch
+ dd m_jump
+ dd L23
+L22:
+ dd m_dup
+L23:
+ dd m_exitcolon
+ CENTRY `tuck`, c_tuck, 4
+ dd m_dup
+ dd m_rpush
+ dd m_xswap
+ dd m_rpop
+ dd m_exitcolon
+ CENTRY `/`, c_divides, 1
+ dd m_slashmod
+ dd c_nip
+ dd m_exitcolon
+ CENTRY `+!`, c_plusstore, 2
+ dd m_dup
+ dd m_fetch
+ dd c_rot
+ dd m_plus
+ dd m_xswap
+ dd m_store
+ dd m_exitcolon
+ CENTRY `invert`, c_invert, 6
+ dd m_literal
+ dd -1
+ dd m_binxor
+ dd m_exitcolon
+ CENTRY `mod`, c_mod, 3
+ dd m_slashmod
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `1+`, c_1plus, 2
+ dd m_literal
+ dd 1
+ dd m_plus
+ dd m_exitcolon
+ CENTRY `1-`, c_1minus, 2
+ dd m_literal
+ dd 1
+ dd m_minus
+ dd m_exitcolon
+ CENTRY `negate`, c_negate, 6
+ dd m_literal
+ dd 0
+ dd m_xswap
+ dd m_minus
+ dd m_exitcolon
+ CENTRY `2*`, c_2multiplies, 2
+ dd m_literal
+ dd 1
+ dd m_lshift
+ dd m_exitcolon
+ CENTRY `2/`, c_2divides, 2
+ dd m_literal
+ dd 1
+ dd m_rshifta
+ dd m_exitcolon
+ CENTRY `0=`, c_0eq, 2
+ dd m_literal
+ dd 0
+ dd m_equal
+ dd m_exitcolon
+ CENTRY `0<`, c_0lt, 2
+ dd m_literal
+ dd 0
+ dd m_less
+ dd m_exitcolon
+ CENTRY `0>`, c_0gt, 2
+ dd m_literal
+ dd 0
+ dd m_greater
+ dd m_exitcolon
+ CENTRY `<>`, c_neq, 2
+ dd m_equal
+ dd c_invert
+ dd m_exitcolon
+ CENTRY `0<>`, c_0neq, 3
+ dd m_literal
+ dd 0
+ dd c_neq
+ dd m_exitcolon
+ CENTRY `max`, c_max, 3
+ dd c_2dup
+ dd m_greater
+ dd m_cjump
+ dd L40
+ dd m_drop
+ dd m_jump
+ dd L41
+L40:
+ dd c_nip
+L41:
+ dd m_exitcolon
+ CENTRY `min`, c_min, 3
+ dd c_2dup
+ dd m_less
+ dd m_cjump
+ dd L43
+ dd m_drop
+ dd m_jump
+ dd L44
+L43:
+ dd c_nip
+L44:
+ dd m_exitcolon
+ CENTRY `signum`, c_signum, 6
+ dd m_dup
+ dd c_0gt
+ dd m_cjump
+ dd L46
+ dd m_drop
+ dd m_literal
+ dd 1
+ dd m_jump
+ dd L47
+L46:
+ dd c_0lt
+ dd m_cjump
+ dd L48
+ dd m_literal
+ dd -1
+ dd m_jump
+ dd L49
+L48:
+ dd m_literal
+ dd 0
+L49:
+L47:
+ dd m_exitcolon
+ CENTRY `within`, c_within, 6
+ dd m_rpush
+ dd m_over
+ dd m_greater
+ dd c_0eq
+ dd m_xswap
+ dd m_rpop
+ dd m_greater
+ dd c_0eq
+ dd m_binand
+ dd m_exitcolon
+ CENTRY `abs`, c_abs, 3
+ dd m_dup
+ dd c_0lt
+ dd m_cjump
+ dd L52
+ dd c_negate
+L52:
+ dd m_exitcolon
+ VENTRY `iobuf`, v_iobuf, 5
+ VENTRY `stdin`, v_stdin, 5
+ VENTRY `stdout`, v_stdout, 6
+ VENTRY `eof`, v_eof, 3
+ CENTRY `key`, c_key, 3
+ dd v_iobuf		; variable iobuf
+ dd m_literal
+ dd 1
+ dd v_stdin		; variable stdin
+ dd m_fetch	; ( iobuf 1 0 -- )
+ dd m_fsread
+ dd c_0eq
+ dd m_cjump
+ dd L78
+ dd v_eof
+ dd c_on
+ dd m_literal
+ dd -1
+ dd m_jump
+ dd L79
+L78:
+ dd v_iobuf
+ dd m_cfetch
+L79:
+ dd m_exitcolon
+ CENTRY `emit`, c_emit, 4	; ( character -- ) TODO correct the below stack notations
+ dd v_iobuf			; variable iobuf
+ dd m_cstore		; variable iobuf has character
+ dd v_iobuf			; variable iobuf
+ dd m_literal
+ dd 1			; ( iobuf 1 -- )
+ dd v_stdout			; variable stdout
+ dd m_fetch		; ( iobuf 1 1 -- )
+ dd m_fswrite		; ( -- ) writes out the character
+ dd m_drop		; the return value of fswrite
+ dd m_exitcolon
+ CENTRY `type`, c_type, 4	; ( addr n -- ) 
+ dd v_stdout			; variable stdout, normally 1
+ dd m_fetch		; ( addr n 1 -- )
+ dd m_fswrite
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `cr`, c_cr, 2
+ dd m_literal
+ dd 10			; ascii value of carriage return
+ dd c_emit			; emit
+ dd m_exitcolon
+ CENTRY `space`, c_space, 5
+ dd c_bl
+ dd c_emit
+ dd m_exitcolon
+ CENTRY `emits`, c_emits, 5
+L85:
+ dd c_qdup
+ dd m_cjump
+ dd L86
+ dd m_over
+ dd c_emit
+ dd c_1minus
+ dd m_jump
+ dd L85
+L86:
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `spaces`, c_spaces, 6
+ dd c_bl
+ dd m_xswap
+ dd c_emits
+ dd m_exitcolon
+ CENTRY `count`, c_count, 5 ; ( a -- a+1 n ) a = counted string
+ dd c_1plus
+ dd m_dup
+ dd c_1minus
+ dd m_cfetch
+ dd m_exitcolon
+ CENTRY `compare`, c_compare, 7 ; ( a1 n1 a2 n2 -- f ) a1 = dictionary entry a2 = word name to search
+ dd c_rot	; ( a1 n1 a2 n2 -- a1 a2 n2 n1 ) 
+ dd c_2dup	; ( -- a1 a2 n2 n1 n2 n1 )
+ dd m_rpush	; ( -- a1 a2 n2 n1 n2 ) (R n1 -- )
+ dd m_rpush	; ( -- a1 a2 n2 n1 ) (R n1 n2 -- )
+ dd c_min	; ( -- a1 a2 nmin ) (R n1 n2 -- )
+ dd m_literal
+ dd 0		; ( -- a1 a2 nmin 0 ) (R n1 n2 -- )
+ dd m_doinit	; ( -- a1 a2 ) (R n1 n2 0 nmin -- )
+L55:
+ dd m_over
+ dd m_i
+ dd m_plus
+ dd m_cfetch
+ dd m_over
+ dd m_i
+ dd m_plus
+ dd m_cfetch
+ dd m_minus
+ dd c_signum
+ dd c_qdup
+ dd m_cjump
+ dd L56
+ dd c_2nip
+ dd m_unloop
+ dd m_unloop
+ dd m_exitcolon
+L56:
+ dd m_doloop
+ dd L55
+ dd c_2drop	; ( a1 a2 -- ) (R n1 n2 -- )
+ dd m_rpop
+ dd m_rpop	; ( n2 n1 -- ) (R -- )
+ dd m_minus	; ( -- n1-n2 )
+ dd c_signum
+ dd m_exitcolon
+ CENTRY `erase`, c_erase, 5
+ dd m_literal
+ dd 0
+ dd m_doinit
+L58:
+ dd m_literal
+ dd 0
+ dd m_over
+ dd m_cstore
+ dd c_1plus
+ dd m_doloop
+ dd L58
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `fill`, c_fill, 4
+ dd m_xswap
+ dd m_literal
+ dd 0
+ dd m_doinit
+L60:
+ dd c_2dup
+ dd m_xswap
+ dd m_i
+ dd m_plus
+ dd m_cstore
+ dd m_doloop
+ dd L60
+ dd c_2drop
+ dd m_exitcolon
+ CENTRY `blank`, c_blank, 5
+ dd c_bl
+ dd c_fill
+ dd m_exitcolon
+ VENTRY `searchlen`, v_searchlen, 9
+ CENTRY `search`, c_search, 6
+ dd v_searchlen
+ dd m_store
+ dd m_xswap
+ dd m_dup
+ dd m_rpush
+ dd v_searchlen
+ dd m_fetch
+ dd m_minus
+ dd c_1plus
+ dd m_literal
+ dd 0
+ dd m_doinit
+L64:
+ dd m_over
+ dd m_i
+ dd m_plus
+ dd m_over
+ dd v_searchlen
+ dd m_fetch
+ dd m_xswap
+ dd v_searchlen
+ dd m_fetch
+ dd c_compare
+ dd c_0eq
+ dd m_cjump
+ dd L65
+ dd m_drop
+ dd m_i
+ dd m_plus
+ dd m_i
+ dd m_unloop
+ dd m_rpop
+ dd m_xswap
+ dd m_minus
+ dd c_true
+ dd m_exitcolon
+L65:
+ dd m_doloop
+ dd L64
+ dd m_drop
+ dd m_rpop
+ dd c_false
+ dd m_exitcolon
+ CENTRY `here`, c_here, 4
+ dd mc_h
+ dd m_fetch
+ dd m_exitcolon
+ CENTRY `,`, c_comma, 1
+ dd c_here
+ dd m_store
+ dd m_literal
+ dd 8
+ dd mc_h
+ dd c_plusstore
+ dd m_exitcolon
+ CENTRY `c,`, c_c, 2
+ dd c_here
+ dd m_cstore
+ dd m_literal
+ dd 1
+ dd mc_h
+ dd c_plusstore
+ dd m_exitcolon
+ CENTRY `allot`, c_allot, 5
+ dd mc_h
+ dd c_plusstore
+ dd m_exitcolon
+ CENTRY `pad`, c_pad, 3
+ dd c_here
+ dd m_literal
+ dd 256
+ dd m_plus
+ dd m_exitcolon
+ CENTRY `align`, c_align, 5
+ dd c_here
+ dd c_aligned
+ dd mc_h
+ dd m_store
+ dd m_exitcolon
+ CENTRY `unused`, c_unused, 6
+ dd mc_heaptop
+ dd m_fetch
+ dd c_here
+ dd m_minus
+ dd m_exitcolon
+ VENTRY `base`, v_base, 4
+ VENTRY `>num`, v_tonum, 4
+ CENTRY `<#`, c_fromhash, 2
+ dd c_pad
+ dd m_literal
+ dd 1024
+ dd m_plus
+ dd v_tonum
+ dd m_store
+ dd m_exitcolon
+ CENTRY `#`, c_hash, 1
+ dd v_base
+ dd m_fetch
+ dd m_uslashmod
+ dd m_xswap
+ dd m_dup
+ dd m_literal
+ dd 9
+ dd m_greater
+ dd m_cjump
+ dd L92
+ dd m_literal
+ dd 97
+ dd m_plus
+ dd m_literal
+ dd 10
+ dd m_minus
+ dd m_jump
+ dd L93
+L92:
+ dd m_literal
+ dd 48
+ dd m_plus
+L93:
+ dd v_tonum
+ dd m_fetch
+ dd c_1minus
+ dd m_dup
+ dd v_tonum
+ dd m_store
+ dd m_cstore
+ dd m_exitcolon
+ CENTRY `#s`, c_hashs, 2
+L95:
+ dd c_hash
+ dd m_dup
+ dd m_cjump
+ dd L96
+ dd m_jump
+ dd L95
+L96:
+ dd m_exitcolon
+ CENTRY `#>`, c_hashfrom, 2
+ dd m_drop
+ dd v_tonum
+ dd m_fetch
+ dd m_dup
+ dd c_pad
+ dd m_literal
+ dd 1024
+ dd m_plus
+ dd m_xswap
+ dd m_minus
+ dd m_exitcolon
+ CENTRY `hold`, c_hold, 4
+ dd v_tonum
+ dd m_fetch
+ dd c_1minus
+ dd m_dup
+ dd m_rpush
+ dd m_cstore
+ dd m_rpop
+ dd v_tonum
+ dd m_store
+ dd m_exitcolon
+ CENTRY `sign`, c_sign, 4
+ dd c_0lt
+ dd m_cjump
+ dd L100
+ dd m_literal
+ dd 45
+ dd c_hold
+L100:
+ dd m_exitcolon
+ CENTRY `.`, c_dot, 1
+ dd m_dup
+ dd c_abs
+ dd c_fromhash
+ dd c_hashs
+ dd m_xswap
+ dd c_sign
+ dd c_hashfrom
+ dd c_type
+ dd c_space
+ dd m_exitcolon
+ CENTRY `.r`, c_dotr, 2
+ dd m_rpush
+ dd m_dup
+ dd c_abs
+ dd c_fromhash
+ dd c_hashs
+ dd m_xswap
+ dd c_sign
+ dd c_hashfrom
+ dd m_rpop
+ dd m_over
+ dd m_minus
+ dd m_literal
+ dd 0
+ dd c_max
+ dd c_spaces
+ dd c_type
+ dd m_exitcolon
+ CENTRY `hex`, c_hex, 3
+ dd m_literal
+ dd 16
+ dd v_base
+ dd m_store
+ dd m_exitcolon
+ CENTRY `decimal`, c_decimal, 7
+ dd m_literal
+ dd 10
+ dd v_base
+ dd m_store
+ dd m_exitcolon
+ CENTRY `digit`, c_digit, 5
+ dd m_dup
+ dd m_literal
+ dd 65
+ dd m_literal
+ dd 91
+ dd c_within
+ dd m_cjump
+ dd L106
+ dd m_literal
+ dd 55
+ dd m_minus
+ dd m_jump
+ dd L107
+L106:
+ dd m_dup
+ dd m_literal
+ dd 97
+ dd m_literal
+ dd 123
+ dd c_within
+ dd m_cjump
+ dd L108
+ dd m_literal
+ dd 87
+ dd m_minus
+ dd m_jump
+ dd L109
+L108:
+ dd m_dup
+ dd m_literal
+ dd 48
+ dd m_literal
+ dd 58
+ dd c_within
+ dd m_cjump
+ dd L110
+ dd m_literal
+ dd 48
+ dd m_minus
+ dd m_jump
+ dd L111
+L110:
+ dd m_drop
+ dd c_false
+ dd m_exitcolon
+L111:
+L109:
+L107:
+ dd m_dup
+ dd v_base
+ dd m_fetch
+ dd m_less
+ dd m_cjump
+ dd L112
+ dd c_true
+ dd m_jump
+ dd L113
+L112:
+ dd m_drop
+ dd c_false
+L113:
+ dd m_exitcolon
+ CENTRY `number`, c_number, 6
+ dd m_xswap
+ dd m_dup
+ dd m_cfetch
+ dd m_literal
+ dd 45
+ dd m_equal
+ dd m_cjump
+ dd L115
+ dd c_1plus
+ dd m_xswap
+ dd c_1minus
+ dd m_literal
+ dd -1
+ dd m_rpush
+ dd m_jump
+ dd L116
+L115:
+ dd m_xswap
+ dd m_literal
+ dd 1
+ dd m_rpush
+L116:
+ dd m_dup
+ dd m_rpush
+ dd m_literal
+ dd 0
+ dd m_xswap
+ dd m_literal
+ dd 0
+ dd m_doinit
+L117:
+ dd v_base
+ dd m_fetch
+ dd m_multiply
+ dd m_over
+ dd m_i
+ dd m_plus
+ dd m_cfetch
+ dd c_digit
+ dd m_cjump
+ dd L118
+ dd m_plus
+ dd m_jump
+ dd L119
+L118:
+ dd m_drop
+ dd m_unloop
+ dd m_rpop
+ dd m_rpop
+ dd m_drop
+ dd c_false
+ dd m_exitcolon
+L119:
+ dd m_doloop
+ dd L117
+ dd m_rpop
+ dd m_drop
+ dd c_nip
+ dd m_rpop
+ dd m_multiply
+ dd c_true
+ dd m_exitcolon
+ VENTRY `>in`, v_toin, 3
+ VENTRY `>limit`, v_tolimit, 6
+ VENTRY `wordbuf`, v_wordbuf, 7
+ VENTRY `abortvec`, v_abortvec, 8
+ VENTRY `findadr`, v_findadr, 7
+ VENTRY `sourcebuf`, v_sourcebuf, 9
+ VENTRY `blk`, v_blk, 3
+ CENTRY `abort`, c_abort, 5
+ dd v_abortvec
+ dd m_fetch
+ dd m_execute
+ dd m_exitcolon
+ CENTRY `source`, c_source, 6
+ dd v_sourcebuf
+ dd m_fetch
+ dd m_exitcolon
+ CENTRY `current-input`, c_current_input, 13
+ dd v_toin
+ dd m_fetch
+ dd c_source
+ dd m_plus
+ dd m_cfetch
+ dd m_exitcolon
+ CENTRY `save-input`, c_save_input, 10
+ dd v_stdin
+ dd m_fetch
+ dd v_toin
+ dd m_fetch
+ dd v_tolimit
+ dd m_fetch
+ dd v_sourcebuf
+ dd m_fetch
+ dd v_blk
+ dd m_fetch
+ dd m_literal
+ dd 5
+ dd m_exitcolon
+ CENTRY `default-input`, c_default_input, 13
+ dd v_stdin
+ dd c_off
+ dd v_toin
+ dd c_off
+ dd v_tolimit
+ dd c_off
+ dd mc_tib
+ dd v_sourcebuf
+ dd m_store
+ dd v_blk
+ dd c_off
+ dd m_exitcolon
+ CENTRY `restore-input`, c_restore_input, 13
+ dd v_eof
+ dd c_off
+ dd m_literal
+ dd 5
+ dd c_neq
+ dd m_cjump
+ dd L133
+ dd c_default_input
+ dd c_false
+ dd m_jump
+ dd L134
+L133:
+ dd v_blk
+ dd m_store
+ dd v_sourcebuf
+ dd m_store
+ dd v_tolimit
+ dd m_store
+ dd v_toin
+ dd m_store
+ dd v_stdin
+ dd m_store
+ dd c_true
+L134:
+ dd m_exitcolon
+ CENTRY `?restore-input`, c_qrestore_input, 14
+ dd c_restore_input
+ dd c_0eq
+ dd m_cjump
+ dd L136
+ dd c_space
+ dd m_literal
+ dd L137
+ dd m_literal
+ dd 23
+ dd c_type
+ dd c_cr
+ dd c_abort
+L136:
+ dd m_exitcolon
+ CENTRY `next-input`, c_next_input, 10
+ dd v_toin
+ dd m_fetch
+ dd v_tolimit
+ dd m_fetch
+ dd m_less
+ dd m_cjump
+ dd L139
+ dd c_true
+ dd c_current_input
+ dd m_jump
+ dd L140
+L139:
+ dd m_literal
+ dd 0
+ dd c_false
+L140:
+ dd m_exitcolon
+ CENTRY `parse`, c_parse, 5
+ dd m_rpush
+ dd v_wordbuf
+ dd m_fetch
+ dd c_1plus
+L142:
+ dd c_next_input
+ dd m_rfetch
+ dd c_neq
+ dd m_binand
+ dd m_cjump
+ dd L143
+ dd c_current_input
+ dd m_over
+ dd m_cstore
+ dd c_1plus
+ dd m_literal
+ dd 1
+ dd v_toin
+ dd c_plusstore
+ dd m_jump
+ dd L142
+L143:
+ dd m_literal
+ dd 1
+ dd v_toin
+ dd c_plusstore
+ dd m_rpop
+ dd m_drop
+ dd v_wordbuf
+ dd m_fetch
+ dd m_dup
+ dd m_rpush
+ dd m_minus
+ dd c_1minus
+ dd m_rfetch
+ dd m_cstore
+ dd m_rpop
+ dd m_exitcolon
+ CENTRY `word`, c_word, 4 ; ( c -- )
+ dd m_rpush	; ( -- ) (R -- c )
+L145:
+ dd c_next_input ; ( -- c2 ) (R c1 -- )
+ dd m_rfetch
+ dd m_equal
+ dd m_binand
+ dd m_cjump
+ dd L146
+ dd m_literal
+ dd 1
+ dd v_toin
+ dd c_plusstore
+ dd m_jump
+ dd L145
+L146:
+ dd m_rpop
+ dd c_parse
+ dd m_exitcolon
+ CENTRY `accept`, c_accept, 6	; ( a n -- ) TODO correct below stack notations
+ dd m_xswap	; ( n a -- )
+ dd m_dup	; ( n a a -- )
+ dd m_rpush
+ dd m_rpush	; ( n -- ) (R a a -- )
+L148:
+ dd c_qdup	; ( n n -- ) (R a a -- )
+ dd m_cjump	; (if)
+ dd L149	; n == 0
+ dd c_key	; n > 0 ( n c -- )
+ dd m_dup	; ( n c c -- )
+ dd m_literal
+ dd 10		; ( n c c 10 -- )
+ dd m_equal	; ( n c f -- )
+ dd m_over	; ( n c f n -- )
+ dd m_literal
+ dd -1		; ( n c f n -1 -- )
+ dd m_equal	; ( n c f1 f2 -- )
+ dd m_binor	; ( n c f -- )
+ dd m_cjump
+ dd L150
+ dd c_2drop	; n == -1 || n == 10 (	-- )
+ dd m_rpop
+ dd m_rpop
+ dd m_minus
+ dd m_exitcolon	; ( 0 -- ) (R -- )
+L150:
+ dd m_rfetch	; ( n c a -- ) (R a a -- )
+ dd m_cstore
+ dd m_rpop	; ( n a -- ) (R a -- )
+ dd c_1plus
+ dd m_rpush	; ( n -- ) (R a1 a2 -- )
+ dd c_1minus	; ( n-1 -- ) (R a1 a2 -- )
+ dd m_jump
+ dd L148
+L149:		; n == 0 ( -- ) (R a a -- )
+ dd m_rpop
+ dd m_rpop	; ( a a -- )
+ dd m_minus	; ( 0 -- )
+ dd m_exitcolon
+ CENTRY `query`, c_query, 5
+ dd v_eof	; variable eof
+ dd c_off	; off sets variable eof = 0
+ dd mc_tib	; constant puts address of tibuffer on the top
+ dd m_literal
+ dd 1024	; ( tibuffer -- tibuffer 1024 )
+ dd c_accept	; ( tibuffer 1024 -- n )
+ dd m_dup
+ dd c_0eq
+ dd v_eof
+ dd m_fetch
+ dd m_binand
+ dd m_cjump
+ dd L152
+ dd m_drop
+ dd c_qrestore_input
+ dd m_jump
+ dd L153
+L152:
+ dd v_tolimit
+ dd m_store
+ dd v_toin
+ dd c_off
+L153:
+ dd m_exitcolon
+ CENTRY `refill`, c_refill, 6
+ dd v_blk
+ dd m_fetch
+ dd m_cjump
+ dd L155
+ dd c_false
+ dd m_jump
+ dd L156
+L155:
+ dd c_query
+ dd c_true
+L156:
+ dd m_exitcolon
+ CENTRY `findname`, c_findname, 8 ; ( a1 -- a2 f ) ; loop through the dictionary names
+ dd v_findadr
+ dd m_store
+ dd mc_dp
+ dd m_fetch	; get dictionary link
+L158:
+ dd c_qdup
+ dd m_cjump
+ dd L159	; seached until the first dictionary entry, get out
+ dd m_dup	; ( a -- a a )
+ dd c_cellplus	; lenth + initial name address
+ dd m_cfetch	; length + initial name
+ dd m_literal
+ dd 64		; max name length?
+ dd m_binand	; keep only the length
+ dd m_cjump
+ dd L160
+ dd m_fetch
+ dd m_jump
+ dd L161
+L160:		; valid length? ( a -- )
+ dd m_dup
+ dd c_cellplus
+ dd c_count	; ( a1 a1+8 -- a1 a1+8+1 n )
+ dd m_literal
+ dd 63
+ dd m_binand	; ( a1 a1+8+1 n 63 -- a1 a1+8+1 n&63 )
+ dd v_findadr
+ dd m_fetch
+ dd c_count	; ( a1 a1+8+1 n&63 a2 n2 -- a1 a1+8+1 n&63 a2+1 n2 )
+ dd c_compare	; ( -- a1 n ) compare dictionary entry with name
+ dd c_0eq	; found a match?
+ dd m_cjump
+ dd L162
+ dd c_cellplus
+ dd c_true
+ dd m_exitcolon
+L162:
+ dd m_fetch
+L161:
+ dd m_jump
+ dd L158
+L159:
+ dd v_findadr
+ dd m_fetch
+ dd c_false
+ dd m_exitcolon
+ CENTRY `find`, c_find, 4 ; ( a1 -- a2 f )?
+ dd c_findname
+ dd m_cjump
+ dd L164
+ dd m_dup
+ dd m_cfetch
+ dd m_xswap
+ dd m_over
+ dd m_literal
+ dd 63
+ dd m_binand
+ dd m_plus
+ dd c_1plus
+ dd c_aligned
+ dd m_xswap
+ dd m_literal
+ dd 128
+ dd m_binand
+ dd m_cjump
+ dd L165
+ dd m_literal
+ dd 1
+ dd m_jump
+ dd L166
+L165:
+ dd m_literal
+ dd -1
+L166:
+ dd m_exitcolon
+ dd m_jump
+ dd L167
+L164:
+ dd c_false
+L167:
+ dd m_exitcolon
+ CENTRY `'`, c_single_quote, 1
+ dd c_bl
+ dd c_word
+ dd c_find
+ dd c_0eq
+ dd m_cjump
+ dd L169
+ dd c_space
+ dd c_count
+ dd c_type
+ dd m_literal
+ dd L170
+ dd m_literal
+ dd 3
+ dd c_type
+ dd c_cr
+ dd c_abort
+L169:
+ dd m_exitcolon
+ CENTRY `?stack`, c_qstack, 6
+ dd m_stackptr
+ dd v_s0
+ dd m_fetch
+ dd m_greater
+ dd m_cjump
+ dd L172
+ dd m_literal
+ dd L173
+ dd m_literal
+ dd 16
+ dd c_type
+ dd c_cr
+ dd c_abort
+L172:
+ dd m_exitcolon
+ CENTRY `interpret`, c_interpret, 9
+L175:
+ dd c_bl
+ dd c_word
+ dd m_dup
+ dd m_cfetch
+ dd c_0neq
+ dd m_cjump
+ dd L176
+ dd c_find	; ( a -- ) a = address of counted string
+ dd m_cjump
+ dd L177
+ dd m_execute
+ dd c_qstack
+ dd m_jump
+ dd L178
+L177:
+ dd c_count
+ dd c_number
+ dd c_0eq
+ dd m_cjump
+ dd L179
+ dd c_space
+ dd c_type
+ dd m_literal
+ dd L180	; error I?
+ dd m_literal
+ dd 3
+ dd c_type
+ dd c_cr
+ dd c_abort
+L179:
+L178:
+ dd m_jump
+ dd L175
+L176:
+ dd m_drop
+ dd m_exitcolon
+ CENTRY `create`, c_create, 6
+ dd c_align
+ dd c_here
+ dd m_rpush
+ dd mc_dp
+ dd m_fetch
+ dd c_comma
+ dd c_bl
+ dd c_word
+ dd m_dup
+ dd m_cfetch
+ dd c_here
+ dd m_xswap
+ dd c_1plus
+ dd m_dup
+ dd m_rpush
+ dd m_cmove
+ dd m_rpop
+ dd c_allot
+ dd c_align
+ dd m_literal
+ dd m_variable
+ dd m_fetch
+ dd c_comma
+ dd m_rpop
+ dd mc_dp
+ dd m_store
+ dd m_exitcolon
+ CENTRY `variable`, c_variable, 8
+ dd c_create
+ dd m_literal
+ dd 0
+ dd c_comma
+ dd m_exitcolon
+ CENTRY `constant`, c_constant, 8
+ dd c_create
+ dd m_literal
+ dd m_constant
+ dd m_fetch
+ dd c_here
+ dd m_literal
+ dd 1
+ dd c_cells
+ dd m_minus
+ dd m_store
+ dd c_comma
+ dd m_exitcolon
+ VENTRY `state`, v_state, 5
+ CENTRY `immediate`, c_immediate, 9
+ dd mc_dp
+ dd m_fetch
+ dd c_cellplus
+ dd m_dup
+ dd m_cfetch
+ dd m_literal
+ dd 128
+ dd m_binor
+ dd m_xswap
+ dd m_cstore
+ dd m_exitcolon
+ CENTRY `>cfa`, c_tocfa, 4
+ dd c_count
+ dd m_literal
+ dd 63
+ dd m_binand
+ dd m_plus
+ dd c_aligned
+ dd m_exitcolon
+ CENTRY `compile`, c_compile, 7
+ dd c_findname
+ dd m_cjump
+ dd L188
+ dd m_dup
+ dd m_cfetch
+ dd m_literal
+ dd 128
+ dd m_binand
+ dd m_cjump
+ dd L189
+ dd c_tocfa	; immediate
+ dd m_execute
+ dd c_qstack
+ dd m_jump
+ dd L190
+L189:
+ dd c_tocfa
+ dd c_comma
+L190:
+ dd m_jump
+ dd L191
+L188:
+ dd c_count
+ dd c_number
+ dd c_0eq
+ dd m_cjump
+ dd L192
+ dd c_space
+ dd c_type
+ dd m_literal
+ dd L193
+ dd m_literal
+ dd 3
+ dd c_type
+ dd c_cr
+ dd c_abort
+ dd m_jump
+ dd L194
+L192:
+ dd m_literal
+ dd m_literal
+ dd c_comma
+ dd c_comma
+L194:
+L191:
+ dd m_exitcolon
+ CENTRY `]`, c_close_bracket, 1
+ dd v_state
+ dd c_on
+L196:
+ dd c_bl
+ dd c_word
+ dd m_dup
+ dd m_cfetch
+ dd c_0eq
+ dd m_cjump
+ dd L197
+ dd m_drop
+ dd c_refill
+ dd m_jump
+ dd L198
+L197:
+ dd c_compile
+ dd v_state
+ dd m_fetch
+L198:
+ dd m_cjump
+ dd L199
+ dd m_jump
+ dd L196
+L199:
+ dd m_exitcolon
+ CIENTRY `[`, ci_open_bracket, 1
+ dd v_state
+ dd c_off
+ dd m_exitcolon
+ CENTRY `smudge`, c_smudge, 6
+ dd mc_dp
+ dd m_fetch
+ dd c_cellplus
+ dd m_dup
+ dd m_cfetch
+ dd m_literal
+ dd 64
+ dd m_binor
+ dd m_xswap
+ dd m_cstore
+ dd m_exitcolon
+ CENTRY `reveal`, c_reveal, 6
+ dd mc_dp
+ dd m_fetch
+ dd c_cellplus
+ dd m_dup
+ dd m_cfetch
+ dd m_literal
+ dd 64
+ dd c_invert
+ dd m_binand
+ dd m_xswap
+ dd m_cstore
+ dd m_exitcolon
+ CENTRY `:`, c_colon, 1
+ dd c_create
+ dd c_smudge
+ dd m_literal
+ dd m_colon
+ dd m_fetch
+ dd c_here
+ dd m_literal
+ dd 1
+ dd c_cells
+ dd m_minus
+ dd m_store
+ dd c_close_bracket
+ dd m_exitcolon
+ CIENTRY `;`, ci_semicolon, 1
+ dd m_literal
+ dd m_exitcolon
+ dd c_comma
+ dd v_state
+ dd c_off
+ dd c_reveal
+ dd m_exitcolon
+ CIENTRY `recurse`, ci_recurse, 7
+ dd mc_dp
+ dd m_fetch
+ dd c_cellplus
+ dd c_tocfa
+ dd c_comma
+ dd m_exitcolon
+ CENTRY `char`, L206, 4
+ dd c_bl
+ dd c_word
+ dd c_1plus
+ dd m_cfetch
+ dd m_exitcolon
+ CENTRY `literal`, c_literal, 7
+ dd m_literal
+ dd m_literal
+ dd c_comma
+ dd c_comma
+ dd m_exitcolon
+ CENTRY `sliteral`, c_sliteral, 8
+ dd m_literal
+ dd m_sliteral
+ dd c_comma
+ dd c_here
+ dd m_literal
+ dd 34
+ dd c_parse
+ dd m_dup
+ dd m_cfetch
+ dd c_1plus
+ dd m_rpush
+ dd m_xswap
+ dd m_rfetch
+ dd m_cmove
+ dd m_rpop
+ dd c_allot
+ dd c_align
+ dd m_exitcolon
+ CENTRY `string`, c_string, 6
+ dd c_word
+ dd m_dup
+ dd m_cfetch
+ dd c_1plus
+ dd m_rpush
+ dd c_here
+ dd m_rfetch
+ dd m_cmove
+ dd m_rpop
+ dd c_allot
+ dd m_exitcolon
+ CIENTRY `[char]`, ci_char_brackets, 6
+ dd c_bl
+ dd c_word
+ dd c_1plus
+ dd m_cfetch
+ dd c_literal
+ dd m_exitcolon
+ CIENTRY `[']`, ci_quote_brackets, 3
+ dd c_single_quote
+ dd c_literal
+ dd m_exitcolon
+ CIENTRY `(`, ci_openparen, 1
+ dd m_literal
+ dd 41
+ dd c_parse
+ dd m_drop
+ dd m_exitcolon
+ CIENTRY `\`, ci_backslash, 1
+ dd v_blk
+ dd m_fetch
+ dd m_cjump
+ dd L214
+ dd v_toin
+ dd m_fetch
+ dd m_literal
+ dd 63
+ dd m_plus
+ dd m_literal
+ dd 63
+ dd c_invert
+ dd m_binand
+ dd v_toin
+ dd m_store
+ dd m_jump
+ dd L215
+L214:
+ dd v_tolimit
+ dd m_fetch
+ dd v_toin
+ dd m_store
+L215:
+ dd m_exitcolon
+ CENTRY `(?abort)`, c_qabort_parens, 8
+ dd v_state
+ dd m_cjump
+ dd L217
+ dd c_space
+ dd c_type
+ dd c_cr
+ dd c_abort
+ dd m_jump
+ dd L218
+L217:
+ dd c_2drop
+L218:
+ dd m_exitcolon
+ CIENTRY `abort"`, ci_abort_double_quote, 6
+ dd c_sliteral
+ dd m_literal
+ dd c_qabort_parens
+ dd c_comma
+ dd m_exitcolon
+ CENTRY `"`, c_double_quote, 1
+ dd m_literal
+ dd 34
+ dd c_word
+ dd c_count
+ dd m_rpush
+ dd c_here
+ dd m_rfetch
+ dd m_cmove
+ dd c_here
+ dd m_rpop
+ dd m_dup
+ dd c_allot
+ dd m_exitcolon
+ CENTRY `c"`, c_cdouble_quote, 2
+ dd m_literal
+ dd 34
+ dd c_word
+ dd m_dup
+ dd m_cfetch
+ dd c_1plus
+ dd m_rpush
+ dd c_here
+ dd m_rfetch
+ dd m_cmove
+ dd c_here
+ dd m_rpop
+ dd c_allot
+ dd m_exitcolon
+ CIENTRY `s"`, ci_sdouble_quote, 2
+ dd c_sliteral
+ dd m_exitcolon
+ CIENTRY `."`, ci_dotstr, 2
+ dd c_sliteral
+ dd m_literal
+ dd c_type
+ dd c_comma
+ dd m_exitcolon
+ CIENTRY `if`, ci_if, 2
+ dd m_literal
+ dd m_cjump
+ dd c_comma
+ dd c_here
+ dd m_literal
+ dd 0
+ dd c_comma
+ dd m_exitcolon
+ CIENTRY `else`, ci_else, 4
+ dd m_literal
+ dd m_jump
+ dd c_comma
+ dd c_here
+ dd m_rpush
+ dd m_literal
+ dd 0
+ dd c_comma
+ dd c_here
+ dd m_xswap
+ dd m_store
+ dd m_rpop
+ dd m_exitcolon
+ CIENTRY `then`, ci_then, 4
+ dd c_here
+ dd m_xswap
+ dd m_store
+ dd m_exitcolon
+ CIENTRY `begin`, ci_begin, 5
+ dd c_here
+ dd m_exitcolon
+ CIENTRY `again`, ci_again, 5
+ dd m_literal
+ dd m_jump
+ dd c_comma
+ dd c_comma
+ dd m_exitcolon
+ CIENTRY `until`, ci_until, 5
+ dd m_literal
+ dd m_cjump
+ dd c_comma
+ dd c_comma
+ dd m_exitcolon
+ CIENTRY `while`, ci_while, 5
+ dd m_literal
+ dd m_cjump
+ dd c_comma
+ dd c_here
+ dd m_literal
+ dd 0
+ dd c_comma
+ dd m_exitcolon
+ CIENTRY `repeat`, ci_repeat, 6
+ dd m_literal
+ dd m_jump
+ dd c_comma
+ dd m_xswap
+ dd c_comma
+ dd c_here
+ dd m_xswap
+ dd m_store
+ dd m_exitcolon
+ CIENTRY `do`, ci_do, 2
+ dd m_literal
+ dd m_doinit
+ dd c_comma
+ dd m_literal
+ dd 0
+ dd c_here
+ dd m_exitcolon
+ CIENTRY `loop`, ci_loop, 4
+ dd m_literal
+ dd m_doloop
+ dd c_comma
+ dd c_comma
+ dd c_qdup
+ dd m_cjump
+ dd L234
+ dd c_here
+ dd m_xswap
+ dd m_store
+L234:
+ dd m_exitcolon
+ CIENTRY `+loop`, ci_ploop, 5
+ dd m_literal
+ dd m_doploop
+ dd c_comma
+ dd c_comma
+ dd c_qdup
+ dd m_cjump
+ dd L236
+ dd c_here
+ dd m_xswap
+ dd m_store
+L236:
+ dd m_exitcolon
+ CENTRY `w/o`, c_wo, 3
+ dd m_literal
+ dd 1
+ dd m_literal
+ dd 512
+ dd m_binor
+ dd m_literal
+ dd 64
+ dd m_binor
+ dd m_exitcolon
+ CENTRY `r/o`, c_ro, 3
+ dd m_literal
+ dd 0
+ dd m_exitcolon
+ CENTRY `r/w`, c_rw, 3
+ dd m_literal
+ dd 2
+ dd m_exitcolon
+ CENTRY `open-file`, c_open_file, 9
+ dd m_rpush
+ dd c_pad
+ dd m_literal
+ dd 1024
+ dd m_plus
+ dd m_xswap
+ dd m_dup
+ dd m_rpush
+ dd m_cmove
+ dd m_literal
+ dd 0
+ dd m_rpop
+ dd c_pad
+ dd m_plus
+ dd m_literal
+ dd 1024
+ dd m_plus
+ dd m_cstore
+ dd c_pad
+ dd m_literal
+ dd 1024
+ dd m_plus
+ dd m_rpop
+ dd m_literal
+ dd 420
+ dd m_fsopen
+ dd m_dup
+ dd m_literal
+ dd -1
+ dd m_greater
+ dd m_exitcolon
+ CENTRY `close-file`, c_close_file, 10
+ dd m_fsclose
+ dd c_0eq
+ dd m_exitcolon
+ CENTRY `read-file`, c_read_file, 9
+ dd m_fsread
+ dd m_dup
+ dd m_literal
+ dd -1
+ dd c_neq
+ dd m_exitcolon
+ CENTRY `write-file`, c_write_file, 10
+ dd m_fswrite
+ dd m_literal
+ dd -1
+ dd c_neq
+ dd m_exitcolon
+ CENTRY `reposition-file`, c_reposition_file, 15
+ dd m_fsseek
+ dd m_literal
+ dd -1
+ dd c_neq
+ dd m_exitcolon
+ CENTRY `?fcheck`, c_qfcheck, 7
+ dd c_0eq
+ dd m_cjump
+ dd L246
+ dd c_space
+ dd m_literal
+ dd L247
+ dd m_literal
+ dd 9
+ dd c_type
+ dd c_cr
+ dd m_errstr
+ dd c_abort
+L246:
+ dd m_exitcolon
+ CENTRY `bye`, c_bye, 3
+ dd m_literal
+ dd 0
+ dd m_terminate
+ dd m_exitcolon
+ CENTRY `include`, c_include, 7
+ dd c_bl
+ dd c_word
+ dd m_rpush
+ dd v_tolimit
+ dd m_fetch
+ dd v_toin
+ dd m_store
+ dd c_save_input
+ dd m_rpop
+ dd c_count
+ dd c_ro
+ dd c_open_file
+ dd c_qfcheck
+ dd v_stdin
+ dd m_store
+ dd m_exitcolon
+ CENTRY `crash`, c_crash, 5
+ dd m_literal
+ dd L251
+ dd m_literal
+ dd 30
+ dd c_type
+ dd c_cr
+ dd c_abort
+ dd m_exitcolon
+ CENTRY `quit`, c_quit, 4 ; TODO correct below stack notations
+ dd m_reset ; initialize return stack
+ dd m_clear	; SP = sstack_end, initialize data stack
+L253:
+ dd c_query
+ dd c_interpret
+ dd v_stdin
+ dd m_fetch	; ( 0 -- )
+ dd c_0eq
+ dd m_cjump
+ dd L254
+ dd m_literal
+ dd L255	; address of string ok
+ dd m_literal
+ dd 3
+ dd c_type	; ( addr n -- ) type 
+ dd c_cr	; cr
+L254:
+ dd m_jump
+ dd L253
+ dd m_exitcolon
+ CENTRY `(abort)`, c_parenabort, 7 ; TODO correct below stack notations
+ dd v_state	; ( v_state -- )
+ dd c_off		; off sets variable state = 0
+ dd mc_tib	; constant puts address of tibuffer on the top of stack
+ dd v_sourcebuf	; variable sourcebuf
+ dd m_store	; variable sourcebuf = address of tibuffer
+ dd v_blk	; variable blk
+ dd c_off		; off variable blk = 0
+ dd v_stdin		; variable stdin
+ dd c_off		; off variable stdin = 0
+ dd m_literal
+ dd 1		; ( 1 -- )
+ dd v_stdout		; variable stdout
+ dd m_store	; variable stdout = 1
+ dd c_quit	; quit resets return stack and data stack
+ dd m_exitcolon
+ CENTRY `oldboot`, c_oldboot, 7 ; TODO correct below stack notations
+ dd m_reset
+ dd m_clear	; SP = sstack_end
+ dd m_stackptr	; (D -- FFEND)
+ dd v_s0
+ dd m_store	; s0 = FFEND
+ dd mc_heaptop	; heaptop = heapend
+ dd m_fetch	; ( heapend -- )
+ dd m_literal
+ dd 1		; ( heapend 1 -- )
+ dd c_cells	; cells ( heapend 8 -- ) 
+ dd m_minus	; ( heapend-8 -- )
+ dd m_fetch	; ( contents_from_heapend-8 -- )
+ dd v_args	; variable args
+ dd m_store	; args = contents_from_heapend-8
+ dd m_literal
+ dd c_parenabort ; ( (abort) -- )
+ dd v_abortvec	; variable abortvec
+ dd m_store	; variable abortvec = (abort) code address
+ dd mc_wordb	; constant puts address of wordbuffer on the top of stack
+ dd v_wordbuf	; variable wordbuf
+ dd m_store	; variable wordbuf = address of wordbuffer
+ dd mc_tib	; constant puts address of tibuffer on the top of stack
+ dd v_sourcebuf	; variable sourcebuf
+ dd m_store	; variable sourcebuf = address of tibuffer
+ dd m_literal
+ dd 0
+ dd v_stdin
+ dd m_store	; stdin = 0
+ dd m_literal
+ dd 1
+ dd v_stdout
+ dd m_store	; stdout = 1
+ dd v_state
+ dd c_off	; off stores 0 at state
+ dd c_decimal	; decimal setting base = 0
+ dd c_quit	; quit
+ dd m_exitcolon
+ CENTRY `boot`, c_boot, 4
+ dd m_reset ; initialize return stack
+ dd m_clear	; SP = sstack_end, initialize data stack
+ dd m_stackptr	; ( -- FFEND)
+ dd v_s0
+ dd m_store	; s0 = FFEND
+			; no args
+ dd m_literal
+ dd c_parenabort ; ( (abort) -- )
+ dd v_abortvec	; variable abortvec
+ dd m_store	; variable abortvec = (abort) code address
+ dd mc_wordb	; constant puts address of wordbuffer on the top of stack
+ dd v_wordbuf	; variable wordbuf
+ dd m_store	; variable wordbuf = address of wordbuffer
+ dd mc_tib	; constant puts address of tibuffer on the top of stack
+ dd v_sourcebuf	; variable sourcebuf
+ dd m_store	; variable sourcebuf = address of tibuffer
+			; no stdin or stdout
+ dd v_state
+ dd c_off	; off stores 0 at state
+ dd c_decimal	; decimal setting base = 0
+ dd c_quit	; quit
+ dd m_exitcolon
+L137:
+ db 'unable to restore input'
+L170:
+ db ' Q?'
+L173:
+ db ' stack underflow'
+L180:
+ db ' I?'
+L193:
+ db ' C?'
+L247:
+ db 'I/O error'
+L251:
+ db 'uninitialized execution vector'
+L255:
+ db ' ok'
--- /dev/null
+++ b/os/pc64/words.awk
@@ -1,0 +1,165 @@
+#!/bin/awk -f
+
+# rc script to build amd64 9front forth words from words-nasm.s
+#	./words words-nassm.s
+# watch -e 'words.awk' 'head words-nasm.s | ./words.awk'
+
+BEGIN{
+	FS=", [ \t]*|[ \t]+"
+	last=""
+	nlines=0
+	addr=""
+	strlabel["L137:"] = 1
+	strlabel["L170:"] = 1
+	strlabel["L173:"] = 1
+	strlabel["L180:"] = 1
+	strlabel["L193:"] = 1
+	strlabel["L247:"] = 1
+	strlabel["L251:"] = 1
+	strlabel["L255:"] = 1
+}
+{
+	lines[++nlines]=sprintf("/* %s */\n", $0);
+}
+function writelast(typ, label, last){
+	if(last == "")
+		lines[++nlines]=sprintf("DATA	%s_%s(SB)/8, LAST\n", typ, label);
+	else
+		lines[++nlines]=sprintf("DATA	%s_%s(SB)/8, $%s\n", typ, label, last);
+}
+$2 == "CENTRY" {
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+	}
+	gsub(/`/,"", $3)
+	name = $3
+	label = $4
+	tot = 0
+	writelast("centry", label, last)
+	last=sprintf("centry_%s(SB)", label);
+	lines[++nlines]=sprintf("DATA	centry_%s+8(SB)/1, $%d\n", label, length(name));
+	for(i=1; i<=length(name); i++){
+		lines[++nlines]=sprintf("DATA	centry_%s+%d(SB)/1, $'%c'\n", label, 8+i, substr(name,i,1));
+	}
+	tot = 8+i;
+	# for alignment
+	if(tot%8 > 0)
+		tot += 8-(tot%8);
+	lines[++nlines]=sprintf("DATA	centry_%s+%d(SB)/8, $colon(SB)\n", label, tot);
+	lines[++nlines]=sprintf("#define	%s(SB) centry_%s+%d(SB)\n", label, label, tot);
+	tot += 8
+	addrlabel = sprintf("centry_%s", label)
+}
+$2 == "CIENTRY" {
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+	}
+	gsub(/`/,"", $3)
+	name = $3
+	label = $4
+	tot = 0
+	writelast("cientry", label, last)
+	last=sprintf("cientry_%s(SB)", label);
+	lines[++nlines]=sprintf("DATA	cientry_%s+8(SB)/1, $%d\n", label, length(name)+128);
+	if(name == "\\"){
+		lines[++nlines]=sprintf("DATA	cientry_%s+%d(SB)/1, $92\n", label, 8+1);
+	} else
+		for(i=1; i<=length(name); i++){
+			lines[++nlines]=sprintf("DATA	cientry_%s+%d(SB)/1, $'%c'\n", label, 8+i, substr(name,i,1));
+		}
+	tot = 8+i;
+	# for alignment
+	if(tot%8 > 0)
+		tot += 8-(tot%8);
+	lines[++nlines]=sprintf("DATA	cientry_%s+%d(SB)/8, $colon(SB)\n", label, tot);
+	lines[++nlines]=sprintf("#define	%s(SB) cientry_%s+%d(SB)\n", label, label, tot);
+	tot += 8
+	addrlabel = sprintf("cientry_%s", label)
+}
+$2 == "VENTRY" {
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+	}
+	gsub(/`/,"", $3)
+	name = $3
+	label = $4
+	tot = 0
+	writelast("ventry", label, last)
+	last=sprintf("ventry_%s(SB)", label);
+	lines[++nlines]=sprintf("DATA	ventry_%s+8(SB)/1, $%d\n", label, length(name));
+	for(i=1; i<=length(name); i++){
+		lines[++nlines]=sprintf("DATA	ventry_%s+%d(SB)/1, $'%c'\n", label, 8+i, substr(name,i,1));
+	}
+	tot = 8+i;
+	# for alignment
+	if(tot%8 > 0)
+		tot += 8-(tot%8);
+	lines[++nlines]=sprintf("DATA	ventry_%s+%d(SB)/8, $variable(SB)\n", label, tot);
+	lines[++nlines]=sprintf("#define	%s(SB) ventry_%s+%d(SB)\n", label, label, tot);
+	tot += 8;
+	lines[++nlines]=sprintf("DATA	ventry_%s+%d(SB)/8, $0\n", label, tot);
+	tot += 8;
+	addrlabel = sprintf("ventry_%s", label)
+}
+$1 ~ /:$/ && $1 in strlabel {
+	if(label != ""){
+		if(last != ""){
+			lines[++nlines]=sprintf("GLOBL	%s, $%d\n", last, tot);
+			lines[++nlines]=sprintf("#undef	LAST\n");
+			lines[++nlines]=sprintf("#define	LAST $%s\n", last);
+		}
+		else
+			lines[++nlines]=sprintf("GLOBL	%s(SB), $%d\n", addrlabel, tot);
+
+	}
+	gsub(/:/,"", $1)
+	name = $3
+	label = $1
+	tot = 0
+	last="" #sprintf("$%s(SB)", label);
+	addrlabel = sprintf("%s", label)
+}
+$2 == "db" {
+	start = index($0,"'")+1
+	str = substr($0,start,length($0)-start)
+	#printf("str length %d %d: %s\n", length(str), index($0,"'"), str);
+	for(i=1; i<=length(str); i++){
+		lines[++nlines]=sprintf("DATA	%s+%d(SB)/1, $'%c'\n", addrlabel, i-1, substr(str,i,1));
+	}
+	tot = i-1
+}
+$2 == "dd" {
+	if($3 ~ /^[-0-9]+$/)
+		lines[++nlines]=sprintf("DATA	%s+%d(SB)/8, $%s\n", addrlabel, tot, $3);
+	else if($3 ~ /^L[0-9]+$/)
+		lines[++nlines]=sprintf("DATA	%s+%d(SB)/8, $%s(SB)\n", addrlabel, tot, $3);
+	else
+		lines[++nlines]=sprintf("DATA	%s+%d(SB)/8, $%s(SB)\n", addrlabel, tot, $3);
+	tot += 8
+	#addr = sprintf("$centry_%s+%d(SB)", label, tot)
+}
+$1 ~ /:$/ && !($1 in strlabel) {
+	l=$1
+	gsub(/:$/,"",l)
+	# for not printing out the labels while still developing the program
+	#	to only print the unprocessed lines
+	#lines[++nlines] = ""
+	printf("#define	%s(SB) %s+%d(SB)\n", l, addrlabel, tot);
+}
+{
+#	if(done == nlines){
+#		print $0
+#	}
+#	for(i = done+1; i <= nlines; i++){
+#		printf("%s", lines[i])
+#	}
+#	done=nlines	
+}
+END{
+	if(label != ""){
+		lines[++nlines]=sprintf("GLOBL	%s(SB), $%d\n", addrlabel, tot);
+	}
+	for(i = 1; i <= nlines; i++){
+		printf("%s", lines[i])
+	}	
+}