OpenCores
URL https://opencores.org/ocsvn/igor/igor/trunk

Subversion Repositories igor

[/] [igor/] [trunk/] [microprogram_assembler/] [microprogram.lisp] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 atypic
(in-package #:mcasm)
2
 
3
(defparameter +microprogram-version+ #x12)
4
 
5
(defun alloc-imm (sz)
6
  (%set-datum-imm $alloc-size sz)
7
  (alloc $alloc-size))
8
 
9
(defun alloc (sz-reg)
10
  (%cpy $alloc-addr $gc-firstfree)
11
  (%add $gc-firstfree sz-reg)
12
  (%cmp-datum $gc-firstfree $gc-mem-limit)
13
  ;; TODO
14
  )
15
 
16
(defun %store-typed (datum-reg addr-reg addr-imm type)
17
  (%set-type-imm $car type)
18
  (%set-datum $car datum-reg)
19
  (%store $car addr-reg addr-imm))
20
 
21
(defun %make-obj (result-reg datum-reg type)
22
  (alloc $one)
23
  (%store-typed datum-reg $alloc-addr 0 type)
24
  (%set-datum result-reg $alloc-addr))
25
 
26
(defun %make-char (result-reg datum-reg)
27
  (with-new-label ("make-char-const" constant-char)
28
    (with-new-label ("make-char-non-const" non-constant-char)
29
      (%set-datum-imm result-reg %area-chars)
30
      (%add result-reg datum-reg)
31
      (with-force-label (non-constant-char)
32
        (%cmp-datum-imm datum-reg +constant-chars+)
33
        (%branch* $zero non-constant-char (not N))
34
        (%cmp-datum-imm datum-reg 0)
35
        (%branch* $zero non-constant-char N))
36
      (jump-imm constant-char)
37
      (make-label non-constant-char)
38
      (%make-obj result-reg datum-reg +type-char+)
39
      (make-label constant-char))))
40
 
41
(defun %make-int (result-reg datum-reg)
42
  (with-new-label ("make-int-const" constant-int)
43
    (with-new-label ("make-int-non-const" non-constant-int)
44
      (%set-datum-imm result-reg %area-ints)
45
      (%add result-reg datum-reg)
46
      (with-force-label (non-constant-int)
47
        (%cmp-datum-imm datum-reg +constant-ints+)
48
        (%branch* $zero non-constant-int (not N))
49
        (%cmp-datum-imm datum-reg 0)
50
        (%branch* $zero non-constant-int N))
51
      (jump-imm constant-int)
52
      (make-label non-constant-int)
53
      (%make-obj result-reg datum-reg +type-int+)
54
      (make-label constant-int))))
55
 
56
(defun %load-typed (result-reg addr-reg addr-imm type err-handler)
57
  (%load result-reg addr-reg addr-imm)
58
  (%cmp-type-imm result-reg type)
59
  (branchimm-false err-handler))
60
 
61
(defun %cons (result-reg car-reg cdr-reg)
62
  (%set-type-imm $car +type-cons+)
63
  (%set-type-imm $cdr +type-snoc+)
64
  (%set-datum $car car-reg)
65
  (%set-datum $cdr cdr-reg)
66
  (alloc $two)
67
  (%store $car $alloc-addr 0)
68
  (%store $cdr $alloc-addr 1)
69
  (%set-datum result-reg $alloc-addr))
70
 
71
(defun %car (result-reg cons-reg err-handler)
72
  (%load result-reg cons-reg 0)
73
  (%cmp-type-imm result-reg +type-cons+)
74
  (branchimm-false err-handler))
75
 
76
(defun %cdr (result-reg cons-reg err-handler)
77
  ;; TODO should check that cons-reg actually points to a cons
78
  ;; cell
79
  (%load result-reg cons-reg 1)
80
  (%cmp-type-imm result-reg +type-snoc+)
81
  (branchimm-false err-handler))
82
 
83
(defun call (addr)
84
  (with-new-label ("call" return-addr)
85
    (%cmp-datum-imm $mc-stack-top $mc-stack-max)
86
    (branchimm :call-error)
87
    (let ((return-addr return-addr))
88
      (force-label return-addr)
89
      (%set-datum-imm (indirect-register $mc-stack-top) return-addr))
90
    (%add $mc-stack-top $one)
91
    (jump-imm addr)
92
    (make-label return-addr)))
93
 
94
(defun ret ()
95
  (%cmp-datum-imm $mc-stack-top $mc-stack-min)
96
  (branchimm :ret-error)
97
  (%sub $mc-stack-top $one)
98
  (jump-reg (indirect-register $mc-stack-top)))
99
 
100
(defun %error-imm (error-type)
101
  (%set-datum-imm $car %error)
102
  (%set-datum-imm $cdr error-type)
103
  (%cons $s-condition $car $cdr)
104
  (%set-datum-imm $mc-stack-top $mc-stack-min)
105
  (call :interrupt)
106
  (jump-imm :main-loop-end))
107
 
108
(defun %error (error-type-reg)
109
  (%set-datum-imm $car %error)
110
  (%cons $s-condition $car error-type-reg)
111
  (%set-datum-imm $mc-stack-top $mc-stack-min)
112
  (call :interrupt)
113
  (jump-imm :main-loop-end))
114
 
115
(defun select-device (devnr-reg)
116
  (%when-not (%cmp-datum $io-devnr devnr-reg)
117
    (%cpy $io-devnr devnr-reg)
118
    (%store $io-devnr $io-mem-addr %io-curdev)))
119
 
120
(defun select-device-imm (devnr)
121
  (%when-not (%cmp-datum-imm $io-devnr devnr)
122
    (%set-datum-imm $io-devnr devnr)
123
    (%store $io-devnr $io-mem-addr %io-curdev)))
124
 
125
(defun message (msg-reg) ; output a char from a register
126
  (select-device-imm +dev-serial+)
127
  (%store msg-reg $io-mem-addr %io-object))
128
 
129
(defun message-reg-no-nl (reg)
130
  (%set-datum $message reg)
131
  (call :message-reg))
132
 
133
(defun message-reg (reg) ; output an integer from a register
134
  (message-reg-no-nl reg)
135
  (message-imm #\Return)
136
  (message-imm #\Newline))
137
 
138
(defun message-imm (msg) ; output an immediate character
139
  (%set-type-imm $message +type-char+)
140
  (%set-datum-imm $message (char-int msg))
141
  (message $message))
142
 
143
(defun message-str-no-nl (str)
144
  (%set-type-imm $message +type-char+)
145
  (select-device-imm +dev-serial+)
146
  (loop for ch across str do
147
       (%set-datum-imm $message (char-int ch))
148
       (%store $message $io-mem-addr %io-object)))
149
 
150
(defun message-str (str)
151
  (message-str-no-nl str)
152
  (message-imm #\Return)
153
  (message-imm #\Newline))
154
 
155
(defun e-expr () (indirect-register $e-expr))
156
(defun e-arg () (indirect-register $e-arg))
157
(defun e-result () (indirect-register $e-result))
158
(defun e-phase () (indirect-register $e-phase))
159
 
160
(defun push-eframe ()
161
  (with-new-label ("push-eframe-free-frame" push-eframe-free-frame)
162
    (%add $e-expr $e/f-frame-size)
163
    (%add $e-arg $e/f-frame-size)
164
    (%add $e-result $e/f-frame-size)
165
    (%add $e-phase $e/f-frame-size)
166
 
167
    ;; new frame in use or above top?
168
    (%cmp-type-imm (indirect-register $e-expr) +type-none+)
169
    ;; if so, call the subroutine to handle such cases
170
    (branchimm push-eframe-free-frame)
171
    (call :push-eframe-handle-overflow)
172
    (make-label push-eframe-free-frame)
173
 
174
    (%set-type-imm (e-expr) +type-cons+)
175
    (%set-datum-imm (e-arg) %nil)
176
    (%set-datum-imm (e-result) %nil))) ; caller must set $e-expr, $e-phase
177
 
178
(defun pop-eframe ()
179
  (with-new-label ("pop-eframe-start" pop-eframe-start)
180
    (with-new-label ("pop-eframe-non-empty-frame" pop-eframe-non-empty-frame)
181
      (with-new-label ("pop-eframe-not-func-frame" pop-eframe-not-func-frame)
182
        (make-label pop-eframe-start)
183
        (%set-type-imm (indirect-register $e-expr) +type-none+)
184
 
185
        (%sub $e-expr $e/f-frame-size)
186
        (%sub $e-arg $e/f-frame-size)
187
        (%sub $e-result $e/f-frame-size)
188
        (%sub $e-phase $e/f-frame-size)
189
 
190
        ;; is this frame empty or below bottom?
191
        (%cmp-type-imm (indirect-register $e-expr) +type-none+)
192
        (branchimm-false pop-eframe-non-empty-frame)
193
        (call :pop-eframe-handle-underflow)
194
        (make-label pop-eframe-non-empty-frame)
195
 
196
        (%cmp-type-imm (indirect-register $e-expr) +type-function+)
197
        (branchimm-false pop-eframe-not-func-frame)
198
        (%set-datum $f-func (indirect-register $e-expr))
199
        (%set-datum $f-env (indirect-register $e-arg))
200
        (jump-imm pop-eframe-start)
201
        (make-label pop-eframe-not-func-frame)))))
202
 
203
 
204
 
205
(defun write-microprogram (&key (output-format :simulator))
206
  (with-assembly ("/tmp/microcode" :output-format output-format)
207
    :init
208
 
209
    ;; I/O init:
210
    (%load $io-devnr $io-mem-addr %io-curdev)
211
 
212
    (message-str (format nil "IGOREV INIT v. 0x~X" +microprogram-version+))
213
 
214
 
215
    ;; write initial data to memory:
216
 
217
    ;; nil/t/symbols, strings:
218
    (%store $init1 $zero %nil)
219
 
220
;;     (message-str "READ NIL,")
221
;;     (%load $tmp1 $zero %nil)
222
;;     (message-reg $tmp1)
223
;;     (%get-type $tmp2 $tmp1)
224
;;     (message-reg $tmp2)
225
 
226
    (%store $init2 $zero 1)
227
    (%set-type-imm $init1 +type-ptr+)
228
    (%set-type-imm $init2 +type-ptr+)
229
    (%set-type-imm $init3 +type-ptr+)
230
    :init-mem-symbols-loop
231
    (%set-datum $init1 (indirect-register $init-counter))
232
    (%shift-r $init1 $init-shift1)
233
    (%set-datum $init2 (indirect-register $init-counter))
234
    (%shift-r $init2 $init-shift2)
235
    (%and $init2 $init-char-mask)
236
    (%set-datum $init3 (indirect-register $init-counter))
237
    (%and $init3 $init-char-mask)
238
    (%set-type-imm (indirect-register $init-counter) 0)
239
    (%set-datum-imm (indirect-register $init-counter) 0)
240
    (%set-datum-imm $init-counter2 $init1)
241
    :init-mem-symbols-loop2
242
    (%cmp-datum-imm (indirect-register $init-counter2) 0)
243
    (branchimm :init-mem-symbols-end-symbol)
244
    (%add (indirect-register $init-counter2) $init-chars-start)
245
    (%incr $init-symbol-char-addr)
246
    (%store (indirect-register $init-counter2) $init-symbol-char-addr 0)
247
    :init-mem-symbols-loop2-continue
248
    (%cmp-datum-imm $init-counter2 $init3)
249
    (branchimm :init-mem-symbols-loop2-end)
250
    (%incr $init-counter2)
251
    (jump-imm :init-mem-symbols-loop2)
252
    :init-mem-symbols-end-symbol
253
    (%store-typed $zero $init-symbol-addr 0 +type-none+) ; in case there is no symbol
254
    (%sub* $init-symbol-array $init-symbol-char-addr $init-symbol-str-addr)
255
    (branchimm
256
     :init-mem-symbols-end-symbol-next) ; if there are no characters,
257
                                        ; just skip to the next symbol
258
    (%set-type-imm $init-symbol-array +type-array+)
259
    (%store $init-symbol-array $init-symbol-str-addr 0)
260
    (%store $list-terminator $init-symbol-char-addr 1)
261
    (%store-typed $init-symbol-str-addr $init-symbol-addr 0 +type-symbol+)
262
    (%add $init-symbol-char-addr 2)
263
    (%set-datum $init-symbol-str-addr $init-symbol-char-addr)
264
    :init-mem-symbols-end-symbol-next
265
    (%incr $init-symbol-addr)
266
    (jump-imm :init-mem-symbols-loop2-continue)
267
    :init-mem-symbols-loop2-end
268
    (%incr $init-counter)
269
    (%cmp-type-imm (indirect-register $init-counter) +type-int+)
270
    (branchimm :init-mem-symbols-loop)
271
 
272
    ;; builtins:
273
    (%set-type-imm $init1 +type-builtin+)
274
    (%set-datum-imm $init1 +first-builtin+)
275
    :init-mem-builtins-loop
276
    (%store $init1 $init1 %area-builtins)
277
    (%cmp-datum-imm $init1 +last-builtin+)
278
    (branchimm :init-mem-builtins-loop-end)
279
    (%incr $init1)
280
    (jump-imm :init-mem-builtins-loop)
281
    :init-mem-builtins-loop-end
282
 
283
    ;; characters:
284
    (%set-type-imm $init1 +type-char+)
285
    (%set-datum-imm $init1 0)
286
    :init-mem-chars-loop
287
    (%store $init1 $init1 %area-chars)
288
    (%incr $init1)
289
    (%cmp-datum-imm $init1 +constant-chars+)
290
    (branchimm-false :init-mem-chars-loop)
291
 
292
    ;; ints:
293
    (%set-type-imm $init1 +type-int+)
294
    (%set-datum-imm $init1 0)
295
    :init-mem-ints-loop
296
    (%store $init1 $init1 %area-ints)
297
    (%incr $init1)
298
    (%cmp-datum-imm $init1 +constant-ints+)
299
    (branchimm-false :init-mem-ints-loop)
300
 
301
    ;; symbol list:
302
    (%set-type-imm $init1 +type-cons+)
303
    (%set-type-imm $init2 +type-snoc+)
304
    (%set-datum-imm $init1 2)                   ; init1: address of symbol
305
    (%set-datum-imm $init2 (+ %area-symlist 2)) ; init2: address of next cons cell
306
    :init-mem-symlist-loop
307
    (%load $init3 $init1 0)                     ; init3: current symbol
308
    (%cmp-type-imm $init3 +type-none+)
309
    (branchimm
310
     :init-mem-symlist-loop-continue) ; skip to next if no symbol
311
                                      ; (there may be gaps)
312
    (%store $init1 $init2 -2)
313
    (%store $init2 $init2 -1)
314
    (%add $init2 $two)
315
    :init-mem-symlist-loop-continue
316
    (%incr $init1)
317
    (%cmp-datum-imm $init1 +last-symbol+)
318
    (branchimm-false :init-mem-symlist-loop)
319
    (%store $init1 $init2 -2)
320
    (%store $list-terminator $init2 -1)
321
 
322
    ;; memory root pointer:
323
    (%set-type-imm $tmp1 +type-cons+)
324
    (%set-datum-imm $tmp1 %nil)
325
    (%store $tmp1 $zero %memory-root)
326
    (%store $list-terminator $zero (+ %memory-root 1))
327
    ;; end memory initialization
328
 
329
    ;; most essential initialization:
330
    (%set-type-imm $zero +type-int+)
331
    (%set-datum-imm $zero 0)
332
 
333
    (%set-type-imm $one +type-int+)
334
    (%set-datum-imm $one 1)
335
 
336
    (%set-type-imm $two +type-int+)
337
    (%set-datum-imm $two 2)
338
 
339
;;     (%set-type-imm $list-terminator +type-snoc+)
340
;;     (%set-datum-imm $list-terminator 0)
341
 
342
    (%set-type-imm $mc-stack-top +type-int+)
343
    (%set-datum-imm $mc-stack-top $mc-stack-min)
344
 
345
    ;;(make-integer $gc-firstfree #x20000)
346
    (%set-type-imm $alloc-size +type-int+)
347
    (%set-type-imm $alloc-addr +type-int+)
348
 
349
;;     (%set-type-imm $io-mem-addr +type-int+)
350
;;     (%set-datum-imm $io-mem-addr #x3FFFF)
351
;;     (%set-datum-imm $tmp1 #x8)
352
;;     (%shift $io-mem-addr $tmp1)
353
    ;; end most essential initialization
354
 
355
 
356
    (message-str-no-nl "BOOT: ")
357
    :boot
358
    (select-device-imm +dev-boot+)
359
    (%load $tmp1 $io-mem-addr %io-size-l) ; $tmp1: boot program size
360
    (message-reg-no-nl $tmp1) (message-str " WORDS")
361
    (select-device-imm +dev-boot+)
362
;;     (%cmp-datum-imm $tmp1 0) ; temporary to avoid loading boot program
363
;;     (branchimm :boot-end)
364
    (%set-type-imm $tmp2 +type-int+)
365
    (%set-datum-imm $tmp2 0)              ; $tmp2: address counter
366
    (%store $tmp2 $io-mem-addr %io-addr-l)
367
    :boot-loop
368
    (%set-datum-imm $tmp4 #xFF)
369
    (%and $tmp4 $tmp2)
370
    (%cmp-datum-imm $tmp4 0)
371
    (branchimm-false :boot-loop-no-print)
372
    (message-reg-no-nl $tmp2)
373
    (message-imm #\Return)
374
    (select-device-imm +dev-boot+)
375
    :boot-loop-no-print
376
 
377
    (%load $tmp3 $io-mem-addr %io-object)
378
    (%store $tmp3 $tmp2 %boot-prog-start)
379
    (%incr $tmp2)
380
    ;;(message-reg $tmp2) (select-device-imm +dev-boot+)
381
    (%cmp-datum $tmp2 $tmp1)
382
    (branchimm-false :boot-loop)
383
    (%set-datum-imm $gc-firstfree %boot-prog-start)
384
    (%add $gc-firstfree $tmp2)
385
    :boot-end
386
    (message-str "COMPLETE")
387
 
388
 
389
    ;; start GC initialization
390
    (%set-datum-imm $gc-rootptr %memory-root)
391
 
392
    (%set-datum-imm $gc-startofmem (- %mem-reserved-top 2)) ; include root pointer
393
 
394
    ;; number of spaces
395
    (%set-datum-imm $gc-spaces +gc-spaces+)
396
    (%set-type-imm $gc-spaces +type-int+)
397
 
398
    ;; calculate spacesize
399
    ;; set this manually for now! not easy to replace div
400
    ;;(%set-datum-imm $gc-spacesize (/ (* 1048576 2) +gc-spaces+))
401
     ;;    (%div* $gc-spacesize $gc-maxblocks $gc-spaces)
402
 
403
    ;; find maximal address + 1 (sup)
404
    (%mul* $gc-sup $gc-spaces $gc-spacesize)
405
 
406
    ;; find start of gcspace
407
    (%sub* $gc-gcspace $gc-sup $gc-spacesize)
408
 
409
    (%set-datum-imm $tmp1 +gc-limit+)
410
    (%sub* $gc-mem-limit $gc-gcspace $tmp1)
411
    ;; end GC initialization
412
 
413
 
414
    ;; initialize evaluation stacks:
415
    (%set-datum-imm $e/f-frame-size 4)
416
    (%set-type-imm $e/f-below-marker +type-none+)
417
    (%set-type-imm $e/f-above-marker +type-cons+)
418
 
419
    (%set-datum-imm $tmp1 $e/f-min)
420
    :clear-e/f-loop
421
    (%set-type-imm (indirect-register $tmp1) +type-none+)
422
    (%set-datum-imm (indirect-register $tmp1) 0)
423
    (%add $tmp1 $one)
424
    (%cmp-datum-imm $tmp1 $e/f-max)
425
    (branchimm-false :clear-e/f-loop)
426
 
427
    (call :init-evaluation-level)
428
 
429
    ;; set current expression and environment to boot program's
430
    ;; expression and environment:
431
    (%set-datum-imm $tmp1 %boot-prog-start)
432
    (%car (e-expr) $tmp1 :err-not-a-pair)
433
    (%cdr $f-env $tmp1 :err-not-a-pair)
434
    (%set-datum-imm (e-phase) %phase-eval)
435
 
436
 
437
 
438
;;     (message-str "NIL IS ")
439
;;     (%load $tmp1 $zero %nil)
440
;;     (message-reg $tmp1)
441
;;     (message-str "TYPE ")
442
;;     (%get-type $tmp2 $tmp1)
443
;;     (message-reg $tmp2)
444
;;     (message-str "T IS ")
445
;;     (%load $tmp1 $zero 1)
446
;;     (message-reg $tmp1)
447
;;     (message-str "TYPE ")
448
;;     (%get-type $tmp2 $tmp1)
449
;;     (message-reg $tmp2)
450
;;     (message-str "IF IS ")
451
;;     (%load $tmp1 $zero 2)
452
;;     (message-reg $tmp1)
453
;;     (message-str "TYPE ")
454
;;     (%get-type $tmp2 $tmp1)
455
;;     (message-reg $tmp2)
456
;;     (message-str "CONS IS ")
457
;;     (%load $tmp1 $zero 6)
458
;;     (message-reg $tmp1)
459
;;     (message-str "TYPE ")
460
;;     (%get-type $tmp2 $tmp1)
461
;;     (message-reg $tmp2)
462
;;     (message-str "PHASE-EVAL IS ")
463
;;     (%load $tmp1 $zero #x40)
464
;;     (message-reg $tmp1)
465
;;     (message-str "TYPE ")
466
;;     (%get-type $tmp2 $tmp1)
467
;;     (message-reg $tmp2)
468
;;     (message-str "CONS FUNCTION IS ")
469
;;     (%load $tmp1 $zero #x106)
470
;;     (message-reg $tmp1)
471
;;     (message-str "TYPE ")
472
;;     (%get-type $tmp2 $tmp1)
473
;;     (message-reg $tmp2)
474
 
475
 
476
 
477
 
478
    :main-loop
479
 
480
    ;; check that phase is valid:
481
    (%cmp-datum-imm (e-phase) +first-phase+)
482
    (%branch* $zero :err-invalid-phase N)
483
    (%cmp-datum-imm (e-phase) (+ +last-phase+ 1))
484
    (%branch* $zero :err-invalid-phase (not N))
485
 
486
    ;;dispatch:
487
    (let ((label :phase-dispatch-table))
488
      (force-label label)
489
      (jump (e-phase) (- label +first-phase+)))
490
 
491
    :phase-dispatch-table
492
    (jump-imm :p-eval)
493
    (jump-imm :p-eval-args)
494
    (jump-imm :p-apply)
495
    (jump-imm :p-eval-if)
496
    (jump-imm :p-initial)
497
    (jump-imm :p-env-lookup)
498
    (jump-imm :p-env-lookup-local)
499
    (jump-imm :p-apply-function2)
500
    (jump-imm :p-bind-args)
501
    (jump-imm :p-eval-progn)
502
    (jump-imm :p-eval-args-top)
503
    (jump-imm :p-eval-args-cdr)
504
    (jump-imm :p-eval-args-cons)
505
    (jump-imm :p-eval-symbol)
506
    (jump-imm :p-set!)
507
 
508
 
509
    ;; PHASE: EVAL
510
 
511
    :p-eval
512
    (%load $car (e-expr) 0)
513
    (%cmp-type-imm $car +type-cons+)
514
    (branchimm :p-eval-form)
515
    (%cmp-type-imm $car +type-symbol+)
516
    (branchimm :p-eval-symbol1)
517
    :p-eval-self-evaluating
518
    (%cpy $tmp1 (e-expr))
519
    (pop-eframe)
520
    (%set-datum (e-result) $tmp1)
521
    (jump-imm :main-loop-end)
522
 
523
 
524
    :p-eval-symbol1
525
    (%cmp-datum-imm (e-expr) +first-magic-var+)
526
    (%branch* $zero :p-eval-symbol1-regular-var N)
527
    (%cmp-datum-imm (e-expr) (+ +last-magic-var+ 1))
528
    (%branch* $zero :p-eval-symbol1-regular-var (not N))
529
 
530
    :p-eval-symbol1-magic-var
531
    (%set-datum-imm $tmp1 %area-builtins)
532
    (%add $tmp1 (e-expr))
533
    (pop-eframe)
534
    (%set-datum (e-result) $tmp1)
535
;;     (%when (%cmp-datum-imm (e-expr) %symbol-table)
536
;;       (%set-datum-imm (e-result) %area-symlist))
537
    (jump-imm :main-loop-end)
538
 
539
    :p-eval-symbol1-regular-var
540
    (%set-datum $tmp1 (e-expr))
541
    (%set-datum-imm (e-phase) %phase-eval-symbol)
542
    (push-eframe)
543
    (%set-datum (e-expr) $tmp1)
544
    (%set-datum (e-arg) $f-env)
545
    (%set-datum-imm (e-phase) %phase-env-lookup)
546
    (jump-imm :main-loop-end)
547
 
548
 
549
    :p-eval-form
550
    (%load $car (e-expr) 0)
551
    (%load $cdr (e-expr) 1)
552
    (%cmp-datum-imm $car %quote)
553
    (branchimm :p-eval-form-quote)
554
    (%cmp-datum-imm $car %if)
555
    (branchimm :p-eval-form-if)
556
    (%cmp-datum-imm $car %lambda)
557
    (branchimm :p-eval-form-lambda)
558
    (%cmp-datum-imm $car %progn)
559
    (branchimm :p-eval-progn1)
560
 
561
    :p-eval-form-function
562
    (%set-datum-imm (e-phase) %phase-eval-args-top)
563
    (%set-datum $tmp1 $car)
564
    (push-eframe)
565
    (%set-datum (e-expr) $tmp1)
566
    (%set-datum-imm (e-phase) %phase-eval)
567
    (jump-imm :main-loop-end)
568
 
569
    :p-eval-form-quote
570
    (%set-datum $tmp1 $cdr)
571
    (pop-eframe)
572
    (%load $car $tmp1 0)
573
    (%set-datum (e-result) $car)
574
    (jump-imm :main-loop-end)
575
 
576
    :p-eval-form-lambda ; (%lambda name param-list expr)
577
    ;; TODO check args
578
    ;; TODO take name as additional argument
579
    (%car $tmp1 $cdr  :err-not-a-list) ; $tmp1: name
580
    (%cdr $cdr  $cdr  :err-not-a-list) ; $cdr: (param-list expr)
581
    (%car $tmp2 $cdr  :err-not-a-list) ; $tmp2: param-list
582
    (%cdr $cdr  $cdr  :err-not-a-list) ; $cdr: (expr)
583
    (%car $tmp3 $cdr  :err-not-a-list) ; $tmp3: expr
584
    (%cdr $cdr  $cdr  :err-not-a-list)
585
    (%cmp-datum-imm $cdr %nil)
586
    (branchimm-false :err-too-many-args)
587
    (%cons $tmp4 $f-env $list-terminator)   ; $tmp4: (env)
588
    (%cons $tmp4 $tmp3 $tmp4)               ; $tmp4: (expr env)
589
    (%cons $tmp4 $tmp2 $tmp4)               ; $tmp4: (param-list expr env)
590
    (%cons $tmp4 $tmp1 $tmp4)               ; $tmp4: (name param-list expr env)
591
    (%make-obj $tmp1 $tmp4 +type-function+) ; $tmp1: function (address)
592
    (pop-eframe)
593
    (%set-datum (e-result) $tmp1)
594
    (jump-imm :main-loop-end)
595
 
596
    :p-eval-form-if ; (%if test a b)
597
    (%load $tmp1 $cdr 0)
598
    ;;(%load $cdr $cdr 1)
599
    (%set-datum-imm (e-phase) %phase-eval-if)
600
    (push-eframe)
601
    (%set-datum (e-expr) $tmp1)
602
    (%set-datum-imm (e-phase) %phase-eval)
603
    (jump-imm :main-loop-end)
604
 
605
 
606
    ;; PHASE: EVAL-IF
607
 
608
    :p-eval-if ; (%if test a b) caddr, cadddr
609
    (%load $cdr (e-expr) 1)
610
    (%load $cdr $cdr 1) ;; cddr
611
    (%cmp-datum-imm (e-result) %nil)
612
    (branchimm-false :p-eval-if-true)
613
    (%load $cdr $cdr 1) ;; cdddr
614
    :p-eval-if-true
615
    (%load $car $cdr 0) ;; caddr/cadddr
616
    (%set-datum (e-expr) $car)
617
    (%set-datum-imm (e-phase) %phase-eval)
618
    (jump-imm :main-loop-end)
619
 
620
 
621
    ;; PHASE: EVAL-PROGN
622
 
623
    :p-eval-progn1 ; this first part belongs to EVAL phase
624
    (%set-datum (e-arg) $cdr)
625
    (%set-datum-imm (e-result) %nil)
626
    (%set-datum-imm (e-phase) %phase-eval-progn)
627
    :p-eval-progn ; (%progn form ...)
628
    (%cmp-datum-imm (e-arg) %nil)
629
    (branchimm :p-eval-progn-empty)
630
    (%car $tmp1 (e-arg) :err-not-a-list)  ; $tmp1: first argument
631
    (%cdr (e-arg) (e-arg) :err-not-a-list)
632
    (%cmp-datum-imm (e-arg) %nil)
633
    (branchimm :p-eval-progn-last)
634
    ;; more than one argument:
635
    (push-eframe)
636
    (%set-datum (e-expr) $tmp1)
637
    (%set-datum-imm (e-phase) %phase-eval)
638
    (jump-imm :main-loop-end)
639
    :p-eval-progn-empty ; no arguments
640
    (pop-eframe)
641
    (%set-datum-imm (e-result) %nil)
642
    (jump-imm :main-loop-end)
643
    :p-eval-progn-last ; exactly one argument, eval it in this eframe
644
    (%set-datum (e-expr) $tmp1)
645
    (%set-datum-imm (e-arg) %nil)
646
    (%set-datum-imm (e-result) %nil)
647
    (%set-datum-imm (e-phase) %phase-eval)
648
    (jump-imm :main-loop-end)
649
 
650
 
651
    ;; PHASE: EVAL-SYMBOL
652
 
653
    :p-eval-symbol
654
    (%cmp-datum-imm (e-result) %nil)
655
    (branchimm :err-unbound-symbol)
656
    (%cdr $tmp1 (e-result) :err-invalid-state)
657
    (pop-eframe)
658
    (%set-datum (e-result) $tmp1)
659
    (jump-imm :main-loop-end)
660
 
661
 
662
    ;; PHASES: EVAL-ARGS, EVAL-ARGS-{TOP,CDR,CONS}
663
 
664
    :p-eval-args-top
665
    (%set-datum (e-arg) (e-result)) ; copy function pointer to (e-arg)
666
    (%set-datum-imm (e-phase) %phase-apply)
667
    (%cdr $tmp1 (e-expr) :err-malformed-form)
668
    (push-eframe)
669
    (%set-datum-imm (e-phase) %phase-eval-args)
670
    (%set-datum (e-expr) $tmp1)
671
    (jump-imm :main-loop-end)
672
 
673
    :p-eval-args
674
    (%cmp-datum-imm (e-expr) %nil)
675
    (branchimm :p-eval-args-empty-list)
676
    (%car $tmp1 (e-expr) :p-eval-args-error)
677
    (%set-datum-imm (e-phase) %phase-eval-args-cdr)
678
    (push-eframe)
679
    (%set-datum (e-expr) $tmp1)
680
    (%set-datum-imm (e-phase) %phase-eval)
681
    (jump-imm :main-loop-end)
682
    :p-eval-args-empty-list
683
    (pop-eframe)
684
    (%set-datum-imm (e-result) %nil)
685
    (jump-imm :main-loop-end)
686
;;     (%set-datum (e-arg) (e-result))
687
;;     (%load $cdr (e-expr) 1)
688
;;     (%cmp-datum-imm $cdr %nil)
689
;;     (branchimm :p-apply1)
690
;;     (%load $cdr $cdr 1)
691
;;     (%load $car $cdr 0)
692
;;     (%set-datum-imm (e-phase) %phase-apply)
693
;;     (call :push-e)
694
;;     (%set-datum (e-expr) $car)
695
;;     (jump-imm :main-loop-end)
696
 
697
    :p-eval-args-cdr
698
    (%set-datum (e-arg) (e-result))
699
    (%cdr $tmp1 (e-expr) :p-eval-args-error)
700
    (%set-datum-imm (e-phase) %phase-eval-args-cons)
701
    (push-eframe)
702
    (%set-datum (e-expr) $tmp1)
703
    (%set-datum-imm (e-phase) %phase-eval-args)
704
    (jump-imm :main-loop-end)
705
 
706
    :p-eval-args-cons
707
    (%cons $tmp1 (e-arg) (e-result))
708
    (pop-eframe)
709
    (%set-datum (e-result) $tmp1)
710
    (jump-imm :main-loop-end)
711
 
712
    :p-eval-args-error ; common to p-eval-args, p-eval-args-cdr, p-eval-args-cons
713
    (%error %err-invalid-arg-list)
714
 
715
 
716
    ;; PHASE: ENV-LOOKUP
717
 
718
    :p-env-lookup
719
    ;; (e-expr): variable name (address)
720
    ;; (e-arg): env (address)
721
    (%cmp-datum-imm (e-result) %nil)
722
    (branchimm-false :p-env-lookup-ret)
723
    (%cmp-datum-imm (e-arg) %nil)
724
    (branchimm :p-env-lookup-ret)
725
    ;;(branchimm :err-unbound-symbol)
726
    (%set-datum $tmp1 (e-expr))
727
    (%car $tmp2 (e-arg) :err-invalid-env)
728
    (%cdr (e-arg) (e-arg) :err-invalid-env)
729
    (push-eframe)
730
    (%set-datum (e-expr) $tmp1)
731
    (%set-datum (e-arg) $tmp2)
732
    (%set-datum-imm (e-phase) %phase-env-lookup-local)
733
    (jump-imm :main-loop-end)
734
    :p-env-lookup-ret
735
    (%set-datum $tmp1 (e-result))
736
    (pop-eframe)
737
    (%set-datum (e-result) $tmp1)
738
    (jump-imm :main-loop-end)
739
 
740
 
741
    ;; PHASE: ENV-LOOKUP-LOCAL
742
 
743
    :p-env-lookup-local
744
    ;; (e-expr): variable name (address)
745
    ;; (e-arg): env binding list (address)
746
    (%set-datum-imm $tmp1 %nil)
747
    (%cmp-datum-imm (e-arg) %nil)
748
    (branchimm :p-env-lookup-local-ret)
749
    (%car $tmp1 (e-arg) :err-invalid-env) ; $tmp1: (symbol . value)
750
    (%car $tmp2 $tmp1 :err-invalid-env)  ; $tmp2: symbol
751
    (%cmp-datum $tmp2 (e-expr))
752
    (branchimm :p-env-lookup-local-ret)
753
    (%cdr (e-arg) (e-arg) :err-invalid-env)
754
    (jump-imm :main-loop-end)
755
    :p-env-lookup-local-ret
756
    (pop-eframe)
757
    (%set-datum (e-result) $tmp1)
758
    (jump-imm :main-loop-end)
759
 
760
 
761
    ;; PHASE: BIND-ARGS
762
 
763
    :p-bind-args
764
    ;; (e-expr): existing bindings
765
    ;; (e-arg): (rest of) param list
766
    ;; (e-result): (rest of) arg list
767
    (%load $params-car (e-arg) 0)
768
    ;; dispatch on type of param list:
769
    (%cmp-type-imm $params-car +type-cons+)
770
    (branchimm :p-bind-args-head)
771
    (%cmp-type-imm $params-car +type-nil+)
772
    (branchimm :p-bind-args-empty)
773
    (%cmp-type-imm $params-car +type-symbol+)
774
    (branchimm :p-bind-args-tail)
775
    (jump-imm :err-invalid-param-list)
776
 
777
    :p-bind-args-head
778
    ;; param list is of form (p1 . rest). check that arg list has form
779
    ;; (a1 . rest) and that p1 is actually a symbol. if so, bind p1 to
780
    ;; a1 and continue cdr-ing down both lists:
781
    (%load $tmp1 $params-car 0)
782
    (%cmp-type-imm $tmp1 +type-symbol+)
783
    (branchimm-false :err-invalid-param-list)
784
    (%load $args-car (e-result) 0)
785
    (%cmp-type-imm $args-car +type-cons+)
786
    (branchimm-false :err-too-few-args)
787
    ;; make a binding (p1 . a1):
788
    (%cons $tmp1 $params-car $args-car)
789
    ;; cons the new binding on the list:
790
    (%cons (e-expr) $tmp1 (e-expr))
791
    ;; cdr down param and arg list:
792
    (%load (e-arg) (e-arg) 1)
793
    (%load (e-result) (e-result) 1)
794
    (jump-imm :main-loop-end)
795
 
796
    :p-bind-args-tail
797
    ;; param list is of form p1, that is, just a single symbol; so
798
    ;; bind this to the whole arglist and return:
799
    (%cons $tmp1 (e-arg) (e-result))
800
    (%cons $tmp1 $tmp1 (e-expr))
801
    (pop-eframe)
802
    (%set-datum (e-result) $tmp1)
803
    (jump-imm :main-loop-end)
804
 
805
    :p-bind-args-empty
806
    ;; empty param list; check that arg list is empty too, and return:
807
    (%cmp-datum-imm (e-result) %nil)
808
    (branchimm-false :err-too-many-args)
809
    (%set-datum $tmp1 (e-expr))
810
    (pop-eframe)
811
    (%set-datum (e-result) $tmp1)
812
    (jump-imm :main-loop-end)
813
 
814
 
815
    ;; PHASE: APPLY
816
 
817
    :p-apply
818
    ;; (e-arg): function (address)
819
    ;; (e-result): argument list (address)
820
    (%load $apply-func (e-arg) 0)
821
    (%cmp-type-imm $apply-func +type-builtin+)
822
    (branchimm :p-apply-builtin)
823
    (%cmp-type-imm $apply-func +type-function+)
824
    (branchimm :p-apply-function1)
825
    (%error-imm %err-not-a-function)
826
 
827
    :p-apply-builtin ; $apply-func contains the identifier of the
828
                     ; function (the adress of the symbol used for
829
                     ; naming it), use this as offset into the table
830
                     ; below
831
    (%set-type-imm $builtin-arg1 +type-none+)
832
    (%set-type-imm $builtin-arg2 +type-none+)
833
    (%set-type-imm $builtin-arg3 +type-none+)
834
 
835
    ;; check builtin identifier:
836
    (%cmp-datum-imm $apply-func +first-builtin+)
837
    (%branch* $zero :err-invalid-builtin N)
838
    (%cmp-datum-imm $apply-func (+ +last-builtin+ 1))
839
    (%branch* $zero :err-invalid-builtin (not N))
840
 
841
    (let ((label :p-apply-table))
842
      (force-label label)
843
      (jump $apply-func (- label +first-builtin+)))
844
    :p-apply-table
845
    (jump-imm :builtin-cons)
846
    (jump-imm :builtin-car)
847
    (jump-imm :builtin-cdr)
848
    (jump-imm :builtin-eval)
849
    (jump-imm :builtin-apply)
850
    (jump-imm :builtin-type)
851
    (jump-imm :builtin-make-array)
852
    (jump-imm :builtin-array-size)
853
    (jump-imm :builtin-array-get)
854
    (jump-imm :builtin-array-set)
855
    (jump-imm :builtin-make-symbol)
856
    (jump-imm :builtin-symbol-to-string)
857
    (jump-imm :builtin-char-to-int)
858
    (jump-imm :builtin-int-to-char)
859
    (jump-imm :builtin-get-char)
860
    (jump-imm :builtin-put-char)
861
    (jump-imm :builtin-num-devices)
862
    (jump-imm :builtin-device-type)
863
    (jump-imm :builtin-set-address)
864
    (jump-imm :builtin-get-address)
865
    (jump-imm :builtin-error)
866
    (jump-imm :builtin-add)
867
    (jump-imm :builtin-sub)
868
    (jump-imm :builtin-mul)
869
    (jump-imm :builtin-div)
870
    (jump-imm :builtin-bitwise-and)
871
    (jump-imm :builtin-bitwise-or)
872
    (jump-imm :builtin-bitwise-not)
873
    (jump-imm :builtin-bitwise-shift)
874
    (jump-imm :builtin-current-environment)
875
    (jump-imm :builtin-make-eval-state)
876
    (jump-imm :builtin-eval-partial)
877
    (jump-imm :builtin-define)
878
    (jump-imm :builtin-undefine)
879
    (jump-imm :builtin-eq?)
880
    (jump-imm :builtin-num-eq?)
881
    (jump-imm :builtin-char-eq?)
882
    (jump-imm :builtin-less-than?)
883
    (jump-imm :builtin-mod)
884
    (jump-imm :builtin-set!)
885
    (jump-imm :builtin-set-car!)
886
    (jump-imm :builtin-set-cdr!)
887
    (jump-imm :builtin-function-data)
888
    (jump-imm :builtin-builtin-name)
889
    (jump-imm :builtin-device-size)
890
    (jump-imm :builtin-device-status)
891
 
892
    :builtin-cons ; (%cons obj1 obj2)
893
    (%set-type-imm $builtin-arg1 +type-t+)
894
    (%set-type-imm $builtin-arg2 +type-t+)
895
    (call :fetch-args)
896
    (%cons $apply-result $builtin-arg1 $builtin-arg2)
897
    (jump-imm :p-apply-end)
898
 
899
    :builtin-car ; (%car cons-cell)
900
    (%set-type-imm $builtin-arg1 +type-cons+)
901
    (call :fetch-args)
902
    (%set-datum $apply-result $builtin-arg1-val)
903
    (jump-imm :p-apply-end)
904
 
905
    :builtin-cdr ; (%cdr cons-cell)
906
    (%set-type-imm $builtin-arg1 +type-cons+)
907
    (call :fetch-args)
908
    (%load $apply-result $builtin-arg1 1)
909
    (jump-imm :p-apply-end)
910
 
911
    :builtin-eq? ; (%eq? obj1 obj2)
912
    (%set-type-imm $builtin-arg1 +type-t+)
913
    (%set-type-imm $builtin-arg2 +type-t+)
914
    (call :fetch-args)
915
    (%set-datum-imm $apply-result %nil)
916
    (when= ($builtin-arg1 $builtin-arg2)
917
      (%set-datum-imm $apply-result %t))
918
    (jump-imm :p-apply-end)
919
 
920
    :builtin-type ; (%type obj)
921
    (%set-type-imm $builtin-arg1 +type-t+)
922
    (call :fetch-args)
923
    (%get-type $tmp1 $builtin-arg1-val)
924
    (%make-obj $apply-result $tmp1 +type-int+)
925
    (jump-imm :p-apply-end)
926
 
927
    :builtin-eval ; (%eval expr env)
928
    (%set-type-imm $builtin-arg1 +type-t+)
929
    (%set-type-imm $builtin-arg2 +type-t+)
930
    (call :fetch-args)
931
    (%set-datum $apply-eval-expr $builtin-arg1)
932
    (%set-datum $apply-eval-env $builtin-arg2)
933
    (call :push-or-reuse-fframe)
934
    (%set-datum-imm $f-func %eval) ; should maybe have a dedicated symbol for this
935
    (%set-datum $f-env $apply-eval-env)
936
    (%set-datum (e-expr) $apply-eval-expr)
937
    (%set-datum-imm (e-phase) %phase-eval)
938
    (jump-imm :main-loop-end) ; note: not :p-apply-end
939
 
940
    :builtin-apply ; (%apply func args)
941
    ;; move stuff around and go through APPLY phase again:
942
    (%set-type-imm $builtin-arg1 +type-t+) ; function or builtin
943
    (%set-type-imm $builtin-arg2 +type-t+) ; list (cons or nil)
944
    (call :fetch-args)
945
    (%set-datum (e-arg) $builtin-arg1)
946
    (%set-datum (e-result) $builtin-arg2)
947
    (jump-imm :main-loop-end)
948
 
949
    :builtin-make-array ; (%make-array size init-value)
950
    (%set-type-imm $builtin-arg1 +type-int+)
951
    (%set-type-imm $builtin-arg2 +type-t+)
952
    (call :fetch-args)
953
    ;; TODO check size
954
    (%set-datum $tmp1 $builtin-arg1-val)
955
    (%add $tmp1 $two) ; $tmp1: words needed (array object + pointers + end marker)
956
    (alloc $tmp1)
957
    (%store-typed $builtin-arg1-val $alloc-addr 0 +type-array+)
958
    (%add $tmp1 $alloc-addr)
959
    (%decr $tmp1)                  ; $tmp1: address of end marker
960
    (%set-datum $tmp2 $alloc-addr)
961
    (%incr $tmp2)                  ; $tmp2: address to store pointer at
962
    :builtin-make-array-loop
963
    (%store-typed $builtin-arg2 $tmp2 0 +type-ptr+)
964
    (%incr $tmp2)
965
    (%cmp-datum $tmp2 $tmp1)
966
    (branchimm-false :builtin-make-array-loop)
967
    (%store-typed $zero $tmp2 0 +type-snoc+) ; end marker
968
    (%set-datum $apply-result $alloc-addr)
969
    (jump-imm :p-apply-end)
970
 
971
    :builtin-array-size ; (%array-size array)
972
    (%set-type-imm $builtin-arg1 +type-array+)
973
    (call :fetch-args)
974
    (%make-obj $apply-result $builtin-arg1-val +type-int+)
975
    (jump-imm :p-apply-end)
976
 
977
    :builtin-array-get ; (%array-get array index)
978
    (%set-type-imm $builtin-arg1 +type-array+)
979
    (%set-type-imm $builtin-arg2 +type-int+)
980
    (call :fetch-args)
981
 
982
    ;; check index;
983
    (%cmp-datum $builtin-arg2-val $builtin-arg1-val)
984
    (%branch* $zero :err-invalid-array-index (not N))
985
    (%cmp-datum $builtin-arg2-val $zero)
986
    (%branch* $zero :err-invalid-array-index N)
987
 
988
    (%add* $tmp1 $builtin-arg1 $builtin-arg2-val)
989
    (%load $apply-result $tmp1 1)
990
    (jump-imm :p-apply-end)
991
 
992
    :builtin-array-set ; (%array-set array index value) => array
993
    (%set-type-imm $builtin-arg1 +type-array+)
994
    (%set-type-imm $builtin-arg2 +type-int+)
995
    (%set-type-imm $builtin-arg3 +type-t+)
996
    (call :fetch-args)
997
 
998
    ;; check index;
999
    (%cmp-datum $builtin-arg2-val $builtin-arg1-val)
1000
    (%branch* $zero :err-invalid-array-index (not N))
1001
    (%cmp-datum $builtin-arg2-val $zero)
1002
    (%branch* $zero :err-invalid-array-index N)
1003
 
1004
    (%add* $tmp1 $builtin-arg1 $builtin-arg2-val)
1005
    (%store-typed $builtin-arg3 $tmp1 1 +type-ptr+)
1006
    (%set-datum $apply-result $builtin-arg1)
1007
    (jump-imm :p-apply-end)
1008
 
1009
    :builtin-make-symbol ; (%make-symbol str)
1010
    (%set-type-imm $builtin-arg1 +type-array+) ; TODO check that it is a string
1011
    (call :fetch-args)
1012
    (%make-obj $apply-result $builtin-arg1 +type-symbol+)
1013
    (jump-imm :p-apply-end)
1014
 
1015
    :builtin-symbol-to-string ; (%symbol-to-string symb)
1016
    (%set-type-imm $builtin-arg1 +type-symbol+)
1017
    (call :fetch-args)
1018
    (%set-datum $apply-result $builtin-arg1-val)
1019
    (jump-imm :p-apply-end)
1020
 
1021
    :builtin-char-to-int ; (%char-to-int ch)
1022
    (%set-type-imm $builtin-arg1 +type-char+)
1023
    (call :fetch-args)
1024
    (%make-int $apply-result $builtin-arg1-val)
1025
    (jump-imm :p-apply-end)
1026
 
1027
    :builtin-int-to-char ; (%int-to-char n)
1028
    (%set-type-imm $builtin-arg1 +type-int+)
1029
    (call :fetch-args)
1030
    (%make-char $apply-result $builtin-arg1-val)
1031
    ;;(%make-obj $apply-result $builtin-arg1-val +type-char+)
1032
    (jump-imm :p-apply-end)
1033
 
1034
    :builtin-char-eq? ; (%char-eq? ch1 ch2)
1035
    (%set-type-imm $builtin-arg1 +type-char+)
1036
    (%set-type-imm $builtin-arg2 +type-char+)
1037
    (call :fetch-args)
1038
    (%set-datum-imm $apply-result %nil)
1039
    (%when (%cmp-datum $builtin-arg1-val $builtin-arg2-val)
1040
      (%set-datum-imm $apply-result %t))
1041
    (jump-imm :p-apply-end)
1042
 
1043
    :builtin-get-char ; (%get-char devnr)
1044
    (%set-type-imm $builtin-arg1 +type-int+)
1045
    (call :fetch-args)
1046
    (select-device $builtin-arg1-val)
1047
;;    :builtin-get-char-read
1048
    (%load-typed $tmp1 $io-mem-addr %io-object +type-char+ :err-io-error)
1049
    ;; TODO handle errors
1050
    (%make-char $apply-result $tmp1)
1051
    (jump-imm :p-apply-end)
1052
 
1053
;;     :builtin-get-char-io-error
1054
;;     (message-str "I/O ERROR")
1055
;;     (message-reg $tmp1)
1056
;;     (%get-type $tmp2 $tmp1)
1057
;;     (message-reg $tmp2)
1058
;;     (jump-imm :builtin-get-char-read)
1059
 
1060
    :builtin-put-char ; (%put-char devnr ch) => ch
1061
    (%set-type-imm $builtin-arg1 +type-int+)
1062
    (%set-type-imm $builtin-arg2 +type-char+)
1063
    (call :fetch-args)
1064
    (select-device $builtin-arg1-val)
1065
    (%store $builtin-arg2-val $io-mem-addr %io-object)
1066
    ;; TODO handle errors
1067
    (%set-datum $apply-result $builtin-arg2)
1068
    (jump-imm :p-apply-end)
1069
 
1070
    :builtin-num-devices ; (%num-devices)
1071
    (call :fetch-args)
1072
    (%load-typed $tmp1 $io-mem-addr %io-devices +type-int+ :err-io-error)
1073
    (%make-int $apply-result $tmp1)
1074
    (jump-imm :p-apply-end)
1075
 
1076
    :builtin-device-type ; (%device-type devnr)
1077
    (%set-type-imm $builtin-arg1 +type-int+)
1078
    (call :fetch-args)
1079
    (select-device $builtin-arg1-val)
1080
    (%load-typed $tmp1 $io-mem-addr %io-identification +type-int+ :err-io-error)
1081
    (%make-int $apply-result $tmp1)
1082
    (jump-imm :p-apply-end)
1083
 
1084
    :builtin-set-address ; (%set-address devnr addr) => addr
1085
    ;; only sets lower part of address as of now
1086
    (%set-type-imm $builtin-arg1 +type-int+)
1087
    (%set-type-imm $builtin-arg2 +type-int+)
1088
    (call :fetch-args)
1089
    (select-device $builtin-arg1-val)
1090
    (%store-typed $builtin-arg2-val $io-mem-addr %io-addr-l +type-int+)
1091
    (%set-datum $apply-result $builtin-arg2)
1092
    (jump-imm :p-apply-end)
1093
 
1094
    :builtin-get-address ; (%get-address devnr)
1095
    ;; only gets lower part of address as of now
1096
    (%set-type-imm $builtin-arg1 +type-int+)
1097
    (call :fetch-args)
1098
    (select-device $builtin-arg1-val)
1099
    (%load-typed $tmp1 $io-mem-addr %io-addr-l +type-int+ :err-io-error)
1100
    (%make-int $apply-result $tmp1)
1101
    (jump-imm :p-apply-end)
1102
 
1103
    :builtin-device-size ; (%builtin-device-size devnr)
1104
    ;; only get lower part of size
1105
    (%set-type-imm $builtin-arg1 +type-int+)
1106
    (call :fetch-args)
1107
    (select-device $builtin-arg1-val)
1108
    (%load-typed $tmp1 $io-mem-addr %io-size-l +type-int+ :err-io-error)
1109
    (%make-int $apply-result $tmp1)
1110
    (jump-imm :p-apply-end)
1111
 
1112
    :builtin-device-status ; (%builtin-device-status devnr)
1113
    (%set-type-imm $builtin-arg1 +type-int+)
1114
    (call :fetch-args)
1115
    (select-device $builtin-arg1-val)
1116
    (%load-typed $tmp1 $io-mem-addr %io-status +type-int+ :err-io-error)
1117
    (%make-int $apply-result $tmp1)
1118
    (jump-imm :p-apply-end)
1119
 
1120
 
1121
 
1122
    :builtin-error ; (%error reason)
1123
    (%set-type-imm $builtin-arg1 +type-t+)
1124
    (call :fetch-args)
1125
    (%error $builtin-arg1)
1126
 
1127
    :builtin-add
1128
    (call :builtin-binop-fetch-args)
1129
    (%add* $apply-result-val $builtin-arg1-val $builtin-arg2-val)
1130
    (%branch* $zero :err-overflow O)
1131
    (jump-imm :builtin-binop-end)
1132
    :builtin-sub
1133
    (call :builtin-binop-fetch-args)
1134
    (%sub* $apply-result-val $builtin-arg1-val $builtin-arg2-val)
1135
    (%branch* $zero :err-overflow O)
1136
    (jump-imm :builtin-binop-end)
1137
    :builtin-mul
1138
    (call :builtin-binop-fetch-args)
1139
    (%mul* $apply-result-val $builtin-arg1-val $builtin-arg2-val)
1140
    (%branch* $zero :err-overflow O)
1141
    (jump-imm :builtin-binop-end)
1142
    :builtin-div
1143
    (call :builtin-binop-fetch-args)
1144
    (%when (%cmp-datum-imm $builtin-arg2-val 0)
1145
      (%error-imm %err-division-by-zero))
1146
    ;; binary search for the answer
1147
    (call :div-wrapper)
1148
    (jump-imm :builtin-binop-end)
1149
    :div-wrapper
1150
    (%sub* $div-res $zero $one)
1151
    (%cpy $div-sign $one)
1152
    (%cmp-datum $builtin-arg1-val $zero)
1153
    (%branch* $zero :div-nozero1 (not N))
1154
    (%xor $div-sign $one)
1155
    (%mul $builtin-arg1-val $div-res)
1156
    :div-nozero1
1157
    (%cmp-datum $builtin-arg2-val $zero)
1158
    (%branch* $zero :div-nozero2 (not N))
1159
    (%xor $div-sign $one)
1160
    (%mul $builtin-arg2-val $div-res)
1161
    :div-nozero2
1162
    (%cmp-datum $div-sign $zero)
1163
    (branchimm-false :div-nofix)
1164
    (%sub $div-sign $one)
1165
    :div-nofix
1166
    (call :div-noneg)
1167
    :div-afterdiv
1168
    (%mul $div-low $div-sign)
1169
    (%cpy $apply-result-val $div-low)
1170
    :div-slutten
1171
    (ret)
1172
 
1173
    ;; binaersoek: gitt arg1, arg2:
1174
    ;; finn ans slik at ans*arg2<=arg1 og (ans+1)*arg2>arg1
1175
 
1176
    :div-noneg
1177
    (%cmp-datum $builtin-arg1-val $builtin-arg2-val)
1178
    (branchimm-false :div-notequal)
1179
    (%cpy $div-low $one)
1180
    (ret)
1181
    :div-notequal
1182
    (%cmp-datum $builtin-arg1-val $builtin-arg2-val)
1183
    (%branch* $zero :div-fortsett (not N))
1184
    (%cpy $div-low $zero)
1185
    (ret)
1186
    :div-fortsett
1187
    (%set-datum $div-low $one)
1188
    (%set-type-imm $div-low +type-int+)
1189
    (%set-datum-imm $div-high 18631)
1190
    (%set-type-imm $div-high +type-int+)
1191
    (%set-datum-imm $div-mid 1801)
1192
    (%set-type-imm $div-mid +type-int+)
1193
    (%mul $div-high $div-mid) ;; voila, 2^25-1 (luckily 25 isn't prime)
1194
 
1195
    (%cmp-datum $builtin-arg2-val $zero)
1196
    (branchimm-false :div-check1)
1197
    (%cpy $div-low $zero)
1198
    (jump-imm :div-end)
1199
    ;; error
1200
    :div-check1
1201
    (%sub* $div-mid $div-high $div-low)
1202
    (%cmp-datum $div-mid $one)
1203
    (branchimm :div-end)
1204
 
1205
    :div-bsloop
1206
    (%sub* $div-mid $div-high $div-low)
1207
    (%shift-r $div-mid $one)
1208
    (%add $div-mid $div-low)
1209
    (%mul* $div-res $div-mid $builtin-arg2-val)
1210
    (%branch* $zero :div-toohigh O)
1211
    (%sub $div-res $one)
1212
    (%cmp-datum $div-res $builtin-arg1-val)
1213
    (%branch* $zero :div-toohigh (not N))
1214
    (%cpy $div-low $div-mid)
1215
    (jump-imm :div-check1)
1216
    :div-toohigh
1217
    (%cpy $div-high $div-mid)
1218
    (jump-imm :div-check1)
1219
    :div-end
1220
    (ret)
1221
    :builtin-mod
1222
    (call :builtin-binop-fetch-args)
1223
    (%cpy $mod-val1 $builtin-arg1-val)
1224
    (%cpy $mod-val2 $builtin-arg2-val)
1225
    (%when (%cmp-datum-imm $builtin-arg2-val 0)
1226
      (%error-imm %err-division-by-zero))
1227
    (call :div-wrapper)
1228
    :modbreak
1229
    (%mul $apply-result-val $mod-val2)
1230
    (%sub $mod-val1 $apply-result-val)
1231
    (%cpy $apply-result-val $mod-val1)
1232
    (jump-imm :builtin-binop-end)
1233
    :builtin-bitwise-and
1234
    (call :builtin-binop-fetch-args)
1235
    (%and* $apply-result-val $builtin-arg1-val $builtin-arg2-val)
1236
    (jump-imm :builtin-binop-end)
1237
    :builtin-bitwise-or
1238
    (call :builtin-binop-fetch-args)
1239
    (%or* $apply-result-val $builtin-arg1-val $builtin-arg2-val)
1240
    (jump-imm :builtin-binop-end)
1241
    :builtin-bitwise-not
1242
    (%set-type-imm $builtin-arg1 +type-int+)
1243
    (call :fetch-args)
1244
    (%set-type-imm $apply-result-val +type-int+)
1245
    (%not $apply-result-val $builtin-arg1-val)
1246
    (jump-imm :p-apply-end)
1247
    :builtin-bitwise-shift
1248
    (%set-type-imm $builtin-arg1 +type-int+)
1249
    (%set-type-imm $builtin-arg2 +type-int+)
1250
    (call :fetch-args)
1251
    (%cpy $apply-result-val $builtin-arg1-val)
1252
    (%cmp-datum-imm $builtin-arg2-val 0)
1253
    (%branch* $zero :builtin-bitwise-shift-right N)
1254
    (%shift-l $apply-result-val $builtin-arg2-val)
1255
    (jump-imm :builtin-binop-end)
1256
    :builtin-bitwise-shift-right
1257
    (%cpy $tmp1 $zero)
1258
    (%sub $tmp1 $builtin-arg2-val) ; $tmp1 = -arg2
1259
    (%shift-r $apply-result-val $tmp1)
1260
    (jump-imm :builtin-binop-end)
1261
 
1262
    :builtin-binop-fetch-args ; subroutine
1263
;;    (%set-type-imm $builtin-arg1 +type-t+)
1264
;;    (%set-type-imm $builtin-arg2 +type-t+)
1265
    (%set-type-imm $builtin-arg1 +type-int+) ; assume all binops want INTs as args
1266
    (%set-type-imm $builtin-arg2 +type-int+)
1267
    (jump-imm :fetch-args) ; tail call
1268
 
1269
    :builtin-binop-end
1270
    ;; TODO check for errors
1271
    (%cmp-type-imm $apply-result-val +type-int+)
1272
    (branchimm :builtin-binop-end-int)
1273
    (alloc-imm 1)
1274
    (%store $apply-result-val $alloc-addr 0)
1275
    (%set-datum $apply-result $alloc-addr)
1276
    (jump-imm :p-apply-end)
1277
    :builtin-binop-end-int
1278
    (%make-int $apply-result $apply-result-val)
1279
    (jump-imm :p-apply-end)
1280
 
1281
    :builtin-num-eq? ; (%num-eq? n1 n2)
1282
    (call :builtin-binop-fetch-args)
1283
    (%set-datum-imm $apply-result %nil)
1284
    (%when (%cmp-datum $builtin-arg1-val $builtin-arg2-val)
1285
      (%set-datum-imm $apply-result %t))
1286
    (jump-imm :p-apply-end)
1287
 
1288
    :builtin-less-than? ; (%less-than? n1 n2)
1289
    (call :builtin-binop-fetch-args)
1290
    (%set-datum-imm $apply-result %t)
1291
    (%cmp-datum $builtin-arg1-val $builtin-arg2-val)
1292
    (%branch* $zero :builtin-less-than?-end N)
1293
    (%set-datum-imm $apply-result %nil)
1294
    :builtin-less-than?-end
1295
    (jump-imm :p-apply-end)
1296
 
1297
    :builtin-current-environment ; (%current-environment)
1298
    (call :fetch-args)
1299
    (%set-datum $apply-result $f-env)
1300
    (jump-imm :p-apply-end)
1301
 
1302
    :builtin-make-eval-state ; (%make-eval-state expr env)
1303
    (%set-type-imm $builtin-arg1 +type-t+)
1304
    (%set-type-imm $builtin-arg2 +type-t+)
1305
    (call :fetch-args)
1306
    ;; TODO should we do some typechecking here?
1307
    (%set-datum $tmp1 $builtin-arg1)
1308
    (%set-datum $tmp2 $builtin-arg2)
1309
    (pop-eframe)
1310
    (call :push-s)
1311
    (call :init-evaluation-level)
1312
    (%set-datum (e-expr) $tmp1)
1313
    (%set-datum-imm (e-phase) %phase-eval)
1314
    (%set-datum $f-env $tmp2)
1315
    (call :interrupt)
1316
    (jump-imm :main-loop-end) ; note: not :p-apply-end
1317
 
1318
    :builtin-eval-partial ; (%eval-partial state iterations) => new-state
1319
    (%set-type-imm $builtin-arg1 +type-t+)
1320
    (%set-type-imm $builtin-arg2 +type-int+)
1321
    (call :fetch-args)
1322
    ;; TODO should we do some typechecking here?
1323
    (%set-datum $tmp1 $builtin-arg1)
1324
    (%set-datum $tmp2 $builtin-arg2-val)
1325
    (pop-eframe)
1326
    (call :push-s)
1327
    (%set-datum $s-addr $tmp1)
1328
    (call :load-sframe-without-parent)
1329
    (%set-datum $s-iterations $tmp2)
1330
    (jump-imm :main-loop)
1331
 
1332
    :builtin-define ; (%define symb val) => val
1333
    (%set-type-imm $builtin-arg1 +type-symbol+)
1334
    (%set-type-imm $builtin-arg2 +type-t+)
1335
    (call :fetch-args)
1336
    (%cons $tmp1 $builtin-arg1 $builtin-arg2) ; $tmp1: new binding
1337
    (%car $tmp2 $f-env :err-invalid-env)      ; $tmp2: local binding list
1338
    (%cons $tmp1 $tmp1 $tmp2)                 ; $tmp1: new local binding list
1339
    (%store-typed $tmp1 $f-env 0 +type-cons+) ; (set-car! $f-env $tmp1)
1340
    (%set-datum $apply-result $builtin-arg2)
1341
    (jump-imm :p-apply-end)
1342
 
1343
    :builtin-undefine ; (%undefine symb) => nil
1344
    ;;(%set-type-imm $builtin-arg1 +type-symbol+)
1345
    ;;(call :fetch-args)
1346
    ;;TODO
1347
    (message-str "UNDEF")
1348
    (%halt)
1349
 
1350
    :builtin-set! ; (%set! symb val) => val
1351
    (%set-type-imm $builtin-arg1 +type-symbol+)
1352
    (%set-type-imm $builtin-arg2 +type-t+)
1353
    (call :fetch-args)
1354
    (%set-datum $tmp1 $builtin-arg1)
1355
    (%set-datum (e-arg) $builtin-arg2)
1356
    (%set-datum-imm (e-phase) %phase-set!)
1357
    (push-eframe)
1358
    (%set-datum (e-expr) $tmp1)
1359
    (%set-datum (e-arg) $f-env)
1360
    (%set-datum-imm (e-phase) %phase-env-lookup)
1361
    (jump-imm :main-loop-end)
1362
 
1363
    :builtin-set-car! ; (%set-car! cell val) => val
1364
    (%set-type-imm $builtin-arg1 +type-cons+)
1365
    (%set-type-imm $builtin-arg2 +type-t+)
1366
    (call :fetch-args)
1367
    (%store-typed $builtin-arg2 $builtin-arg1 0 +type-cons+)
1368
    (%set-datum $apply-result $builtin-arg2)
1369
    (jump-imm :p-apply-end)
1370
 
1371
    :builtin-set-cdr! ; (%set-cdr! cell val) => val
1372
    (%set-type-imm $builtin-arg1 +type-cons+)
1373
    (%set-type-imm $builtin-arg2 +type-t+)
1374
    (call :fetch-args)
1375
    (%store-typed $builtin-arg2 $builtin-arg1 0 +type-snoc+)
1376
    (%set-datum $apply-result $builtin-arg2)
1377
    (jump-imm :p-apply-end)
1378
 
1379
    :builtin-function-data
1380
    (%set-type-imm $builtin-arg1 +type-function+)
1381
    (call :fetch-args)
1382
    (%load $apply-result $builtin-arg1 0)
1383
    (jump-imm :p-apply-end)
1384
 
1385
    :builtin-builtin-name
1386
    (%set-type-imm $builtin-arg1 +type-builtin+)
1387
    (call :fetch-args)
1388
    (%load $apply-result $builtin-arg1 0)
1389
    (jump-imm :p-apply-end)
1390
 
1391
 
1392
    :p-apply-end
1393
    (pop-eframe)
1394
    (%set-datum (e-result) $apply-result)
1395
    (jump-imm :main-loop-end)
1396
 
1397
 
1398
    ;; subroutine for getting the arguments to a builtin function
1399
    :fetch-args
1400
    (%set-datum $fetch-args-arglist (e-result))
1401
 
1402
    (%set-datum-imm $fetch-args-arg-reg $builtin-arg1)
1403
    (%set-datum-imm $fetch-args-argval-reg $builtin-arg1-val)
1404
    :fetch-args-loop
1405
 
1406
    (%cmp-type-imm (indirect-register $fetch-args-arg-reg) +type-none+)
1407
    (branchimm :fetch-args-end)
1408
    (%car $fetch-args-arg $fetch-args-arglist :err-too-few-args)
1409
    (%load $fetch-args-argval $fetch-args-arg 0)
1410
    (%when-not (%cmp-type-imm (indirect-register $fetch-args-arg-reg) +type-t+)
1411
      (%when-not (%cmp-type (indirect-register $fetch-args-arg-reg) $fetch-args-argval)
1412
        (%error-imm %err-type-error)))
1413
    (%cpy (indirect-register $fetch-args-arg-reg) $fetch-args-arg)
1414
    (%cpy (indirect-register $fetch-args-argval-reg) $fetch-args-argval)
1415
    (%cdr $fetch-args-arglist $fetch-args-arglist :err-too-few-args)
1416
 
1417
    (%cmp-datum-imm $fetch-args-arg-reg $builtin-arg3)
1418
    (branchimm :fetch-args-end)
1419
    (%add $fetch-args-arg-reg $one)
1420
    (%add $fetch-args-argval-reg $one)
1421
    (jump-imm :fetch-args-loop)
1422
 
1423
    :fetch-args-end
1424
    (%cmp-datum-imm $fetch-args-arglist %nil)
1425
    (branchimm-false :err-too-many-args)
1426
    (ret)
1427
 
1428
 
1429
 
1430
    :p-apply-function1
1431
    (%set-datum-imm (e-phase) %phase-apply-function)
1432
    (%cdr $tmp1 $apply-func :err-invalid-function) ; $tmp1: (param-list expr env)
1433
    (%car $tmp1 $tmp1 :err-invalid-function)       ; $tmp1: param list
1434
    (%set-datum $tmp2 (e-result))                   ; $tmp2: arg list
1435
    (push-eframe)
1436
    (%set-datum-imm (e-expr) %nil)
1437
    (%set-datum (e-arg) $tmp1)
1438
    (%set-datum (e-result) $tmp2)
1439
    (%set-datum-imm (e-phase) %phase-bind-args)
1440
    (jump-imm :main-loop-end)
1441
 
1442
    ;; PHASE: APPLY-FUNCTION
1443
 
1444
    :p-apply-function2
1445
    ;; (e-arg): function (address)
1446
    ;; (e-result): list of argument bindings (address)
1447
    (%load-typed $apply-func (e-arg) 0 +type-function+ :err-not-a-function)
1448
    (%cdr $cdr  $apply-func :err-invalid-function) ; $cdr: (param-list expr env)
1449
    (%cdr $cdr  $cdr        :err-invalid-function) ; $cdr: (expr env)
1450
    (%car $tmp1 $cdr        :err-invalid-function) ; $tmp1: expr
1451
    (%cdr $cdr  $cdr        :err-invalid-function) ; $cdr: (env)
1452
    (%car $tmp2 $cdr        :err-invalid-function) ; $tmp2: env
1453
    (%cons $tmp2 (e-result) $tmp2)                  ; $tmp2: new env
1454
    (%set-datum $tmp3 (e-arg))                      ; $tmp3: function (address)
1455
    (call :push-or-reuse-fframe)
1456
    (%set-datum $f-func $tmp3)
1457
    (%set-datum $f-env $tmp2)
1458
    (%set-datum (e-expr) $tmp1)
1459
    (%set-datum-imm (e-phase) %phase-eval)
1460
    (jump-imm :main-loop-end)
1461
 
1462
 
1463
    ;; PHASE: SET!
1464
 
1465
    :p-set!
1466
    ;; (e-arg): new value
1467
    ;; (e-result): existing binding (or nil if variable is unbound)
1468
    (%cmp-datum-imm (e-result) %nil)
1469
    (branchimm :err-unbound-symbol)
1470
    (%car $tmp1 (e-result) :err-invalid-state) ; check that (e-result) is a cons cell
1471
    (%store-typed (e-arg) (e-result) 1 +type-snoc+) ; (set-cdr! (e-result) (e-arg))
1472
    (%set-datum $tmp1 (e-arg))
1473
    (pop-eframe)
1474
    (%set-datum (e-result) $tmp1)
1475
    (jump-imm :main-loop-end)
1476
 
1477
 
1478
    ;; PHASE: INITIAL
1479
 
1480
    :p-initial
1481
    (%when (%cmp-datum-imm $s-parent %nil)
1482
      (message-str "HALT")
1483
      (%halt))
1484
    (call :interrupt)
1485
    ;; (jump-imm :main-loop-end) ; not necessary here
1486
 
1487
 
1488
    ;; All paths inside the main loop lead to here
1489
    :main-loop-end
1490
    (%cmp-datum $gc-firstfree $gc-mem-limit)   ; lots of memory left?
1491
    (%branch* $zero :main-loop-end-after-gc N) ; if so, skip GC
1492
    ;; Not enough memory, invoke GC. First store the evaluation state:
1493
    (call :store-sframe)
1494
    (%set-type-imm $tmp1 +type-cons+)
1495
    (%set-datum $tmp1 $s-addr)
1496
    (%store $tmp1 $zero %memory-root)
1497
    ;; Then call garbage collector:
1498
    (call :gc-garbagecollect)
1499
    (%cmp-datum $gc-firstfree $gc-mem-limit) ; lots of memory now?
1500
    (%branch* $zero :out-of-memory (not N))  ; if not, give up completely
1501
    (%load $s-addr $zero %memory-root)
1502
    (call :load-sframe)
1503
    :main-loop-end-after-gc
1504
    (%cmp-datum-imm $s-iterations 0)
1505
    (branchimm :main-loop)
1506
    (%sub $s-iterations $one)
1507
    (%cmp-datum-imm $s-iterations 0)
1508
    (branchimm-false :main-loop)
1509
    (%set-datum-imm $s-condition %timeout)
1510
    (call :interrupt)
1511
    (jump-imm :main-loop)
1512
 
1513
 
1514
    :out-of-memory
1515
    (message-str "ERROR: OUT OF MEMORY")
1516
    (%halt)
1517
 
1518
 
1519
    ;; ERROR HANDLERS:
1520
 
1521
    :err-not-a-list
1522
    (%error-imm %err-not-a-list)
1523
 
1524
    :err-not-a-pair
1525
    (%error-imm %err-not-a-pair)
1526
 
1527
    :err-not-a-function
1528
    (%error-imm %err-not-a-function)
1529
 
1530
    :err-malformed-form
1531
    (%error-imm %err-malformed-form)
1532
 
1533
    :err-invalid-function
1534
    (%error-imm %err-invalid-function)
1535
 
1536
    :err-invalid-builtin
1537
    (%error-imm %err-invalid-builtin)
1538
 
1539
    :err-invalid-env
1540
    (%error-imm %err-invalid-env)
1541
 
1542
    :err-unbound-symbol
1543
    (%error-imm %err-unbound-symbol)
1544
 
1545
    :err-invalid-param-list
1546
    (%error-imm %err-invalid-param-list)
1547
    :err-too-few-args
1548
    (%error-imm %err-too-few-args)
1549
    :err-too-many-args
1550
    (%error-imm %err-too-many-args)
1551
 
1552
    :err-invalid-array-index
1553
    (%error-imm %err-invalid-array-index)
1554
 
1555
    :err-invalid-phase
1556
    (%error-imm %err-invalid-phase)
1557
 
1558
    :err-invalid-state
1559
    (%error-imm %err-invalid-state)
1560
 
1561
    :err-io-error
1562
    (%error-imm %err-io-error)
1563
 
1564
    :err-overflow
1565
    (%error-imm %err-overflow)
1566
 
1567
 
1568
    ;; SUBROUTINES:
1569
 
1570
    :make-empty-environment
1571
    (%set-datum-imm $env %nil)
1572
    (%cons $env $env $env)
1573
    (ret)
1574
 
1575
 
1576
    ;; Subroutine. Initializes a new evaluation level (that is, a new
1577
    ;; state). Puts an initial e-frame at the bottom of the e/f
1578
    ;; buffer, pushes an e-frame on top of it (it is the caller's
1579
    ;; responsibility to initialize expr and phase in this new frame).
1580
    :init-evaluation-level
1581
    (%set-datum-imm $s-condition %nil)
1582
    (%set-datum-imm $s-iterations 0)
1583
 
1584
    (%set-datum-imm $f-func %nil)
1585
    (call :make-empty-environment)
1586
    (%set-datum $f-env $env)
1587
    (%set-datum-imm $f-addr %nil)
1588
 
1589
    (%set-datum-imm $e-expr $e/f-min-expr)
1590
    (%set-datum-imm $e-arg $e/f-min-arg)
1591
    (%set-datum-imm $e-result $e/f-min-result)
1592
    (%set-datum-imm $e-phase $e/f-min-phase)
1593
 
1594
    (%set-type-imm (e-expr) +type-cons+)
1595
    (%set-datum-imm (e-expr) %nil)
1596
    (%set-datum-imm (e-arg) %nil)
1597
    (%set-datum-imm (e-result) %nil)
1598
    (%set-datum-imm (e-phase) %phase-initial)
1599
    (%set-datum-imm $e-addr %nil)
1600
    (push-eframe)
1601
    (ret)
1602
 
1603
 
1604
    ;; Subroutine. End the current evaluation level. Stores the whole
1605
    ;; state to memory, returns it to the active e-frame in the
1606
    ;; previous level (or halt the machine if we were at the
1607
    ;; top-level).
1608
    :interrupt
1609
    (%cmp-datum-imm $s-parent %nil)
1610
    (branchimm :interrupt-at-top-level)
1611
    (call :store-sframe-without-parent)
1612
    (%set-datum $interrupt-tmp $s-addr)
1613
    (call :pop-s)
1614
    (%set-datum (e-result) $interrupt-tmp)
1615
    (ret)
1616
    :interrupt-at-top-level
1617
    (message-str "ERR:INTERRUPT")
1618
    (%load $tmp1 $s-condition 1)
1619
    (message-reg $tmp1)
1620
    (message-reg $e-expr)
1621
    (message-reg $e-arg)
1622
    (message-reg $e-result)
1623
    (message-reg $e-phase)
1624
    (%halt)
1625
 
1626
 
1627
    ;; STACK SUBROUTINES
1628
 
1629
    ;; Subroutine to take care of the cases in pushing e-frames when the
1630
    ;; new place isn't immediately available. This might be either because
1631
    ;; it is above the top of the buffer (in which case we should wrap
1632
    ;; around) or because it is occupied (in which case we should store
1633
    ;; the frame which is there to main memory).
1634
    :push-eframe-handle-overflow
1635
    (%cmp-datum-imm $e-expr $e/f-above-marker)
1636
    (branchimm-false :push-eframe-handle-overflow-store)
1637
    (%set-datum-imm $e-expr $e/f-min-expr)
1638
    (%set-datum-imm $e-arg $e/f-min-arg)
1639
    (%set-datum-imm $e-result $e/f-min-result)
1640
    (%set-datum-imm $e-phase $e/f-min-phase)
1641
    (%cmp-type-imm (e-expr) +type-none+)
1642
    (branchimm :push-eframe-handle-overflow-end)
1643
    :push-eframe-handle-overflow-store
1644
    ;; buffer is full
1645
    (%cmp-type-imm (e-expr) +type-function+)
1646
    (branchimm-false :push-eframe-handle-overflow-store-e)
1647
    (call :store-fframe)                ; sets $f-addr
1648
    (jump-imm :push-eframe-handle-overflow-end)
1649
    :push-eframe-handle-overflow-store-e
1650
    (call :store-eframe)                ; sets $e-addr
1651
    :push-eframe-handle-overflow-end
1652
    (%set-datum-imm (e-expr) +type-cons+)
1653
    (ret)
1654
 
1655
 
1656
    :pop-eframe-handle-underflow
1657
    (%cmp-datum-imm $e-expr $e/f-below-marker)
1658
    (branchimm-false :pop-eframe-handle-underflow-load)
1659
    (%set-datum-imm $e-expr $e/f-max-expr)
1660
    (%set-datum-imm $e-arg $e/f-max-arg)
1661
    (%set-datum-imm $e-result $e/f-max-result)
1662
    (%set-datum-imm $e-phase $e/f-max-phase)
1663
    (%cmp-type-imm (e-expr) +type-none+)
1664
    (branchimm-false :pop-eframe-handle-underflow-end)
1665
    :pop-eframe-handle-underflow-load
1666
    ;; buffer is empty
1667
    (%cmp-datum-imm $e-addr %nil)
1668
    (branchimm-false :pop-eframe-handle-underflow-load-e)
1669
    (jump-imm :load-fframe) ; tail call
1670
;;     (call :load-f-and-e-frame-to-empty-buffer) ; sets $e-addr, $f-addr
1671
;;     (ret)
1672
    :pop-eframe-handle-underflow-load-e
1673
    (call :load-eframe)
1674
    :pop-eframe-handle-underflow-end
1675
    (ret)
1676
 
1677
 
1678
 
1679
 
1680
    :store-eframe
1681
    (%set-type-imm (indirect-register $e-expr) +type-cons+)
1682
    (%set-type-imm (indirect-register $e-arg) +type-cons+)
1683
    (%set-type-imm (indirect-register $e-result) +type-cons+)
1684
    (%set-type-imm (indirect-register $e-phase) +type-cons+)
1685
    (%set-type-imm $e-addr +type-cons+)
1686
    (alloc-imm 10)
1687
    (%set-type-imm $e-tmp1 +type-snoc+)
1688
    (%set-datum $e-tmp1 $alloc-addr)
1689
    (%set-type-imm $e-tmp2 +type-int+)
1690
    (%set-datum-imm $e-tmp2 2)
1691
    (%set-type-imm $e-tmp3 +type-int+)
1692
    (%set-datum $e-tmp3 $e-tmp1)
1693
    (%store $e-addr $e-tmp1 0)
1694
    (%store $list-terminator $e-tmp1 1)
1695
    (%store (indirect-register $e-phase) $e-tmp1 2)
1696
    (%store $e-tmp1 $e-tmp1 3)
1697
    (%add $e-tmp3 $e-tmp2)
1698
    (%set-datum $e-tmp1 $e-tmp3)
1699
    (%store (indirect-register $e-result) $e-tmp1 2)
1700
    (%store $e-tmp1 $e-tmp1 3)
1701
    (%add $e-tmp3 $e-tmp2)
1702
    (%set-datum $e-tmp1 $e-tmp3)
1703
    (%store (indirect-register $e-arg) $e-tmp1 2)
1704
    (%store $e-tmp1 $e-tmp1 3)
1705
    (%add $e-tmp3 $e-tmp2)
1706
    (%set-datum $e-tmp1 $e-tmp3)
1707
    (%store (indirect-register $e-expr) $e-tmp1 2)
1708
    (%store $e-tmp1 $e-tmp1 3)
1709
    (%add $e-tmp3 $e-tmp2)
1710
    (%set-datum $e-addr $e-tmp3)
1711
    (ret)
1712
 
1713
    :load-eframe
1714
    (%car (indirect-register $e-expr) $e-addr :load-eframe-error)
1715
    (%cdr $e-tmp1 $e-addr :load-eframe-error)
1716
    (%car (indirect-register $e-arg) $e-tmp1 :load-eframe-error)
1717
    (%cdr $e-tmp1 $e-tmp1 :load-eframe-error)
1718
    (%car (indirect-register $e-result) $e-tmp1 :load-eframe-error)
1719
    (%cdr $e-tmp1 $e-tmp1 :load-eframe-error)
1720
    (%car (indirect-register $e-phase) $e-tmp1 :load-eframe-error)
1721
    (%cdr $e-tmp1 $e-tmp1 :load-eframe-error)
1722
    (%car $e-addr $e-tmp1 :load-eframe-error)
1723
    (ret)
1724
    :load-eframe-error
1725
    (message-str "ERR:L-E")
1726
    (%halt)
1727
 
1728
 
1729
 
1730
    ;; Subroutine. Makes sure there is a function frame with a single
1731
    ;; evaluation frame at the top of the stack. These might be the
1732
    ;; frames currently at the top (if the current e-frame has no
1733
    ;; parent, in which case it is safe to tail-call optimize) or new
1734
    ;; frames. If a new f-frame is pushed, the current e-frame is
1735
    ;; popped first.
1736
    :push-or-reuse-fframe
1737
    (%sub* $f-tmp1 $e-expr $e/f-frame-size)
1738
    (%when (%cmp-datum-imm $f-tmp1 $e/f-below-marker)
1739
      (%set-datum-imm $f-tmp1 $e/f-max-expr))
1740
    ;; is frame below current a func frame?
1741
    (%cmp-type-imm (indirect-register $f-tmp1) +type-function+)
1742
    ;; if it is, eframe has no parent, so we can reuse fframe:
1743
    (branchimm :push-or-reuse-fframe-can-reuse)
1744
    ;; is frame below current empty?
1745
    (%cmp-type-imm (indirect-register $f-tmp1) +type-none+)
1746
    ;; if not, eframe has parent in e/f buffer, so we cannot reuse fframe:
1747
    (branchimm-false :push-or-reuse-fframe-cannot-reuse)
1748
    ;; if we got here, $e-addr is the address of this e-frame's
1749
    ;; parent. check if it is NIL:
1750
    (%cmp-datum-imm $e-addr %nil)
1751
    ;; if not, eframe has parent in memory, so cannot reuse fframe:
1752
    (branchimm-false :push-or-reuse-fframe-cannot-reuse)
1753
    :push-or-reuse-fframe-can-reuse
1754
    ;; if we get to here, the eframe has no parent, so we can reuse fframe:
1755
    (%set-datum-imm (indirect-register $e-arg) %nil)
1756
    (%set-datum-imm (indirect-register $e-result) %nil) ; caller must set $e-expr, $e-phase
1757
    (ret)
1758
    :push-or-reuse-fframe-cannot-reuse
1759
    (pop-eframe)
1760
    (call :push-fframe)
1761
    (push-eframe)
1762
    (ret)
1763
 
1764
 
1765
    ;; Subroutine. Pushes the current f-frame onto the e/f buffer.
1766
    :push-fframe
1767
    ;; get a nice empty place in the e/f buffer:
1768
    (push-eframe)
1769
    ;; put our current fframe there:
1770
    (%set-datum (indirect-register $e-expr) $f-func)
1771
    (%set-datum (indirect-register $e-arg) $f-env)
1772
    ;; mark this as being an fframe by setting the type of the first
1773
    ;; register:
1774
    (%set-type-imm (indirect-register $e-expr) +type-function+)
1775
    (ret)
1776
 
1777
 
1778
 
1779
    ;; Subroutine. Stores the current frame in e/f buffer as an
1780
    ;; f-frame. Sets $f-addr to the address it was stored to, $e-addr to
1781
    ;; %nil (to indicate that the e-frame directly above this in the
1782
    ;; buffer has no parent).
1783
    :store-fframe
1784
    (%set-type-imm (indirect-register $e-expr) +type-cons+)
1785
    (%set-type-imm (indirect-register $e-arg) +type-cons+)
1786
    (%set-type-imm $f-addr +type-cons+)
1787
    (alloc-imm 8)
1788
    (%set-type-imm $f-tmp1 +type-snoc+)
1789
    (%set-datum $f-tmp1 $alloc-addr)
1790
    (%set-type-imm $f-tmp2 +type-int+)
1791
    (%set-datum-imm $f-tmp2 2)
1792
    (%set-type-imm $f-tmp3 +type-int+)
1793
    (%set-datum $f-tmp3 $f-tmp1)
1794
    (%store $f-addr $f-tmp1 0)
1795
    (%store $list-terminator $f-tmp1 1)
1796
    (%store $e-addr $f-tmp1 2)
1797
    (%store $f-tmp1 $f-tmp1 3)
1798
    (%add $f-tmp3 $f-tmp2)
1799
    (%set-datum $f-tmp1 $f-tmp3)
1800
    (%store (indirect-register $e-arg) $f-tmp1 2)
1801
    (%store $f-tmp1 $f-tmp1 3)
1802
    (%add $f-tmp3 $f-tmp2)
1803
    (%set-datum $f-tmp1 $f-tmp3)
1804
    (%store (indirect-register $e-expr) $f-tmp1 2)
1805
    (%store $f-tmp1 $f-tmp1 3)
1806
    (%add $f-tmp3 $f-tmp2)
1807
    (%set-datum $f-addr $f-tmp3)
1808
    (%set-datum-imm $e-addr %nil)
1809
    (ret)
1810
 
1811
    ;; Subroutine. Loads an f-frame into the e/f buffer. The f-frame is
1812
    ;; found at the memory address in $f-addr; this register is changed to
1813
    ;; be the address of this frame's parent. Sets $e-addr to the address
1814
    ;; of the top e-frame in this f-frame.
1815
    :load-fframe
1816
    (%car $f-tmp1 $f-addr :load-fframe-error)
1817
    (%set-datum (e-expr) $f-tmp1)
1818
    (%set-type-imm (e-expr) +type-function+)
1819
    (%cdr $f-tmp1 $f-addr :load-fframe-error)
1820
    (%car (e-arg) $f-tmp1 :load-fframe-error)
1821
    (%cdr $f-tmp1 $f-tmp1 :load-fframe-error)
1822
    (%car $e-addr $f-tmp1 :load-fframe-error)
1823
    (%cdr $f-tmp1 $f-tmp1 :load-fframe-error)
1824
    (%car $f-addr $f-tmp1 :load-fframe-error)
1825
    (ret)
1826
    ;;(jump-imm :load-eframe)                   ; tail call
1827
    :load-fframe-error
1828
    (message-str "ERR:L-F")
1829
    (%halt)
1830
 
1831
 
1832
    :load-f-and-e-frame-to-empty-buffer
1833
    (call :load-fframe)
1834
    (%set-datum $f-func (e-expr))
1835
    (%set-datum $f-env (e-arg))
1836
    (%set-type-imm (e-expr) +type-none+)
1837
    (jump-imm :load-eframe)             ; tail call
1838
 
1839
 
1840
 
1841
    :store-e/f-stack
1842
    (call :push-fframe)           ; put current fframe into e/f buffer
1843
    (%set-datum $e/f-top $e-expr)       ; remember current position
1844
    ;; Traverse the whole buffer, pushing dummy frames. This has the
1845
    ;; effect that all frames in the buffer will be stored to main memory.
1846
    :store-e/f-stack-loop
1847
    (push-eframe)
1848
    (%set-type-imm (indirect-register $e-expr) +type-none+)
1849
    (%cmp-datum $e-expr $e/f-top)
1850
    (branchimm-false :store-e/f-stack-loop)
1851
    (ret)
1852
 
1853
 
1854
    :push-s
1855
    (call :store-sframe)
1856
    (%set-datum $s-parent $s-addr)
1857
    (ret)
1858
 
1859
 
1860
    :store-sframe
1861
    (%cons $s-tmp $s-parent $list-terminator)
1862
    :store-sframe-without-parent-1
1863
    (%make-obj $s-iterations $s-iterations +type-int+)
1864
    (%cons $s-tmp $s-iterations $s-tmp)
1865
    (%cons $s-tmp $s-condition $s-tmp)
1866
    (call :store-e/f-stack) ; stores the whole e/f buffer, we get address
1867
                                        ; of top f-frame in $f-addr
1868
    (%cons $s-tmp $f-addr $s-tmp)
1869
    (%set-datum $s-addr $s-tmp)
1870
    (ret)
1871
    :store-sframe-without-parent
1872
    (%set-datum-imm $s-tmp %nil)
1873
    (jump-imm :store-sframe-without-parent-1)
1874
 
1875
 
1876
 
1877
    :pop-s
1878
    (%set-datum $s-addr $s-parent)
1879
    :load-sframe
1880
    (call :load-sframe-common)
1881
    (%cdr $s-tmp $s-tmp :load-sframe-error)
1882
    (%car $s-parent $s-tmp :load-sframe-error)
1883
    (jump-imm :load-f-and-e-frame-to-empty-buffer) ; tail call
1884
    :load-sframe-error
1885
    ;;(%error %err-invalid-state)
1886
    (message-str "ERR:L-S")
1887
    (%halt)
1888
 
1889
 
1890
 
1891
    :load-sframe-without-parent
1892
    (call :load-sframe-common)
1893
    (jump-imm :load-f-and-e-frame-to-empty-buffer) ; tail call
1894
    :load-sframe-without-parent-error
1895
    (%halt)
1896
 
1897
    :load-sframe-common
1898
    (%car $f-addr $s-addr :load-sframe-error)
1899
    (%cdr $s-tmp $s-addr :load-sframe-error)
1900
    (%car $s-condition $s-tmp :load-sframe-error)
1901
    (%cdr $s-tmp $s-tmp :load-sframe-error)
1902
    (%car $s-iterations $s-tmp :load-sframe-error)
1903
    (%load $s-iterations $s-iterations 0)
1904
    (ret)
1905
 
1906
 
1907
 
1908
    ;; OUTPUT
1909
 
1910
    ;; Subroutine, print int from $message
1911
    :message-reg
1912
    (select-device-imm +dev-serial+)
1913
    (%set-datum-imm $message-shift 24)
1914
    (%set-datum-imm $message-mask #xF)
1915
    :message-reg-loop
1916
    (%set-datum $message-tmp1 $message)
1917
    (%shift-r $message-tmp1 $message-shift)
1918
    (%and $message-tmp1 $message-mask)
1919
    (%set-datum-imm $message-tmp2 (char-int #\0))
1920
    (%cmp-datum-imm $message-tmp1 #xA)
1921
    (%branch* $zero :message-reg-below-a N)
1922
    (%set-datum-imm $message-tmp2 (- (char-int #\A) #xA))
1923
    :message-reg-below-a
1924
    (%add $message-tmp1 $message-tmp2)
1925
    (%store $message-tmp1 $io-mem-addr %io-object)
1926
    (%cmp-datum-imm $message-shift 0)
1927
    (branchimm :message-reg-loop-end)
1928
    (%set-datum-imm $message-tmp1 4)
1929
    (%sub $message-shift $message-tmp1)
1930
    (jump-imm :message-reg-loop)
1931
    :message-reg-loop-end
1932
    (ret)
1933
 
1934
 
1935
 
1936
 
1937
    ;; GARBAGE COLLECTOR
1938
 
1939
 
1940
    ;; Garbage collection subroutine
1941
    :gc-garbagecollect
1942
    (message-str-no-nl ":")
1943
 
1944
    ;; mark everything as free
1945
    (%cpy $gc-vi $gc-startofmem)
1946
 
1947
    :gc-loop1
1948
    ;; load the contents of memory address (contained in gc-vi)
1949
    ;; into register gc-1)
1950
    ;; loop tested in emu: OK
1951
    (%load $gc-1 $gc-vi 0)
1952
    ;; if gc-flag already free, stop
1953
    (%cmp-gc-imm $gc-1 +gc-free+)
1954
    (branchimm :gc-nodeletegc)
1955
    (%set-gc-imm $gc-1 +gc-free+)
1956
    (%store $gc-1 $gc-vi 0)
1957
    :gc-nodeletegc
1958
    (%add $gc-vi $one)
1959
    (%cmp-datum $gc-vi $gc-gcspace)
1960
    (branchimm-false :gc-loop1)
1961
    ;; pointer reversal! skrekk og gru
1962
    ;; algorithm based on tiger book
1963
 
1964
    ;; start of pointer reversal
1965
    ;; the algorithm is able to "slide" sideways without reversing
1966
    ;; underlying pointers within the following structures
1967
    ;; CONS - SNOC
1968
    ;; ARRAY - PTR - ... - PTR - SNOC
1969
 
1970
    ;; CONS/ARRAY are identified as start of structure
1971
    ;; SNOC is identified as end of structure
1972
 
1973
    (%set-type-imm $gc-t +type-int+)
1974
    (%set-datum-imm $gc-t 0)
1975
    (%cpy $gc-x $gc-rootptr)
1976
 
1977
 
1978
    :gc-mainreverseloop
1979
 
1980
    ;; visit current block
1981
    ;; gc-x holds current memory address
1982
    ;; gc-y will hold the contents of the address
1983
    (%load $gc-y $gc-x 0)
1984
    (%set-gc-imm $gc-y +gc-used+)
1985
    (%store $gc-y $gc-x 0)
1986
 
1987
    (%cpy $gc-followp $zero)
1988
    (%cpy $gc-cannext $zero)
1989
    (%cpy $gc-canprev $zero)
1990
 
1991
    ;; if memory address x contains a pointer, and it points to
1992
    ;; a memory address marked as gc-free (ie. unvisited so far)
1993
    ;; set followp to true (1)
1994
    ;; the following types have pointers: CONS PTR SNOC
1995
    ;; tested OK for case: cell is pointer, cell pointed to is unvisited
1996
    (%cmp-type-imm $gc-y +type-cons+)
1997
    (branchimm :gc-setfollowp)
1998
    (%cmp-type-imm $gc-y +type-snoc+)
1999
    (branchimm :gc-setfollowp)
2000
    (%cmp-type-imm $gc-y +type-ptr+)
2001
    (branchimm :gc-setfollowp)
2002
    (%cmp-type-imm $gc-y +type-function+)
2003
    (branchimm :gc-setfollowp)
2004
    (%cmp-type-imm $gc-y +type-symbol+)
2005
    (branchimm :gc-setfollowp)
2006
    (%cmp-type-imm $gc-y +type-builtin+)
2007
    (branchimm :gc-setfollowp)
2008
    ;; if any other types contain pointers, add them here!
2009
    (jump-imm :gc-afterfollowp)
2010
 
2011
    :gc-setfollowp
2012
 
2013
    ;; don't follow pointer if it's a low address
2014
;    (%cmp-datum $gc-y $gc-startofmem)
2015
;    (%branch* $zero :gc-afterfollowp (not N))
2016
 
2017
    ; copy from memory location $gc-y, into $gc-v
2018
    (%load $gc-v $gc-y 0)
2019
    (%cmp-gc-imm $gc-v +gc-used+)
2020
    (branchimm :gc-afterfollowp)
2021
    (%cpy $gc-followp $one)
2022
 
2023
    :gc-afterfollowp
2024
 
2025
    ;; if we aren't at the last position of a memory structure spanning
2026
    ;; several addresses and the next adress is free, set cannext=1
2027
    ;; currently, these types can occur at the non-end: CONS, ARRAY, PTR
2028
    ;; tested OK for case: cell is not end of structure, next cell is unvisited
2029
    (%cmp-type-imm $gc-y +type-cons+)
2030
    (branchimm :gc-setcannext)
2031
    (%cmp-type-imm $gc-y +type-array+)
2032
    (branchimm :gc-setcannext)
2033
    (%cmp-type-imm $gc-y +type-ptr+)
2034
    (branchimm :gc-setcannext)
2035
    (jump-imm :gc-aftercannext)
2036
    :gc-setcannext
2037
    (%cpy $gc-1 $gc-x) ;; check is address x+1 is unvisited
2038
    (%add $gc-1 $one)
2039
    (%load $gc-1 $gc-1 0) ;; lykkebo says this is safe
2040
    (%cmp-gc-imm $gc-1 +gc-used+)
2041
    (branchimm :gc-aftercannext)
2042
    (%cpy $gc-cannext $one)
2043
 
2044
    :gc-aftercannext
2045
 
2046
    ;; if we aren't at the first position of a memory structure spanning
2047
    ;; several addresses, set canprev=1
2048
    ;; the following types can occur at the non-start: SNOC PTR
2049
    ;; tested OK for case: cell is not end of structure
2050
    (%cmp-type-imm $gc-y +type-snoc+)
2051
    (branchimm :gc-setcanprev)
2052
    (%cmp-type-imm $gc-y +type-ptr+)
2053
    (branchimm :gc-setcanprev)
2054
    (jump-imm :gc-aftercanprev)
2055
    :gc-setcanprev
2056
    (%cpy $gc-canprev $one)
2057
 
2058
    :gc-aftercanprev
2059
 
2060
    ;; do stuff based on followp, cannext, canprev
2061
    ;; follow the pointer we're at, and reverse the pointer
2062
    (%cmp-datum $gc-followp $one)
2063
    (branchimm-false :gc-afterfollowedp)
2064
    (%cpy $gc-temp $gc-x)
2065
    (%load $gc-mem $gc-temp 0)
2066
    (%set-datum $gc-mem $gc-t)
2067
    (%store $gc-mem $gc-temp 0)
2068
    (%cpy $gc-t $gc-temp)
2069
    (%set-datum $gc-x $gc-y)
2070
    (jump-imm :gc-mainreverseloop)
2071
 
2072
    :gc-afterfollowedp
2073
 
2074
    ;; move to next memory location
2075
    (%cmp-datum $gc-cannext $one)
2076
    (branchimm-false :gc-aftercouldnext)
2077
    (%add $gc-x $one)
2078
    (jump-imm :gc-mainreverseloop)
2079
 
2080
    :gc-aftercouldnext
2081
 
2082
    ;; move to previous memory location
2083
    (%cmp-datum $gc-canprev $one)
2084
    (branchimm-false :gc-aftercouldprev)
2085
    ;; address 0x48
2086
    (%sub $gc-x $one)
2087
    (jump-imm :gc-mainreverseloop)
2088
 
2089
    :gc-aftercouldprev
2090
 
2091
    ;; all cases exhausted: follow pointer back and reverse the reversal
2092
    (%cmp-datum $gc-t $zero)
2093
    (branchimm :gc-donepointerreversal)
2094
    (%load $gc-temp $gc-t 0) ;; read from address gc-t, into gc-temp
2095
    (%cpy $gc-mem $gc-temp)
2096
    (%set-datum $gc-mem $gc-x)
2097
    (%store $gc-mem $gc-t 0) ;; restore the correct pointer in gc-t
2098
    (%cpy $gc-x $gc-t)
2099
    (%cpy $gc-t $gc-temp)
2100
    (jump-imm :gc-mainreverseloop)
2101
 
2102
    :gc-donepointerreversal
2103
 
2104
 
2105
    (message-str-no-nl ",")
2106
 
2107
    ;; end of pointer reversal routine, from this point on,
2108
    ;; all variables marked with "ptr-rev" are free for other use
2109
 
2110
    ;; pre-fill low memory values into translation area
2111
    (%cpy $gc-from $zero)
2112
    (%cpy $gc-to $gc-gcspace)
2113
    :gc-prefill
2114
    (%store $gc-from $gc-to 0)
2115
    (%add $gc-from $one)
2116
    (%add $gc-to $one)
2117
    (%cmp-datum $gc-from $gc-startofmem)
2118
    (branchimm-false :gc-prefill)
2119
 
2120
    ;; copy the stuff
2121
 
2122
    (%cpy $gc-to $gc-from)
2123
    (%cpy $gc-baseaddr $zero)
2124
    :gc-copyloop
2125
 
2126
    (%load $gc-mem $gc-from 0) ;; read from gc-from into gc-mem
2127
    (%cmp-gc-imm $gc-mem +gc-used+)
2128
    (branchimm-false :gc-notrans)
2129
    ;; put address in translation table
2130
    (%cpy $gc-temp $gc-from)
2131
    (%sub $gc-temp $gc-baseaddr)
2132
;    (%div* $gc-mem $gc-from $gc-spacesize)
2133
;    (%mul $gc-mem $gc-spacesize)
2134
;    (%cpy $gc-temp2 $gc-from)
2135
;    (%sub $gc-temp2 $gc-mem)
2136
    (%add $gc-temp $gc-gcspace)
2137
    (%store $gc-to $gc-temp 0) ;; write to-address to gc-temp
2138
    ;; copy
2139
;;    (%load $gc-mem $gc-from 0)
2140
    (%store $gc-mem $gc-to 0)
2141
    (%add $gc-to $one)
2142
    :gc-notrans
2143
    (%add $gc-from $one)
2144
 
2145
    (%cpy $gc-temp $gc-baseaddr)
2146
    (%add $gc-temp $gc-spacesize)
2147
 
2148
 
2149
;    (%div* $gc-temp $gc-from $gc-spacesize)
2150
;    (%mul $gc-temp $gc-spacesize)
2151
;    (%sub* $gc-temp2 $gc-from $gc-temp)
2152
    (%cmp-datum $gc-from $gc-temp)
2153
    (branchimm-false :gc-noconvert)
2154
 
2155
    ;; translate pointers
2156
    :gc-transloop
2157
    (%cpy $gc-vi $gc-startofmem)
2158
 
2159
    (message-str-no-nl ".")
2160
 
2161
    :gc-transloop2
2162
    (%load $gc-mem $gc-vi 0) ;; read from address gc-i and put into gc-mem
2163
    (%cmp-gc-imm $gc-mem +gc-used+)
2164
    (branchimm-false :gc-nexttrans)
2165
    (%cmp-type-imm $gc-mem +type-ptr+)
2166
    (branchimm :gc-isptr)
2167
    (%cmp-type-imm $gc-mem +type-cons+)
2168
    (branchimm :gc-isptr)
2169
    (%cmp-type-imm $gc-mem +type-snoc+)
2170
    (branchimm :gc-isptr)
2171
    (%cmp-type-imm $gc-mem +type-symbol+)
2172
    (branchimm :gc-isptr)
2173
    (%cmp-type-imm $gc-mem +type-function+)
2174
    (branchimm :gc-isptr)
2175
    (%cmp-type-imm $gc-mem +type-builtin+)
2176
    (branchimm :gc-isptr)
2177
    (jump-imm :gc-nexttrans)
2178
 
2179
    :gc-isptr
2180
;; check that these branches work
2181
;; OK for mem>=from-spacesize og mem
2182
    (%sub* $gc-temp $gc-from $gc-spacesize)
2183
    (%cmp-datum $gc-mem $gc-temp)
2184
    (%branch* $zero :gc-nexttrans N)
2185
    (%cmp-datum $gc-mem $gc-from)
2186
    (%branch* $zero :gc-nexttrans (not N))
2187
 
2188
    ;; calculate gcspace+val%spacesize, put in val
2189
    (%cpy $gc-val $gc-mem)
2190
    (%sub $gc-val $gc-baseaddr)
2191
    (%add $gc-val $gc-gcspace)
2192
 
2193
;    (%div* $gc-temp $gc-val $gc-spacesize)
2194
;    (%mul $gc-temp $gc-spacesize)
2195
;    (%sub* $gc-temp2 $gc-val $gc-temp)
2196
;    (%add* $gc-val $gc-temp2 $gc-gcspace)
2197
    (%load $gc-temp2 $gc-val 0)
2198
    (%set-datum $gc-mem $gc-temp2)
2199
    (%store $gc-mem $gc-vi 0)
2200
 
2201
    :gc-nexttrans
2202
    (%add $gc-vi $one)
2203
    (%cmp-datum $gc-vi $gc-to)
2204
    (branchimm-false :gc-noto)
2205
    (%cpy $gc-vi $gc-from)
2206
    :gc-noto
2207
    (%cmp-datum $gc-vi $gc-gcspace)
2208
    (branchimm-false :gc-transloop2)
2209
 
2210
    ;; done with one block, increase base address
2211
    (%add $gc-baseaddr $gc-spacesize)
2212
 
2213
    :gc-noconvert
2214
 
2215
    (%cmp-datum $gc-from $gc-gcspace)
2216
    (branchimm-false :gc-copyloop)
2217
 
2218
    ;; whee, gc is finished and we have a new address where
2219
    ;; free space starts
2220
    (%cpy $gc-firstfree $gc-to)
2221
    (message-str-no-nl ":")
2222
    (ret)
2223
    ;; End of garbage collection subroutine
2224
 
2225
 
2226
    :call-error
2227
    (message-str "ERR:CALL")
2228
    (%halt)
2229
    :ret-error
2230
    (message-str "ERR:RET")
2231
    (%halt)
2232
    ))
2233
 
2234
 
2235
(defun write-register-file ()
2236
  (with-open-file (s
2237
                   "/tmp/regfile"
2238
                   :element-type 'character
2239
                   :direction :output
2240
                   :if-does-not-exist :create
2241
                   :if-exists :supersede)
2242
    (let ((symbols-start #x100))
2243
      (format s "size ~X~%" +n-regs+)
2244
      ;; initialize some general registers:
2245
      (format s "addr 0~%")
2246
      (format s "int 0~%")               ; $zero
2247
      (format s "int 1~%")               ; $one
2248
      (format s "int 2~%")               ; $two
2249
      (format s "addr ~X~%" $list-terminator)
2250
      (format s "snoc ~X~%" %nil)
2251
      (format s "addr ~X~%" $mc-stack-top)
2252
      (format s "int ~X~%" $mc-stack-min)
2253
      (format s "addr ~X~%" $io-mem-addr)
2254
      (format s "int 3FFFF00~%")
2255
      (format s "addr ~X~%" $gc-maxblocks)
2256
      (format s "int ~X~%" +memory-size+)
2257
      (format s "addr ~X~%" $gc-spacesize)
2258
      (format s "int ~X~%" (floor (/ +memory-size+ +gc-spaces+)))
2259
      ;; write symbol strings in compressed form (three characters per
2260
      ;; register):
2261
      (format s "addr ~X~%" symbols-start)
2262
      (loop for v in (compress-symbols (make-symbols))
2263
         do (format s "int ~X~%" v))
2264
      ;; initialize registers used by initialization:
2265
      (format s "addr ~X~%" $init1)
2266
      (format s "nil~%")                  ; init1
2267
      (format s "t~%")                    ; init2
2268
      (format s "none~%")                 ; init3
2269
      (format s "int ~X~%" symbols-start) ; init-counter
2270
      (format s "int 0~%")                ; init-counter2
2271
      (format s "int 10~%")               ; init-shift1
2272
      (format s "int 8~%")                ; init-shift2
2273
      (format s "int FF~%")               ; init-char-mask
2274
      (format s "int ~X~%" %area-chars)   ; init-chars-start
2275
      (format s "int 2~%")                ; init-symbol-addr
2276
      (format s "int ~X~%" %area-strings) ; init-symbol-str-addr
2277
      (format s "int ~X~%" %area-strings) ; init-symbol-char-addr
2278
      (format s "array 0~%")              ; init-symbol-array
2279
      )))
2280
 
2281
(defun make-symbols ()
2282
  (let ((symbols "%IF
2283
%QUOTE
2284
%LAMBDA
2285
%PROGN
2286
%CONS
2287
%CAR
2288
%CDR
2289
%EVAL
2290
%APPLY
2291
%TYPE
2292
%MAKE-ARRAY
2293
%ARRAY-SIZE
2294
%ARRAY-GET
2295
%ARRAY-SET
2296
%MAKE-SYMBOL
2297
%SYMBOL-TO-STRING
2298
%CHAR-TO-INT
2299
%INT-TO-CHAR
2300
%GET-CHAR
2301
%PUT-CHAR
2302
%NUM-DEVICES
2303
%DEVICE-TYPE
2304
%SET-ADDRESS
2305
%GET-ADDRESS
2306
%ERROR
2307
%ADD
2308
%SUB
2309
%MUL
2310
%DIV
2311
%BITWISE-AND
2312
%BITWISE-OR
2313
%BITWISE-NOT
2314
%BITWISE-SHIFT
2315
%CURRENT-ENVIRONMENT
2316
%MAKE-EVAL-STATE
2317
%EVAL-PARTIAL
2318
%DEFINE
2319
%UNDEFINE
2320
%EQ?
2321
%NUM-EQ?
2322
%CHAR-EQ?
2323
%LESS-THAN?
2324
%MOD
2325
%SET!
2326
%SET-CAR!
2327
%SET-CDR!
2328
%FUNCTION-DATA
2329
%BUILTIN-NAME
2330
%DEVICE-SIZE
2331
%DEVICE-STATUS
2332
 
2333
 
2334
 
2335
 
2336
 
2337
 
2338
 
2339
 
2340
 
2341
 
2342
 
2343
%SYMBOL-TABLE
2344
%PHASE-EVAL
2345
%PHASE-EVAL-ARGS
2346
%PHASE-APPLY
2347
%PHASE-EVAL-IF
2348
%PHASE-INITIAL
2349
%PHASE-ENV-LOOKUP
2350
%PHASE-ENV-LOOKUP-LOCAL
2351
%PHASE-APPLY-FUNCTION
2352
%PHASE-BIND-ARGS
2353
%PHASE-EVAL-PROGN
2354
%PHASE-EVAL-ARGS-TOP
2355
%PHASE-EVAL-ARGS-CDR
2356
%PHASE-EVAL-ARGS-CONS
2357
%PHASE-EVAL-SYMBOL
2358
%PHASE-SET!
2359
 
2360
%TIMEOUT
2361
%ERR-INVALID-PHASE
2362
%ERR-UNBOUND-SYMBOL
2363
%ERR-INVALID-PARAM-LIST
2364
%ERR-TOO-FEW-ARGS
2365
%ERR-TOO-MANY-ARGS
2366
%ERR-INVALID-STATE
2367
%ERR-INVALID-ARG-LIST
2368
%ERR-TYPE-ERROR
2369
%ERR-NOT-A-LIST
2370
%ERR-NOT-A-FUNCTION
2371
%ERR-INVALID-FUNCTION
2372
%ERR-MALFORMED-FORM
2373
%ERR-INVALID-BUILTIN
2374
%ERR-INVALID-ARRAY-INDEX
2375
%ERR-INVALID-ENV
2376
%ERR-NOT-A-PAIR
2377
%ERR-IO-ERROR
2378
%ERR-DIVISION-BY-ZERO
2379
%ERR-OVERFLOW
2380
"))
2381
    (loop for ch across symbols
2382
         collect (if (char= ch #\Newline)
2383
 
2384
                     (char-int ch)))))
2385
 
2386
(defun compress-symbols (char-list)
2387
  (if char-list
2388
      (let* ((c1 (car char-list))
2389
             (l1 (cdr char-list))
2390
             (c2 (if l1 (car l1) 0))
2391
             (l2 (if l1 (cdr l1) nil))
2392
             (c3 (if l2 (car l2) 0))
2393
             (l3 (if l2 (cdr l2) nil)))
2394
        (cons (logior (ash c1 16)
2395
                      (ash c2 8)
2396
                      c3)
2397
              (compress-symbols l3)))
2398
      nil))

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.