ARM assembler written in uLisp


#1

I’ve recently been working on an experimental assembler written in uLisp that generates and runs ARM Thumb code from within uLisp on an ATSAMD21 M0 board or similar.

The project is currently a work in progress, but I thought it would be interesting to describe where I’ve got to, and I’d be interested to hear suggestions for extensions or improvements.

The assembler generates ARM Thumb code, and I’ve tested it on ARM M0 platforms, such as the Adafruit ItsyBitsy M0, and ARM M4 platforms, such as the Adafruit Metro M4. It is currently restricted to generating one assembler routine with up to three integer parameters, and returning an integer result.

uLisp extensions

The assembler uses a special version of uLisp to which I’ve added two functions:

The assemble function takes a series of 16-bit integer arguments comprising the machine code of the routine being assembled. These are written into RAM. Any argument can also return nil, in which case it is ignored.

The call function will then call the assembler routine in RAM, and return the result.

The actual instruction generation is handled by an assembler written in Lisp. This makes it easy to check the generated code, and extend the assembler to handle additional instructions and addressing modes.

The assembler is written using Lisp functions, and where possible the syntax is very similar to standard ARM assembler syntax.

Example

For example, here’s a simple routine to calculate the Greatest Common Divisor:

; Greatest Common Divisor
(let ((swap 0) (again 0) (minus 0))
  (dotimes (p 2)
    (setq *pc* 0)
    (assemble
     ($push '(r4 lr))
     ($label 'swap)
     ($mov 'r4 'r1)
     ($mov 'r1 'r0)
     ($label 'again)
     ($mov 'r0 'r4)
     ($label 'minus)
     ($sub 'r4 'r4 'r1)
     ($blt 'swap)
     ($bne 'again)
     ($pop '(r4 pc)))))

For example, to find the GCD of 3287 and 3460:

> (call 3287 3460)
173

For more information see: ARM Assembler in Lisp.


#2

Would anyone be interested in a similar thing for the ESP32, to allow you to assemble Xtensa LX6 code on an ESP32 version of uLisp?


#3

Hi David ,

This looks really cool !
Reminds me of my assembler period.
What I’m interested in is , if it is possible to read/write to the sfr’s of the arm chip. ?

Kind regards,
Ronny Suy


#4

Yes, anything you can run in ARM machine code should be possible. Try it and let me know how you get on!


#5

Hi David ,
I will do some tests in the weekend , I don’t have much time now.
I was a bit confused about your writing on the website , about mentioning thumb code.
I’ve recalled a few things. It is like this : cortex m0/m0+ are using thumb instructions , with addition of 6 32bit thumb-2 instructions. The cortex m3 and m4 can use the full thumb-2 instruction set , but also the thumb set.
I have a nice sheet from a book that shows it nicely. I’ve uploaded it here.
Anyway I will do some testing , as this interests me a lot. I believe it’s a great addition to ulisp for arm !
I will keep you informed about my testing.

Kind regards,
Ronny


#6

I’ve followed the disassembled code generated by the ARM GCC compiler for the Adafruit ItsyBitsy M0 and Adafruit Metro M4, in conjunction with the table of 16-bit Thumb instruction set encodings in the Appendix B2 document I linked to in the footnote of the page ARM Assembler in Lisp.


#7

Today I’ve uploaded an improved version of the ARM assembler written in uLisp:

ARM Assembler

I’ve also added some additional examples to the original article:

ARM Assembler in Lisp


#8

Hi David ,

No offence meant at all in my former post. I was just a bit confused about thumb vs thumb2.
I see you have an improved version , I will ‘test’ it asap.
Thanks very much !

Kind regards ,
Ronny


#9

No offence taken! I’m new to assembler programming on the ARM, so would welcome guidance.


#10

Thanks David .

I already re-installed my crossworks for arm assembler so that I can check code generated by lisp.
You can check it at rowley.co.uk. I believe you can test drive the software free for a month.
It’s a C and assembler and runs on windows , linux and mac !
They also have some manuals on their site.
I have a personal license for some years now.
I have some good ebooks about arm assembler , If you like I can email them to you.

Kind regards ,
Ronny


#11

Great! I look forward to hearing how you get on. Yes, I’d be interested to see the ebooks, thanks.


#12

ARM Version 3.1 of uLisp now incorporates the finished version of my assembler written in uLisp, which allows you to generate and run ARM Thumb code functions alongside Lisp: ARM assembler overview.

It uses a special defcode form, and an assembler written in uLisp.

For example, here’s a simple routine to calculate the Greatest Common Divisor:

; Greatest Common Divisor
(defcode gcd (x y)
  swap
  ($mov 'r2 'r1)
  ($mov 'r1 'r0)
  again
  ($mov 'r0 'r2)
  ($sub 'r2 'r2 'r1)
  ($blt swap)
  ($bne again)
  ($bx 'lr))

Evaluating this form generates the following assembler listing:

0000      swap
0000 000a ($mov 'r2 'r1)
0002 0001 ($mov 'r1 'r0)
0004      again
0004 0010 ($mov 'r0 'r2)
0006 1a52 ($sub 'r2 'r2 'r1)
0008 dbfa ($blt swap)
000a d1fb ($bne again)
000c 4770 ($bx 'lr)

Now, to find the GCD of 3287 and 3460 you can evaluate:

> (gcd 3287 3460)
173