#lang scheme/base
(require
scheme/control
scheme/match
"../target.ss"
"../tools.ss"
"../op.ss"
"../ns.ss"
"pointers.ss"
"environ.ss"
)
(provide
assemble! assemble-simple
)
(define get hash-ref)
(define put! hash-set!)
(define table alist->hash)
(define table->alist hash->alist)
(define (assemble-simple asm-code . args)
(let-values
(((bin pointers)
(apply assemble!
(list (new-target-word #:name 'test
#:realm 'code
#:code asm-code))
args)))
(values (car bin)
pointers)))
(define (proto->asm-error-handler asm arguments)
(match-lambda*
((list 'overflow type value bits)
(error 'asm-overflow
"~a overflow error in ~a at ~a (~a doesnt fit in ~a bits)"
(cond
((eq? type 1) 'unsigned)
((eq? type -1) 'signed)
(else 'unknown-type))
(instruction->string (asm-current-instruction))
(pointer-get 'code)
value bits))))
(define (assemble! word-chains
[pointers
'((code 0)
(data 0))])
(define all-words
(apply append (map (lambda (w)
(reverse (target-chain->list w)))
word-chains)))
(define *pointers* #f)
(define (init-pointers!)
(set! *pointers*
(table pointers)))
(define *spans*
(table
(map (lambda (w)
(cons w
(map (lambda (ins) 0)
(target-word-code w))))
all-words)))
(define *addresses*
(table
(map (lambda (w)
(cons w (target-word-address w)))
all-words)))
(define (current-src-location)
(or (target-word->error-string (asm-current-word))
(target-word->error-string (asm-current-chain))
""))
(define (report-error ex)
(let ((chain (asm-current-chain)))
(for-each
(lambda (w) (set-target-word-address! w #f))
(target-chain->list chain))
(printf "~a\n" (current-src-location))
(print-target-word chain)
(raise ex)))
(define (relaxed?!)
(define relaxed #t)
(define (also! p)
(set! relaxed (and relaxed p)))
(for-each
(lambda (word)
(let ((now (target-word-address word))
(last (get *addresses* word
(lambda ()
(error 'undefined-word "~a"
(target-word-name word))))))
(put! *addresses* word now)
(also! (and last now (= last now)))))
all-words)
relaxed)
(define *nop* (nop)) (define (asm-single-word! word)
(parameterize ((asm-current-word word))
(let* ((realm (target-word-realm word))
(addr (pointer-get realm)))
(set-target-word-address! word addr)
(let next
((span (reverse (get *spans* word)))
(asm (reverse (target-word-code word)))
(bin '())
(span+ '()))
(if (null? asm)
(begin
(put! *spans* word span+)
bin)
(let
((padded
(with-handlers
((void report-error))
(assemble/pad (car asm)
(car span)
*nop*))))
(next
(cdr span)
(cdr asm)
(cons padded bin)
(cons (length padded) span+))))))))
(define (asm-word-chain! w)
(parameterize ((asm-current-chain w))
(let* ((name (target-word-name w))
(org target-value->number)
(go! (lambda ()
(map asm-single-word!
(reverse (target-chain->list w))))))
(match name
((list 'org addr)
(begin
(with-pointer 'code (org addr) go!)))
((list 'org! addr)
(begin
(pointer-set! 'code (org addr))
(go!)))
(_
(go!))))))
(define (asm-pass!)
(init-pointers!)
(parameterize
((asm-pointers *pointers*))
(apply append
(reverse
(map asm-word-chain!
(reverse word-chains))))))
(define (asm!)
(parameterize ((asm-phase 0))
(let ((bin
(let next ((b (asm-pass!)))
(when (> (asm-phase) 100)
(error 'asm-relax-loop))
(if (not (relaxed?!))
(begin
(asm-phase (add1 (asm-phase)))
(next (asm-pass!)))
(map (lambda (inss word)
(set-target-word-bin! word inss)
(apply append inss)) b all-words))))
(pointers
(table->alist *pointers*)))
(values bin pointers))))
(asm!))
(define (assemble/pad ins span nop)
(parameterize
((asm-current-instruction ins)) (let pad ((i
(or (target-value-catch-undefined
(lambda () (apply resolve/assemble ins)))
'())))
(if (< (length i) span)
(pad (cons nop i))
i))))
(define (resolve/assemble opcode . arguments)
(unless (asm? opcode)
(error 'invalid-instruction
"~a" (cons opcode arguments)))
(let*
((asm
(or (asm-fn opcode)
(error 'virtual-op "~a" (asm-name opcode))))
(args
(map
target-value->number
arguments))
(code
(parameterize
((asm-error
(proto->asm-error-handler asm args)))
(reverse (apply asm
(pointer-get 'code)
args))
)))
(pointer-allot! 'code (length code))
code))
(define (nop) 0)