README 10.3 KB
Newer Older
1
2
3


*** Armish - An assembler quite contraire
Ties Stuij's avatar
initial  
Ties Stuij committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Armish is the Amish of the computer-world. The Amish plough forth through life
under the twin burden of an extreme religion and an accompanying extreme way of
life. As a result they're marginalized and they watch life pass them by. But
they might just hold the seed for a future way of living, you know, with global
warming and all. It has worked in the past; You never know. You never know I
say.

Armish ploughs through bit-space under the twin burden of being an assembler
and being written in lisp. As a result it will be marginalized and it will
watch with an unending waxing headache how programmers pass it by, riding their
high octane steeds of high-level languages. But it might just hold the seed for
a future mass acceptance of languages long forgotten, garbage collected os-ses
of yonder, recursive programming-joys untold... (*sigh*) ...  You never
know... You never know, da#@^$it!!


21

Ties Stuij's avatar
initial  
Ties Stuij committed
22
23
24
25
26
27
28
29
** License - LLGPL, see the LICENSE file

** Authors

- Jeff Massung 
- Ties Stuij


30

Ties Stuij's avatar
initial  
Ties Stuij committed
31
32
** Concept

33
34
35
36
37
38
39
Armish is an assembler like any other. With parenthesis around the instructions.
It's Armish's aim is to be a bit on the general side. It assembles arm and thumb
code, but new features of the latest processors are not (yet/ever) supported.
They're quite backwards compatible though, those processors, last time I checked.
Armish should be usable for arm architectures 3 through 5 (till arm9), and of those
just the core. No enhanced dsp instructions or such. Complaints about missing
features are welcome. See Liards, for a lib that actually uses it.
Ties Stuij's avatar
initial  
Ties Stuij committed
40
41
42
43
44
45
46
47
48



** Installation

To get the latest development version, do a darcs get:

darcs get http://common-lisp.net/project/armish/darcs/armish

49
50
51
52
53
54
55
56
Versioned releases have been put to a halt atm.

Armish depends on Umpa-Lumpa, Arnesi, Split-Sequence and FiveAM.

darcs get http://common-lisp.net/project/liards/darcs/umpa-lumpa
darcs get http://common-lisp.net/project/bese/repos/arnesi_dev
darcs get http://common-lisp.net/project/bese/repos/fiveam
http://ww.telent.net/cclan/split-sequence.tar.gz
Ties Stuij's avatar
initial  
Ties Stuij committed
57

58
59
Once you've got those wired into your asdf machinery together with Armish,
just fire it up.
Ties Stuij's avatar
initial  
Ties Stuij committed
60

61

Ties Stuij's avatar
initial  
Ties Stuij committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
** Testing

