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 (define expand-loads ;; ADDED
98 (if (eq? (car e) 'load)
100 (expand-loads (with-input-from-file (cadr e) read-all)))
107 (with-input-from-file "library.scm" read-all))
109 (expand-loads (append library ;; ADDED (didn't have expand-loads)
110 (with-input-from-file filename read-all))))
114 (parse-top (cons 'begin toplevel-exprs) global-env)))
118 (mark-needed-global-vars! global-env node))
123 (lambda (defs after-defs)
125 (define make-seq-preparsed
127 (let ((r (make-seq #f exprs)))
128 (for-each (lambda (x) (node-parent-set! x r)) exprs)
131 (define make-call-preparsed
133 (let ((r (make-call #f exprs)))
134 (for-each (lambda (x) (node-parent-set! x r)) exprs)
138 (env-lookup global-env '#%readyq))
140 (list (make-seq-preparsed defs)
142 (list (parse 'value '#%start-first-process global-env)
146 (extract-ids pattern))
148 (make-prc #f '() #f (has-rest-param? pattern) #f))
150 (env-extend global-env ids r))
152 (make-seq-preparsed after-defs)))
155 (map (lambda (id) (env-lookup new-env id))
157 (node-children-set! r (list body))
158 (node-parent-set! body r)
170 (define extract-parts
173 (not (def? (car lst))))
178 (cont (cons (car lst) d) ad))))))
180 ;------------------------------------------------------------------------------
184 ;------------------------------------------------------------------------------
189 (lambda (code hex-filename)
190 (let loop1 ((lst code)
191 (constants (predef-constants))
192 (globals (predef-globals))
196 (let ((instr (car lst)))
197 (cond ((number? instr)
201 (cons (cons instr (asm-make-label 'label))
203 ((eq? (car instr) 'push-constant)
204 (add-constant (cadr instr)
207 (lambda (new-constants)
212 ((memq (car instr) '(push-global set-global))
213 (add-global (cadr instr)
215 (lambda (new-globals)
226 (let ((constants (sort-constants constants)))
228 (define (label-instr label opcode)
231 3) ;; TODO BARF was 2, maybe was length ? seems to be fixed
233 (let ((pos (- (asm-label-pos label) code-start)))
234 ;; (asm-8 (+ (quotient pos 256) opcode))
235 ;; TODO do we mess up any offsets ? FOOBAR
237 (asm-8 (quotient pos 256))
238 (asm-8 (modulo pos 256))))))
240 (define (push-constant n)
245 (asm-8 (quotient n 256))
246 (asm-8 (modulo n 256))))) ;; TODO with 13-bit objects, we need 2 bytes, maybe limit to 12, so we could use a byte and a half, but we'd need to use an opcode with only 4 bits, maybe the call/jump stuff can be combined ? FOOBAR
248 (define (push-stack n)
250 (compiler-error "stack is too deep")
253 (define (push-global n)
254 (asm-8 (+ #x40 n)) ;; TODO maybe do the same as for csts, have a push-long-global to have more ?
256 ;; (compiler-error "too many global variables")
257 ;; (asm-8 (+ #x40 n)))
258 ) ;; TODO actually inline most, or put as csts
260 (define (set-global n)
262 ;; (if (> n 15) ;; ADDED prevented the stack from compiling
263 ;; (compiler-error "too many global variables")
264 ;; (asm-8 (+ #x50 n)))
269 (compiler-error "call has too many arguments")
274 (compiler-error "call has too many arguments")
277 (define (call-toplevel label) ;; TODO use 8-bit opcodes for these
278 (label-instr label #x80))
280 (define (jump-toplevel label)
281 (label-instr label #x90))
284 (label-instr label #xa0))
286 (define (goto-if-false label)
287 (label-instr label #xb0))
289 (define (closure label)
290 (label-instr label #xc0)) ;; FOOBAR change here ?
295 (define (prim.number?) (prim 0))
296 (define (prim.+) (prim 1))
297 (define (prim.-) (prim 2))
298 (define (prim.*) (prim 3))
299 (define (prim.quotient) (prim 4))
300 (define (prim.remainder) (prim 5))
301 (define (prim.neg) (prim 6))
302 (define (prim.=) (prim 7))
303 (define (prim.<) (prim 8))
304 (define (prim.ior) (prim 9))
305 (define (prim.>) (prim 10))
306 (define (prim.xor) (prim 11))
307 (define (prim.pair?) (prim 12))
308 (define (prim.cons) (prim 13))
309 (define (prim.car) (prim 14))
310 (define (prim.cdr) (prim 15))
311 (define (prim.set-car!) (prim 16))
312 (define (prim.set-cdr!) (prim 17))
313 (define (prim.null?) (prim 18))
314 (define (prim.eq?) (prim 19))
315 (define (prim.not) (prim 20))
316 (define (prim.get-cont) (prim 21))
317 (define (prim.graft-to-cont) (prim 22))
318 (define (prim.return-to-cont) (prim 23))
319 (define (prim.halt) (prim 24))
320 (define (prim.symbol?) (prim 25))
321 (define (prim.string?) (prim 26))
322 (define (prim.string->list) (prim 27))
323 (define (prim.list->string) (prim 28))
325 (define (prim.print) (prim 32))
326 (define (prim.clock) (prim 33))
327 (define (prim.motor) (prim 34))
328 (define (prim.led) (prim 35))
329 (define (prim.led2-color) (prim 36))
330 (define (prim.getchar-wait) (prim 37))
331 (define (prim.putchar) (prim 38))
332 (define (prim.beep) (prim 39))
333 (define (prim.adc) (prim 40))
334 (define (prim.dac) (prim 41))
335 (define (prim.sernum) (prim 42)) ;; TODO necessary ?
337 (define (prim.shift) (prim 45))
338 (define (prim.pop) (prim 46))
339 (define (prim.return) (prim 47))
341 (define big-endian? #f)
343 (asm-begin! code-start #f)
347 (asm-8 (length constants))
350 (pp (list constants: constants globals: globals)) ;; TODO debug
354 (let* ((descr (cdr x))
355 (label (vector-ref descr 1))
358 ;; see the vm source for a description of encodings
359 (cond ((and (integer? obj) (exact? obj))
361 (asm-8 (bitwise-and (arithmetic-shift obj -16) 255))
362 (asm-8 (bitwise-and (arithmetic-shift obj -8) 255))
363 (asm-8 (bitwise-and obj 255)))
365 (let ((obj-car (encode-constant (car obj) constants))
366 (obj-cdr (encode-constant (cdr obj) constants)))
367 (asm-8 (+ #x80 (arithmetic-shift obj-car -8)))
368 (asm-8 (bitwise-and obj-car #xff))
369 (asm-8 (+ 0 (arithmetic-shift obj-cdr -8)))
370 (asm-8 (bitwise-and obj-cdr #xff))))
377 (let ((obj-enc (encode-constant (vector-ref descr 3)
379 (asm-8 (+ #x80 (arithmetic-shift obj-enc -8)))
380 (asm-8 (bitwise-and obj-enc #xff))
384 (let ((obj-enc (encode-constant (vector-ref descr 3)
386 (asm-8 (+ #x80 (arithmetic-shift obj-enc -8)))
387 (asm-8 (bitwise-and obj-enc #xff))
391 (compiler-error "unknown object type" obj)))))
394 (let loop2 ((lst code))
396 (let ((instr (car lst)))
398 (cond ((number? instr)
399 (let ((label (cdr (assq instr labels))))
402 ((eq? (car instr) 'entry)
403 (let ((np (cadr instr))
404 (rest? (caddr instr)))
405 (asm-8 (if rest? (- np) np))))
407 ((eq? (car instr) 'push-constant) ;; TODO FOOBAR 12 bits for constants now (actually, I don't think it matters here)
408 (let ((n (encode-constant (cadr instr) constants)))
411 ((eq? (car instr) 'push-stack)
412 (push-stack (cadr instr)))
414 ((eq? (car instr) 'push-global)
415 (push-global (cdr (assq (cadr instr) globals))))
417 ((eq? (car instr) 'set-global)
418 (set-global (cdr (assq (cadr instr) globals))))
420 ((eq? (car instr) 'call)
423 ((eq? (car instr) 'jump)
426 ((eq? (car instr) 'call-toplevel)
427 (let ((label (cdr (assq (cadr instr) labels))))
428 (call-toplevel label)))
430 ((eq? (car instr) 'jump-toplevel)
431 (let ((label (cdr (assq (cadr instr) labels))))
432 (jump-toplevel label)))
434 ((eq? (car instr) 'goto)
435 (let ((label (cdr (assq (cadr instr) labels))))
438 ((eq? (car instr) 'goto-if-false)
439 (let ((label (cdr (assq (cadr instr) labels))))
440 (goto-if-false label)))
442 ((eq? (car instr) 'closure)
443 (let ((label (cdr (assq (cadr instr) labels))))
446 ((eq? (car instr) 'prim)
448 ((#%number?) (prim.number?))
452 ((#%quotient) (prim.quotient))
453 ((#%remainder) (prim.remainder))
460 ((#%pair?) (prim.pair?))
461 ((#%cons) (prim.cons))
464 ((#%set-car!) (prim.set-car!))
465 ((#%set-cdr!) (prim.set-cdr!))
466 ((#%null?) (prim.null?))
469 ((#%get-cont) (prim.get-cont))
470 ((#%graft-to-cont) (prim.graft-to-cont))
471 ((#%return-to-cont) (prim.return-to-cont))
472 ((#%halt) (prim.halt))
473 ((#%symbol?) (prim.symbol?))
474 ((#%string?) (prim.string?))
475 ((#%string->list) (prim.string->list))
476 ((#%list->string) (prim.list->string))
478 ((#%print) (prim.print))
479 ((#%clock) (prim.clock))
480 ((#%motor) (prim.motor))
482 ((#%led2-color) (prim.led2-color))
483 ((#%getchar-wait) (prim.getchar-wait))
484 ((#%putchar) (prim.putchar))
485 ((#%beep) (prim.beep))
488 ((#%sernum) (prim.sernum))
490 (compiler-error "unknown primitive" (cadr instr)))))
492 ((eq? (car instr) 'return)
495 ((eq? (car instr) 'pop)
498 ((eq? (car instr) 'shift)
502 (compiler-error "unknown instruction" instr)))
508 (asm-write-hex-file hex-filename)
513 (lambda (hex-filename)
517 (shell-command "gcc -o picobit-vm picobit-vm.c")
518 (shell-command (string-append "./picobit-vm " hex-filename)))
519 (shell-command (string-append "./robot . 1 " hex-filename)))))
521 (define (sort-list l <?)
523 (define (mergesort l)
525 (define (merge l1 l2)
526 (cond ((null? l1) l2)
529 (let ((e1 (car l1)) (e2 (car l2)))
531 (cons e1 (merge (cdr l1) l2))
532 (cons e2 (merge l1 (cdr l2))))))))
535 (if (or (null? l) (null? (cdr l)))
537 (cons (car l) (split (cddr l)))))
539 (if (or (null? l) (null? (cdr l)))
541 (let* ((l1 (mergesort (split l)))
542 (l2 (mergesort (split (cdr l)))))
547 ;------------------------------------------------------------------------------
551 (let* ((node (parse-file filename))
554 (path-strip-extension filename)
557 ; (pp (node->expr node))
559 (let ((ctx (comp-none node (make-init-context))))
560 (let ((prog (linearize (optimize-code (context-code ctx)))))
561 ; (pp (list code: prog env: (context-env ctx)))
562 (assemble prog hex-filename)
563 (execute hex-filename))))))
570 ;------------------------------------------------------------------------------
573 (define (asm-write-hex-file filename)
574 (with-output-to-file filename
577 (define (print-hex n)
578 (display (string-ref "0123456789ABCDEF" n)))
580 (define (print-byte n)
582 (print-hex (quotient n 16))
583 (print-hex (modulo n 16)))
585 (define (print-line type addr bytes)
586 (let ((n (length bytes))
587 (addr-hi (quotient addr 256))
588 (addr-lo (modulo addr 256)))
591 ; (print-byte addr-hi)
592 ; (print-byte addr-lo)
594 (for-each print-byte bytes)
596 (modulo (- (apply + n addr-hi addr-lo type bytes)) 256)))
600 (let loop ((lst (cdr asm-code-stream))
603 (if (not (null? lst))
606 (let ((kind (vector-ref x 0)))
607 (if (not (eq? kind 'LISTING))
608 (compiler-internal-error
609 "asm-write-hex-file, code stream not assembled"))
617 (if (= (modulo pos 8) 0)
620 (- pos (length rev-bytes))
628 (if (not (null? rev-bytes))
630 (- pos (length rev-bytes))
631 (reverse rev-bytes)))
632 (print-line 1 0 '())))))))