Assembler in Common Lisp

From: Greg Menke (gregm-news_at_toadmail.com)
Date: 07/29/04


Date: 29 Jul 2004 17:18:39 -0400


Sometime last Fall I asked a question about how CL might be used to
create a macro assembler for a microcontroller. I finally got around
to giving it a try and I think its working. Its not entirely
complete, there are more instructions & directives to implement and
things related to generating binary images to do, but I wanted to
sanity check some of the basic design. The assembler is working now
with the instructions I've implemented so far. Hopefully this is
enough detail to suggest if I'm doing things right or not, which I
hope you might comment on.

- Assembler implementation is in package 'asm51. The assembler
  creates a "private" package & imports 'common-lisp and the assembler
  compile-time symbols. Code to be assembled is presented to the
  Assembler via a stream.

- Assembly occurs with *package* set to the private package, so all of
  common-lisp and the assembler directives are directly available to
  the user's sourcecode.

- Two directives are implemented as macros, "defcode" and "defdata".
  They accept a lambda-ish arrangement of sexp-formatted assembly, as
  follows;

        (defcode temp
           (nop)
           (mov A 1)
           (call 'xyzpdq)
           (ret))

  Which causes the assembler to create a symbol named "TEMP" in the
  private package & save off all sexps after the symbol name as the
  contents of the symbol, to be assembled later. Note the quoted
  symbol, it refers to a symbol introduced by an invocation of defcode
  elsewhere in the source.

- Each instruction is set up as a defmethod with specializations for
  all the legal combinations of parameters. In the (nop) example,
  there is only one specialization. The (mov ..) example, a number of
  specializations exist, including one that serves this case, a
  literal value is moved to the accumulator register. All the cpu
  registers exist as variously typed symbols to support the
  specializations.

- First, (read) is used to get each sexp. (eval) is used to execute
  it. This causes the defcode/defdata macros to expand & execute,
  introducing each symbol in the sourcecode.

- After all symbols are introduced, the contents of each symbol are
  individually (eval)'ed, causing the specialized defmethods to be
  invoked which themselves yield Lisp "object" macros that will be
  used last to generate the binary output. Additionally, this step
  provides the runtime size of the code or data represented by the
  symbol, so now each symbol knows how long it is & runtime addresses
  are then assigned.

- Symbol references like 'xyzpdq above are resolved last. Once each
  symbol has a runtime address, the address is stored to the symbol's
  symbol-value, so the presence of a symbol in an expression will
  yield its runtime address in the last step.

- Lastly the "object" macros in each symbol are (eval)ed, yielding the
  output binary.

The upshot of (read) and (eval) here is that the user can employ all
of Common Lisp as an assembly-time "metalanguage". I think this means
I can use defmacros ,etc.. in the source code to build a fancy macro
assembler. By introducing each symbol given in the source as a
full-blown Lisp symbol, I don't have to parse anything by hand or keep
anything anywhere outside an instance of a defstruct in each symbol's
plist which the assembler references as necessary. The assembler
internals sanity check incoming values as code is emitted, so
incorrect types/magnitudes will be caught.

The assembler source remains nice and simple, the bulk of the content
is defintions of the cpu registers and the instruction defmethods.

Does this sound like the right sort of approach?

Thanks,

Gregm



Relevant Pages

  • Re: "We Never Use Assembly Language"
    ... too bad that I expect the same from macros that I use. ... I guess Rosasm is no longer written in assembly. ... does not detract from a tool being an assembler. ... it raises HLA some levels. ...
    (alt.lang.asm)
  • Re: "We Never Use Assembly Language"
    ... > too bad that I expect the same from macros that I use. ... Are you unable to see the diffrence?The rosasm macros are little else but clever text replacesments for asm instructions. ... but it has nothing todo inside an assembler. ... well feature for feature to the Rosasm IDE which took near a decade. ...
    (alt.lang.asm)
  • Re: RosAsm?
    ... not what the instructions are. ... With a good set of macros this can be made even clearer... ... in this vain in my option the only programmers who should be ... by the assembler in a "Label not defined" error and probably ...
    (alt.lang.asm)
  • Re: RosAsm - right click
    ... not actually suggesting the final syntax on ... > of the features of the assembler directives, as you can see it goes ... > (This is fairly similar to how the NASM macros ... > allow us to implement all of these data structure tooltips via ...
    (alt.lang.asm)
  • Do People Really Learn Assembly with HLA?
    ... > crowd who thinks that macros are Assemblys' high level constructs. ... than MASM, for example). ... of any assembler available for the x86 back then (and today, ... only to HLA). ...
    (alt.lang.asm)