1 Warning, the examples with variables in this log are
2 all wrong. This update explains:
3
4 !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!!
5 ! In log19.txt, I realize that my variable !
6 ! handling is wrong. Variables should leave !
7 ! their addresses on the stack, not their !
8 ! values! We need FETCH to get the value from !
9 ! the address! !
10 !!!!!!!!!!!!!!!!!!!! Update !!!!!!!!!!!!!!!!!!!!
11
12 Now I've ported the primitive memory words.
13 Actually, I'd already done FETCH ('@') because it was
14 required by INTERPRET.
15
16 ! store value at address
17 @ get value from address
18 +! add value to value at address
19 -! subtract value from value at address
20 C! store byte
21 C@ fetch byte
22 C@C! copy 1 byte from source addr to dest addr
23 CMOVE copy n bytes from source addr to dest addr
24
25 So far, it's been easy to figure out how to test new
26 words as I add them. But these memory primitives aren't
27 so obvious because how do I know where I can read/write
28 memory?
29
30 The VARIABLE word which creates new variables won't be
31 defined until the second half of JonesFORTH runs...and
32 that's defined in FORTH, not asm!
33
34 Thankfully, we have some existing variables which should
35 be helpful:
36
37 STATE compiling (1) or executing (0)
38 LATEST Points to the most recently defined word
39 HERE Points to the next free byte of memory
40 S0 The address of the top of the parameter stack
41 BASE The current base for printing and reading numbers
42
43 So, on with the testing, starting with storing and fetching
44 from HERE.
45
46 HERE .
47 134537216
48 5 HERE !
49 HERE @ .
50 5
51 HERE @ HERE @ . .
52 55
53
54 Now the in-place addition and subtraction.
55
56 1 HERE +! HERE @ .
57 6
58 2 HERE -! HERE @ .
59 4
60
61 For the byte-wise operators, I'll set the
62 native-sized 4 bytes to all 1s, then it'll be
63 clear if we're just storing/fetching the lower
64 byte.
65
66 0 INVERT HERE ! HERE @ .
67 65535
68 0 HERE C! HERE @ .
69 65280
70 HERE C@ .
71 0
72
73 Now to copy a byte from memory to another
74 memory location, let's get an interesting
75 byte - the 'L' from 'LATEST' in the name
76 portion of the word definition:
77
78 LATEST .
79 134522384
80 LATEST 5 + C@ EMIT
81 L
82 LATEST 5 + HERE C@C!
83 HERE @ .
84 65356
85 HERE C@ EMIT
86 L
87
88 That's neat, but we can do one better by
89 copying the entire string. I'll reformat
90 the responses to make it even clearer:
91
92 LATEST 5 + HERE 6 CMOVE
93 HERE 0 + @ EMIT L
94 HERE 1 + @ EMIT A
95 HERE 2 + @ EMIT T
96 HERE 3 + @ EMIT E
97 HERE 4 + @ EMIT S
98 HERE 5 + @ EMIT T
99
100 Neat!
101
102 Next are return stack manipulation words. Forth
103 is surely unique in inviting programmers to monkey
104 about with the return stack for storing temporary
105 values or perform other clever tricks.
106
107 >R move value from param stack to return stack
108 R> move value from return stack to param stack
109 RSP@ get the actual address RSP points to
110 RSP! set the address RSP points to
111 RDROP move RSP to "pop" value and throw it away
112
113 According to Leo Brodie's Starting Forth, storing stuff
114 on the return stack should be safe to use when defining
115 a word. Outside of that, it'll likely cause a crash.
116
117 : store-add >R + R> ;
118 1 2 3 store-add . .
119 33
120
121 That works. Stows the 3 from the param stack on the return
122 stack, adds the 1 and 2 from the param stack and puts the
123 resulting 3 onto the param stack, restores the 3 from the
124 return stack back to the param stack.
125
126 We can look at the address of the return stack pointer (RSP).
127 Which is currently equal to the top of the return stack
128 memory address, stored in constant R0:
129
130 RSP@ .
131 134530680
132 R0 .
133 134530680
134
135 This isn't a very good demonstration of setting RSP since
136 I'm setting it to the existing value:
137
138 RSP@ RSP!
139
140 Now let's see if we can "drop" the value on the return
141 stack:
142
143 RSP@ @ .
144 0
145 5 >R
146 RSP@ @ .
147 5
148 RDROP
149 RSP@ @ .
150 0
151
152 Yup!
153
154 Like the return stack, we can mess directly with the param
155 stack with two words:
156
157 DSP@ - fetch address of param ("data") stack pointer
158 DSP! - set address of param stack pointer
159
160 Let's view the DSP address:
161
162 DSP@ .
163 3221223824
164
165 And it should go lower when we push a value because it
166 grows "upward":
167
168 55
169 DSP@ .
170
171 We can view the value on the stack by fetching it from
172 the address:
173
174 3221223820
175 DSP@ @ .
176 55
177
178 Let's put another value on the stack. DSP will get lower.
179 And we can view the new value:
180
181 77
182 DSP@ .
183 3221223816
184 DSP@ @ .
185 77
186
187 Let's try setting DSP "back" to a higher address to point
188 to and view the previous value again:
189
190 DSP@ 4 + DSP!
191 DSP@ .
192 3221223820
193 DSP@ @ .
194 55
195
196 Neat!