You can check if (a subset of) all the standard instructions work by first
building aasm from the supplied c source if you're not on linux or windows, and
be sure to name it aasm. For linux the executable is already there. Make the
executable executable (`chmod 755 aasm' or equivalent) and then execute: (run!
'arm-suite)

There might by errors here caused by the fact i faultily tried to support your
implementation or operating system. The test tries to access an external
assembler supplied with Armish to test the instructions; however the functions
to read and write to other processes is implementation-dependent. Armish is
only tested on sbcl on Linux, so if you can, please fix by editing run-prog and
process-output in helpers.lisp and control-check in test.lisp. Oh! and send a
fix if you want! Thanks. Or just remove your implementation from the two
feature-query lists in control-check.

This will compare the output of Armish with that of a reference implementation,
included in this release. This shouldn't be to interesting for the average
user. I would myself at least expect the tested functionality to work. It might
give you a warm fuzzy feeling to know this assembler doesn't just fool you
along, like it would me. More interesting is perhaps that you can check the
syntax of this assembler by looking at the test-cases in the test.lisp file.

More practical for if you do feel the need to hack on this assembler-thing (i
for one encourage it) is that you'll find some handy functions in the test.lisp
file that can help with debugging.


91

Ties Stuij's avatar
initial  
Ties Stuij committed
92
93
94
** Exported functions

- assemble - Assembles forms into a list of opcodes for specified chip and
95
processor mode.  syntax: (assemble chip mode forms) where:
Ties Stuij's avatar
initial  
Ties Stuij committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

chip - decides which chipset to assemble for - is a number or a symbol

Atm assemble accepts the first value of the pairings below, and it translates
into the latter. The higher the value, the newer the chip. Check the function
get-version to see the latest supported symbols or to add your own.

0 0 'all 0 3 3 4 4 'version-4 4 '4t 4.2 'ARM7TDMI 4.2 'arm7 4.2 5 5 'version-5
5 '5TExP 5.3 '5TE 5.4 'ARM946E-S 5.4 'arm9 5.4


mode - decides if you want to start in arm or thumb mode - accepts one of the
following symbols: 'arm 'code32 'thumb 'code16


forms - are, yes, the forms to be assembled

113
114
example usage:
(assemble 'arm9 'arm
115
  '(:label (mov r3 r4) (b :label)))
116
117

==> (4 48 160 225 253 255 255 234)
Ties Stuij's avatar
initial  
Ties Stuij committed
118

119
120
121

- emit-asm - emits a list of assembly forms ready to be fed to assemble. Emit-asm
escapes variables which are not part of the assembler syntax, so we can enrich the
122
123
124
assembler with variables, while still keeping a clean, uniform syntax. Inside
emit-asm, escape forms you want to evaluate as Common Lisp with (ea ...), as in
escape assembler.
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

syntax: (emit-asm form1 form2 ...)

example usage:

(let ((foo 'r4)
      (bar 'r6))
  (emit-asm
   :loop
   (stmib r3 (r3 foo_bar))
   (b :loop)))

==> (:LOOP (STMIB R3 (R3 R4_R6)) (B :LOOP))


Ties Stuij's avatar
initial  
Ties Stuij committed
140
- align - aligns a list of bytes to a bytes byte boundry by padding
141
142
143
zeroes. Defaults to four if bytes is not supplied

syntax: (align byte-lst &optional bytes)
Ties Stuij's avatar
initial  
Ties Stuij committed
144
145
146
147
148

example usage: (align '(1 2 3 4 5)) ==> (1 2 3 4 5 0 0 0)


- aligned - returns the next bytes byte aligned address. Defaults to four if
149
150
151
bytes is not supplied

syntax: (aligned address &optional bytes)
Ties Stuij's avatar
initial  
Ties Stuij committed
152
153
154
155
156
157
158
159
160
161

example usage: (aligned (length '(1 2 3 4 5))) ==> 8

There are some other functions exported (actually just one at the time of
writing), but those are simple helper functions that might aid the programmer
on a general level. I had a seperate package for that, but decided to cut it to
keep the package-count down. But i might reintroduce it again. Look in
helpers.lisp for functions that might aid you.


162
163
164
165
166
167
168
169
170
171
172
173
- set-armish-string-encoding - sets the armish string encoding. Armish passes
the encoding to the arnesi string-to-octets fuction, which tries to do the right
thing. From the documentation: "We gurantee that :UTF-8, :UTF-16 and :ISO-8859-1 will
work as expected. Any other values are simply passed to the underlying lisp's
function and the results are implementation dependant.

syntax: (set-armish-string-encoding :keyword)

example usage: (set-armish-string-encoding :ISO-8859-1) ==> :ISO-8859-1



Ties Stuij's avatar
initial  
Ties Stuij committed
174
175
176
177
** Instruction syntax

Basically this assembler follows the arm assembler syntax but then lispified:
Wrap the expressions in parenthesis, get rid of the comma's, substitute curly
178
179
braces and braces for parenthesis, substitute - for _ in register lists for
multiple load/store instructions and get rid of the pound signs before
Ties Stuij's avatar
initial  
Ties Stuij committed
180
181
literals and immediates. Barrel rolling modifiers and labels are keywords.

182
183
examples:
standard assembly syntax            lisp syntax
Ties Stuij's avatar
initial  
Ties Stuij committed
184

185
186
ldmhied r12!, {r2, r15, r13-r14} -> (ldmhied r12! (r2 r15 r13_r14))
ldrbt r5, [r2], -r1 ror #12      -> (ldrbt r5 (r2) -r1 :ror 12)
Ties Stuij's avatar
initial  
Ties Stuij committed
187
188
189
190
191

For a pretty extensive, case by case comparison of the instructions, see the
test cases in the test.lisp file.


192

Ties Stuij's avatar
initial  
Ties Stuij committed
193
194
** Assembler format, features and conventions

195

Ties Stuij's avatar
initial  
Ties Stuij committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
* Directives

code16 - assemble as thumb code32 - assemble as arm

pool - dump the literary pool

align - align code to a 4 byte boundary align-hw - align code to a 2 byte
boundary (align &optional bytes) - aligns code to a bytes byte boundary;
defaults to four if bytes is not supplied

(dcb byte &rest bytes) - define one or more bytes (byte byte &rest bytes) -
same as dcb

(dcw byte &rest bytes) - define one or more 16 bit words (hword byte &rest
bytes) - same as dcw

(dcd byte &rest bytes) - define one or more 32 bit words (word byte &rest
bytes) - same asl dcd

(dword byte &rest bytes) - define one or more 64 bit words (quad byte &rest
bytes) -define one or more 64 bit words

218
219
220
221
222
223
224
225
226
(bin byte-size bin-list) - a more general directive than the previous ones.
First specify how many bytes of storage space the data items of the bin-list
should take, then supply the list itself. For example assembling
(bin 2 (1 2 3 4)) results in (1 0 2 0 3 0 4 0) 

(binae lis-of-bin-lists) - same as above, but now we specify a list of
byte-size - bin-list lists. For example assembling
(binae ((2 (1 2)) (4 (3 4)))) results in (1 0 2 0 3 0 0 0 4 0 0 0)

Ties Stuij's avatar
initial  
Ties Stuij committed
227
228
229
(space size &optional (fill 0)) - pad assembly output with size amount of
bytes, all of value fill

230
231
232
"string" - a literal string will be encoded as *string-encoding* (defaults to :utf-8)
specified transformed bytes, at arnesi's string-to-octets discretion and will be
*string-end* (defaults to 0) terminated 
Ties Stuij's avatar
initial  
Ties Stuij committed
233

234
235
236
237
(string &rest strings) - strings will be concatenated and then encoded as
*string-encoding* (defaults to :utf-8) transformed bytes, at arnesi's
string-to-octets discretion. If the symbol :null-terminated is present,
the concatenated (so NOT the individual) strings will be null-terminated.
Ties Stuij's avatar
initial  
Ties Stuij committed
238
239
240

:label - an unadulterated keyword will be treated as a label

241
242
243
244
For convenience the to be compiled forms are appended with the :code-end label,
for if one wants to jump to code which might be placed directly after the compiled
code.

245

Ties Stuij's avatar
initial  
Ties Stuij committed
246
247
* pseudo-instructions

248
249
250
251
252
253
254
255
(ldr register literal) - loads the value of literal in register. Encodes in two's
complement
(ldr register literal :pi) - loads the value of literal in register, as Positive
Integer, understand (or 0)

(adr register label) - loads the address of label in register
(nop) - no opcode; translates into (mov r0 r0) in arm and
(mov r8 r8) in thumb
Ties Stuij's avatar
initial  
Ties Stuij committed
256
257
258
259
260
261
262
263
264
265
266
267
268
269


* register and coprocessor syntax

Registers can be written in the familiar way: rx, where x is a number from 0 to
15. the lr, sp, and pc can be written like lr, sp and pc.

Coprocessor registers can be written as cx or crx where x is a number from 0 to
15.

Coprocessors can be written as px or cpx where x is a number from 0 to 15.



270
** History
Ties Stuij's avatar
initial  
Ties Stuij committed
271
272
273
274
275
276
277
278
279

The core of the thing is a file called thumb.lisp, which Jeff Massung was so
kind to dig up from his digital archive. It was a beta version of a thumb
assembler and it assembled thumb opcodes if you fed it instructions. It has
been expanded upon a bit by the Armish team of one by modifying the thumb code
a bit and by adding arm instructions and facilities to make it more like a
traditional assembler. Who knows, maybe you can even have some use for it.


280

Ties Stuij's avatar
initial  
Ties Stuij committed
281
282
** Todo

283
- no arm or thumb adrl pseudo-instruction
284
285
286
- in the arm ldr instruction, encode a constant load more efficiently if possible
in stead of always loading from memory
- write enhanced dsp instructions
Ties Stuij's avatar
initial  
Ties Stuij committed
287
- document code think about a comment-extractor