1 ;;;; File: "encoding.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.
6 (define min-fixnum-encoding 3)
8 (define max-fixnum 255)
9 (define min-rom-encoding (+ min-fixnum-encoding (- max-fixnum min-fixnum) 1))
10 (define min-ram-encoding 512)
11 (define max-ram-encoding 4095)
12 (define min-vec-encoding 4096)
13 (define max-vec-encoding 8191)
15 (define code-start #x5000)
17 (define (predef-constants) (list))
19 (define (predef-globals) (list))
21 (define (encode-direct obj)
32 (+ obj (- min-fixnum-encoding min-fixnum)))
36 (define (translate-constant obj)
41 (define (encode-constant obj constants)
42 (let ((o (translate-constant obj)))
43 (let ((e (encode-direct o)))
46 (let ((x (assoc o constants)))
48 (vector-ref (cdr x) 0)
49 (compiler-error "unknown object" obj)))))))
51 ;; TODO actually, seem to be in a pair, scheme object in car, vector in cdr
52 ;; constant objects are represented by vectors
53 ;; 0 : encoding (ROM address) TODO really the ROM address ?
54 ;; 1 : TODO asm label constant ?
55 ;; 2 : number of occurences of this constant in the code
56 ;; 3 : pointer to content, used at encoding time
57 (define (add-constant obj constants from-code? cont)
58 (let ((o (translate-constant obj)))
59 (let ((e (encode-direct o)))
62 (let ((x (assoc o constants)))
66 (vector-set! (cdr x) 2 (+ (vector-ref (cdr x) 2) 1)))
70 (asm-make-label 'constant)
77 (add-constants (list (car o) (cdr o))
83 (let ((chars (map char->integer (string->list o))))
84 (vector-set! descr 3 chars)
89 ((vector? o) ; ordinary vectors are stored as lists
90 (let ((elems (vector->list o)))
91 (vector-set! descr 3 elems)
97 (let ((elems (u8vector->list o)))
98 (vector-set! descr 3 elems)
103 ((and (number? o) (exact? o))
104 ; (pp (list START-ENCODING: o))
105 (let ((hi (arithmetic-shift o -16)))
106 (vector-set! descr 3 hi)
107 ;; recursion will stop once we reach 0 or -1 as the
108 ;; high part, which will be matched by encode-direct
114 (cont new-constants))))))))))
116 (define (add-constants objs constants cont)
119 (add-constant (car objs)
122 (lambda (new-constants)
123 (add-constants (cdr objs)
127 (define (add-global var globals cont)
128 (let ((x (assq var globals)))
131 ;; increment reference counter
132 (vector-set! (cdr x) 1 (+ (vector-ref (cdr x) 1) 1))
135 (cons (cons var (vector (length globals) 1))
137 (cont new-globals)))))
139 (define (sort-constants constants)
143 (> (vector-ref (cdr x) 2)
144 (vector-ref (cdr y) 2))))))
145 (let loop ((i min-rom-encoding)
148 ;; constants can use all the rom addresses up to 256 constants since
149 ;; their number is encoded in a byte at the beginning of the bytecode
150 (if (or (> i min-ram-encoding) (> (- i min-rom-encoding) 256))
151 (compiler-error "too many constants")
154 (vector-set! (cdr (car lst)) 0 i)
158 (define (sort-globals globals) ;; TODO a lot in common with sort-constants, ABSTRACT
162 (> (vector-ref (cdr x) 1)
163 (vector-ref (cdr y) 1))))))
167 (if (> i 256) ;; the number of globals is encoded on a byte
168 (compiler-error "too many global variables")
171 (vector-set! (cdr (car lst)) 0 i)
176 (lambda (code hex-filename)
177 (let loop1 ((lst code)
178 (constants (predef-constants))
179 (globals (predef-globals))
183 (let ((instr (car lst)))
184 (cond ((number? instr)
188 (cons (cons instr (asm-make-label 'label))
190 ((eq? (car instr) 'push-constant)
191 (add-constant (cadr instr)
194 (lambda (new-constants)
199 ((memq (car instr) '(push-global set-global))
200 (add-global (cadr instr)
202 (lambda (new-globals)
213 (let ((constants (sort-constants constants))
214 (globals (sort-globals globals)))
216 (define (label-instr label opcode)
218 ;; if the distance from pc to the label fits in a single byte,
219 ;; a short instruction is used, containing a relative address
220 ;; if not, the full 16-bit label is used
222 ;;; (let ((dist (- (asm-label-pos label) self)))
223 ;;; (and (< dist 256) ;; TODO have this between -128 and 127 ? would be more flexible, I guess
227 ;;; (asm-8 (+ opcode 5))
228 ;;; (asm-8 (- (asm-label-pos label) self)))
229 ;; TODO doesn't work at the moment
234 (let ((pos (- (asm-label-pos label) code-start)))
236 (asm-8 (quotient pos 256))
237 (asm-8 (modulo pos 256))))))
239 (define (push-constant n)
243 (asm-8 (+ #x90 (quotient n 256)))
244 (asm-8 (modulo n 256)))))
246 (define (push-stack n)
248 (compiler-error "stack is too deep")
251 (define (push-global n)
257 (define (set-global n)
265 (compiler-error "call has too many arguments")
270 (compiler-error "call has too many arguments")
273 (define (call-toplevel label)
274 (label-instr label #x80))
276 (define (jump-toplevel label)
277 (label-instr label #x81))
280 (label-instr label #x82))
282 (define (goto-if-false label)
283 (label-instr label #x83))
285 (define (closure label)
286 (label-instr label #x84))
291 (define (prim.number?) (prim 0))
292 (define (prim.+) (prim 1))
293 (define (prim.-) (prim 2))
294 (define (prim.*) (prim 3))
295 (define (prim.quotient) (prim 4))
296 (define (prim.remainder) (prim 5))
297 (define (prim.neg) (prim 6))
298 (define (prim.=) (prim 7))
299 (define (prim.<) (prim 8))
300 (define (prim.<=) (prim 9))
301 (define (prim.>) (prim 10))
302 (define (prim.>=) (prim 11))
303 (define (prim.pair?) (prim 12))
304 (define (prim.cons) (prim 13))
305 (define (prim.car) (prim 14))
306 (define (prim.cdr) (prim 15))
307 (define (prim.set-car!) (prim 16))
308 (define (prim.set-cdr!) (prim 17))
309 (define (prim.null?) (prim 18))
310 (define (prim.eq?) (prim 19))
311 (define (prim.not) (prim 20))
312 (define (prim.get-cont) (prim 21))
313 (define (prim.graft-to-cont) (prim 22))
314 (define (prim.return-to-cont) (prim 23))
315 (define (prim.halt) (prim 24))
316 (define (prim.symbol?) (prim 25))
317 (define (prim.string?) (prim 26))
318 (define (prim.string->list) (prim 27))
319 (define (prim.list->string) (prim 28))
320 (define (prim.make-u8vector) (prim 29))
321 (define (prim.u8vector-ref) (prim 30))
322 (define (prim.u8vector-set!) (prim 31))
323 (define (prim.print) (prim 32))
324 (define (prim.clock) (prim 33))
325 (define (prim.motor) (prim 34))
326 (define (prim.led) (prim 35))
327 (define (prim.led2-color) (prim 36))
328 (define (prim.getchar-wait) (prim 37))
329 (define (prim.putchar) (prim 38))
330 (define (prim.beep) (prim 39))
331 (define (prim.adc) (prim 40))
332 (define (prim.u8vector?) (prim 41))
333 (define (prim.sernum) (prim 42))
334 (define (prim.u8vector-length) (prim 43))
335 (define (prim.u8vector-copy!) (prim 44))
336 (define (prim.shift) (prim 45))
337 (define (prim.pop) (prim 46))
338 (define (prim.return) (prim 47))
339 (define (prim.boolean?) (prim 48))
340 (define (prim.network-init) (prim 49))
341 (define (prim.network-cleanup) (prim 50))
342 (define (prim.receive-packet-to-u8vector) (prim 51))
343 (define (prim.send-packet-from-u8vector) (prim 52))
344 (define (prim.ior) (prim 53))
345 (define (prim.xor) (prim 54))
347 (define big-endian? #f)
349 (asm-begin! code-start #f)
353 (asm-8 (length constants))
354 (asm-8 (length globals))
356 '(pp (list constants: constants globals: globals))
360 (let* ((descr (cdr x))
361 (label (vector-ref descr 1))
364 ;; see the vm source for a description of encodings
365 ;; TODO have comments here to explain encoding, at least magic number that give the type
366 (cond ((and (integer? obj) (exact? obj)) ;; TODO FOOBGIGNUMS
367 (let ((hi (encode-constant (vector-ref descr 3)
369 ; (pp (list ENCODE: (vector-ref descr 3) to: hi lo: obj))
370 (asm-8 (+ 0 (arithmetic-shift hi -8))) ;; TODO -5 has low 16 at 00fb, should be fffb, 8 bits ar lost
371 (asm-8 (bitwise-and hi #xff)) ; pointer to hi
372 (asm-8 (arithmetic-shift obj -8)) ; bits 8-15
373 (asm-8 (bitwise-and obj #xff)))) ; bits 0-7
375 (let ((obj-car (encode-constant (car obj) constants))
376 (obj-cdr (encode-constant (cdr obj) constants)))
377 (asm-8 (+ #x80 (arithmetic-shift obj-car -8)))
378 (asm-8 (bitwise-and obj-car #xff))
379 (asm-8 (+ 0 (arithmetic-shift obj-cdr -8)))
380 (asm-8 (bitwise-and obj-cdr #xff))))
387 (let ((obj-enc (encode-constant (vector-ref descr 3)
389 (asm-8 (+ #x80 (arithmetic-shift obj-enc -8)))
390 (asm-8 (bitwise-and obj-enc #xff))
393 ((vector? obj) ; ordinary vectors are stored as lists
394 (let* ((elems (vector-ref descr 3))
395 (obj-car (encode-constant (car elems)
397 (obj-cdr (encode-constant (cdr elems)
399 (asm-8 (+ #x80 (arithmetic-shift obj-car -8)))
400 (asm-8 (bitwise-and obj-car #xff))
401 (asm-8 (+ 0 (arithmetic-shift obj-cdr -8)))
402 (asm-8 (bitwise-and obj-cdr #xff))))
404 (let ((obj-enc (encode-constant (vector-ref descr 3)
406 (l (length (vector-ref descr 3))))
407 ;; length is stored raw, not encoded as an object
408 ;; however, the bytes of content are encoded as
410 (asm-8 (+ #x80 (arithmetic-shift l -8)))
411 (asm-8 (bitwise-and l #xff))
412 (asm-8 (+ #x60 (arithmetic-shift obj-enc -8)))
413 (asm-8 (bitwise-and obj-enc #xff))))
415 (compiler-error "unknown object type" obj)))))
418 (let loop2 ((lst code))
420 (let ((instr (car lst)))
422 (cond ((number? instr)
423 (let ((label (cdr (assq instr labels))))
426 ((eq? (car instr) 'entry)
427 (let ((np (cadr instr))
428 (rest? (caddr instr)))
429 (asm-8 (if rest? (- np) np))))
431 ((eq? (car instr) 'push-constant)
432 (let ((n (encode-constant (cadr instr) constants)))
435 ((eq? (car instr) 'push-stack)
436 (push-stack (cadr instr)))
438 ((eq? (car instr) 'push-global)
439 (push-global (vector-ref
440 (cdr (assq (cadr instr) globals))
443 ((eq? (car instr) 'set-global)
444 (set-global (vector-ref
445 (cdr (assq (cadr instr) globals))
448 ((eq? (car instr) 'call)
451 ((eq? (car instr) 'jump)
454 ((eq? (car instr) 'call-toplevel)
455 (let ((label (cdr (assq (cadr instr) labels))))
456 (call-toplevel label)))
458 ((eq? (car instr) 'jump-toplevel)
459 (let ((label (cdr (assq (cadr instr) labels))))
460 (jump-toplevel label)))
462 ((eq? (car instr) 'goto)
463 (let ((label (cdr (assq (cadr instr) labels))))
466 ((eq? (car instr) 'goto-if-false)
467 (let ((label (cdr (assq (cadr instr) labels))))
468 (goto-if-false label)))
470 ((eq? (car instr) 'closure)
471 (let ((label (cdr (assq (cadr instr) labels))))
474 ((eq? (car instr) 'prim)
476 ((#%number?) (prim.number?))
480 ((#%quotient) (prim.quotient))
481 ((#%remainder) (prim.remainder))
488 ((#%pair?) (prim.pair?))
489 ((#%cons) (prim.cons))
492 ((#%set-car!) (prim.set-car!))
493 ((#%set-cdr!) (prim.set-cdr!))
494 ((#%null?) (prim.null?))
497 ((#%get-cont) (prim.get-cont))
498 ((#%graft-to-cont) (prim.graft-to-cont))
499 ((#%return-to-cont) (prim.return-to-cont))
500 ((#%halt) (prim.halt))
501 ((#%symbol?) (prim.symbol?))
502 ((#%string?) (prim.string?))
503 ((#%string->list) (prim.string->list))
504 ((#%list->string) (prim.list->string))
505 ((#%make-u8vector) (prim.make-u8vector))
506 ((#%u8vector-ref) (prim.u8vector-ref))
507 ((#%u8vector-set!) (prim.u8vector-set!))
508 ((#%print) (prim.print))
509 ((#%clock) (prim.clock))
510 ((#%motor) (prim.motor))
512 ((#%led2-color) (prim.led2-color))
513 ((#%getchar-wait ) (prim.getchar-wait))
514 ((#%putchar) (prim.putchar))
515 ((#%beep) (prim.beep))
517 ((#%u8vector?) (prim.u8vector?))
518 ((#%sernum) (prim.sernum))
519 ((#%u8vector-length) (prim.u8vector-length))
520 ((#%u8vector-copy!) (prim.u8vector-copy!))
521 ((#%boolean?) (prim.boolean?))
522 ((#%network-init) (prim.network-init))
523 ((#%network-cleanup) (prim.network-cleanup))
524 ((#%receive-packet-to-u8vector) (prim.receive-packet-to-u8vector))
525 ((#%send-packet-from-u8vector) (prim.send-packet-from-u8vector))
529 (compiler-error "unknown primitive" (cadr instr)))))
531 ((eq? (car instr) 'return)
534 ((eq? (car instr) 'pop)
537 ((eq? (car instr) 'shift)
541 (compiler-error "unknown instruction" instr)))
547 (asm-write-hex-file hex-filename)