1 ;;;; File: "picobit.scm", Time-stamp: <2006-05-08 16:04:37 feeley>
3 ;;;; Copyright (C) 2004-2009 by Marc Feeley and Vincent St-Amour
4 ;;;; All Rights Reserved.
7 (proper-tail-calls-set! #f)
11 ;-----------------------------------------------------------------------------
13 (define compiler-error
14 (lambda (msg . others)
15 (display "*** ERROR -- ")
17 (for-each (lambda (x) (display " ") (write x)) others)
21 ;-----------------------------------------------------------------------------
25 (cond ((null? lst) '())
26 ((keep? (car lst)) (cons (car lst) (keep keep? (cdr lst))))
27 (else (keep keep? (cdr lst))))))
32 (cons (car lst) (take (- n 1) (cdr lst)))
38 (drop (- n 1) (cdr lst))
44 (cons x (repeat (- n 1) x))
49 (let loop ((lst lst) (i 0))
50 (cond ((not (pair? lst)) #f)
52 (else (loop (cdr lst) (+ i 1)))))))
57 (and (pred? (car lst))
58 (every pred? (cdr lst))))))
60 ;-----------------------------------------------------------------------------
62 ;; Syntax-tree node representation.
65 extender: define-type-of-node
70 (define-type-of-node cst
74 (define-type-of-node ref
78 (define-type-of-node def
82 (define-type-of-node set
86 (define-type-of-node if
89 (define-type-of-node prc
95 (define-type-of-node call
98 (define-type-of-node seq
101 (define-type-of-node fix
108 (let ((val (cst-val node)))
113 (var-id (ref-var node)))
116 (var-id (def-var node))
117 (node->expr (child1 node))))
120 (var-id (set-var node))
121 (node->expr (child1 node))))
124 (node->expr (child1 node))
125 (node->expr (child2 node))
126 (node->expr (child3 node))))
128 (if (seq? (child1 node))
130 (cons (build-pattern (prc-params node) (prc-rest? node))
131 (nodes->exprs (node-children (child1 node)))))
133 (build-pattern (prc-params node) (prc-rest? node))
134 (node->expr (child1 node)))))
136 (map node->expr (node-children node)))
138 (let ((children (node-children node)))
139 (cond ((null? children)
141 ((null? (cdr children))
142 (node->expr (car children)))
145 (nodes->exprs children))))))
147 (let ((children (node-children node)))
149 (map (lambda (var val)
153 (take (- (length children) 1) children))
154 (node->expr (list-ref children (- (length children) 1))))))
156 (compiler-error "unknown expression type" node)))))
162 (if (seq? (car nodes))
163 (append (nodes->exprs (node-children (car nodes)))
164 (nodes->exprs (cdr nodes)))
165 (cons (node->expr (car nodes))
166 (nodes->exprs (cdr nodes)))))))
168 (define build-pattern
169 (lambda (params rest?)
170 (cond ((null? params)
172 ((null? (cdr params))
174 (var-id (car params))
175 (list (var-id (car params)))))
177 (cons (var-id (car params))
178 (build-pattern (cdr params) rest?))))))
180 ;-----------------------------------------------------------------------------
182 ;; Environment representation.
194 (define-type primitive
200 (define-type renaming
204 (define make-global-env
207 (make-var '#%number? #t '() '() '() #f (make-primitive 1 #f #f))
208 (make-var '#%+ #t '() '() '() #f (make-primitive 2 #f #f))
209 (make-var '#%- #t '() '() '() #f (make-primitive 2 #f #f))
210 (make-var '#%* #t '() '() '() #f (make-primitive 2 #f #f))
211 (make-var '#%quotient #t '() '() '() #f (make-primitive 2 #f #f))
212 (make-var '#%remainder #t '() '() '() #f (make-primitive 2 #f #f))
213 (make-var '#%neg #t '() '() '() #f (make-primitive 1 #f #f))
214 (make-var '#%= #t '() '() '() #f (make-primitive 2 #f #f))
215 (make-var '#%< #t '() '() '() #f (make-primitive 2 #f #f))
216 (make-var '#%ior #t '() '() '() #f (make-primitive 2 #f #f))
217 (make-var '#%> #t '() '() '() #f (make-primitive 2 #f #f))
218 (make-var '#%xor #t '() '() '() #f (make-primitive 2 #f #f))
219 (make-var '#%pair? #t '() '() '() #f (make-primitive 1 #f #f))
220 (make-var '#%cons #t '() '() '() #f (make-primitive 2 #f #f))
221 (make-var '#%car #t '() '() '() #f (make-primitive 1 #f #f))
222 (make-var '#%cdr #t '() '() '() #f (make-primitive 1 #f #f))
223 (make-var '#%set-car! #t '() '() '() #f (make-primitive 2 #f #t))
224 (make-var '#%set-cdr! #t '() '() '() #f (make-primitive 2 #f #t))
225 (make-var '#%null? #t '() '() '() #f (make-primitive 1 #f #f))
226 (make-var '#%eq? #t '() '() '() #f (make-primitive 2 #f #f))
227 (make-var '#%not #t '() '() '() #f (make-primitive 1 #f #f))
228 (make-var '#%get-cont #t '() '() '() #f (make-primitive 0 #f #f))
229 (make-var '#%graft-to-cont #t '() '() '() #f (make-primitive 2 #f #f))
230 (make-var '#%return-to-cont #t '() '() '() #f (make-primitive 2 #f #f))
231 (make-var '#%halt #t '() '() '() #f (make-primitive 0 #f #t))
232 (make-var '#%symbol? #t '() '() '() #f (make-primitive 1 #f #f))
233 (make-var '#%string? #t '() '() '() #f (make-primitive 1 #f #f))
234 (make-var '#%string->list #t '() '() '() #f (make-primitive 1 #f #f))
235 (make-var '#%list->string #t '() '() '() #f (make-primitive 1 #f #f))
236 (make-var '#%make-u8vector #t '() '() '() #f (make-primitive 2 #f #f))
237 (make-var '#%u8vector-ref #t '() '() '() #f (make-primitive 2 #f #f))
238 (make-var '#%u8vector-set! #t '() '() '() #f (make-primitive 3 #f #t))
239 (make-var '#%print #t '() '() '() #f (make-primitive 1 #f #t))
240 (make-var '#%clock #t '() '() '() #f (make-primitive 0 #f #f))
241 (make-var '#%motor #t '() '() '() #f (make-primitive 2 #f #t))
242 (make-var '#%led #t '() '() '() #f (make-primitive 3 #f #t))
243 (make-var '#%led2-color #t '() '() '() #f (make-primitive 1 #f #t))
244 (make-var '#%getchar-wait #t '() '() '() #f (make-primitive 2 #f #f))
245 (make-var '#%putchar #t '() '() '() #f (make-primitive 2 #f #t))
246 (make-var '#%beep #t '() '() '() #f (make-primitive 2 #f #f))
247 (make-var '#%adc #t '() '() '() #f (make-primitive 1 #f #f))
248 (make-var '#%u8vector? #t '() '() '() #f (make-primitive 1 #f #f))
249 (make-var '#%sernum #t '() '() '() #f (make-primitive 0 #f #f))
250 (make-var '#%u8vector-length #t '() '() '() #f (make-primitive 1 #f #f))
251 (make-var '#%u8vector-copy! #t '() '() '() #f (make-primitive 5 #f #t))
252 (make-var '#%boolean? #t '() '() '() #f (make-primitive 1 #f #f))
253 (make-var '#%network-init #t '() '() '() #f (make-primitive 0 #f #t))
254 (make-var '#%network-cleanup #t '() '() '() #f (make-primitive 0 #f #t))
255 (make-var '#%receive-packet-to-u8vector #t '() '() '() #f (make-primitive 1 #f #f))
256 (make-var '#%send-packet-from-u8vector #t '() '() '() #f (make-primitive 2 #f #f))
257 (make-var '#%<= #t '() '() '() #f (make-primitive 2 #f #f))
258 (make-var '#%>= #t '() '() '() #f (make-primitive 2 #f #f))
260 (make-var '#%readyq #t '() '() '() #f #f)
261 ;; TODO put in a meaningful order
264 ;; list of primitives that can be safely substituted for the equivalent
265 ;; function when it is called.
266 ;; this saves the calls to the primitive wrapper functions, which are still
267 ;; needed if a program needs the value of a "primitive", for example in :
269 (define substitute-primitives
270 '((number? . #%number?)
271 (quotient . #%quotient)
272 (remainder . #%remainder)
282 (set-car! . #%set-car!)
283 (set-cdr! . #%set-cdr!)
287 (modulo . #%remainder)
288 (symbol? . #%symbol?)
289 (string? . #%string?)
290 (string->list . #%string->list)
291 (list->string . #%list->string)
299 (bitwise-ior . #%ior)
300 (bitwise-xor . #%xor)
301 (current-time . #%clock)
302 (u8vector-length . #%u8vector-length)
303 (u8vector-ref . #%u8vector-ref)
304 (u8vector-set! . #%u8vector-set!)
305 (make-u8vector . #%make-u8vector)
306 (u8vector-copy! . #%u8vector-copy!)
307 (boolean? . #%boolean?)
308 (network-init . #%network-init)
309 (network-cleanup . #%network-cleanup)
310 (receive-packet-to-u8vector . #%receive-packet-to-u8vector)
311 (send-packet-from-u8vector . #%send-packet-from-u8vector)
316 (let loop ((lst env) (id id))
318 (cond ((and (renaming? b)
319 (assq id (renaming-renamings b)))
322 (loop (cdr lst) (cadr x))))
327 (let ((x (make-var id #t '() '() '() #f #f)))
328 (set-cdr! lst (cons x '()))
331 (loop (cdr lst) id)))))))
334 (lambda (env ids def)
335 (append (map (lambda (id)
336 (make-var id #f '() '() (list def) #f #f))
340 (define env-extend-renamings
341 (lambda (env renamings)
342 (cons (make-renaming renamings) env)))
344 (define *macros* '())
346 ;-----------------------------------------------------------------------------
350 (define parse-program
352 (let ((x (parse-top expr env)))
354 (parse 'value #f env))
358 (let ((r (make-seq #f x)))
359 (for-each (lambda (y) (node-parent-set! y r)) x)
364 (cond ((and (pair? expr)
365 (eq? (car expr) 'define-macro))
367 (cons (cons (caadr expr)
368 (eval `(lambda ,(cdadr expr) . ,(cddr expr))))
372 (eq? (car expr) 'begin))
373 (parse-top-list (cdr expr) env))
375 (eq? (car expr) 'hide))
376 (parse-top-hide (cadr expr) (cddr expr) env))
378 (eq? (car expr) 'rename))
379 (parse-top-rename (cadr expr) (cddr expr) env))
381 (eq? (car expr) 'define))
383 (if (pair? (cadr expr))
387 (if (pair? (cadr expr))
388 (cons 'lambda (cons (cdr (cadr expr)) (cddr expr)))
390 (let* ((var2 (env-lookup env var))
391 (val2 (parse 'value val env))
392 (r (make-def #f (list val2) var2)))
393 (node-parent-set! val2 r)
394 (var-defs-set! var2 (cons r (var-defs var2)))
397 (list (parse 'value expr env))))))
399 (define parse-top-list
402 (append (parse-top (car lst) env)
403 (parse-top-list (cdr lst) env))
406 (define parse-top-hide
407 (lambda (renamings body env)
410 (env-extend-renamings env renamings))
412 ;; (map (lambda (x) (list 'define (car x) (cadr x))) renamings)
416 (define parse-top-rename
417 (lambda (renamings body env)
419 (env-extend-renamings env renamings))))
422 (lambda (use expr env)
423 (cond ((self-eval? expr)
424 (make-cst #f '() expr))
426 (let* ((var (env-lookup env expr))
427 (r (make-ref #f '() var)))
428 (var-refs-set! var (cons r (var-refs var)))
429 (if (not (var-global? var))
430 (let* ((unbox (parse 'value '#%unbox env))
431 (app (make-call #f (list unbox r))))
432 (node-parent-set! r app)
433 (node-parent-set! unbox app)
437 (assq (car expr) *macros*))
438 => (lambda (p) (parse use (apply (cdr p) (cdr expr)) env)))
440 (eq? (car expr) 'set!))
441 (let ((var (env-lookup env (cadr expr))))
442 (if (var-global? var)
443 (let* ((val (parse 'value (caddr expr) env))
444 (r (make-set #f (list val) var)))
445 (node-parent-set! val r)
446 (var-sets-set! var (cons r (var-sets var)))
448 (let* ((body (parse 'value (caddr expr) env))
449 (ref (make-ref #f '() var))
450 (bs (make-ref #f '() (env-lookup env '#%box-set!)))
451 (r (make-call #f (list bs ref body))))
452 (node-parent-set! body r)
453 (node-parent-set! ref r)
454 (node-parent-set! bs r)
455 (var-sets-set! var (cons r (var-sets var)))
458 (eq? (car expr) 'quote))
459 (make-cst #f '() (cadr expr)))
461 (eq? (car expr) 'if))
462 (let* ((a (parse 'test (cadr expr) env))
463 (b (parse use (caddr expr) env))
464 (c (if (null? (cdddr expr))
466 (parse use (cadddr expr) env)))
467 (r (make-if #f (list a b c))))
468 (node-parent-set! a r)
469 (node-parent-set! b r)
470 (node-parent-set! c r)
473 (eq? (car expr) 'lambda))
474 (let* ((pattern (cadr expr))
475 (ids (extract-ids pattern))
476 ;; parent children params rest? entry-label
477 (r (make-prc #f '() #f (has-rest-param? pattern) #f))
478 (new-env (env-extend env ids r))
479 (body (parse-body (cddr expr) new-env))
483 (let ((v (env-lookup new-env id)))
484 (if (mutable-var? v) (list v) '())))
489 (map (lambda (id) (env-lookup new-env id))
491 (node-children-set! r (list body))
492 (node-parent-set! body r)
494 (let* ((prc (make-prc #f (list body) mut-vars #f #f))
495 (new-vars (map var-id mut-vars))
496 (tmp-env (env-extend env new-vars r))
503 (cons '#%box (cons id '()))
506 ;; (lambda (a b) (set! a b))
507 ;; => (lambda (_a b) ((lambda (a) (box-set! a b)) (box _a)))
508 (for-each (lambda (var) (var-defs-set! var (list prc)))
510 (for-each (lambda (n) (node-parent-set! n app))
511 (cdr (node-children app)))
512 (node-parent-set! prc app)
514 (map (lambda (id) (env-lookup tmp-env id))
516 (node-children-set! r (list app))
517 (node-parent-set! body prc)
520 (eq? (car expr) 'letrec))
521 (let ((ks (map car (cadr expr)))
522 (vs (map cadr (cadr expr))))
525 (cons (map (lambda (k) (list k #f)) ks)
526 (append (map (lambda (k v) (list 'set! k v))
531 (eq? (car expr) 'begin))
532 (let* ((exprs (map (lambda (x) (parse 'value x env)) (cdr expr)))
533 (r (make-seq #f exprs)))
534 (for-each (lambda (x) (node-parent-set! x r)) exprs)
537 (eq? (car expr) 'let))
538 (if (symbol? (cadr expr))
540 `(letrec ((,(cadr expr) (lambda ,(map car (caddr expr)) .
542 (,(cadr expr) . ,(map cadr (caddr expr))))
546 (cons (map car (cadr expr))
548 (map cadr (cadr expr)))
551 (eq? (car expr) 'let*))
552 (if (null? (cadr expr))
554 (cons 'let (cdr expr))
558 (list (list (caar (cadr expr))
559 (cadar (cadr expr))))
561 (cons (cdr (cadr expr))
565 (eq? (car expr) 'and))
566 (cond ((null? (cdr expr))
578 (cons 'and (cddr expr))
582 (eq? (car expr) 'or))
583 (cond ((null? (cdr expr))
596 (cons 'or (cddr expr)))
602 (list (list v (cadr expr)))
606 (cons 'or (cddr expr)))))
608 ;; primitive substitution here
609 ;; TODO do this optimization in the following pass instead of at parse time ?
611 (assoc (car expr) substitute-primitives))
615 (cons (cdr prim) (cdr expr))
617 ;; binary arthimetic operations can use primitives directly
619 (= (length (cdr expr)) 2)
620 (assoc (car expr) '((+ . #%+) (- . #%-) (* . #%*))))
624 (cons (cdr prim) (cdr expr))
628 '(quote quasiquote unquote unquote-splicing lambda if
629 set! cond and or case let let* letrec begin do define
631 (compiler-error "the compiler does not implement the special form" (car expr)))
633 (let* ((exprs (map (lambda (x) (parse 'value x env)) expr))
634 (r (make-call #f exprs)))
635 (for-each (lambda (x) (node-parent-set! x r)) exprs)
638 (compiler-error "unknown expression" expr)))))
642 (parse 'value (cons 'begin exprs) env)))
654 (cons (car pattern) (extract-ids (cdr pattern)))
655 (if (symbol? pattern)
659 (define has-rest-param?
662 (has-rest-param? (cdr pattern))
665 (define (adjust-unmutable-references! node)
666 '(pretty-print (list unmut: (node->expr node)))
667 (if (and (call? node)
669 (ref? (car (node-children node)))
671 (eq? '#%unbox (var-id (ref-var (car (node-children node)))))
673 (ref? (cadr (node-children node)))
675 (not (mutable-var? (ref-var (cadr (node-children node)))))
676 '(display "unmut! "))
677 (let* ((parent (node-parent node)) (child (cadr (node-children node))))
678 (node-parent-set! child parent)
680 (node-children-set! parent
681 (map (lambda (c) (if (eq? c node) child c))
682 (node-children parent))))
684 (begin (for-each (lambda (n) (adjust-unmutable-references! n))
685 (node-children node))
688 ;-----------------------------------------------------------------------------
690 ;; Compilation context representation.
698 (define context-change-code
702 (context-env2 ctx))))
704 (define context-change-env
706 (make-context (context-code ctx)
708 (context-env2 ctx))))
710 (define context-change-env2
712 (make-context (context-code ctx)
716 (define make-init-context
718 (make-context (make-init-code)
722 (define context-make-label
724 (context-change-code ctx (code-make-label (context-code ctx)))))
726 (define context-last-label
728 (code-last-label (context-code ctx))))
730 (define context-add-bb
732 (context-change-code ctx (code-add-bb (context-code ctx) label))))
734 (define context-add-instr
736 (context-change-code ctx (code-add-instr (context-code ctx) instr))))
738 ;; Representation of code.
750 (define make-init-code
753 (list (make-bb 0 (list))))))
755 (define code-make-label
757 (let ((label (+ (code-last-label code) 1)))
759 (code-rev-bbs code)))))
764 (code-last-label code)
765 (cons (make-bb label '())
766 (code-rev-bbs code)))))
768 (define code-add-instr
770 (let* ((rev-bbs (code-rev-bbs code))
772 (rev-instrs (bb-rev-instrs bb)))
774 (code-last-label code)
775 (cons (make-bb (bb-label bb)
776 (cons instr rev-instrs))
779 ;; Representation of compile-time stack.
782 size ; number of slots
783 slots ; for each slot, the variable (or #f) contained in the slot
786 (define make-init-stack
791 (lambda (x nb-slots stk)
792 (let ((size (stack-size stk)))
795 (append (repeat nb-slots x) (stack-slots stk))))))
797 (define stack-discard
798 (lambda (nb-slots stk)
799 (let ((size (stack-size stk)))
802 (list-tail (stack-slots stk) nb-slots)))))
804 ;; Representation of compile-time environment.
811 (define make-init-env
813 (make-env (make-init-stack)
816 (define env-change-local
821 (define env-change-closed
823 (make-env (env-local env)
826 (define find-local-var
828 (let ((i (pos-in-list var (stack-slots (env-local env)))))
830 (- (+ (pos-in-list var (env-closed env)) 1))))))
835 (let ((params (prc-params prc)))
836 (make-stack (length params)
837 (append (map var-id params) '())))
838 (let ((vars (varset->list (non-global-fv prc))))
839 ; (pp (map var-id vars))
840 (map var-id vars)))))
842 ;-----------------------------------------------------------------------------
844 (define gen-instruction
845 (lambda (instr nb-pop nb-push ctx)
851 (stack-discard nb-pop
853 (context-add-instr (context-change-env ctx (env-change-local env stk))
857 (lambda (nparams rest? ctx)
858 (gen-instruction (list 'entry nparams rest?) 0 0 ctx)))
860 (define gen-push-constant
862 (gen-instruction (list 'push-constant val) 0 1 ctx)))
864 (define gen-push-unspecified
866 (gen-push-constant #f ctx)))
868 (define gen-push-local-var
870 ; (pp (list var: var local: (stack-slots (env-local (context-env ctx))) (env-closed (context-env ctx))))
871 (let ((i (find-local-var var (context-env ctx))))
873 (gen-push-stack i ctx)
875 ;; this +1 is needed because closures are in the environment, but
876 ;; don't contain a value, and must therefore be skipped
879 (length (stack-slots (env-local (context-env ctx))))) ctx)))))
881 (define gen-push-stack
883 (gen-instruction (list 'push-stack pos) 0 1 ctx)))
885 (define gen-push-global
887 (gen-instruction (list 'push-global var) 0 1 ctx)))
889 (define gen-set-global
891 (gen-instruction (list 'set-global var) 1 0 ctx)))
895 (gen-instruction (list 'call nargs) (+ nargs 1) 1 ctx)))
899 (gen-instruction (list 'jump nargs) (+ nargs 1) 1 ctx)))
901 (define gen-call-toplevel
902 (lambda (nargs id ctx)
903 (gen-instruction (list 'call-toplevel id) nargs 1 ctx)))
905 (define gen-jump-toplevel
906 (lambda (nargs id ctx)
907 (gen-instruction (list 'jump-toplevel id) nargs 1 ctx)))
911 (gen-instruction (list 'goto label) 0 0 ctx)))
913 (define gen-goto-if-false
914 (lambda (label-false label-true ctx)
915 (gen-instruction (list 'goto-if-false label-false label-true) 1 0 ctx)))
918 (lambda (label-entry ctx)
919 (gen-instruction (list 'closure label-entry) 1 1 ctx)))
922 (lambda (id nargs unspec-result? ctx)
926 (if unspec-result? 0 1)
932 (gen-instruction (list 'shift) 1 0 (gen-shift (- n 1) ctx))
937 (gen-instruction (list 'pop) 1 0 ctx)))
941 (let ((ss (stack-size (env-local (context-env ctx)))))
942 (gen-instruction (list 'return) ss 0 ctx))))
944 ;-----------------------------------------------------------------------------
948 (car (node-children node))))
952 (cadr (node-children node))))
956 (caddr (node-children node))))
961 (cond ((or (cst? node)
967 (let ((var (def-var node)))
968 (if (toplevel-prc-with-non-rest-correct-calls? var)
969 (comp-prc (child1 node) #f ctx)
970 (if (var-needed? var)
971 (let ((ctx2 (comp-push (child1 node) ctx)))
972 (gen-set-global (var-id var) ctx2))
973 (comp-none (child1 node) ctx)))))
976 (let ((var (set-var node)))
977 (if (var-needed? var)
978 (let ((ctx2 (comp-push (child1 node) ctx)))
979 (gen-set-global (var-id var) ctx2))
980 (comp-none (child1 node) ctx))))
984 (context-make-label ctx))
986 (context-last-label ctx2))
988 (context-make-label ctx2))
990 (context-last-label ctx3))
992 (context-make-label ctx3))
994 (context-last-label ctx4))
996 (context-make-label ctx4))
998 (context-last-label ctx5))
1000 (context-make-label ctx5))
1002 (context-last-label ctx6))
1004 (comp-test (child1 node) label-then label-else ctx6))
1008 (comp-none (child3 node)
1009 (context-change-env2
1010 (context-add-bb ctx7 label-else)
1015 (comp-none (child2 node)
1017 (context-add-bb ctx8 label-then)
1018 (context-env2 ctx7)))))
1022 (context-add-bb ctx9 label-else-join)))
1026 (context-add-bb ctx10 label-then-join)))
1028 (context-add-bb ctx11 label-join)))
1032 (comp-call node 'none ctx))
1035 (let ((children (node-children node)))
1036 (if (null? children)
1038 (let loop ((lst children)
1040 (if (null? (cdr lst))
1041 (comp-none (car lst) ctx)
1043 (comp-none (car lst) ctx)))))))
1046 (compiler-error "unknown expression type" node)))))
1051 (cond ((or (cst? node)
1058 (gen-return (comp-push node ctx)))
1062 (context-make-label ctx))
1064 (context-last-label ctx2))
1066 (context-make-label ctx2))
1068 (context-last-label ctx3))
1070 (comp-test (child1 node) label-then label-else ctx3))
1072 (comp-tail (child3 node)
1073 (context-change-env2
1074 (context-add-bb ctx4 label-else)
1077 (comp-tail (child2 node)
1079 (context-add-bb ctx5 label-then)
1080 (context-env2 ctx4)))))
1084 (comp-call node 'tail ctx))
1087 (let ((children (node-children node)))
1088 (if (null? children)
1089 (gen-return (gen-push-unspecified ctx))
1090 (let loop ((lst children)
1092 (if (null? (cdr lst))
1093 (comp-tail (car lst) ctx)
1095 (comp-none (car lst) ctx)))))))
1098 (compiler-error "unknown expression type" node)))))
1104 (display "--------------\n")
1105 (pp (node->expr node))
1111 (let ((val (cst-val node)))
1112 (gen-push-constant val ctx)))
1115 (let ((var (ref-var node)))
1116 (if (var-global? var)
1117 (if (null? (var-defs var))
1118 (compiler-error "undefined variable:" (var-id var))
1119 (let ((val (child1 (car (var-defs var)))))
1120 (if (and (not (mutable-var? var))
1121 (cst? val)) ;; immutable global, counted as cst
1122 (gen-push-constant (cst-val val) ctx)
1123 (gen-push-global (var-id var) ctx))))
1124 (gen-push-local-var (var-id var) ctx))))
1128 (gen-push-unspecified (comp-none node ctx)))
1132 (context-make-label ctx))
1134 (context-last-label ctx2))
1136 (context-make-label ctx2))
1138 (context-last-label ctx3))
1140 (context-make-label ctx3))
1142 (context-last-label ctx4))
1144 (context-make-label ctx4))
1146 (context-last-label ctx5))
1148 (context-make-label ctx5))
1150 (context-last-label ctx6))
1152 (comp-test (child1 node) label-then label-else ctx6))
1156 (comp-push (child3 node)
1157 (context-change-env2
1158 (context-add-bb ctx7 label-else)
1163 (comp-push (child2 node)
1165 (context-add-bb ctx8 label-then)
1166 (context-env2 ctx7)))))
1170 (context-add-bb ctx9 label-else-join)))
1174 (context-add-bb ctx10 label-then-join)))
1176 (context-add-bb ctx11 label-join)))
1180 (comp-prc node #t ctx))
1183 (comp-call node 'push ctx))
1186 (let ((children (node-children node)))
1187 (if (null? children)
1188 (gen-push-unspecified ctx)
1189 (let loop ((lst children)
1191 (if (null? (cdr lst))
1192 (comp-push (car lst) ctx)
1194 (comp-none (car lst) ctx)))))))
1197 (compiler-error "unknown expression type" node)))))
1199 (define (build-closure label-entry vars ctx)
1201 (define (build vars ctx)
1203 (gen-push-constant '() ctx)
1208 (gen-push-local-var (car vars) ctx)))))
1211 (gen-closure label-entry
1212 (gen-push-constant '() ctx))
1213 (gen-closure label-entry
1217 (lambda (node closure? ctx)
1219 (context-make-label ctx))
1221 (context-last-label ctx2))
1223 (context-make-label ctx2))
1225 (context-last-label ctx3))
1230 (build-closure label-entry (env-closed body-env) ctx3)
1233 (gen-goto label-continue ctx4))
1235 (gen-entry (length (prc-params node))
1237 (context-add-bb (context-change-env ctx5
1241 (comp-tail (child1 node) ctx6)))
1242 (prc-entry-label-set! node label-entry)
1243 (context-add-bb (context-change-env ctx7 (context-env ctx5))
1247 (lambda (node reason ctx)
1248 (let* ((op (child1 node))
1249 (args (cdr (node-children node)))
1250 (nargs (length args)))
1251 (let loop ((lst args)
1255 (let ((arg (car lst)))
1257 (comp-push arg ctx)))
1259 (cond ((and (ref? op)
1260 (var-primitive (ref-var op)))
1261 (let* ((var (ref-var op))
1263 (primitive (var-primitive var))
1264 (prim-nargs (primitive-nargs primitive)))
1268 (cond ((eq? reason 'tail)
1270 (if (primitive-unspecified-result? primitive)
1271 (gen-push-unspecified ctx2)
1274 (if (primitive-unspecified-result? primitive)
1275 (gen-push-unspecified ctx2)
1278 (if (primitive-unspecified-result? primitive)
1283 (if (primitive-inliner primitive)
1284 ((primitive-inliner primitive) ctx)
1286 (not (= nargs prim-nargs))
1288 "primitive called with wrong number of arguments"
1293 (primitive-unspecified-result? primitive)
1298 (toplevel-prc-with-non-rest-correct-calls?
1302 (cond ((eq? reason 'tail)
1303 (gen-jump-toplevel nargs prc ctx))
1305 (gen-call-toplevel nargs prc ctx))
1307 (gen-pop (gen-call-toplevel nargs prc ctx))))))
1310 (let ((ctx2 (comp-push op ctx)))
1311 (cond ((eq? reason 'tail)
1312 (gen-jump nargs ctx2))
1314 (gen-call nargs ctx2))
1316 (gen-pop (gen-call nargs ctx2))))))))))))
1319 (lambda (node label-true label-false ctx)
1323 (let ((val (cst-val node)))
1328 (context-change-env2 ctx2 (context-env ctx2))))
1337 (comp-push node ctx))
1339 (gen-goto-if-false label-false label-true ctx2)))
1340 (context-change-env2 ctx3 (context-env ctx3))))
1344 (gen-goto label-true ctx)))
1345 (context-change-env2 ctx2 (context-env ctx2))))
1348 (compiler-error "unknown expression type" node)))))
1350 ;-----------------------------------------------------------------------------
1352 (define toplevel-prc?
1354 (and (not (mutable-var? var))
1355 (let ((d (var-defs var)))
1358 (let ((val (child1 (car d))))
1362 (define toplevel-prc-with-non-rest-correct-calls?
1364 (let ((prc (toplevel-prc? var)))
1366 (not (prc-rest? prc))
1368 (let ((parent (node-parent r)))
1370 (eq? (child1 parent) r)
1371 (= (length (prc-params prc))
1372 (- (length (node-children parent)) 1)))))
1376 (define mutable-var?
1378 (not (null? (var-sets var)))))
1384 (varset->list (fv node))))))
1386 (define non-global-fv
1389 (keep (lambda (x) (not (var-global? x)))
1390 (varset->list (fv node))))))
1397 (let ((var (ref-var node)))
1398 (varset-singleton var)))
1400 (let ((var (def-var node))
1401 (val (child1 node)))
1403 (varset-singleton var)
1406 (let ((var (set-var node))
1407 (val (child1 node)))
1409 (varset-singleton var)
1412 (let ((a (list-ref (node-children node) 0))
1413 (b (list-ref (node-children node) 1))
1414 (c (list-ref (node-children node) 2)))
1415 (varset-union-multi (list (fv a) (fv b) (fv c)))))
1417 (let ((body (list-ref (node-children node) 0)))
1420 (build-params-varset (prc-params node)))))
1422 (varset-union-multi (map fv (node-children node))))
1424 (varset-union-multi (map fv (node-children node))))
1426 (compiler-error "unknown expression type" node)))))
1428 (define build-params-varset
1430 (list->varset params)))
1432 (define mark-needed-global-vars!
1433 (lambda (global-env node)
1436 (env-lookup global-env '#%readyq))
1440 (if (and (var-global? var)
1441 (not (var-needed? var))
1442 ;; globals that obey the following conditions are considered
1444 (not (and (not (mutable-var? var))
1445 ;; to weed out primitives, which have no definitions
1446 (> (length (var-defs var)) 0)
1447 (cst? (child1 (car (var-defs var)))))))
1449 (var-needed?-set! var #t)
1452 (let ((val (child1 def)))
1453 (if (side-effect-less? val)
1456 (if (eq? var readyq)
1459 (env-lookup global-env '#%start-first-process))
1461 (env-lookup global-env '#%exit))))))))
1463 (define side-effect-less?
1473 (let ((var (ref-var node)))
1476 (let ((var (def-var node))
1477 (val (child1 node)))
1478 (if (not (side-effect-less? val))
1481 (let ((var (set-var node))
1482 (val (child1 node)))
1485 (let ((a (list-ref (node-children node) 0))
1486 (b (list-ref (node-children node) 1))
1487 (c (list-ref (node-children node) 2)))
1492 (let ((body (list-ref (node-children node) 0)))
1495 (for-each mark! (node-children node)))
1497 (for-each mark! (node-children node)))
1499 (compiler-error "unknown expression type" node)))))
1504 ;-----------------------------------------------------------------------------
1508 (define (varset-empty) ; return the empty set
1511 (define (varset-singleton x) ; create a set containing only 'x'
1514 (define (list->varset lst) ; convert list to set
1517 (define (varset->list set) ; convert set to list
1520 (define (varset-size set) ; return cardinality of set
1523 (define (varset-empty? set) ; is 'x' the empty set?
1526 (define (varset-member? x set) ; is 'x' a member of the 'set'?
1527 (and (not (null? set))
1528 (or (eq? x (car set))
1529 (varset-member? x (cdr set)))))
1531 (define (varset-adjoin set x) ; add the element 'x' to the 'set'
1532 (if (varset-member? x set) set (cons x set)))
1534 (define (varset-remove set x) ; remove the element 'x' from 'set'
1540 (cons (car set) (varset-remove (cdr set) x)))))
1542 (define (varset-equal? s1 s2) ; are 's1' and 's2' equal sets?
1543 (and (varset-subset? s1 s2)
1544 (varset-subset? s2 s1)))
1546 (define (varset-subset? s1 s2) ; is 's1' a subset of 's2'?
1549 ((varset-member? (car s1) s2)
1550 (varset-subset? (cdr s1) s2))
1554 (define (varset-difference set1 set2) ; return difference of sets
1557 ((varset-member? (car set1) set2)
1558 (varset-difference (cdr set1) set2))
1560 (cons (car set1) (varset-difference (cdr set1) set2)))))
1562 (define (varset-union set1 set2) ; return union of sets
1563 (define (union s1 s2)
1566 ((varset-member? (car s1) s2)
1567 (union (cdr s1) s2))
1569 (cons (car s1) (union (cdr s1) s2)))))
1570 (if (varset-smaller? set1 set2)
1574 (define (varset-intersection set1 set2) ; return intersection of sets
1575 (define (intersection s1 s2)
1578 ((varset-member? (car s1) s2)
1579 (cons (car s1) (intersection (cdr s1) s2)))
1581 (intersection (cdr s1) s2))))
1582 (if (varset-smaller? set1 set2)
1583 (intersection set1 set2)
1584 (intersection set2 set1)))
1586 (define (varset-intersects? set1 set2) ; do sets 'set1' and 'set2' intersect?
1587 (not (varset-empty? (varset-intersection set1 set2))))
1589 (define (varset-smaller? set1 set2)
1594 (varset-smaller? (cdr set1) (cdr set2)))))
1596 (define (varset-union-multi sets)
1599 (n-ary varset-union (car sets) (cdr sets))))
1601 (define (n-ary function first rest)
1604 (n-ary function (function first (car rest)) (cdr rest))))
1606 ;------------------------------------------------------------------------------
1608 (define code->vector
1610 (let ((v (make-vector (+ (code-last-label code) 1))))
1613 (vector-set! v (bb-label bb) bb))
1614 (code-rev-bbs code))
1617 (define bbs->ref-counts
1619 (let ((ref-counts (make-vector (vector-length bbs) 0)))
1623 (let ((ref-count (vector-ref ref-counts label)))
1624 (vector-set! ref-counts label (+ ref-count 1))
1626 (let* ((bb (vector-ref bbs label))
1627 (rev-instrs (bb-rev-instrs bb)))
1630 (let ((opcode (car instr)))
1631 (cond ((eq? opcode 'goto)
1632 (visit (cadr instr)))
1633 ((eq? opcode 'goto-if-false)
1634 (visit (cadr instr))
1635 (visit (caddr instr)))
1636 ((or (eq? opcode 'closure)
1637 (eq? opcode 'call-toplevel)
1638 (eq? opcode 'jump-toplevel))
1639 (visit (cadr instr))))))
1646 (define resolve-toplevel-labels!
1649 (if (< i (vector-length bbs))
1650 (let* ((bb (vector-ref bbs i))
1651 (rev-instrs (bb-rev-instrs bb)))
1654 (map (lambda (instr)
1655 (let ((opcode (car instr)))
1656 (cond ((eq? opcode 'call-toplevel)
1658 (prc-entry-label (cadr instr))))
1659 ((eq? opcode 'jump-toplevel)
1661 (prc-entry-label (cadr instr))))
1667 (define tighten-jump-cascades!
1669 (let ((ref-counts (bbs->ref-counts bbs)))
1673 (let* ((bb (vector-ref bbs label))
1674 (rev-instrs (bb-rev-instrs bb)))
1675 (and (or (null? (cdr rev-instrs))
1676 (= (vector-ref ref-counts label) 1))
1682 (if (< i (vector-length bbs))
1683 (if (> (vector-ref ref-counts i) 0)
1684 (let* ((bb (vector-ref bbs i))
1685 (rev-instrs (bb-rev-instrs bb))
1686 (jump (car rev-instrs))
1687 (opcode (car jump)))
1688 (cond ((eq? opcode 'goto)
1689 (let* ((label (cadr jump))
1690 (jump-replacement (resolve label)))
1691 (if jump-replacement
1696 (make-bb (bb-label bb)
1697 (append jump-replacement
1703 ((eq? opcode 'goto-if-false)
1704 (let* ((label-then (cadr jump))
1705 (label-else (caddr jump))
1706 (jump-then-replacement (resolve label-then))
1707 (jump-else-replacement (resolve label-else)))
1708 (if (and jump-then-replacement
1709 (null? (cdr jump-then-replacement))
1710 jump-else-replacement
1711 (null? (cdr jump-else-replacement))
1712 (or (eq? (caar jump-then-replacement)
1714 (eq? (caar jump-else-replacement)
1725 (if (eq? (caar jump-then-replacement)
1727 (cadar jump-then-replacement)
1729 (if (eq? (caar jump-else-replacement)
1731 (cadar jump-else-replacement)
1746 (define remove-useless-bbs!
1748 (let ((ref-counts (bbs->ref-counts bbs)))
1749 (let loop1 ((label 0) (new-label 0))
1750 (if (< label (vector-length bbs))
1751 (if (> (vector-ref ref-counts label) 0)
1752 (let ((bb (vector-ref bbs label)))
1756 (make-bb new-label (bb-rev-instrs bb)))
1757 (loop1 (+ label 1) (+ new-label 1)))
1758 (loop1 (+ label 1) new-label))
1759 (renumber-labels bbs ref-counts new-label))))))
1761 (define renumber-labels
1762 (lambda (bbs ref-counts n)
1763 (let ((new-bbs (make-vector n)))
1764 (let loop2 ((label 0))
1765 (if (< label (vector-length bbs))
1766 (if (> (vector-ref ref-counts label) 0)
1767 (let* ((bb (vector-ref bbs label))
1768 (new-label (bb-label bb))
1769 (rev-instrs (bb-rev-instrs bb)))
1776 (bb-label (vector-ref bbs label))))
1778 (let ((opcode (car instr)))
1779 (cond ((eq? opcode 'closure)
1781 (new-label (cadr instr))))
1782 ((eq? opcode 'call-toplevel)
1783 (list 'call-toplevel
1784 (new-label (cadr instr))))
1785 ((eq? opcode 'jump-toplevel)
1786 (list 'jump-toplevel
1787 (new-label (cadr instr))))
1790 (new-label (cadr instr))))
1791 ((eq? opcode 'goto-if-false)
1792 (list 'goto-if-false
1793 (new-label (cadr instr))
1794 (new-label (caddr instr))))
1801 (make-bb new-label (map fix rev-instrs)))
1802 (loop2 (+ label 1)))
1803 (loop2 (+ label 1)))
1808 (let* ((done (make-vector (vector-length bbs) #f)))
1810 (define unscheduled?
1812 (not (vector-ref done label))))
1815 (lambda (instrs todo)
1817 (let* ((instr (car instrs))
1818 (opcode (car instr)))
1819 (cond ((or (eq? opcode 'closure)
1820 (eq? opcode 'call-toplevel)
1821 (eq? opcode 'jump-toplevel))
1822 (label-refs (cdr instrs) (cons (cadr instr) todo)))
1824 (label-refs (cdr instrs) todo))))
1827 (define schedule-here
1828 (lambda (label new-label todo cont)
1829 (let* ((bb (vector-ref bbs label))
1830 (rev-instrs (bb-rev-instrs bb))
1831 (jump (car rev-instrs))
1833 (new-todo (label-refs rev-instrs todo)))
1834 (vector-set! bbs label (make-bb new-label rev-instrs))
1835 (vector-set! done label #t)
1836 (cond ((eq? opcode 'goto)
1837 (let ((label (cadr jump)))
1838 (if (unscheduled? label)
1839 (schedule-here label
1843 (cont (+ new-label 1)
1845 ((eq? opcode 'goto-if-false)
1846 (let ((label-then (cadr jump))
1847 (label-else (caddr jump)))
1848 (cond ((unscheduled? label-else)
1849 (schedule-here label-else
1851 (cons label-then new-todo)
1853 ((unscheduled? label-then)
1854 (schedule-here label-then
1859 (cont (+ new-label 1)
1862 (cont (+ new-label 1)
1865 (define schedule-somewhere
1866 (lambda (label new-label todo cont)
1867 (schedule-here label new-label todo cont)))
1869 (define schedule-todo
1870 (lambda (new-label todo)
1872 (let ((label (car todo)))
1873 (if (unscheduled? label)
1874 (schedule-somewhere label
1878 (schedule-todo new-label
1882 (schedule-here 0 0 '() schedule-todo)
1884 (renumber-labels bbs
1885 (make-vector (vector-length bbs) 1)
1886 (vector-length bbs)))))
1890 (let loop ((label (- (vector-length bbs) 1))
1893 (let* ((bb (vector-ref bbs label))
1894 (rev-instrs (bb-rev-instrs bb))
1895 (jump (car rev-instrs))
1896 (opcode (car jump)))
1901 (cond ((eq? opcode 'goto)
1902 (if (= (cadr jump) (+ label 1))
1905 ((eq? opcode 'goto-if-false)
1906 (cond ((= (caddr jump) (+ label 1))
1907 (cons (list 'goto-if-false (cadr jump))
1909 ((= (cadr jump) (+ label 1))
1910 (cons (list 'goto-if-not-false (caddr jump))
1913 (cons (list 'goto (caddr jump))
1914 (cons (list 'goto-if-false (cadr jump))
1915 (cdr rev-instrs))))))
1921 (define optimize-code
1923 (let ((bbs (code->vector code)))
1924 (resolve-toplevel-labels! bbs)
1925 (tighten-jump-cascades! bbs)
1926 (let ((bbs (remove-useless-bbs! bbs)))
1930 (define expand-includes
1933 (if (eq? (car e) 'include)
1936 (with-input-from-file (cadr e) read-all)))
1942 (let* ((library ;; TODO do not hard-code path
1943 (with-input-from-file "/home/vincent/src/picobit/dev/library.scm" read-all))
1947 (with-input-from-file filename read-all))))
1951 (parse-top (cons 'begin toplevel-exprs) global-env)))
1955 (mark-needed-global-vars! global-env node))
1960 (lambda (defs after-defs)
1962 (define make-seq-preparsed
1964 (let ((r (make-seq #f exprs)))
1965 (for-each (lambda (x) (node-parent-set! x r)) exprs)
1968 (define make-call-preparsed
1970 (let ((r (make-call #f exprs)))
1971 (for-each (lambda (x) (node-parent-set! x r)) exprs)
1975 (env-lookup global-env '#%readyq))
1977 (list (make-seq-preparsed defs)
1978 (make-call-preparsed
1979 (list (parse 'value '#%start-first-process global-env)
1983 (extract-ids pattern))
1988 (has-rest-param? pattern)
1991 (env-extend global-env ids r))
1993 (make-seq-preparsed after-defs)))
1996 (map (lambda (id) (env-lookup new-env id))
1998 (node-children-set! r (list body))
1999 (node-parent-set! body r)
2009 global-env))))))))))
2011 (define extract-parts
2014 (not (def? (car lst))))
2019 (cont (cons (car lst) d) ad))))))
2021 ;------------------------------------------------------------------------------
2023 ;;(include "asm.scm")
2027 ;;; This module implements the generic assembler.
2029 ;;(##declare (standard-bindings) (fixnum) (block))
2031 (define compiler-internal-error error)
2033 ;; (asm-begin! start-pos big-endian?) initializes the assembler and
2034 ;; starts a new empty code stream at address "start-pos". It must be
2035 ;; called every time a new code stream is to be built. The argument
2036 ;; "big-endian?" indicates the byte ordering to use for 16, 32 and 64
2037 ;; bit values. After a call to "asm-begin!" the code stream is built
2038 ;; by calling the following procedures:
2040 ;; asm-8 to add an 8 bit integer to the code stream
2041 ;; asm-16 to add a 16 bit integer to the code stream
2042 ;; asm-32 to add a 32 bit integer to the code stream
2043 ;; asm-64 to add a 64 bit integer to the code stream
2044 ;; asm-float64 to add a 64 bit IEEE float to the code stream
2045 ;; asm-string to add a null terminated string to the code stream
2046 ;; asm-label to set a label to the current position in the code stream
2047 ;; asm-align to add enough zero bytes to force alignment
2048 ;; asm-origin to add enough zero bytes to move to a particular address
2049 ;; asm-at-assembly to defer code production to assembly time
2050 ;; asm-listing to add textual information to the listing
2052 (define (asm-begin! start-pos big-endian?)
2053 (set! asm-start-pos start-pos)
2054 (set! asm-big-endian? big-endian?)
2055 (set! asm-code-stream (asm-make-stream))
2058 ;; (asm-end!) must be called to finalize the assembler.
2061 (set! asm-code-stream #f)
2064 ;; (asm-8 n) adds an 8 bit signed or unsigned integer to the code stream.
2067 (asm-code-extend (asm-bits-0-to-7 n)))
2069 ;; (asm-16 n) adds a 16 bit signed or unsigned integer to the code stream.
2073 (begin (asm-8 (asm-bits-8-and-up n)) (asm-8 n))
2074 (begin (asm-8 n) (asm-8 (asm-bits-8-and-up n)))))
2076 ;; (asm-32 n) adds a 32 bit signed or unsigned integer to the code stream.
2080 (begin (asm-16 (asm-bits-16-and-up n)) (asm-16 n))
2081 (begin (asm-16 n) (asm-16 (asm-bits-16-and-up n)))))
2083 ;; (asm-64 n) adds a 64 bit signed or unsigned integer to the code stream.
2087 (begin (asm-32 (asm-bits-32-and-up n)) (asm-32 n))
2088 (begin (asm-32 n) (asm-32 (asm-bits-32-and-up n)))))
2090 ;; (asm-float64 n) adds a 64 bit IEEE floating point number to the code stream.
2092 (define (asm-float64 n)
2093 (asm-64 (asm-float->bits n)))
2095 ;; (asm-string str) adds a null terminated string to the code stream.
2097 (define (asm-string str)
2098 (let ((len (string-length str)))
2102 (asm-8 (char->integer (string-ref str i)))
2106 ;; (asm-make-label id) creates a new label object. A label can
2107 ;; be queried with "asm-label-pos" to obtain the label's position
2108 ;; relative to the start of the code stream (i.e. "start-pos").
2109 ;; The argument "id" gives a name to the label (not necessarily
2110 ;; unique) and is only needed for debugging purposes.
2112 (define (asm-make-label id)
2113 (vector 'LABEL #f id))
2115 ;; (asm-label label-obj) sets the label to the current position in the
2118 (define (asm-label label-obj)
2119 (if (vector-ref label-obj 1)
2120 (compiler-internal-error
2121 "asm-label, label multiply defined" (asm-label-id label-obj))
2123 (vector-set! label-obj 1 0)
2124 (asm-code-extend label-obj))))
2126 ;; (asm-label-id label-obj) returns the identifier of the label object.
2128 (define (asm-label-id label-obj)
2129 (vector-ref label-obj 2))
2131 ;; (asm-label-pos label-obj) returns the position of the label
2132 ;; relative to the start of the code stream (i.e. "start-pos").
2133 ;; This procedure can only be called at assembly time (i.e.
2134 ;; within the call to "asm-assemble") or after assembly time
2135 ;; for labels declared prior to assembly time with "asm-label".
2136 ;; A label declared at assembly time can only be queried after
2137 ;; assembly time. Moreover, at assembly time the position of a
2138 ;; label may vary from one call to the next due to the actions
2139 ;; of the assembler.
2141 (define (asm-label-pos label-obj)
2142 (let ((pos (vector-ref label-obj 1)))
2145 (compiler-internal-error
2146 "asm-label-pos, undefined label" (asm-label-id label-obj)))))
2148 ;; (asm-align multiple offset) adds enough zero bytes to the code
2149 ;; stream to force alignment to the next address congruent to
2150 ;; "offset" modulo "multiple".
2152 (define (asm-align multiple offset)
2155 (modulo (- multiple (- self offset)) multiple))
2157 (let loop ((n (modulo (- multiple (- self offset)) multiple)))
2161 (loop (- n 1))))))))
2163 ;; (asm-origin address) adds enough zero bytes to the code stream to move
2164 ;; to the address "address".
2166 (define (asm-origin address)
2171 (let ((len (- address self)))
2173 (compiler-internal-error "asm-origin, can't move back")
2178 (loop (- n 1))))))))))
2180 ;; (asm-at-assembly . procs) makes it possible to defer code
2181 ;; production to assembly time. A useful application is to generate
2182 ;; position dependent and span dependent code sequences. This
2183 ;; procedure must be passed an even number of procedures. All odd
2184 ;; indexed procedures (including the first procedure) are called "check"
2185 ;; procedures. The even indexed procedures are the "production"
2186 ;; procedures which, when called, produce a particular code sequence.
2187 ;; A check procedure decides if, given the current state of assembly
2188 ;; (in particular the current positioning of the labels), the code
2189 ;; produced by the corresponding production procedure is valid.
2190 ;; If the code is not valid, the check procedure must return #f.
2191 ;; If the code is valid, the check procedure must return the length
2192 ;; of the code sequence in bytes. The assembler will try each check
2193 ;; procedure in order until it finds one that does not return #f
2194 ;; (the last check procedure must never return #f). For convenience,
2195 ;; the current position in the code sequence is passed as the single
2196 ;; argument of check and production procedures.
2198 ;; Here is a sample call of "asm-at-assembly" to produce the
2199 ;; shortest branch instruction to branch to label "x" for a
2200 ;; hypothetical processor:
2204 ;; (lambda (self) ; first check procedure
2205 ;; (let ((dist (- (asm-label-pos x) self)))
2206 ;; (if (and (>= dist -128) (<= dist 127)) ; short branch possible?
2210 ;; (lambda (self) ; first production procedure
2211 ;; (asm-8 #x34) ; branch opcode for 8 bit displacement
2212 ;; (asm-8 (- (asm-label-pos x) self)))
2214 ;; (lambda (self) 5) ; second check procedure
2216 ;; (lambda (self) ; second production procedure
2217 ;; (asm-8 #x35) ; branch opcode for 32 bit displacement
2218 ;; (asm-32 (- (asm-label-pos x) self))))
2220 (define (asm-at-assembly . procs)
2221 (asm-code-extend (vector 'DEFERRED procs)))
2223 ;; (asm-listing text) adds text to the right side of the listing.
2224 ;; The atoms in "text" will be output using "display" (lists are
2225 ;; traversed recursively). The listing is generated by calling
2226 ;; "asm-display-listing".
2228 (define (asm-listing text)
2229 (asm-code-extend (vector 'LISTING text)))
2231 ;; (asm-assemble) assembles the code stream. After assembly, the
2232 ;; label objects will be set to their final position and the
2233 ;; alignment bytes and the deferred code will have been produced. It
2234 ;; is possible to extend the code stream after assembly. However, if
2235 ;; any of the procedures "asm-label", "asm-align", and
2236 ;; "asm-at-assembly" are called, the code stream will have to be
2237 ;; assembled once more.
2239 (define (asm-assemble)
2240 (let ((fixup-lst (asm-pass1)))
2243 (let loop2 ((lst fixup-lst)
2245 (pos asm-start-pos))
2247 (if changed? (loop1))
2248 (let* ((fixup (car lst))
2249 (pos (+ pos (car fixup)))
2252 (if (eq? (vector-ref x 0) 'LABEL)
2254 (if (= (vector-ref x 1) pos)
2255 (loop2 (cdr lst) changed? pos)
2257 (vector-set! x 1 pos)
2258 (loop2 (cdr lst) #t pos)))
2261 (let ((n ((car (vector-ref x 1)) pos)))
2263 (loop2 (cdr lst) changed? (+ pos n))
2265 (vector-set! x 1 (cddr (vector-ref x 1)))
2268 (let loop4 ((prev asm-code-stream)
2269 (curr (cdr asm-code-stream))
2270 (pos asm-start-pos))
2272 (set-car! asm-code-stream prev)
2273 (let ((x (car curr))
2276 (let ((kind (vector-ref x 0)))
2277 (cond ((eq? kind 'LABEL)
2278 (let ((final-pos (vector-ref x 1)))
2280 (if (not (= pos final-pos))
2281 (compiler-internal-error
2282 "asm-assemble, inconsistency detected"))
2283 (vector-set! x 1 pos))
2284 (set-cdr! prev next)
2285 (loop4 prev next pos)))
2286 ((eq? kind 'DEFERRED)
2287 (let ((temp asm-code-stream))
2288 (set! asm-code-stream (asm-make-stream))
2289 ((cadr (vector-ref x 1)) pos)
2290 (let ((tail (car asm-code-stream)))
2291 (set-cdr! tail next)
2292 (let ((head (cdr asm-code-stream)))
2293 (set-cdr! prev head)
2294 (set! asm-code-stream temp)
2295 (loop4 prev head pos)))))
2297 (loop4 curr next pos))))
2298 (loop4 curr next (+ pos 1))))))))
2300 ;; (asm-display-listing port) produces a listing of the code stream
2301 ;; on the given output port. The bytes generated are shown in
2302 ;; hexadecimal on the left side of the listing and the right side
2303 ;; of the listing contains the text inserted by "asm-listing".
2305 (define (asm-display-listing port)
2307 (define text-col 24)
2308 (define pos-width 6)
2309 (define byte-width 2)
2311 (define (output text)
2312 (cond ((null? text))
2315 (output (cdr text)))
2317 (display text port))))
2319 (define (print-hex n)
2320 (display (string-ref "0123456789ABCDEF" n) port))
2322 (define (print-byte n)
2323 (print-hex (quotient n 16))
2324 (print-hex (modulo n 16)))
2326 (define (print-pos n)
2330 (print-byte (quotient n #x10000))
2331 (print-byte (modulo (quotient n #x100) #x100))
2332 (print-byte (modulo n #x100)))))
2334 (let loop1 ((lst (cdr asm-code-stream)) (pos asm-start-pos) (col 0))
2338 (let ((x (car lst)))
2340 (let ((kind (vector-ref x 0)))
2341 (cond ((eq? kind 'LISTING)
2342 (let loop2 ((col col))
2343 (if (< col text-col)
2345 (display (integer->char 9) port)
2346 (loop2 (* 8 (+ (quotient col 8) 1))))))
2347 (output (vector-ref x 1))
2349 (loop1 (cdr lst) pos 0))
2351 (compiler-internal-error
2352 "asm-display-listing, code stream not assembled"))))
2353 (if (or (= col 0) (>= col (- text-col byte-width)))
2355 (if (not (= col 0)) (newline port))
2359 (loop1 (cdr lst) (+ pos 1) (+ (+ pos-width 1) byte-width)))
2362 (loop1 (cdr lst) (+ pos 1) (+ col byte-width)))))))))
2364 ;; (asm-write-code filename) outputs the code stream (i.e. the sequence
2365 ;; of bytes produced) on the named file.
2367 (define (asm-write-code filename)
2368 (with-output-to-file filename
2370 (let loop ((lst (cdr asm-code-stream)))
2371 (if (not (null? lst))
2372 (let ((x (car lst)))
2374 (let ((kind (vector-ref x 0)))
2375 (if (not (eq? kind 'LISTING))
2376 (compiler-internal-error
2377 "asm-write-code, code stream not assembled"))
2380 (write-char (integer->char x))
2381 (loop (cdr lst))))))))))
2383 (define (asm-write-hex-file filename)
2384 (with-output-to-file filename
2387 (define (print-hex n)
2388 (display (string-ref "0123456789ABCDEF" n)))
2390 (define (print-byte n)
2391 (print-hex (quotient n 16))
2392 (print-hex (modulo n 16)))
2394 (define (print-line type addr bytes)
2395 (let ((n (length bytes))
2396 (addr-hi (quotient addr 256))
2397 (addr-lo (modulo addr 256)))
2400 (print-byte addr-hi)
2401 (print-byte addr-lo)
2403 (for-each print-byte bytes)
2405 (modulo (- (apply + n addr-hi addr-lo type bytes)) 256)))
2409 (let loop ((lst (cdr asm-code-stream))
2412 (if (not (null? lst))
2413 (let ((x (car lst)))
2415 (let ((kind (vector-ref x 0)))
2416 (if (not (eq? kind 'LISTING))
2417 (compiler-internal-error
2418 "asm-write-hex-file, code stream not assembled"))
2426 (if (= (modulo pos 16) 0)
2429 (- pos (length rev-bytes))
2430 (reverse rev-bytes))
2437 (if (not (null? rev-bytes))
2439 (- pos (length rev-bytes))
2440 (reverse rev-bytes)))
2441 (print-line 1 0 '())
2444 (display (- pos asm-start-pos) ##stderr-port)
2445 (display " bytes\n" ##stderr-port)))))))))
2449 (define asm-start-pos #f) ; start position of the code stream
2450 (define asm-big-endian? #f) ; endianness to use
2451 (define asm-code-stream #f) ; current code stream
2453 (define (asm-make-stream) ; create an empty stream
2454 (let ((x (cons '() '())))
2458 (define (asm-code-extend item) ; add an item at the end of current code stream
2459 (let* ((stream asm-code-stream)
2461 (cell (cons item '())))
2462 (set-cdr! tail cell)
2463 (set-car! stream cell)))
2465 (define (asm-pass1) ; construct fixup list and make first label assignment
2466 (let loop ((curr (cdr asm-code-stream))
2469 (pos asm-start-pos))
2472 (let ((x (car curr)))
2474 (let ((kind (vector-ref x 0)))
2475 (cond ((eq? kind 'LABEL)
2476 (vector-set! x 1 pos) ; first approximation of position
2477 (loop (cdr curr) (cons (cons span curr) fixup-lst) 0 pos))
2478 ((eq? kind 'DEFERRED)
2479 (loop (cdr curr) (cons (cons span curr) fixup-lst) 0 pos))
2481 (loop (cdr curr) fixup-lst span pos))))
2482 (loop (cdr curr) fixup-lst (+ span 1) (+ pos 1)))))))
2484 ;(##declare (generic))
2486 (define (asm-bits-0-to-7 n) ; return bits 0 to 7 of a signed integer
2489 (define (asm-bits-8-and-up n) ; return bits 8 and up of a signed integer
2492 (- (quotient (+ n 1) #x100) 1)))
2494 (define (asm-bits-16-and-up n) ; return bits 16 and up of a signed integer
2496 (quotient n #x10000)
2497 (- (quotient (+ n 1) #x10000) 1)))
2499 (define (asm-bits-32-and-up n) ; return bits 32 and up of a signed integer
2501 (quotient n #x100000000)
2502 (- (quotient (+ n 1) #x100000000) 1)))
2504 ; The following procedures convert floating point numbers into their
2505 ; machine representation. They perform bignum and flonum arithmetic.
2507 (define (asm-float->inexact-exponential-format x)
2509 (define (exp-form-pos x y i)
2510 (let ((i*2 (+ i i)))
2511 (let ((z (if (and (not (< asm-ieee-e-bias i*2))
2513 (exp-form-pos x (* y y) i*2)
2515 (let ((a (car z)) (b (cdr z)))
2516 (let ((i+b (+ i b)))
2517 (if (and (not (< asm-ieee-e-bias i+b))
2520 (set-car! z (/ a y))
2524 (define (exp-form-neg x y i)
2525 (let ((i*2 (+ i i)))
2526 (let ((z (if (and (< i*2 asm-ieee-e-bias-minus-1)
2528 (exp-form-neg x (* y y) i*2)
2530 (let ((a (car z)) (b (cdr z)))
2531 (let ((i+b (+ i b)))
2532 (if (and (< i+b asm-ieee-e-bias-minus-1)
2535 (set-car! z (/ a y))
2539 (define (exp-form x)
2540 (if (< x asm-inexact-+1)
2541 (let ((z (exp-form-neg x asm-inexact-+1/2 1)))
2542 (set-car! z (* asm-inexact-+2 (car z)))
2543 (set-cdr! z (- -1 (cdr z)))
2545 (exp-form-pos x asm-inexact-+2 1)))
2548 (let ((z (exp-form (- asm-inexact-0 x))))
2549 (set-car! z (- asm-inexact-0 (car z)))
2553 (define (asm-float->exact-exponential-format x)
2554 (let ((z (asm-float->inexact-exponential-format x)))
2556 (cond ((not (< y asm-inexact-+2))
2557 (set-car! z asm-ieee-+m-min)
2558 (set-cdr! z asm-ieee-e-bias-plus-1))
2559 ((not (< asm-inexact--2 y))
2560 (set-car! z asm-ieee--m-min)
2561 (set-cdr! z asm-ieee-e-bias-plus-1))
2564 (truncate (inexact->exact (* (car z) asm-inexact-m-min))))))
2565 (set-cdr! z (- (cdr z) asm-ieee-m-bits))
2568 (define (asm-float->bits x) ; returns the 64 bit integer encoding the float "x"
2571 (if (< a asm-ieee-+m-min)
2573 (+ (- a asm-ieee-+m-min)
2574 (* (+ (+ b asm-ieee-m-bits) asm-ieee-e-bias)
2577 (let ((z (asm-float->exact-exponential-format x)))
2578 (let ((a (car z)) (b (cdr z)))
2580 (+ asm-ieee-sign-bit (bits (- 0 a) b))
2583 ; Parameters for ANSI-IEEE Std 754-1985 representation of
2584 ; doubles (i.e. 64 bit floating point numbers):
2586 (define asm-ieee-m-bits 52)
2587 (define asm-ieee-e-bits 11)
2588 (define asm-ieee-+m-min 4503599627370496) ; (expt 2 asm-ieee-m-bits)
2589 (define asm-ieee--m-min -4503599627370496) ; (- asm-ieee-+m-min)
2590 (define asm-ieee-sign-bit #x8000000000000000); (expt 2 (+ asm-ieee-e-bits asm-ieee-m-bits))
2592 (define asm-ieee-e-bias 1023) ; (- (expt 2 (- asm-ieee-e-bits 1)) 1)
2593 (define asm-ieee-e-bias-plus-1 1024) ; (+ asm-ieee-e-bias 1)
2594 (define asm-ieee-e-bias-minus-1 1022) ; (- asm-ieee-e-bias 1)
2596 (define asm-inexact-m-min (exact->inexact asm-ieee-+m-min))
2597 (define asm-inexact-+2 (exact->inexact 2))
2598 (define asm-inexact--2 (exact->inexact -2))
2599 (define asm-inexact-+1 (exact->inexact 1))
2600 (define asm-inexact-+1/2 (exact->inexact (/ 1 2)))
2601 (define asm-inexact-0 (exact->inexact 0))
2603 ;------------------------------------------------------------------------------
2605 (define min-fixnum-encoding 3)
2606 (define min-fixnum -1)
2607 (define max-fixnum 255)
2608 (define min-rom-encoding (+ min-fixnum-encoding (- max-fixnum min-fixnum) 1))
2609 (define min-ram-encoding 512)
2610 (define max-ram-encoding 4095)
2611 (define min-vec-encoding 4096)
2612 (define max-vec-encoding 8191)
2614 (define code-start #x5000)
2616 (define (predef-constants) (list))
2618 (define (predef-globals) (list))
2620 (define (encode-direct obj)
2627 ((and (integer? obj)
2630 (<= obj max-fixnum))
2631 (+ obj (- min-fixnum-encoding min-fixnum)))
2635 (define (translate-constant obj)
2640 (define (encode-constant obj constants)
2641 (let ((o (translate-constant obj)))
2642 (let ((e (encode-direct o)))
2645 (let ((x (assoc o constants)))
2647 (vector-ref (cdr x) 0)
2648 (compiler-error "unknown object" obj)))))))
2650 ;; TODO actually, seem to be in a pair, scheme object in car, vector in cdr
2651 ;; constant objects are represented by vectors
2652 ;; 0 : encoding (ROM address) TODO really the ROM address ?
2653 ;; 1 : TODO asm label constant ?
2654 ;; 2 : number of occurences of this constant in the code
2655 ;; 3 : pointer to content, used at encoding time
2656 (define (add-constant obj constants from-code? cont)
2657 (let ((o (translate-constant obj)))
2658 (let ((e (encode-direct o)))
2661 (let ((x (assoc o constants)))
2665 (vector-set! (cdr x) 2 (+ (vector-ref (cdr x) 2) 1)))
2669 (asm-make-label 'constant)
2673 (cons (cons o descr)
2676 (add-constants (list (car o) (cdr o))
2680 (cont new-constants))
2682 (let ((chars (map char->integer (string->list o))))
2683 (vector-set! descr 3 chars)
2688 ((vector? o) ; ordinary vectors are stored as lists
2689 (let ((elems (vector->list o)))
2690 (vector-set! descr 3 elems)
2696 (let ((elems (u8vector->list o)))
2697 (vector-set! descr 3 elems)
2702 ((and (number? o) (exact? o))
2703 ; (pp (list START-ENCODING: o))
2704 (let ((hi (arithmetic-shift o -16)))
2705 (vector-set! descr 3 hi)
2706 ;; recursion will stop once we reach 0 or -1 as the
2707 ;; high part, which will be matched by encode-direct
2711 cont))) ;; TODO FOOBIGNUMS
2713 (cont new-constants))))))))))
2715 (define (add-constants objs constants cont)
2718 (add-constant (car objs)
2721 (lambda (new-constants)
2722 (add-constants (cdr objs)
2726 (define (add-global var globals cont)
2727 (let ((x (assq var globals)))
2730 ;; increment reference counter
2731 (vector-set! (cdr x) 1 (+ (vector-ref (cdr x) 1) 1))
2734 (cons (cons var (vector (length globals) 1))
2736 (cont new-globals)))))
2738 (define (sort-constants constants)
2740 (sort-list constants
2742 (> (vector-ref (cdr x) 2)
2743 (vector-ref (cdr y) 2))))))
2744 (let loop ((i min-rom-encoding)
2747 ;; constants can use all the rom addresses up to 256 constants since
2748 ;; their number is encoded in a byte at the beginning of the bytecode
2749 (if (or (> i min-ram-encoding) (> (- i min-rom-encoding) 256))
2750 (compiler-error "too many constants")
2753 (vector-set! (cdr (car lst)) 0 i)
2757 (define (sort-globals globals) ;; TODO a lot in common with sort-constants, ABSTRACT
2761 (> (vector-ref (cdr x) 1)
2762 (vector-ref (cdr y) 1))))))
2766 (if (> i 256) ;; the number of globals is encoded on a byte
2767 (compiler-error "too many global variables")
2770 (vector-set! (cdr (car lst)) 0 i)
2775 (lambda (code hex-filename)
2776 (let loop1 ((lst code)
2777 (constants (predef-constants))
2778 (globals (predef-globals))
2782 (let ((instr (car lst)))
2783 (cond ((number? instr)
2787 (cons (cons instr (asm-make-label 'label))
2789 ((eq? (car instr) 'push-constant)
2790 (add-constant (cadr instr)
2793 (lambda (new-constants)
2798 ((memq (car instr) '(push-global set-global))
2799 (add-global (cadr instr)
2801 (lambda (new-globals)
2812 (let ((constants (sort-constants constants))
2813 (globals (sort-globals globals)))
2815 (define (label-instr label opcode)
2817 ;; if the distance from pc to the label fits in a single byte,
2818 ;; a short instruction is used, containing a relative address
2819 ;; if not, the full 16-bit label is used
2821 ;;; (let ((dist (- (asm-label-pos label) self)))
2822 ;;; (and (< dist 256) ;; TODO have this between -128 and 127 ? would be more flexible, I guess
2826 ;;; (asm-8 (+ opcode 5))
2827 ;;; (asm-8 (- (asm-label-pos label) self)))
2828 ;; TODO doesn't work at the moment
2833 (let ((pos (- (asm-label-pos label) code-start)))
2835 (asm-8 (quotient pos 256))
2836 (asm-8 (modulo pos 256))))))
2838 (define (push-constant n)
2842 (asm-8 (+ #x90 (quotient n 256)))
2843 (asm-8 (modulo n 256)))))
2845 (define (push-stack n)
2847 (compiler-error "stack is too deep")
2848 (asm-8 (+ #x20 n))))
2850 (define (push-global n)
2856 (define (set-global n)
2864 (compiler-error "call has too many arguments")
2865 (asm-8 (+ #x60 n))))
2869 (compiler-error "call has too many arguments")
2870 (asm-8 (+ #x70 n))))
2872 (define (call-toplevel label)
2873 (label-instr label #x80))
2875 (define (jump-toplevel label)
2876 (label-instr label #x81))
2878 (define (goto label)
2879 (label-instr label #x82))
2881 (define (goto-if-false label)
2882 (label-instr label #x83))
2884 (define (closure label)
2885 (label-instr label #x84))
2890 (define (prim.number?) (prim 0))
2891 (define (prim.+) (prim 1))
2892 (define (prim.-) (prim 2))
2893 (define (prim.*) (prim 3))
2894 (define (prim.quotient) (prim 4))
2895 (define (prim.remainder) (prim 5))
2896 (define (prim.neg) (prim 6))
2897 (define (prim.=) (prim 7))
2898 (define (prim.<) (prim 8))
2899 (define (prim.ior) (prim 9))
2900 (define (prim.>) (prim 10))
2901 (define (prim.xor) (prim 11))
2902 (define (prim.pair?) (prim 12))
2903 (define (prim.cons) (prim 13))
2904 (define (prim.car) (prim 14))
2905 (define (prim.cdr) (prim 15))
2906 (define (prim.set-car!) (prim 16))
2907 (define (prim.set-cdr!) (prim 17))
2908 (define (prim.null?) (prim 18))
2909 (define (prim.eq?) (prim 19))
2910 (define (prim.not) (prim 20))
2911 (define (prim.get-cont) (prim 21))
2912 (define (prim.graft-to-cont) (prim 22))
2913 (define (prim.return-to-cont) (prim 23))
2914 (define (prim.halt) (prim 24))
2915 (define (prim.symbol?) (prim 25))
2916 (define (prim.string?) (prim 26))
2917 (define (prim.string->list) (prim 27))
2918 (define (prim.list->string) (prim 28))
2919 (define (prim.make-u8vector) (prim 29))
2920 (define (prim.u8vector-ref) (prim 30))
2921 (define (prim.u8vector-set!) (prim 31))
2922 (define (prim.print) (prim 32))
2923 (define (prim.clock) (prim 33))
2924 (define (prim.motor) (prim 34))
2925 (define (prim.led) (prim 35))
2926 (define (prim.led2-color) (prim 36))
2927 (define (prim.getchar-wait) (prim 37))
2928 (define (prim.putchar) (prim 38))
2929 (define (prim.beep) (prim 39))
2930 (define (prim.adc) (prim 40))
2931 (define (prim.u8vector?) (prim 41))
2932 (define (prim.sernum) (prim 42))
2933 (define (prim.u8vector-length) (prim 43))
2934 (define (prim.u8vector-copy!) (prim 44))
2935 (define (prim.shift) (prim 45))
2936 (define (prim.pop) (prim 46))
2937 (define (prim.return) (prim 47))
2938 (define (prim.boolean?) (prim 48))
2939 (define (prim.network-init) (prim 49))
2940 (define (prim.network-cleanup) (prim 50))
2941 (define (prim.receive-packet-to-u8vector) (prim 51))
2942 (define (prim.send-packet-from-u8vector) (prim 52))
2943 (define (prim.<=) (prim 53))
2944 (define (prim.>=) (prim 54))
2946 (define big-endian? #f)
2948 (asm-begin! code-start #f)
2952 (asm-8 (length constants))
2953 (asm-8 (length globals))
2955 '(pp (list constants: constants globals: globals))
2959 (let* ((descr (cdr x))
2960 (label (vector-ref descr 1))
2963 ;; see the vm source for a description of encodings
2964 ;; TODO have comments here to explain encoding, at least magic number that give the type
2965 (cond ((and (integer? obj) (exact? obj)) ;; TODO FOOBGIGNUMS
2966 (let ((hi (encode-constant (vector-ref descr 3)
2968 ; (pp (list ENCODE: (vector-ref descr 3) to: hi lo: obj))
2969 (asm-8 (+ 0 (arithmetic-shift hi -8))) ;; TODO -5 has low 16 at 00fb, should be fffb, 8 bits ar lost
2970 (asm-8 (bitwise-and hi #xff)) ; pointer to hi
2971 (asm-8 (arithmetic-shift obj -8)) ; bits 8-15
2972 (asm-8 (bitwise-and obj #xff)))) ; bits 0-7
2974 (let ((obj-car (encode-constant (car obj) constants))
2975 (obj-cdr (encode-constant (cdr obj) constants)))
2976 (asm-8 (+ #x80 (arithmetic-shift obj-car -8)))
2977 (asm-8 (bitwise-and obj-car #xff))
2978 (asm-8 (+ 0 (arithmetic-shift obj-cdr -8)))
2979 (asm-8 (bitwise-and obj-cdr #xff))))
2986 (let ((obj-enc (encode-constant (vector-ref descr 3)
2988 (asm-8 (+ #x80 (arithmetic-shift obj-enc -8)))
2989 (asm-8 (bitwise-and obj-enc #xff))
2992 ((vector? obj) ; ordinary vectors are stored as lists
2993 (let* ((elems (vector-ref descr 3))
2994 (obj-car (encode-constant (car elems)
2996 (obj-cdr (encode-constant (cdr elems)
2998 (asm-8 (+ #x80 (arithmetic-shift obj-car -8)))
2999 (asm-8 (bitwise-and obj-car #xff))
3000 (asm-8 (+ 0 (arithmetic-shift obj-cdr -8)))
3001 (asm-8 (bitwise-and obj-cdr #xff))))
3003 (let ((obj-enc (encode-constant (vector-ref descr 3)
3005 (l (length (vector-ref descr 3))))
3006 ;; length is stored raw, not encoded as an object
3007 ;; however, the bytes of content are encoded as
3009 (asm-8 (+ #x80 (arithmetic-shift l -8)))
3010 (asm-8 (bitwise-and l #xff))
3011 (asm-8 (+ #x60 (arithmetic-shift obj-enc -8)))
3012 (asm-8 (bitwise-and obj-enc #xff))))
3014 (compiler-error "unknown object type" obj)))))
3017 (let loop2 ((lst code))
3019 (let ((instr (car lst)))
3021 (cond ((number? instr)
3022 (let ((label (cdr (assq instr labels))))
3025 ((eq? (car instr) 'entry)
3026 (let ((np (cadr instr))
3027 (rest? (caddr instr)))
3028 (asm-8 (if rest? (- np) np))))
3030 ((eq? (car instr) 'push-constant)
3031 (let ((n (encode-constant (cadr instr) constants)))
3034 ((eq? (car instr) 'push-stack)
3035 (push-stack (cadr instr)))
3037 ((eq? (car instr) 'push-global)
3038 (push-global (vector-ref
3039 (cdr (assq (cadr instr) globals))
3042 ((eq? (car instr) 'set-global)
3043 (set-global (vector-ref
3044 (cdr (assq (cadr instr) globals))
3047 ((eq? (car instr) 'call)
3048 (call (cadr instr)))
3050 ((eq? (car instr) 'jump)
3051 (jump (cadr instr)))
3053 ((eq? (car instr) 'call-toplevel)
3054 (let ((label (cdr (assq (cadr instr) labels))))
3055 (call-toplevel label)))
3057 ((eq? (car instr) 'jump-toplevel)
3058 (let ((label (cdr (assq (cadr instr) labels))))
3059 (jump-toplevel label)))
3061 ((eq? (car instr) 'goto)
3062 (let ((label (cdr (assq (cadr instr) labels))))
3065 ((eq? (car instr) 'goto-if-false)
3066 (let ((label (cdr (assq (cadr instr) labels))))
3067 (goto-if-false label)))
3069 ((eq? (car instr) 'closure)
3070 (let ((label (cdr (assq (cadr instr) labels))))
3073 ((eq? (car instr) 'prim)
3075 ((#%number?) (prim.number?))
3079 ((#%quotient) (prim.quotient))
3080 ((#%remainder) (prim.remainder))
3081 ((#%neg) (prim.neg))
3084 ((#%ior) (prim.ior))
3086 ((#%xor) (prim.xor))
3087 ((#%pair?) (prim.pair?))
3088 ((#%cons) (prim.cons))
3089 ((#%car) (prim.car))
3090 ((#%cdr) (prim.cdr))
3091 ((#%set-car!) (prim.set-car!))
3092 ((#%set-cdr!) (prim.set-cdr!))
3093 ((#%null?) (prim.null?))
3094 ((#%eq?) (prim.eq?))
3095 ((#%not) (prim.not))
3096 ((#%get-cont) (prim.get-cont))
3097 ((#%graft-to-cont) (prim.graft-to-cont))
3098 ((#%return-to-cont) (prim.return-to-cont))
3099 ((#%halt) (prim.halt))
3100 ((#%symbol?) (prim.symbol?))
3101 ((#%string?) (prim.string?))
3102 ((#%string->list) (prim.string->list))
3103 ((#%list->string) (prim.list->string))
3104 ((#%make-u8vector) (prim.make-u8vector))
3105 ((#%u8vector-ref) (prim.u8vector-ref))
3106 ((#%u8vector-set!) (prim.u8vector-set!))
3107 ((#%print) (prim.print))
3108 ((#%clock) (prim.clock))
3109 ((#%motor) (prim.motor))
3110 ((#%led) (prim.led))
3111 ((#%led2-color) (prim.led2-color))
3112 ((#%getchar-wait ) (prim.getchar-wait))
3113 ((#%putchar) (prim.putchar))
3114 ((#%beep) (prim.beep))
3115 ((#%adc) (prim.adc))
3116 ((#%u8vector?) (prim.u8vector?))
3117 ((#%sernum) (prim.sernum))
3118 ((#%u8vector-length) (prim.u8vector-length))
3119 ((#%u8vector-copy!) (prim.u8vector-copy!))
3120 ((#%boolean?) (prim.boolean?))
3121 ((#%network-init) (prim.network-init))
3122 ((#%network-cleanup) (prim.network-cleanup))
3123 ((#%receive-packet-to-u8vector) (prim.receive-packet-to-u8vector))
3124 ((#%send-packet-from-u8vector) (prim.send-packet-from-u8vector))
3128 (compiler-error "unknown primitive" (cadr instr)))))
3130 ((eq? (car instr) 'return)
3133 ((eq? (car instr) 'pop)
3136 ((eq? (car instr) 'shift)
3140 (compiler-error "unknown instruction" instr)))
3142 (loop2 (cdr lst)))))
3146 (asm-write-hex-file hex-filename)
3151 (lambda (hex-filename)
3155 (shell-command "gcc -o picobit-vm picobit-vm.c")
3156 (shell-command (string-append "./picobit-vm " hex-filename)))
3157 (shell-command (string-append "./robot . 1 " hex-filename)))))
3159 (define (sort-list l <?)
3161 (define (mergesort l)
3163 (define (merge l1 l2)
3164 (cond ((null? l1) l2)
3167 (let ((e1 (car l1)) (e2 (car l2)))
3169 (cons e1 (merge (cdr l1) l2))
3170 (cons e2 (merge l1 (cdr l2))))))))
3173 (if (or (null? l) (null? (cdr l)))
3175 (cons (car l) (split (cddr l)))))
3177 (if (or (null? l) (null? (cdr l)))
3179 (let* ((l1 (mergesort (split l)))
3180 (l2 (mergesort (split (cdr l)))))
3185 ;------------------------------------------------------------------------------
3189 (let* ((node (parse-file filename))
3192 (path-strip-extension filename)
3195 (adjust-unmutable-references! node)
3197 ; (pp (node->expr node))
3199 (let ((ctx (comp-none node (make-init-context))))
3200 (let ((prog (linearize (optimize-code (context-code ctx)))))
3201 ; (pp (list code: prog env: (context-env ctx)))
3202 (assemble prog hex-filename)
3203 (execute hex-filename))))))
3208 (compile filename)))
3210 ;------------------------------------------------------------------------------
3213 (define (asm-write-hex-file filename)
3214 (with-output-to-file filename
3217 (define (print-hex n)
3218 (display (string-ref "0123456789ABCDEF" n)))
3220 (define (print-byte n)
3222 (print-hex (quotient n 16))
3223 (print-hex (modulo n 16)))
3225 (define (print-line type addr bytes)
3226 (let ((n (length bytes))
3227 (addr-hi (quotient addr 256))
3228 (addr-lo (modulo addr 256)))
3231 ; (print-byte addr-hi)
3232 ; (print-byte addr-lo)
3234 (for-each print-byte bytes)
3236 (modulo (- (apply + n addr-hi addr-lo type bytes)) 256)))
3240 (let loop ((lst (cdr asm-code-stream))
3243 (if (not (null? lst))
3244 (let ((x (car lst)))
3246 (let ((kind (vector-ref x 0)))
3247 (if (not (eq? kind 'LISTING))
3248 (compiler-internal-error
3249 "asm-write-hex-file, code stream not assembled"))
3257 (if (= (modulo pos 8) 0)
3260 (- pos (length rev-bytes))
3261 (reverse rev-bytes))
3268 (if (not (null? rev-bytes))
3270 (- pos (length rev-bytes))
3271 (reverse rev-bytes)))
3272 (print-line 1 0 '())))))))