Various little a.out output-related bugfixes.
[m68k-assembler.git] / machine.lisp
blob08c39e08336e912d9db4e59e2c4b8bfc9c32cf4a
1 ;;; Tables and things which are truly machine (m68k) specific.
2 ;;;
3 ;;; Julian Squires/2005
5 (in-package :m68k-assembler)
7 (defparameter *asm-opcode-table*
8 ;; first field is the opcode name, sans modifiers. remaining fields
9 ;; are either pairs of operand constraints and code generation
10 ;; masks, or functions. these are matched or called in sequence,
11 ;; until one can be found which matches.
13 ;; Code generation masks are lists in the form: (size code) where
14 ;; size indicates the number of bits this part should take up, and
15 ;; code is the code to evaluate when generating this part of the
16 ;; expression. (Actually, code should be a function call, now.)
17 ;; The list starts from the most significant bit of the instruction
18 ;; word and moves down. SIZE fields of ? indicate a variable size,
19 ;; where the code in question will return a suitable size value as a
20 ;; second value.
21 `(,@(mapcar
22 (lambda (x)
23 `(,x
24 (((byte) (data-register) (data-register)) .
25 ((4 ,(if (string= x "ABCD") #b1101 #b1001))
26 (3 (register-idx second-operand)) (6 #b100000)
27 (3 (register-idx first-operand))))
28 (((byte) (predecrement-indirect) (predecrement-indirect))
29 ((4 ,(if (string= x "ABCD") #b1101 #b1001))
30 (3 (register-idx second-operand)) (6 #b100001)
31 (3 (register-idx first-operand))))))
32 '("ABCD" "SBCD"))
34 ,@(mapcan
35 (lambda (x)
36 `((,x
37 (((byte word long) (all-ea-modes) (data-register))
38 ((4 ,(if (string= x "ADD") #b1101 #b1001))
39 (3 (register-idx second-operand)) (1 #b0)
40 (2 (modifier-bits modifier))
41 (6 (effective-address-mode first-operand modifier))
42 (? (effective-address-extra first-operand modifier))))
43 (((byte word long) (data-register) (memory-alterable-modes))
44 ((4 ,(if (string= x "ADD") #b1101 #b1001))
45 (3 (register-idx first-operand)) (1 #b1)
46 (2 (modifier-bits modifier))
47 (6 (effective-address-mode second-operand modifier))
48 (? (effective-address-extra second-operand modifier))))
49 ,(concatenate 'string x "A")
50 ,(concatenate 'string x "I")
51 ,(concatenate 'string x "Q")
52 ,(concatenate 'string x "X"))
53 (,(concatenate 'string x "A")
54 (((word long) (all-ea-modes) (address-register))
55 ((4 ,(if (string= x "ADD") #b1101 #b1001))
56 (3 (register-idx second-operand))
57 (3 (if-eql-word-p modifier #b011 #b111))
58 (6 (effective-address-mode first-operand modifier))
59 (? (effective-address-extra first-operand modifier)))))
60 (,(concatenate 'string x "I")
61 (((byte word long) (immediate) (data-alterable-modes))
62 ((8 ,(if (string= x "ADD") #b00000110 #b00000100))
63 (2 (modifier-bits modifier))
64 (6 (effective-address-mode second-operand modifier))
65 (? (immediate-value first-operand modifier))
66 (? (effective-address-extra second-operand modifier)))))
67 (,(concatenate 'string x "Q")
68 (((byte word long) (immediate (<= 1 value 8)) (alterable-modes))
69 ((4 #b0101) (3 (addq-immediate-value first-operand))
70 (1 ,(if (string= x "ADD") 0 1))
71 (2 (modifier-bits modifier))
72 (6 (effective-address-mode second-operand modifier))
73 (? (effective-address-extra second-operand modifier)))))
74 (,(concatenate 'string x "X")
75 (((byte word long) (data-register) (data-register))
76 ((4 ,(if (string= x "ADD") #b1101 #b1001))
77 (3 (register-idx second-operand)) (1 #b1)
78 (2 (modifier-bits modifier))
79 (3 #b000) (3 (register-idx first-operand))))
80 (((byte word long) (predecrement-indirect) (predecrement-indirect))
81 ((4 #b1101) (3 (register-idx second-operand)) (1 #b1)
82 (2 (modifier-bits modifier))
83 (3 #b001) (3 (register-idx first-operand)))))))
84 '("ADD" "SUB"))
86 ,@(mapcan
87 (lambda (x)
88 `((,x
89 ,@(unless (string= x "EOR")
90 `((((byte word long) (data-addressing-modes) (data-register))
91 ((4 ,(cond ((string= x "AND") #b1100)
92 ((string= x "OR") #b1000)))
93 (3 (register-idx second-operand)) (1 #b0)
94 (2 (modifier-bits modifier))
95 (6 (effective-address-mode first-operand modifier))
96 (? (effective-address-extra first-operand modifier))))))
97 (((byte word long) (data-register) (memory-alterable-modes))
98 ((4 ,(cond ((string= x "AND") #b1100)
99 ((string= x "EOR") #b1011)
100 ((string= x "OR") #b1000)))
101 (3 (register-idx first-operand)) (1 #b1)
102 (2 (modifier-bits modifier))
103 (6 (effective-address-mode second-operand modifier))
104 (? (effective-address-extra second-operand modifier))))
105 ,(concatenate 'string x "I"))
106 (,(concatenate 'string x "I")
107 (((byte word long) (immediate) (data-alterable-modes))
108 ((4 #b0000)
109 (4 ,(cond ((string= x "AND") #b0010)
110 ((string= x "EOR") #b1010)
111 ((string= x "OR") #b0000)))
112 (2 (modifier-bits modifier))
113 (6 (effective-address-mode second-operand modifier))
114 (? (immediate-value first-operand modifier))
115 (? (effective-address-extra second-operand modifier))))
116 (((byte) (immediate) (register (string-equal value "CCR")))
117 ((4 #b0000)
118 (4 ,(cond ((string= x "AND") #b0010)
119 ((string= x "EOR") #b1010)
120 ((string= x "OR") #b0000)))
121 (16 #b0011110000000000)
122 (8 (immediate-value first-operand 'byte))))
123 (((word) (immediate) (register (string-equal value "SR")))
124 ((4 #b0000)
125 (4 ,(cond ((string= x "AND") #b0010)
126 ((string= x "EOR") #b1010)
127 ((string= x "OR") #b0000)))
128 (8 #b01111100)
129 (16 (immediate-value first-operand 'word)))))))
130 '("AND" "EOR" "OR"))
132 ,@(mapcar
133 (lambda (x)
134 `(,x
135 (((byte word long) (data-register) (data-register))
136 ((4 #b1110) (3 (register-idx first-operand))
137 (1 ,(if (string= x "L" :start1 (1- (length x))) 1 0))
138 (2 (modifier-bits modifier))
139 (3 ,(cond ((string= x "LS" :end1 2) #b001)
140 ((string= x "AS" :end1 2) #b000)
141 ((string= x "ROX" :end1 3) #b010)
142 (t #b011)))
143 (3 (register-idx second-operand))))
144 (((byte word long) (immediate (<= 1 value 8)) (data-register))
145 ((4 #b1110) (3 (immediate-value first-operand))
146 (1 ,(if (string= x "L" :start1 (1- (length x))) 1 0))
147 (2 (modifier-bits modifier))
148 (3 ,(cond ((string= x "LS" :end1 2) #b101)
149 ((string= x "AS" :end1 2) #b100)
150 ((string= x "ROX" :end1 3) #b110)
151 (t #b111)))
152 (3 (register-idx second-operand))))
153 (((byte word long) (memory-alterable-modes))
154 ((5 #b11100)
155 (2 ,(cond ((string= x "LS" :end1 2) #b01)
156 ((string= x "AS" :end1 2) #b00)
157 ((string= x "ROX" :end1 3) #b10)
158 (t #b11)))
159 (1 ,(if (string= x "L" :start1 (1- (length x))) 1 0))
160 (2 #b11) (6 (effective-address-mode first-operand modifier))
161 (? (effective-address-extra first-operand modifier))))))
162 '("ASL" "ASR" "LSL" "LSR" "ROL" "ROR" "ROXL" "ROXR"))
164 ,@(mapcar
165 (lambda (x)
166 `(,(car x)
167 (((byte word) (absolute))
168 ((4 #b0110) (4 ,(cdr x))
169 (? (branch-displacement-bits first-operand modifier))))))
170 '(("BCC" . #b0100) ("BCS" . #b0101) ("BEQ" . #b0111) ("BGE" . #b1100)
171 ("BGT" . #b1110) ("BHI" . #b0010) ("BLE" . #b1111) ("BLS" . #b0011)
172 ("BLT" . #b1101) ("BMI" . #b1011) ("BNE" . #b0110) ("BPL" . #b1010)
173 ("BVC" . #b1000) ("BVS" . #b1001) ("BRA" . #b0000) ("BSR" . #b0001)))
175 ,@(mapcar
176 (lambda (x)
177 `(,(car x)
178 (((byte long) (data-register) (data-alterable-modes))
179 ((4 #b0000) (3 (register-idx first-operand))
180 (1 #b1) (2 ,(cdr x))
181 (6 (effective-address-mode second-operand modifier))
182 (? (effective-address-extra second-operand modifier))))
183 (((byte long) (immediate) (data-alterable-modes))
184 ((8 #b00001000) (2 ,(cdr x))
185 (6 (effective-address-mode second-operand modifier))
186 (8 #b00000000) (8 (immediate-value immediate 'byte))
187 (? (effective-address-extra second-operand modifier))))))
188 '(("BCHG" . #b01) ("BCLR" . #b10) ("BSET" . #b11) ))
189 ;; Note that BTST supports PC-relative, while the above three do
190 ;; not.
191 ("BTST"
192 (((byte long) (data-register) (data-addressing-modes))
193 ((4 #b0000) (3 (register-idx first-operand))
194 (3 #b100)
195 (6 (effective-address-mode second-operand modifier))
196 (? (effective-address-extra second-operand modifier))))
197 (((byte long) (immediate) (data-addressing-modes))
198 ((10 #b0000100000)
199 (6 (effective-address-mode second-operand modifier))
200 (8 #b00000000) (8 (immediate-value immediate 'byte))
201 (? (effective-address-extra second-operand modifier)))))
203 ("CHK"
204 (((word) (data-addressing-modes) (data-register))
205 ((4 #b0100) (3 (register-idx second-operand)) (3 #b110)
206 (6 (effective-address-mode first-operand modifier))
207 (? (effective-address-extra first-operand modifier)))))
209 ,@(mapcar
210 (lambda (x)
211 `(,x
212 (((byte word long) (data-alterable-modes))
213 ((5 #b01000)
214 (3 ,(cond ((string= x "NOT") #b110)
215 ((string= x "NEG") #b100)
216 ((string= x "NEGX") #b000)
217 ((string= x "CLR") #b010)))
218 (2 (modifier-bits modifier))
219 (6 (effective-address-mode first-operand modifier))
220 (? (effective-address-extra first-operand modifier))))))
221 '("CLR" "NEG" "NEGX" "NOT"))
223 ("CMP"
224 (((byte word long) (all-ea-modes) (data-register))
225 ((4 #b1011) (3 (register-idx second-operand)) (1 #b0)
226 (2 (modifier-bits modifier))
227 (6 (effective-address-mode first-operand modifier))
228 (? (effective-address-extra first-operand modifier))))
229 "CMPA" "CMPI" "CMPM")
230 ("CMPA"
231 (((word long) (all-ea-modes) (address-register))
232 ((4 #b1011) (3 (register-idx second-operand))
233 (3 (if-eql-word-p modifier #b011 #b111))
234 (6 (effective-address-mode first-operand modifier))
235 (? (effective-address-extra first-operand modifier)))))
236 ("CMPI"
237 (((byte word long) (immediate) (data-alterable-modes))
238 ((8 #b00001100) (2 (modifier-bits modifier))
239 (6 (effective-address-mode second-operand modifier))
240 (? (immediate-value first-operand modifier))
241 (? (effective-address-extra second-operand modifier)))))
242 ("CMPM"
243 (((byte word long) (postincrement-indirect) (postincrement-indirect))
244 ((4 #b1011) (3 (register-idx second-operand))
245 (1 #b1) (2 (modifier-bits modifier)) (3 #b001)
246 (3 (register-idx first-operand)))))
248 ,@(mapcar
249 (lambda (x)
250 `(,(car x)
251 (((word) (data-register) (absolute))
252 ((4 #b0101) (4 ,(cdr x)) (5 #b11001)
253 (3 (register-idx first-operand))
254 (16 (branch-displacement-bits second-operand modifier
255 :db-p t))))))
256 '(("DBCC" . #b0100) ("DBCS" . #b0101) ("DBEQ" . #b0111)
257 ("DBGE" . #b1100) ("DBGT" . #b1110) ("DBHI" . #b0010)
258 ("DBLE" . #b1111) ("DBLS" . #b0011) ("DBLT" . #b1101)
259 ("DBMI" . #b1011) ("DBNE" . #b0110) ("DBPL" . #b1010)
260 ("DBVC" . #b1000) ("DBVS" . #b1001) ("DBT" . #b0000)
261 ("DBRA" . #b0000) ("DBF" . #b0001)))
263 ,@(mapcar
264 (lambda (x)
265 `(,x
266 (((word) (data-addressing-modes) (data-register))
267 ((4 ,(if (or (string= x "DIVS") (string= x "DIVU"))
268 #b1000 #b1100))
269 (3 (register-idx second-operand))
270 (3 ,(if (or (string= x "DIVS") (string= x "MULS"))
271 #b111 #b011))
272 (6 (effective-address-mode first-operand modifier))
273 (? (effective-address-extra first-operand modifier))))))
274 '("DIVS" "DIVU" "MULS" "MULU"))
276 ("EXG"
277 (((long) (data-register) (data-register))
278 ((4 #b1100) (3 (register-idx first-operand))
279 (6 #b101000) (3 (register-idx second-operand))))
280 (((long) (address-register) (address-register))
281 ((4 #b1100) (3 (register-idx first-operand))
282 (6 #b101001) (3 (register-idx second-operand))))
283 (((long) (data-register) (address-register))
284 ((4 #b1100) (3 (register-idx first-operand))
285 (6 #b110001) (3 (register-idx second-operand)))))
287 ("EXT"
288 (((word long) (data-register))
289 ((7 #b0100100) (3 (if-eql-word-p modifier #b010 #b011))
290 (3 #b000) (3 (register-idx first-operand)))))
292 ("ILLEGAL" (nil ((16 #b0100101011111100))))
294 ("JMP"
295 ((nil (control-addressing-modes))
296 ((10 #b0100111011) (6 (effective-address-mode first-operand modifier))
297 (? (effective-address-extra first-operand modifier)))))
298 ("JSR"
299 ((nil (control-addressing-modes))
300 ((10 #b0100111010) (6 (effective-address-mode first-operand modifier))
301 (? (effective-address-extra first-operand modifier)))))
303 ("LEA"
304 (((long) (control-addressing-modes) (address-register))
305 ((4 #b0100) (3 (register-idx second-operand)) (3 #b111)
306 (6 (effective-address-mode first-operand modifier))
307 (? (effective-address-extra first-operand modifier)))))
309 ("LINK"
310 ((nil (address-register) (immediate))
311 ((13 #b0100111001010) (3 (register-idx first-operand))
312 (16 (immediate-value immediate)))))
314 ("MOVE"
315 (((byte word long) (all-ea-modes) (data-alterable-modes))
316 ((2 #b00) (2 (modifier-bits-for-move modifier))
317 (6 (effective-address-mode second-operand modifier :flipped-p t))
318 (6 (effective-address-mode first-operand modifier))
319 (? (effective-address-extra first-operand modifier))
320 (? (effective-address-extra second-operand modifier))))
321 (((word) (register (string-equal value "CCR"))
322 (data-alterable-modes))
323 ((10 #b0100001011) (6 (effective-address-mode second-operand modifier))
324 (? (effective-address-extra second-operand modifier))))
325 (((word) (data-addressing-modes) (register (string-equal value "CCR")))
326 ((10 #b0100010011) (6 (effective-address-mode first-operand modifier))
327 (? (effective-address-extra first-operand modifier))))
328 (((word) (data-addressing-modes) (register (string-equal value "SR")))
329 ((10 #b0100011011) (6 (effective-address-mode first-operand modifier))
330 (? (effective-address-extra first-operand modifier))))
331 (((word) (register (string-equal value "SR")) (data-alterable-modes))
332 ((10 #b0100000011) (6 (effective-address-mode second-operand modifier))
333 (? (effective-address-extra second-operand modifier))))
334 (((long) (register (string-equal value "USP")) (address-register))
335 ((13 #b0100111001101) (3 (register-idx second-operand))))
336 (((long) (register (string-equal value "USP")) (address-register))
337 ((13 #b0100111001101) (3 (register-idx second-operand))))
338 "MOVEA" "MOVEQ")
339 ("MOVEA"
340 (((word long) (all-ea-modes) (address-register))
341 ((2 #b00) (2 (modifier-bits-for-move modifier))
342 (3 (register-idx second-operand)) (3 #b001)
343 (6 (effective-address-mode first-operand modifier))
344 (? (effective-address-extra first-operand modifier)))))
345 ("MOVEC") ;; XXX I don't understand the syntax for this one.
346 ("MOVEM"
347 (((word long) (register-list) (movem-pre-modes))
348 ((9 #b010010001) (1 (if-eql-word-p modifier 0 1))
349 (6 (effective-address-mode second-operand modifier))
350 (16 (register-mask-list first-operand :flipped-p t))
351 (? (effective-address-extra second-operand modifier))))
352 (((word long) (movem-post-modes) (register-list))
353 ((9 #b010011001) (1 (if-eql-word-p modifier 0 1))
354 (6 (effective-address-mode first-operand modifier))
355 (16 (register-mask-list second-operand :flipped-p nil))
356 (? (effective-address-extra first-operand modifier)))))
357 ("MOVEP"
358 (((word long) (data-register) (displacement-indirect))
359 ((4 #b0000) (3 (register-idx first-operand))
360 (3 (if-eql-word-p modifier #b110 #b111)) (3 #b001)
361 (3 (register-idx (indirect-base-register second-operand)))))
362 (((word long) (displacement-indirect) (data-register))
363 ((4 #b0000) (3 (register-idx second-operand))
364 (3 (if-eql-word-p modifier #b100 #b101)) (3 #b001)
365 (3 (register-idx (indirect-base-register first-operand))))))
366 ("MOVEQ"
367 (((long) (immediate (<= 0 value 255)) (data-register))
368 ((4 #b0111) (3 (register-idx second-operand)) (1 #b0)
369 (8 (immediate-value first-operand)))))
370 ;; XXX MOVES (68010 instruction)
372 ("NBCD"
373 (((byte) (data-alterable-modes))
374 ((10 #b0100100000) (6 (effective-address-mode first-operand modifier))
375 (? (effective-address-extra first-operand modifier)))))
377 ("RESET" (nil ((16 #b0100111001110000))))
378 ("NOP" (nil ((16 #b0100111001110001))))
379 ("STOP" (nil ((16 #b0100111001110010))))
380 ("RTE" (nil ((16 #b0100111001110011))))
381 ("RTD" (nil ((16 #b0100111001110100))))
382 ("RTS" (nil ((16 #b0100111001110101))))
383 ("TRAPV" (nil ((16 #b0100111001110110))))
384 ("RTR" (nil ((16 #b0100111001110111))))
386 ("PEA"
387 (((long) (control-addressing-modes))
388 ((10 #b0100100001) (6 (effective-address-mode first-operand modifier))
389 (? (effective-address-extra first-operand modifier)))))
391 ,@(mapcar
392 (lambda (x)
393 `(,(car x)
394 (((byte) (data-alterable-modes))
395 ((4 #b0101) (4 ,(cdr x)) (2 #b11)
396 (6 (effective-mode-mode first-operand))
397 (? (effective-mode-extra first-operand))))))
398 '(("SCC" . #b0100) ("SCS" . #b0101) ("SEQ" . #b0111) ("SGE" . #b1100)
399 ("SGT" . #b1110) ("SHI" . #b0010) ("SLE" . #b1111) ("SLS" . #b0011)
400 ("SLT" . #b1101) ("SMI" . #b1011) ("SNE" . #b0110) ("SPL" . #b1010)
401 ("SVC" . #b1000) ("SVS" . #b1001) ("ST" . #b0000) ("SF" . #b0001)))
403 ("SWAP"
404 (((word) (data-register))
405 ((13 #b0100100001000) (3 (register-idx first-operand)))))
407 ("TAS"
408 (((byte) (data-alterable-modes))
409 ((10 #b0100101011) (6 (effective-address-mode first-operand modifier))
410 (? (effective-address-extra first-operand modifier)))))
412 ("TRAP"
413 ((nil (immediate (<= 0 value 15)))
414 ((12 #b010011100100) (4 (immediate-value first-operand)))))
416 ("TST"
417 (((byte word long) (data-alterable-modes))
418 ((8 #b01001010) (2 (modifier-bits modifier))
419 (6 (effective-address-mode first-operand modifier))
420 (? (effective-address-extra first-operand modifier)))))
422 ("UNLK"
423 ((nil (address-register))
424 ((13 #b0100111001011) (3 (register-idx first-operand)))))))
427 ;; The order of elements in this table are significant.
428 (defparameter *asm-register-table*
429 #(("d0") ("d1") ("d2") ("d3") ("d4") ("d5") ("d6") ("d7")
430 ("a0") ("a1") ("a2") ("a3") ("a4") ("a5") ("a6") ("a7")
431 ("pc") ("ccr") ("sr") ("ssp") ("usp")))
434 ;;;; HELPER FUNCTIONS
436 (defun munge-modifier (string)
437 (let ((modifier nil))
438 (awhen (position #\. string)
439 (setf modifier (subseq string (1+ it)))
440 (setf string (subseq string 0 it)))
441 (values string modifier)))
443 (defun register-substitutions (string)
444 ;; XXX: allow dynamic register substitutions for EQUR directive
445 (when (string-equal string "sp") (setf string "a7"))
446 string)
448 (defun register-p (string)
449 (find string *asm-register-table* :key #'car :test #'string-equal))
451 (defun opcode-p (string)
452 (find string *asm-opcode-table* :key #'car :test #'string-equal))
454 ;; PSEUDO-OP-P has been moved to assembler.lisp
456 ;;; Really dumb, but this was the only thing in the code generation
457 ;;; table that needed to be changed to a function call in order to
458 ;;; stop using eval in the code generator.
459 (defun if-eql-word-p (modifier a b)
460 (if (eql modifier 'word) a b))