Re: 8051 assembler in Common Lisp



Peter Seibel <peter@xxxxxxxxxxxxxxx> writes:


> Greg Menke <gregm-xyzpdq@xxxxxxxxxxxx> writes:
>
> > But I intern top-level symbols at read time but do the labels in the
> > final link pass once all addresses are known. I add an item to each
> > top-level symbol's property list. The symbol-value is set to the linked
> > address for all symbols so the address arithmetic will work.
>
> Can you show us the code that "intern[s] top-level symbols at read
> time"? Unless you wrote your own reader, the reader is already
> interning the symbols which makes my wonder what you're really
> doing. Also, a symbol doesn't need to be interned to have it's
> symbol-value set. So, basically, what you're saying doesn't make any
> sense. That may be because you're talking about something sensical in
> a slightly incorrect way or because what you're doing actually doesn't
> make complete sense.

Sure. Once the assember is working "industrially" enough to compile
some projects so I can test it on real hardware, I'll post the full
code. Right now its changing quickly and I still need to generate .lis
files and symbol crossreferences.

Regards,

Gregm


Some terminology;

sym is always bound to a top-level symbol

syminst is the compiler state data struct recorded in each top-level
symbol's property list


(sym-labels) accessor that gets/sets the list of labels contained in a
top-level symbol

(sym-data) accessor that gets/sets the non-evaled list of sexps forming the code
in a top-level symbol

(sym-compiled) accessor that gets/sets the list of eval'ed sexps of a
top-level symbol.

(sym-linked) accessor for the output of the compiler; a sequence of
bytes comprising the compiled and linked code



These macros handle creating and interning the top-level symbols at read time;


(defmacro with-sym-setup ((name opts symtype rest) &body body)
`(let ((sym (intern (string ',name)))
(syminst (make-instance ,symtype )))

(proclaim '(special ,name))

;; symbol-value is the symbol's linked address
(setf (symbol-value sym) nil)

;; add syminst to the symbol's prop list
(setf (get sym 'syminst) syminst)

;; and init the syminst fields
(setf (sym-name syminst) (symbol-name sym))
(setf (sym-address syminst) nil)

(setf (sym-org syminst) (getf ',opts :org nil))
(setf (sym-align syminst) (getf ',opts :align nil))

(setf (sym-data syminst) ',rest)

(setf asm51::*cursymbol* syminst)

,@body ))


(defmacro deftext (name opts &rest rest)
`(asm51::with-sym-setup (,name ,opts '_textsym ,rest)
(push sym asm51::*textsyms*)))

(defmacro defdata (name opts &rest rest)
`(asm51::with-sym-setup (,name ,opts '_datasym ,rest)
(push sym asm51::*datasyms*)))

(defmacro defbss (name opts &rest rest)
`(asm51::with-sym-setup (,name ,opts '_bsssym ,rest)
(push sym asm51::*bsssyms*)))


via this loop in pass #1 (read pass)

(loop for e = (read str nil nil)
while e
do
(eval e))


In pass #2 (top-level symbol sexp-by-sexp code eval), I identify and
record each label symbol but do not intern it;

(loop for se in (sym-data syminst)
for e = nil
with rv = nil
do
;;
;; evaluate the sexp, accumulate non-nil results in rv
;;
(cond ((symbolp se)
;; se is symbol, make a label out of it
(setf e (make-label se))
;; save it in the labels list
(push e (sym-labels syminst)) )

(t
;; not a symbol, eval it
(setf e (eval se)) ) )








Now later on in pass #5 (link pass), I intern & set the value of the
label sybols within each top-level symbol. I do it here so the same
labels can be used in different top-level symbols, but are only defined
within the top-level symbol- sort of a "local" label.


;; define all the labels in this symbol so the code-gen eval
;; can be done
(loop for e in (sym-labels syminst)
for name = (lab-name e)
do
(eval `(progn
(intern (string ',name))
(proclaim '(special ,name))
(setf ,name (lab-address ,e)))) )


and after linking all the code in the top-level symbol, I un-intern the labels;


;; symbol is compiled, release all its labels
;;
(loop for e in (sym-labels syminst)
for name = (lab-name e)
do
(eval `(unintern ',name)) ) )

.