1 |
3 |
atypic |
;; needed variables (registers) for gc
|
2 |
|
|
|
3 |
|
|
;; register values that must be predefined
|
4 |
|
|
;; set these when testing gc standalone in emulator
|
5 |
|
|
(defreg gc-maxblocks #x70) ;; total memory size
|
6 |
|
|
(defreg gc-spaces #x71) ;; number of spaces we'll divide the memory in
|
7 |
|
|
(defreg gc-startofmem #x76) ;; start of variable address space
|
8 |
|
|
|
9 |
|
|
;; registers set by evaluator before invoking gc
|
10 |
|
|
;; set these when testing gc standalone in emulator
|
11 |
|
|
(defreg gc-rootptr #x78) ;; pointer to topmost object! hopefully
|
12 |
|
|
;; there will be only one
|
13 |
|
|
|
14 |
|
|
;; registers set by init, keep these throughout
|
15 |
|
|
(defreg gc-spacesize #x72) ;; size of each space: maxblocks / spaces
|
16 |
|
|
(defreg gc-sup #x73) ;; first address beyond legal space:
|
17 |
|
|
;; spaces * spacesize (NB: can be lower than
|
18 |
|
|
;; maxblocks)
|
19 |
|
|
(defreg gc-gcspace #x74) ;; start of gc exclusize space, sup - spacesize
|
20 |
|
|
|
21 |
|
|
;; registers used by everyone
|
22 |
|
|
(defreg gc-firstfree #x75) ;; first free memory block
|
23 |
|
|
;; (might exist already in other microcode)
|
24 |
|
|
|
25 |
|
|
;; scratch registers, can be used when gc is not running (but gc will
|
26 |
|
|
;; destroy them)
|
27 |
|
|
|
28 |
|
|
(defreg gc-1 #x80) ;; temp
|
29 |
|
|
(defreg gc-vi #x83)
|
30 |
|
|
(defreg gc-t #x84) ;; ptr-rev
|
31 |
|
|
(defreg gc-x #x85) ;; ptr-rev
|
32 |
|
|
(defreg gc-y #x86) ;; ptr-rev
|
33 |
|
|
(defreg gc-v #x87) ;; ptr-rev
|
34 |
|
|
(defreg gc-followp #x88) ;; ptr-rev
|
35 |
|
|
(defreg gc-cannext #x89) ;; ptr-rev
|
36 |
|
|
(defreg gc-canprev #x8a) ;; ptr-rev
|
37 |
|
|
|
38 |
|
|
(defreg gc-temp #x8b)
|
39 |
|
|
(defreg gc-mem #x8c)
|
40 |
|
|
(defreg gc-from #x84) ;; at this stage we're no longer using
|
41 |
|
|
(defreg gc-to #x85) ;; some of the above variables
|
42 |
|
|
(defreg gc-val #x86)
|
43 |
|
|
(defreg gc-temp2 #x87)
|
44 |
|
|
|
45 |
|
|
;;(def-gc free #x00) ;; eirik must do eirik-magic to make
|
46 |
|
|
;;(def-gc used #x01) ;; these work as i want to
|
47 |
|
|
(defparameter +gc-free+ #x00)
|
48 |
|
|
(defparameter +gc-used+ #x01)
|
49 |
|
|
|
50 |
|
|
;; initialization of gc
|
51 |
|
|
;; call this before evaluator is run for the first time
|
52 |
|
|
|
53 |
|
|
(defun write-microprogram (&key (output-format :simulator))
|
54 |
|
|
(with-assembly ("/tmp/microcode" :output-format output-format)
|
55 |
|
|
:gc-init
|
56 |
|
|
|
57 |
|
|
;; for testing, delete later
|
58 |
|
|
(%set-datum-imm $one 1)
|
59 |
|
|
(%set-type-imm $one +type-int+)
|
60 |
|
|
(%set-datum-imm $zero 0)
|
61 |
|
|
(%set-type-imm $zero +type-int+)
|
62 |
|
|
|
63 |
|
|
;; temporarily commented out for testing, as this is set via register file
|
64 |
|
|
;; MAGIC CONSTANTS, define max memory size here
|
65 |
|
|
;; (%set-datum-imm $gc-maxblocks (* 1048576 2))
|
66 |
|
|
;; (%set-type-imm $gc-maxblocks +type-int+)
|
67 |
|
|
|
68 |
|
|
;; number of spaces
|
69 |
|
|
;; (%set-datum-imm $gc-spaces 10)
|
70 |
|
|
;; (%set-type-imm $gc-spaces +type-int+)
|
71 |
|
|
|
72 |
|
|
;; set start of gcspace (allowed heap space)
|
73 |
|
|
;; (%set-datum-imm $gc-firstfree 123) ;; TODO replace with proper number
|
74 |
|
|
;; (%set-type-imm $gc-firstfree +type-int+)
|
75 |
|
|
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
;; calculate spacesize
|
79 |
|
|
(%div* $gc-spacesize $gc-maxblocks $gc-spaces)
|
80 |
|
|
|
81 |
|
|
;; find maximal address + 1 (sup)
|
82 |
|
|
(%mul* $gc-sup $gc-spaces $gc-spacesize)
|
83 |
|
|
|
84 |
|
|
;; find start of gcspace
|
85 |
|
|
(%sub* $gc-gcspace $gc-sup $gc-spacesize)
|
86 |
|
|
|
87 |
|
|
|
88 |
|
|
;; do not want to ret while testing
|
89 |
|
|
;; (ret)
|
90 |
|
|
|
91 |
|
|
;; garbagecollect - the entry point
|
92 |
|
|
|
93 |
|
|
:gc-garbagecollect
|
94 |
|
|
;; mark everything as free
|
95 |
|
|
(%cpy $gc-vi $gc-startofmem)
|
96 |
|
|
|
97 |
|
|
|
98 |
|
|
:gc-loop1
|
99 |
|
|
;; load the contents of memory address (contained in gc-vi)
|
100 |
|
|
;; into register gc-1)
|
101 |
|
|
;; loop tested in emu: OK
|
102 |
|
|
(%load $gc-1 $gc-vi 0)
|
103 |
|
|
(%set-gc-imm $gc-1 +gc-free+)
|
104 |
|
|
(%store $gc-1 $gc-vi 0)
|
105 |
|
|
(%add $gc-vi $one)
|
106 |
|
|
(%cmp-datum $gc-vi $gc-gcspace)
|
107 |
|
|
(branchimm-false :gc-loop1)
|
108 |
|
|
|
109 |
|
|
;; pointer reversal! skrekk og gru
|
110 |
|
|
;; algorithm based on tiger book
|
111 |
|
|
|
112 |
|
|
;; start of pointer reversal
|
113 |
|
|
;; the algorithm is able to "slide" sideways without reversing
|
114 |
|
|
;; underlying pointers within the following structures
|
115 |
|
|
;; CONS - SNOC
|
116 |
|
|
;; ARRAY - PTR - ... - PTR - SNOC
|
117 |
|
|
|
118 |
|
|
;; CONS/ARRAY are identified as start of structure
|
119 |
|
|
;; SNOC is identified as end of structure
|
120 |
|
|
|
121 |
|
|
(%set-type-imm $gc-t +type-int+)
|
122 |
|
|
(%set-datum-imm $gc-t 0)
|
123 |
|
|
(%cpy $gc-x $gc-rootptr)
|
124 |
|
|
|
125 |
|
|
|
126 |
|
|
:gc-mainreverseloop
|
127 |
|
|
|
128 |
|
|
;; visit current block
|
129 |
|
|
;; gc-x holds current memory address
|
130 |
|
|
;; gc-y will hold the contents of the address
|
131 |
|
|
;; address 0x14
|
132 |
|
|
(%load $gc-y $gc-x 0)
|
133 |
|
|
(%set-gc-imm $gc-y +gc-used+)
|
134 |
|
|
(%store $gc-y $gc-x 0)
|
135 |
|
|
|
136 |
|
|
(%cpy $gc-followp $zero)
|
137 |
|
|
(%cpy $gc-cannext $zero)
|
138 |
|
|
(%cpy $gc-canprev $zero)
|
139 |
|
|
|
140 |
|
|
;; if memory address x contains a pointer, and it points to
|
141 |
|
|
;; a memory address marked as gc-free (ie. unvisited so far)
|
142 |
|
|
;; set followp to true (1)
|
143 |
|
|
;; the following types have pointers: CONS PTR SNOC
|
144 |
|
|
;; tested OK for case: cell is pointer, cell pointed to is unvisited
|
145 |
|
|
(%cmp-type-imm $gc-y +type-cons+)
|
146 |
|
|
(branchimm :gc-setfollowp)
|
147 |
|
|
(%cmp-type-imm $gc-y +type-snoc+)
|
148 |
|
|
(branchimm :gc-setfollowp)
|
149 |
|
|
(%cmp-type-imm $gc-y +type-ptr+)
|
150 |
|
|
(branchimm :gc-setfollowp)
|
151 |
|
|
;; if any other types contain pointers, add them here!
|
152 |
|
|
(jump-imm :gc-afterfollowp)
|
153 |
|
|
|
154 |
|
|
:gc-setfollowp
|
155 |
|
|
|
156 |
|
|
; copy from memory location $gc-y, into $gc-v
|
157 |
|
|
(%load $gc-v $gc-y 0)
|
158 |
|
|
(%cmp-gc-imm $gc-v +gc-used+)
|
159 |
|
|
(branchimm :gc-afterfollowp)
|
160 |
|
|
(%cpy $gc-followp $one)
|
161 |
|
|
|
162 |
|
|
:gc-afterfollowp
|
163 |
|
|
|
164 |
|
|
;; if we aren't at the last position of a memory structure spanning
|
165 |
|
|
;; several addresses and the next adress is free, set cannext=1
|
166 |
|
|
;; currently, these types can occur at the non-end: CONS, ARRAY, PTR
|
167 |
|
|
;; tested OK for case: cell is not end of structure, next cell is unvisited
|
168 |
|
|
(%cmp-type-imm $gc-y +type-cons+)
|
169 |
|
|
(branchimm :gc-setcannext)
|
170 |
|
|
(%cmp-type-imm $gc-y +type-array+)
|
171 |
|
|
(branchimm :gc-setcannext)
|
172 |
|
|
(%cmp-type-imm $gc-y +type-ptr+)
|
173 |
|
|
(branchimm :gc-setcannext)
|
174 |
|
|
(jump-imm :gc-aftercannext)
|
175 |
|
|
:gc-setcannext
|
176 |
|
|
(%cpy $gc-1 $gc-x) ;; check is address x+1 is unvisited
|
177 |
|
|
(%add $gc-1 $one)
|
178 |
|
|
(%load $gc-1 $gc-1 0) ;; lykkebo says this is safe
|
179 |
|
|
(%cmp-gc-imm $gc-1 +gc-used+)
|
180 |
|
|
(branchimm :gc-aftercannext)
|
181 |
|
|
(%cpy $gc-cannext $one)
|
182 |
|
|
|
183 |
|
|
:gc-aftercannext
|
184 |
|
|
|
185 |
|
|
;; if we aren't at the first position of a memory structure spanning
|
186 |
|
|
;; several addresses, set canprev=1
|
187 |
|
|
;; the following types can occur at the non-start: SNOC PTR
|
188 |
|
|
;; tested OK for case: cell is not end of structure
|
189 |
|
|
(%cmp-type-imm $gc-y +type-snoc+)
|
190 |
|
|
(branchimm :gc-setcanprev)
|
191 |
|
|
(%cmp-type-imm $gc-y +type-ptr+)
|
192 |
|
|
(branchimm :gc-setcanprev)
|
193 |
|
|
(jump-imm :gc-aftercanprev)
|
194 |
|
|
:gc-setcanprev
|
195 |
|
|
(%cpy $gc-canprev $one)
|
196 |
|
|
|
197 |
|
|
:gc-aftercanprev
|
198 |
|
|
|
199 |
|
|
;; do stuff based on followp, cannext, canprev
|
200 |
|
|
;; follow the pointer we're at, and reverse the pointer
|
201 |
|
|
;; =====> addr 0x39 <======
|
202 |
|
|
(%cmp-datum $gc-followp $one)
|
203 |
|
|
(branchimm-false :gc-afterfollowedp)
|
204 |
|
|
(%cpy $gc-temp $gc-x)
|
205 |
|
|
(%load $gc-mem $gc-temp 0)
|
206 |
|
|
(%set-datum $gc-mem $gc-t)
|
207 |
|
|
(%store $gc-mem $gc-temp 0)
|
208 |
|
|
(%cpy $gc-t $gc-temp)
|
209 |
|
|
(%set-datum $gc-x $gc-y)
|
210 |
|
|
(jump-imm :gc-mainreverseloop)
|
211 |
|
|
|
212 |
|
|
:gc-afterfollowedp
|
213 |
|
|
|
214 |
|
|
;; move to next memory location
|
215 |
|
|
(%cmp-datum $gc-cannext $one)
|
216 |
|
|
(branchimm-false :gc-aftercouldnext)
|
217 |
|
|
(%add $gc-x $one)
|
218 |
|
|
(jump-imm :gc-mainreverseloop)
|
219 |
|
|
|
220 |
|
|
:gc-aftercouldnext
|
221 |
|
|
|
222 |
|
|
;; move to previous memory location
|
223 |
|
|
(%cmp-datum $gc-canprev $one)
|
224 |
|
|
(branchimm-false :gc-aftercouldprev)
|
225 |
|
|
;; address 0x48
|
226 |
|
|
(%sub $gc-x $one)
|
227 |
|
|
(jump-imm :gc-mainreverseloop)
|
228 |
|
|
|
229 |
|
|
:gc-aftercouldprev
|
230 |
|
|
|
231 |
|
|
;; all cases exhausted: follow pointer back and reverse the reversal
|
232 |
|
|
(%cmp-datum $gc-t $zero)
|
233 |
|
|
(branchimm :gc-donepointerreversal)
|
234 |
|
|
(%load $gc-temp $gc-t 0) ;; read from address gc-t, into gc-temp
|
235 |
|
|
(%cpy $gc-mem $gc-temp)
|
236 |
|
|
(%set-datum $gc-mem $gc-x)
|
237 |
|
|
(%store $gc-mem $gc-t 0) ;; restore the correct pointer in gc-t
|
238 |
|
|
(%cpy $gc-x $gc-t)
|
239 |
|
|
(%cpy $gc-t $gc-temp)
|
240 |
|
|
(jump-imm :gc-mainreverseloop)
|
241 |
|
|
|
242 |
|
|
:gc-donepointerreversal
|
243 |
|
|
|
244 |
|
|
;; end of pointer reversal routine, from this point on,
|
245 |
|
|
;; all variables marked with "ptr-rev" are free for other use
|
246 |
|
|
;; ========> address 0x52 <=======
|
247 |
|
|
|
248 |
|
|
;; find the first address that's going to be copied
|
249 |
|
|
(%cpy $gc-from $gc-startofmem)
|
250 |
|
|
(%cpy $gc-to $gc-startofmem)
|
251 |
|
|
:gc-findchangeloop
|
252 |
|
|
(%cmp-datum $gc-from $gc-gcspace)
|
253 |
|
|
(branchimm :gc-findnextloop)
|
254 |
|
|
(%load $gc-mem $gc-from 0)
|
255 |
|
|
(%cmp-gc-imm $gc-mem +gc-free+)
|
256 |
|
|
(branchimm :gc-findnextloop)
|
257 |
|
|
(%add $gc-from $one)
|
258 |
|
|
(%add $gc-to $one)
|
259 |
|
|
(jump-imm :gc-findchangeloop)
|
260 |
|
|
:gc-findnextloop
|
261 |
|
|
;; we found the first hole, find the next element
|
262 |
|
|
(%cmp-datum $gc-from $gc-gcspace)
|
263 |
|
|
(branchimm :gc-copyloop)
|
264 |
|
|
(%load $gc-mem $gc-from 0)
|
265 |
|
|
(%cmp-gc-imm $gc-mem +gc-used+)
|
266 |
|
|
(branchimm :gc-copyloop)
|
267 |
|
|
(%add $gc-from $one)
|
268 |
|
|
(jump-imm :gc-findnextloop)
|
269 |
|
|
|
270 |
|
|
;; copy the stuff
|
271 |
|
|
;; address 0x63
|
272 |
|
|
|
273 |
|
|
:gc-copyloop
|
274 |
|
|
|
275 |
|
|
(%load $gc-mem $gc-from 0) ;; read from gc-from into gc-mem
|
276 |
|
|
(%cmp-gc-imm $gc-mem +gc-used+)
|
277 |
|
|
(branchimm-false :gc-notrans)
|
278 |
|
|
;; put address in translation table
|
279 |
|
|
(%cpy $gc-temp $gc-mem)
|
280 |
|
|
(%div* $gc-mem $gc-from $gc-spacesize)
|
281 |
|
|
(%mul $gc-mem $gc-spacesize)
|
282 |
|
|
(%cpy $gc-temp2 $gc-from)
|
283 |
|
|
(%sub $gc-temp2 $gc-mem)
|
284 |
|
|
(%add $gc-temp2 $gc-gcspace)
|
285 |
|
|
(%store $gc-to $gc-temp2 0) ;; write to-address to gc-temp2
|
286 |
|
|
;; copy
|
287 |
|
|
(%load $gc-mem $gc-from 0)
|
288 |
|
|
(%store $gc-temp $gc-to 0)
|
289 |
|
|
(%add $gc-to $one)
|
290 |
|
|
:gc-notrans
|
291 |
|
|
(%add $gc-from $one)
|
292 |
|
|
|
293 |
|
|
(%div* $gc-temp $gc-from $gc-spacesize)
|
294 |
|
|
(%mul $gc-temp $gc-spacesize)
|
295 |
|
|
(%sub* $gc-temp2 $gc-from $gc-temp)
|
296 |
|
|
(%cmp-datum $gc-temp2 $zero)
|
297 |
|
|
(branchimm-false :gc-noconvert)
|
298 |
|
|
|
299 |
|
|
;; translate pointers
|
300 |
|
|
;; address 0x79
|
301 |
|
|
:gc-transloop
|
302 |
|
|
(%cpy $gc-vi $gc-startofmem)
|
303 |
|
|
:gc-transloop2
|
304 |
|
|
(%load $gc-mem $gc-vi 0) ;; read from address gc-i and put into gc-mem
|
305 |
|
|
(%cmp-gc-imm $gc-mem +gc-used+)
|
306 |
|
|
(branchimm-false :gc-nexttrans)
|
307 |
|
|
(%cmp-type-imm $gc-mem +type-ptr+)
|
308 |
|
|
(branchimm :gc-isptr)
|
309 |
|
|
(%cmp-type-imm $gc-mem +type-cons+)
|
310 |
|
|
(branchimm :gc-isptr)
|
311 |
|
|
(%cmp-type-imm $gc-mem +type-snoc+)
|
312 |
|
|
(branchimm :gc-isptr)
|
313 |
|
|
(jump-imm :gc-nexttrans)
|
314 |
|
|
|
315 |
|
|
:gc-isptr
|
316 |
|
|
;; check that these branches work
|
317 |
|
|
;; OK for mem>=from-spacesize og mem
|
318 |
|
|
(%sub* $gc-temp $gc-from $gc-spacesize)
|
319 |
|
|
(%cmp-datum $gc-mem $gc-temp)
|
320 |
|
|
(%branch* $zero :gc-nexttrans N)
|
321 |
|
|
(%cmp-datum $gc-mem $gc-from)
|
322 |
|
|
(%branch* $zero :gc-nexttrans (not N))
|
323 |
|
|
|
324 |
|
|
;; TODO replace the following section whenever (if) we get a
|
325 |
|
|
;; modulo instruction!
|
326 |
|
|
|
327 |
|
|
;; calculate gcspace+val%spacesize, put in val
|
328 |
|
|
(%cpy $gc-val $gc-mem)
|
329 |
|
|
(%div* $gc-temp $gc-val $gc-spacesize)
|
330 |
|
|
(%mul $gc-temp $gc-spacesize)
|
331 |
|
|
(%sub* $gc-temp2 $gc-val $gc-temp)
|
332 |
|
|
(%add* $gc-val $gc-temp2 $gc-gcspace)
|
333 |
|
|
(%load $gc-temp2 $gc-val 0)
|
334 |
|
|
(%set-datum $gc-mem $gc-temp2)
|
335 |
|
|
(%store $gc-mem $gc-vi 0)
|
336 |
|
|
|
337 |
|
|
:gc-nexttrans
|
338 |
|
|
(%add $gc-vi $one)
|
339 |
|
|
(%cmp $gc-vi $gc-to)
|
340 |
|
|
(branchimm-false :gc-noto)
|
341 |
|
|
(%cpy $gc-vi $gc-from)
|
342 |
|
|
:gc-noto
|
343 |
|
|
(%cmp $gc-vi $gc-gcspace)
|
344 |
|
|
(branchimm-false :gc-transloop2)
|
345 |
|
|
|
346 |
|
|
:gc-noconvert
|
347 |
|
|
|
348 |
|
|
(%cmp-datum $gc-from $gc-gcspace)
|
349 |
|
|
(branchimm-false :gc-copyloop)
|
350 |
|
|
|
351 |
|
|
;; whee, gc is finished and we have a new address where
|
352 |
|
|
;; free space starts
|
353 |
|
|
(%cpy $gc-firstfree $gc-to)
|
354 |
|
|
|
355 |
|
|
;; dummy-labels
|
356 |
|
|
:ret-error
|
357 |
|
|
:call-error
|
358 |
|
|
;; address 0x9E (as of now)
|
359 |
|
|
|
360 |
|
|
(ret)))
|
361 |
|
|
|