1 ; File: "picobit.scm", Time-stamp: <2006-05-08 16:04:37 feeley>
3 ; Copyright (C) 2006 by Marc Feeley, All Rights Reserved.
6 (proper-tail-calls-set! #f)
10 ;-----------------------------------------------------------------------------
12 (define compiler-error
13 (lambda (msg . others)
14 (display "*** ERROR -- ")
16 (for-each (lambda (x) (display " ") (write x)) others)
20 ;-----------------------------------------------------------------------------
24 (cond ((null? lst) '())
25 ((keep? (car lst)) (cons (car lst) (keep keep? (cdr lst))))
26 (else (keep keep? (cdr lst))))))
31 (cons (car lst) (take (- n 1) (cdr lst)))
37 (drop (- n 1) (cdr lst))
43 (cons x (repeat (- n 1) x))
48 (let loop ((lst lst) (i 0))
49 (cond ((not (pair? lst)) #f)
51 (else (loop (cdr lst) (+ i 1)))))))
56 (and (pred? (car lst))
57 (every pred? (cdr lst))))))
59 ;-----------------------------------------------------------------------------
63 ;-----------------------------------------------------------------------------
67 ;-----------------------------------------------------------------------------
71 ;-----------------------------------------------------------------------------
75 ;-----------------------------------------------------------------------------
79 ;-----------------------------------------------------------------------------
83 ;-----------------------------------------------------------------------------
87 ;-----------------------------------------------------------------------------
91 ;------------------------------------------------------------------------------
95 (let ((v (make-vector (+ (code-last-label code) 1))))
98 (vector-set! v (bb-label bb) bb))
102 (define bbs->ref-counts
104 (let ((ref-counts (make-vector (vector-length bbs) 0)))
108 (let ((ref-count (vector-ref ref-counts label)))
109 (vector-set! ref-counts label (+ ref-count 1))
111 (let* ((bb (vector-ref bbs label))
112 (rev-instrs (bb-rev-instrs bb)))
115 (let ((opcode (car instr)))
116 (cond ((eq? opcode 'goto)
117 (visit (cadr instr)))
118 ((eq? opcode 'goto-if-false)
120 (visit (caddr instr)))
121 ((or (eq? opcode 'closure)
122 (eq? opcode 'call-toplevel)
123 (eq? opcode 'jump-toplevel))
124 (visit (cadr instr))))))
131 (define resolve-toplevel-labels!
134 (if (< i (vector-length bbs))
135 (let* ((bb (vector-ref bbs i))
136 (rev-instrs (bb-rev-instrs bb)))
140 (let ((opcode (car instr)))
141 (cond ((eq? opcode 'call-toplevel)
143 (prc-entry-label (cadr instr))))
144 ((eq? opcode 'jump-toplevel)
146 (prc-entry-label (cadr instr))))
152 (define tighten-jump-cascades!
154 (let ((ref-counts (bbs->ref-counts bbs)))
158 (let* ((bb (vector-ref bbs label))
159 (rev-instrs (bb-rev-instrs bb)))
160 (and (or (null? (cdr rev-instrs))
161 (= (vector-ref ref-counts label) 1))
167 (if (< i (vector-length bbs))
168 (if (> (vector-ref ref-counts i) 0)
169 (let* ((bb (vector-ref bbs i))
170 (rev-instrs (bb-rev-instrs bb))
171 (jump (car rev-instrs))
173 (cond ((eq? opcode 'goto)
174 (let* ((label (cadr jump))
175 (jump-replacement (resolve label)))
181 (make-bb (bb-label bb)
182 (append jump-replacement
188 ((eq? opcode 'goto-if-false)
189 (let* ((label-then (cadr jump))
190 (label-else (caddr jump))
191 (jump-then-replacement (resolve label-then))
192 (jump-else-replacement (resolve label-else)))
193 (if (and jump-then-replacement
194 (null? (cdr jump-then-replacement))
195 jump-else-replacement
196 (null? (cdr jump-else-replacement))
197 (or (eq? (caar jump-then-replacement) 'goto)
198 (eq? (caar jump-else-replacement) 'goto)))
203 (make-bb (bb-label bb)
204 (cons (list 'goto-if-false
205 (if (eq? (caar jump-then-replacement) 'goto)
206 (cadar jump-then-replacement)
208 (if (eq? (caar jump-else-replacement) 'goto)
209 (cadar jump-else-replacement)
224 (define remove-useless-bbs!
226 (let ((ref-counts (bbs->ref-counts bbs)))
227 (let loop1 ((label 0) (new-label 0))
228 (if (< label (vector-length bbs))
229 (if (> (vector-ref ref-counts label) 0)
230 (let ((bb (vector-ref bbs label)))
234 (make-bb new-label (bb-rev-instrs bb)))
235 (loop1 (+ label 1) (+ new-label 1)))
236 (loop1 (+ label 1) new-label))
237 (renumber-labels bbs ref-counts new-label))))))
239 (define renumber-labels
240 (lambda (bbs ref-counts n)
241 (let ((new-bbs (make-vector n)))
242 (let loop2 ((label 0))
243 (if (< label (vector-length bbs))
244 (if (> (vector-ref ref-counts label) 0)
245 (let* ((bb (vector-ref bbs label))
246 (new-label (bb-label bb))
247 (rev-instrs (bb-rev-instrs bb)))
254 (bb-label (vector-ref bbs label))))
256 (let ((opcode (car instr)))
257 (cond ((eq? opcode 'closure)
259 (new-label (cadr instr))))
260 ((eq? opcode 'call-toplevel)
262 (new-label (cadr instr))))
263 ((eq? opcode 'jump-toplevel)
265 (new-label (cadr instr))))
268 (new-label (cadr instr))))
269 ((eq? opcode 'goto-if-false)
271 (new-label (cadr instr))
272 (new-label (caddr instr))))
279 (make-bb new-label (map fix rev-instrs)))
286 (let* ((done (make-vector (vector-length bbs) #f)))
290 (not (vector-ref done label))))
293 (lambda (instrs todo)
295 (let* ((instr (car instrs))
296 (opcode (car instr)))
297 (cond ((or (eq? opcode 'closure)
298 (eq? opcode 'call-toplevel)
299 (eq? opcode 'jump-toplevel))
300 (label-refs (cdr instrs) (cons (cadr instr) todo)))
302 (label-refs (cdr instrs) todo))))
305 (define schedule-here
306 (lambda (label new-label todo cont)
307 (let* ((bb (vector-ref bbs label))
308 (rev-instrs (bb-rev-instrs bb))
309 (jump (car rev-instrs))
311 (new-todo (label-refs rev-instrs todo)))
312 (vector-set! bbs label (make-bb new-label rev-instrs))
313 (vector-set! done label #t)
314 (cond ((eq? opcode 'goto)
315 (let ((label (cadr jump)))
316 (if (unscheduled? label)
321 (cont (+ new-label 1)
323 ((eq? opcode 'goto-if-false)
324 (let ((label-then (cadr jump))
325 (label-else (caddr jump)))
326 (cond ((unscheduled? label-else)
327 (schedule-here label-else
329 (cons label-then new-todo)
331 ((unscheduled? label-then)
332 (schedule-here label-then
337 (cont (+ new-label 1)
340 (cont (+ new-label 1)
343 (define schedule-somewhere
344 (lambda (label new-label todo cont)
345 (schedule-here label new-label todo cont)))
347 (define schedule-todo
348 (lambda (new-label todo)
350 (let ((label (car todo)))
351 (if (unscheduled? label)
352 (schedule-somewhere label
356 (schedule-todo new-label
360 (schedule-here 0 0 '() schedule-todo)
363 (make-vector (vector-length bbs) 1)
364 (vector-length bbs)))))
368 (let loop ((label (- (vector-length bbs) 1))
371 (let* ((bb (vector-ref bbs label))
372 (rev-instrs (bb-rev-instrs bb))
373 (jump (car rev-instrs))
379 (cond ((eq? opcode 'goto)
380 (if (= (cadr jump) (+ label 1))
383 ((eq? opcode 'goto-if-false)
384 (cond ((= (caddr jump) (+ label 1))
385 (cons (list 'goto-if-false (cadr jump))
387 ((= (cadr jump) (+ label 1))
388 (cons (list 'goto-if-not-false (caddr jump))
391 (cons (list 'goto (caddr jump))
392 (cons (list 'goto-if-false (cadr jump))
393 (cdr rev-instrs))))))
399 (define optimize-code
401 (let ((bbs (code->vector code)))
402 (resolve-toplevel-labels! bbs)
403 (tighten-jump-cascades! bbs)
404 (let ((bbs (remove-useless-bbs! bbs)))
407 (define expand-loads ;; ADDED
410 (if (eq? (car e) 'load)
412 (expand-loads (with-input-from-file (cadr e) read-all)))
419 (with-input-from-file "library.scm" read-all))
421 (expand-loads (append library ;; ADDED (didn't have expand-loads)
422 (with-input-from-file filename read-all))))
426 (parse-top (cons 'begin toplevel-exprs) global-env)))
430 (mark-needed-global-vars! global-env node))
435 (lambda (defs after-defs)
437 (define make-seq-preparsed
439 (let ((r (make-seq #f exprs)))
440 (for-each (lambda (x) (node-parent-set! x r)) exprs)
443 (define make-call-preparsed
445 (let ((r (make-call #f exprs)))
446 (for-each (lambda (x) (node-parent-set! x r)) exprs)
450 (env-lookup global-env '#%readyq))
452 (list (make-seq-preparsed defs)
454 (list (parse 'value '#%start-first-process global-env)
458 (extract-ids pattern))
460 (make-prc #f '() #f (has-rest-param? pattern) #f))
462 (env-extend global-env ids r))
464 (make-seq-preparsed after-defs)))
467 (map (lambda (id) (env-lookup new-env id))
469 (node-children-set! r (list body))
470 (node-parent-set! body r)
482 (define extract-parts
485 (not (def? (car lst))))
490 (cont (cons (car lst) d) ad))))))
492 ;------------------------------------------------------------------------------
496 ;------------------------------------------------------------------------------
501 (lambda (code hex-filename)
502 (let loop1 ((lst code)
503 (constants (predef-constants))
504 (globals (predef-globals))
508 (let ((instr (car lst)))
509 (cond ((number? instr)
513 (cons (cons instr (asm-make-label 'label))
515 ((eq? (car instr) 'push-constant)
516 (add-constant (cadr instr)
519 (lambda (new-constants)
524 ((memq (car instr) '(push-global set-global))
525 (add-global (cadr instr)
527 (lambda (new-globals)
538 (let ((constants (sort-constants constants)))
540 (define (label-instr label opcode)
545 (let ((pos (- (asm-label-pos label) code-start)))
546 (asm-8 (+ (quotient pos 256) opcode))
547 (asm-8 (modulo pos 256))))))
549 (define (push-constant n)
556 (define (push-stack n)
558 (compiler-error "stack is too deep")
561 (define (push-global n)
562 (asm-8 (+ #x40 n)) ;; TODO we are actually limited to 16 constants, since we only have 4 bits to represent them
563 ;; (if (> n 15) ;; ADDED prevented the stack from compiling
564 ;; (compiler-error "too many global variables")
565 ;; (asm-8 (+ #x40 n)))
566 ) ;; TODO actually inline most, or put as csts
568 (define (set-global n)
570 ;; (if (> n 15) ;; ADDED prevented the stack from compiling
571 ;; (compiler-error "too many global variables")
572 ;; (asm-8 (+ #x50 n)))
577 (compiler-error "call has too many arguments")
582 (compiler-error "call has too many arguments")
585 (define (call-toplevel label)
586 (label-instr label #x80))
588 (define (jump-toplevel label)
589 (label-instr label #x90))
592 (label-instr label #xa0))
594 (define (goto-if-false label)
595 (label-instr label #xb0))
597 (define (closure label)
598 (label-instr label #xc0))
603 (define (prim.number?) (prim 0))
604 (define (prim.+) (prim 1))
605 (define (prim.-) (prim 2))
606 (define (prim.*) (prim 3))
607 (define (prim.quotient) (prim 4))
608 (define (prim.remainder) (prim 5))
609 (define (prim.neg) (prim 6))
610 (define (prim.=) (prim 7))
611 (define (prim.<) (prim 8))
612 (define (prim.ior) (prim 9)) ;; ADDED
613 (define (prim.>) (prim 10))
614 (define (prim.xor) (prim 11)) ;; ADDED
615 (define (prim.pair?) (prim 12))
616 (define (prim.cons) (prim 13))
617 (define (prim.car) (prim 14))
618 (define (prim.cdr) (prim 15))
619 (define (prim.set-car!) (prim 16))
620 (define (prim.set-cdr!) (prim 17))
621 (define (prim.null?) (prim 18))
622 (define (prim.eq?) (prim 19))
623 (define (prim.not) (prim 20))
624 (define (prim.get-cont) (prim 21))
625 (define (prim.graft-to-cont) (prim 22))
626 (define (prim.return-to-cont) (prim 23))
627 (define (prim.halt) (prim 24))
628 (define (prim.symbol?) (prim 25))
629 (define (prim.string?) (prim 26))
630 (define (prim.string->list) (prim 27))
631 (define (prim.list->string) (prim 28))
632 (define (prim.set-fst!) (prim 29)) ;; ADDED
633 (define (prim.set-snd!) (prim 30)) ;; ADDED
634 (define (prim.set-trd!) (prim 31)) ;; ADDED
636 (define (prim.print) (prim 32))
637 (define (prim.clock) (prim 33))
638 (define (prim.motor) (prim 34))
639 (define (prim.led) (prim 35))
640 (define (prim.getchar-wait) (prim 36))
641 (define (prim.putchar) (prim 37))
642 (define (prim.light) (prim 38))
644 (define (prim.triplet?) (prim 39)) ;; ADDED
645 (define (prim.triplet) (prim 40)) ;; ADDED
646 (define (prim.fst) (prim 41)) ;; ADDED
647 (define (prim.snd) (prim 42)) ;; ADDED
648 (define (prim.trd) (prim 43)) ;; ADDED
650 (define (prim.shift) (prim 45))
651 (define (prim.pop) (prim 46))
652 (define (prim.return) (prim 47))
654 (define big-endian? #f)
656 (asm-begin! code-start #f)
660 (asm-8 (length constants)) ;; TODO maybe more constants ? that would mean more rom adress space, and less for ram, for now we are ok
663 (pp (list constants: constants globals: globals)) ;; TODO debug
667 (let* ((descr (cdr x))
668 (label (vector-ref descr 1))
671 (cond ((and (integer? obj) (exact? obj))
673 (asm-8 (bitwise-and (arithmetic-shift obj -16) 255))
674 (asm-8 (bitwise-and (arithmetic-shift obj -8) 255))
675 (asm-8 (bitwise-and obj 255)))
676 ((pair? obj) ;; TODO this is ok no matter how many csts we have
677 (let ((obj-car (encode-constant (car obj) constants))
678 (obj-cdr (encode-constant (cdr obj) constants)))
679 ;; car and cdr are both represented in 12 bits, the
680 ;; center byte being shared between the 2
684 (arithmetic-shift (bitwise-and obj-car #xff0) -4))
686 (bitwise-ior (arithmetic-shift
687 (bitwise-and obj-car #xf)
690 (bitwise-and obj-cdr #xf00)
692 (asm-8 (bitwise-and obj-cdr #xff))))
699 (let ((obj-enc (encode-constant (vector-ref descr 3)
701 (asm-8 4) ;; TODO changed
702 (asm-8 (arithmetic-shift (bitwise-and obj-enc #xff0)
704 (asm-8 (arithmetic-shift (bitwise-and obj-enc #xf)
708 (let ((obj-enc (encode-constant (vector-ref descr 3)
710 (asm-8 5) ;; TODO changed, and factor code
711 (asm-8 (arithmetic-shift (bitwise-and obj-enc #xff0)
713 (asm-8 (arithmetic-shift (bitwise-and obj-enc #xf)
717 (compiler-error "unknown object type" obj)))))
720 (let loop2 ((lst code))
722 (let ((instr (car lst)))
724 (cond ((number? instr)
725 (let ((label (cdr (assq instr labels))))
728 ((eq? (car instr) 'entry)
729 (let ((np (cadr instr))
730 (rest? (caddr instr)))
731 (asm-8 (if rest? (- np) np))))
733 ((eq? (car instr) 'push-constant) ;; TODO FOOBAR 12 bits for constants now
734 (let ((n (encode-constant (cadr instr) constants)))
737 ((eq? (car instr) 'push-stack)
738 (push-stack (cadr instr)))
740 ((eq? (car instr) 'push-global)
741 (push-global (cdr (assq (cadr instr) globals))))
743 ((eq? (car instr) 'set-global)
744 (set-global (cdr (assq (cadr instr) globals))))
746 ((eq? (car instr) 'call)
749 ((eq? (car instr) 'jump)
752 ((eq? (car instr) 'call-toplevel)
753 (let ((label (cdr (assq (cadr instr) labels))))
754 (call-toplevel label)))
756 ((eq? (car instr) 'jump-toplevel)
757 (let ((label (cdr (assq (cadr instr) labels))))
758 (jump-toplevel label)))
760 ((eq? (car instr) 'goto)
761 (let ((label (cdr (assq (cadr instr) labels))))
764 ((eq? (car instr) 'goto-if-false)
765 (let ((label (cdr (assq (cadr instr) labels))))
766 (goto-if-false label)))
768 ((eq? (car instr) 'closure)
769 (let ((label (cdr (assq (cadr instr) labels))))
772 ((eq? (car instr) 'prim)
774 ((#%number?) (prim.number?))
778 ((#%quotient) (prim.quotient))
779 ((#%remainder) (prim.remainder))
783 ((#%ior) (prim.ior)) ;; ADDED
785 ((#%xor) (prim.xor)) ;; ADDED
786 ((#%pair?) (prim.pair?))
787 ((#%cons) (prim.cons))
790 ((#%set-car!) (prim.set-car!))
791 ((#%set-cdr!) (prim.set-cdr!))
792 ((#%null?) (prim.null?))
795 ((#%get-cont) (prim.get-cont))
796 ((#%graft-to-cont) (prim.graft-to-cont))
797 ((#%return-to-cont) (prim.return-to-cont))
798 ((#%halt) (prim.halt))
799 ((#%symbol?) (prim.symbol?))
800 ((#%string?) (prim.string?))
801 ((#%string->list) (prim.string->list))
802 ((#%list->string) (prim.list->string))
803 ((#%set-fst!) (prim.set-fst!)) ;; ADDED
804 ((#%set-snd!) (prim.set-snd!)) ;; ADDED
805 ((#%set-trd!) (prim.set-trd!)) ;; ADDED
807 ((#%print) (prim.print))
808 ((#%clock) (prim.clock))
809 ((#%motor) (prim.motor))
811 ((#%getchar-wait) (prim.getchar-wait))
812 ((#%putchar) (prim.putchar))
813 ((#%light) (prim.light))
815 ((#%triplet?) (prim.triplet?)) ;; ADDED
816 ((#%triplet) (prim.triplet)) ;; ADDED
817 ((#%fst) (prim.fst)) ;; ADDED
818 ((#%snd) (prim.snd)) ;; ADDED
819 ((#%trd) (prim.trd)) ;; ADDED
821 (compiler-error "unknown primitive" (cadr instr)))))
823 ((eq? (car instr) 'return)
826 ((eq? (car instr) 'pop)
829 ((eq? (car instr) 'shift)
833 (compiler-error "unknown instruction" instr)))
839 (asm-write-hex-file hex-filename)
844 (lambda (hex-filename)
848 (shell-command "gcc -o picobit-vm picobit-vm.c")
849 (shell-command (string-append "./picobit-vm " hex-filename)))
850 (shell-command (string-append "./robot . 1 " hex-filename)))))
852 (define (sort-list l <?)
854 (define (mergesort l)
856 (define (merge l1 l2)
857 (cond ((null? l1) l2)
860 (let ((e1 (car l1)) (e2 (car l2)))
862 (cons e1 (merge (cdr l1) l2))
863 (cons e2 (merge l1 (cdr l2))))))))
866 (if (or (null? l) (null? (cdr l)))
868 (cons (car l) (split (cddr l)))))
870 (if (or (null? l) (null? (cdr l)))
872 (let* ((l1 (mergesort (split l)))
873 (l2 (mergesort (split (cdr l)))))
878 ;------------------------------------------------------------------------------
882 (let* ((node (parse-file filename))
885 (path-strip-extension filename)
888 ; (pp (node->expr node))
890 (let ((ctx (comp-none node (make-init-context))))
891 (let ((prog (linearize (optimize-code (context-code ctx)))))
892 ; (pp (list code: prog env: (context-env ctx)))
893 (assemble prog hex-filename)
894 (execute hex-filename))))))
901 ;------------------------------------------------------------------------------
904 (define (asm-write-hex-file filename)
905 (with-output-to-file filename
908 (define (print-hex n)
909 (display (string-ref "0123456789ABCDEF" n)))
911 (define (print-byte n)
913 (print-hex (quotient n 16))
914 (print-hex (modulo n 16)))
916 (define (print-line type addr bytes)
917 (let ((n (length bytes))
918 (addr-hi (quotient addr 256))
919 (addr-lo (modulo addr 256)))
922 ; (print-byte addr-hi)
923 ; (print-byte addr-lo)
925 (for-each print-byte bytes)
927 (modulo (- (apply + n addr-hi addr-lo type bytes)) 256)))
931 (let loop ((lst (cdr asm-code-stream))
934 (if (not (null? lst))
937 (let ((kind (vector-ref x 0)))
938 (if (not (eq? kind 'LISTING))
939 (compiler-internal-error
940 "asm-write-hex-file, code stream not assembled"))
948 (if (= (modulo pos 8) 0)
951 (- pos (length rev-bytes))
959 (if (not (null? rev-bytes))
961 (- pos (length rev-bytes))
962 (reverse rev-bytes)))
963 (print-line 1 0 '())))))))