This repository has been archived by the owner on Sep 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdesign-notes.txt
165 lines (135 loc) · 6.23 KB
/
design-notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
***********************************************************
* Meow5 Design Notes *
***********************************************************
Just some quick notes to self for now - just trying not
to forget what I woke up with in my head!
===========================================================
DONE: write header AFTER the word (to make it dirt-simple
to calc length of machine instructions and write it there)
DONE: use linked list like i learned how to implement in
jonesforth
===========================================================
STARTED: Add a regression test suite to test all
functionality as I add it (probably best added after I make
this take input from STDIN!)
===========================================================
Display free memory and bytes compiled so far - on start up
and/or on demand.
===========================================================
DONE: get as quickly as possible to
: meow5 meow meow meow meow meow ;
first compound word after meow5 could be:
: exit0 0 exit ;
===========================================================
Idea: Add description/usage instructions strings to word
'tails' so they can be read (maybe even searched?) while in
the interpreter. A totally easy feature that wouldn't have
made sense on the old memory-started machines of the late
1960s. I'm thinking that some stack annotations could be
semi-automated, too. Well, there is a ton of low-hanging
usability fruit once you go down this avenue. Gotta stick
with the minimum viable PoC for now...would be so easy to
get wrapped up in shaving those yaks and choosing juuuuuust
the right colors for that bike shed...
Also consider automatically generating the "stack effect"
comments that explain the input and output params on the
stack.
(*Also* consider (optionally) enforcing them!)
===========================================================
DONE/YES: A rule: COMPILE mode words can _only_ be
defined via 'colon' OR composed entirely of machine code
with no CALLWORD macros?
===========================================================
DONE: Challenge: how to have dictionary words that can be
called in meow5 itself to form the basis of the language
(specifically, 'find', 'inline', etc.)? The "tails" that
make them words make them not function as good assembly
citizens.
Right now, I've got a temporary variable in BSS that
functions as a single return address for these words.
What I think I might need to do is make a macro that detects
that a return is requested and then does it.
DONE: Yup, went with this idea: OR have two labels at the
end of those words - one that is the end when you
inline/compile it as a word and the 'tail' label. The length
of the word would be considered the instructions before the
"return" jump mechanism. So when inlined, it wouldn't even
check for a jump, it would just flow on through to the next
word.
DONE: And I think i'll probably need to have a mini-stack
for return addresses in this tiny subset of
words-that-can-be-called-like-functions. Just a handful of
nested calls (i'm not going to use recursion or anything
like that):
return_stack: resb 32
return_stack_pointer: resb 4
Something like that.
NOTE: Turns out, an "inline all the things!" language can't
have nested calls anyway (kinda obvious in retrospect) so
I'm removing the return stack and replacing it with my
original single return address. This is only used in
immediate mode to return from a single word's immidate
exection.
===========================================================
Display machine code (at least) and all 'tail' meta-info
about a word (or all words), maybe even with some nice
ansi color coding. I wanna make this look pretty so much,
but I know I've gotta hold off on the curtains and carpet
and get the walls and floors built first..
===========================================================
DONE: have explicit interpret-time vs comp-time context
words.
Regular interpret-time:
: foo 1 2 add ;
Compile-time:
:comp if ... ;
And when searching, we can skip any words that don't
match:
* name length
* name
* context (compile or interpret)
Which ALSO means that we can define two different words
with the same name for compile/run (or interp/comp) time
===========================================================
DONE: Use stack for all word param passing - don't
get fancy with trying to keep track of registers
with this proof of concept!!!
===========================================================
How hard is it to write an elf executable? it would
be super cool to be able to write any compiled word
straight to disk as a tiny, self-contained executable!
Especially when done right from the interpreter REPL.
I bet not many languages have *that* feature! (I don't
know of any).
===========================================================
Done? As long as we have free space for them, strings have a
place in memory now...
Challenge: Programs are built up by concatenating words
togeher, so by definition, everything a top-level word needs
is guaranteed to be contained in that word (if we wanted to
write it out as a stand-alone executable.) But how do we
reference data like strings? And variables/constants?
How do other compiling Forths handle that, for that matter?
Do they write out every word in the dictionary? And is the
outer interpreter always included???
===========================================================
Register Usage
Typical usage notes (JF = JONESFORTH)
EAX: The accumulator/return val
EBX: often for pointers
ECX: often for counters
EDX: whatever
ESI: The source index for string operations.
JF used ESI for NEXT word address pointer
EDI: The destination index for string operations.
EBP: pointer to current fn stack frame base
JF used EBP as Return stack pointer ("RSP")
ESP: pointer to current fn stack frame top
JF used the stack as THE parameter stack
EIP: instruction pointer!
===========================================================
DONE: Hmmm... as much as possible, I'll use the stack and
other in-memory pointers to avoid having to think about
explicit registers as much as possible. Certainly some
of the ones needed for a traditional "threaded interpreted"
Forth won't be needed for Meow5!