* gas/testsuite/gas/arm/arm.exp: Run arm9e tests.
[deliverable/binutils-gdb.git] / gas / testsuite / gas / arm / maverick.c
1 /* Copyright (C) 2000 Free Software Foundation
2 * Contributed by Alexandre Oliva <aoliva@cygnus.com>
3 *
4 * This file is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* Generator of tests for Maverick.
20 *
21 * See the following file for usage and documentation. */
22 #include "../all/test-gen.c"
23
24 /* These are the ARM registers. Some of them have canonical names
25 * other than r##, so we'll use both in the asm input, but only the
26 * canonical names in the expected disassembler output. */
27 char *arm_regs[] = {
28 /* Canonical names. */
29 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
30 "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
31 /* Alternate names, i.e., those that can be used in the assembler,
32 * but that will never be emitted by the disassembler. */
33 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
34 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
35 };
36
37 /* The various types of registers: ARM's registers, Maverick's
38 * f/d/fx/dx registers, Maverick's accumulators and Maverick's status
39 * register. */
40 #define armreg(shift) \
41 reg_r (arm_regs, shift, 0xf, mk_get_bits (5u))
42 #define mvreg(prefix, shift) \
43 reg_p ("mv" prefix, shift, mk_get_bits (4u))
44 #define acreg(shift) \
45 reg_p ("mvax", shift, mk_get_bits (2u))
46 #define dspsc \
47 literal ("dspsc"), tick_random
48
49 /* This outputs the condition flag that may follow each ARM insn.
50 * Since the condition 15 is invalid, we use it to check that the
51 * assembler recognizes the absence of a condition as `al'. However,
52 * the disassembler won't ever output `al', so, if we emit it in the
53 * assembler, expect the condition to be omitted in the disassembler
54 * output. */
55 int
56 arm_cond (func_arg *arg, insn_data *data)
57 #define arm_cond { arm_cond }
58 {
59 static const char conds[16][3] = {
60 "eq", "ne", "cs", "cc",
61 "mi", "pl", "vs", "vc",
62 "hi", "ls", "ge", "lt",
63 "gt", "le", "al", ""
64 };
65 unsigned val = get_bits (4u);
66
67 data->as_in = data->dis_out = strdup (conds[val]);
68 if (val == 14)
69 data->dis_out = strdup ("");
70 data->bits = (val == 15 ? 14 : val) << 28;
71 return 0;
72 }
73
74 /* The sign of an offset is actually used to determined whether the
75 * absolute value of the offset should be added or subtracted, so we
76 * must adjust negative values so that they do not overflow: -256 is
77 * not valid, but -0 is distinct from +0. */
78 int
79 off8s (func_arg *arg, insn_data *data)
80 #define off8s { off8s }
81 {
82 int val = get_bits (9s);
83 char value[6], *strt = value;
84 *strt++ = '#';
85 if (val < 0)
86 {
87 *strt++ = '-';
88 ++val;
89 val = -val;
90 data->bits = val;
91 }
92 else
93 data->bits = val | (1 << 23);
94 sprintf (strt, "%i", val);
95 data->as_in = data->dis_out = strdup (value);
96 return 0;
97 }
98
99 /* This function generates a 7-bit signed constant, emitted as
100 * follows: the 4 least-significant bits are stored in the 4
101 * least-significant bits of the word; the 3 most-significant bits are
102 * stored in bits 7:5, i.e., bit 4 is skipped. */
103 int
104 imm7 (func_arg *arg, insn_data *data)
105 #define imm7 { imm7 }
106 {
107 int val = get_bits (7s);
108 char value[6];
109
110 data->bits = (val & 0x0f) | (2 * (val & 0x70));
111 sprintf (value, "#%i", val);
112 data->as_in = data->dis_out = strdup (value);
113 return 0;
114 }
115
116 /* Convenience wrapper to define_insn, that prefixes every insn with
117 * `cf' (so, if you specify command-line arguments, remember that `cf'
118 * must *not* be part of the string), and post-fixes a condition code.
119 * insname and insnvar specify the main insn name and a variant;
120 * they're just concatenated, and insnvar is often empty. word is the
121 * bit pattern that defines the insn, properly shifted, and funcs is a
122 * sequence of funcs that define the operands and the syntax of the
123 * insn. */
124 #define mv_insn(insname, insnvar, word, funcs...) \
125 define_insn(insname ## insnvar, \
126 literal ("cf"), \
127 insn_bits (insname, word), \
128 arm_cond, \
129 tab, \
130 ## funcs)
131
132 /* Define a single LDC/STC variant. op is the main insn opcode; ld
133 * stands for load (it should be 0 on stores), dword selects 64-bit
134 * operations, pre should be enabled for pre-increment, and wb, for
135 * write-back. sep1, sep2 and sep3 are syntactical elements ([]!)
136 * that the assembler will use to enable pre and wb. It would
137 * probably have been cleaner to couple the syntactical elements with
138 * the pre/wb bits directly, but it would have required the definition
139 * of more functions. */
140 #define LDST(insname, insnvar, op, ld, dword, regname, pre, wb, sep1, sep2, sep3) \
141 mv_insn (insname, insnvar, \
142 (12<<24)|(op<<8)|(ld<<20)|(pre<<24)|(dword<<22)|(wb<<21), \
143 mvreg (regname, 12), comma, \
144 lsqbkt, armreg (16), sep1, comma, off8s, sep2, sep3, \
145 tick_random)
146
147 /* Define all variants of an LDR or STR instruction, namely,
148 * pre-indexed without write-back, pre-indexed with write-back and
149 * post-indexed. */
150 #define LDSTall(insname, op, ld, dword, regname) \
151 LDST (insname, _p, op, ld, dword, regname, 1, 0, nothing, rsqbkt, nothing); \
152 LDST (insname, _pw, op, ld, dword, regname, 1, 1, nothing, rsqbkt, literal("!")); \
153 LDST (insname, ,op, ld, dword, regname, 0, 0, rsqbkt, nothing, nothing)
154
155 /* Produce the insn identifiers of all LDST variants of a given insn.
156 * To be used in the initialization of an insn group array. */
157 #define insns_LDSTall(insname) \
158 insn (insname ## _p), insn (insname ## _pw), insn (insname)
159
160 /* Define a CDP variant that uses two registers, at offsets 12 and 16.
161 * The two opcodes and the co-processor number identify the CDP
162 * insn. */
163 #define CDP2(insname, var, cpnum, opcode1, opcode2, reg1name, reg2name) \
164 mv_insn (insname##var, , \
165 (14<<24)|((opcode1)<<20)|((cpnum)<<8)|((opcode2)<<5), \
166 mvreg (reg1name, 12), comma, mvreg (reg2name, 16))
167
168 /* Define a 32-bit integer CDP instruction with two operands. */
169 #define CDP2fx(insname, opcode1, opcode2) \
170 CDP2 (insname, 32, 5, opcode1, opcode2, "fx", "fx")
171
172 /* Define a 64-bit integer CDP instruction with two operands. */
173 #define CDP2dx(insname, opcode1, opcode2) \
174 CDP2 (insname, 64, 5, opcode1, opcode2, "dx", "dx")
175
176 /* Define a float CDP instruction with two operands. */
177 #define CDP2f(insname, opcode1, opcode2) \
178 CDP2 (insname, s, 4, opcode1, opcode2, "f", "f")
179
180 /* Define a double CDP instruction with two operands. */
181 #define CDP2d(insname, opcode1, opcode2) \
182 CDP2 (insname, d, 4, opcode1, opcode2, "d", "d")
183
184 /* Define a CDP instruction with two register operands and one 7-bit
185 * signed immediate generated with imm7. */
186 #define CDP2_imm7(insname, cpnum, opcode1, reg1name, reg2name) \
187 mv_insn (insname, , (14<<24)|((opcode1)<<20)|((cpnum)<<8), \
188 mvreg (reg1name, 12), comma, mvreg (reg2name, 16), comma, imm7, \
189 tick_random)
190
191 /* Produce the insn identifiers of CDP floating-point or integer insn
192 * pairs (i.e., it appends the suffixes for 32-bit and 64-bit
193 * insns. */
194 #define CDPfp_insns(insname) \
195 insn (insname ## s), insn (insname ## d)
196 #define CDPx_insns(insname) \
197 insn (insname ## 32), insn (insname ## 64)
198
199 /* Define a CDP instruction with 3 operands, at offsets 12, 16, 0. */
200 #define CDP3(insname, var, cpnum, opcode1, opcode2, reg1name, reg2name, reg3name) \
201 mv_insn (insname##var, , \
202 (14<<24)|((opcode1)<<20)|((cpnum)<<8)|((opcode2)<<5), \
203 mvreg (reg1name, 12), comma, mvreg (reg2name, 16), comma, \
204 mvreg (reg3name, 0), tick_random)
205
206 /* Define a 32-bit integer CDP instruction with three operands. */
207 #define CDP3fx(insname, opcode1, opcode2) \
208 CDP3 (insname, 32, 5, opcode1, opcode2, "fx", "fx", "fx")
209
210 /* Define a 64-bit integer CDP instruction with three operands. */
211 #define CDP3dx(insname, opcode1, opcode2) \
212 CDP3 (insname, 64, 5, opcode1, opcode2, "dx", "dx", "dx")
213
214 /* Define a float CDP instruction with three operands. */
215 #define CDP3f(insname, opcode1, opcode2) \
216 CDP3 (insname, s, 4, opcode1, opcode2, "f", "f", "f")
217
218 /* Define a double CDP instruction with three operands. */
219 #define CDP3d(insname, opcode1, opcode2) \
220 CDP3 (insname, d, 4, opcode1, opcode2, "d", "d", "d")
221
222 /* Define a CDP instruction with four operands, at offsets 5, 12, 16
223 * and 0. Used only for ACC instructions. */
224 #define CDP4(insname, opcode1, reg2spec, reg3name, reg4name) \
225 mv_insn (insname, , (14<<24)|((opcode1)<<20)|(6<<8), \
226 acreg (5), comma, reg2spec, comma, \
227 mvreg (reg3name, 16), comma, mvreg (reg4name, 0))
228
229 /* Define a CDP4 instruction with one accumulator operands. */
230 #define CDP41A(insname, opcode1) \
231 CDP4 (insname, opcode1, mvreg ("fx", 12), "fx", "fx")
232
233 /* Define a CDP4 instruction with two accumulator operands. */
234 #define CDP42A(insname, opcode1) \
235 CDP4 (insname, opcode1, acreg (12), "fx", "fx")
236
237 /* Define a MCR or MRC instruction with two register operands. */
238 #define MCRC2(insname, cpnum, opcode1, dir, opcode2, reg1spec, reg2spec) \
239 mv_insn (insname, , \
240 ((14<<24)|((opcode1)<<21)|((dir)<<20)| \
241 ((cpnum)<<8)|((opcode2)<<5)|(1<<4)), \
242 reg1spec, comma, reg2spec)
243
244 /* Define a move from a DSP register to an ARM register. */
245 #define MVDSPARM(insname, cpnum, opcode2, regDSPname) \
246 MCRC2 (mv ## insname, cpnum, 0, 0, opcode2, \
247 mvreg (regDSPname, 16), armreg(12))
248
249 /* Define a move from an ARM register to a DSP register. */
250 #define MVARMDSP(insname, cpnum, opcode2, regDSPname) \
251 MCRC2 (mv ## insname, cpnum, 0, 1, opcode2, \
252 armreg (12), mvreg (regDSPname, 16))
253
254 /* Define a move from a DSP register to a DSP accumulator. */
255 #define MVDSPACC(insname, opcode2, regDSPname) \
256 MCRC2 (mv ## insname, 6, 0, 1, opcode2, acreg (0), mvreg (regDSPname, 16))
257
258 /* Define a move from a DSP accumulator to a DSP register. */
259 #define MVACCDSP(insname, opcode2, regDSPname) \
260 MCRC2 (mv ## insname, 6, 0, 0, opcode2, mvreg (regDSPname, 0), acreg (16))
261
262 /* Define move insns between a float DSP register and an ARM
263 * register. */
264 #define MVf(nameAD, nameDA, opcode2) \
265 MVDSPARM (nameAD, 4, opcode2, "f"); \
266 MVARMDSP (nameDA, 4, opcode2, "f")
267
268 /* Define move insns between a double DSP register and an ARM
269 * register. */
270 #define MVd(nameAD, nameDA, opcode2) \
271 MVDSPARM (nameAD, 4, opcode2, "d"); \
272 MVARMDSP (nameDA, 4, opcode2, "d")
273
274 /* Define move insns between a 32-bit integer DSP register and an ARM
275 * register. */
276 #define MVfx(nameAD, nameDA, opcode2) \
277 MVDSPARM (nameAD, 5, opcode2, "fx"); \
278 MVARMDSP (nameDA, 5, opcode2, "fx")
279
280 /* Define move insns between a 64-bit integer DSP register and an ARM
281 * register. */
282 #define MVdx(nameAD, nameDA, opcode2) \
283 MVDSPARM (nameAD, 5, opcode2, "dx"); \
284 MVARMDSP (nameDA, 5, opcode2, "dx")
285
286 /* Define move insns between a 32-bit DSP register and a DSP
287 * accumulator. */
288 #define MVfxa(nameFA, nameAF, opcode2) \
289 MVDSPACC (nameFA, opcode2, "fx"); \
290 MVACCDSP (nameAF, opcode2, "fx")
291
292 /* Define move insns between a 64-bit DSP register and a DSP
293 * accumulator. */
294 #define MVdxa(nameDA, nameAD, opcode2) \
295 MVDSPACC (nameDA, opcode2, "dx"); \
296 MVACCDSP (nameAD, opcode2, "dx")
297
298 /* Produce the insn identifiers for a pair of mv insns. */
299 #define insns_MV(name1, name2) \
300 insn (mv ## name1), insn (mv ## name2)
301
302 /* Define a MCR or MRC instruction with three register operands. */
303 #define MCRC3(insname, cpnum, opcode1, dir, opcode2, reg1spec, reg2spec, reg3spec) \
304 mv_insn (insname, , \
305 ((14<<24)|((opcode1)<<21)|((dir)<<20)| \
306 ((cpnum)<<8)|((opcode2)<<5)|(1<<4)), \
307 reg1spec, comma, reg2spec, comma, reg3spec, \
308 tick_random)
309
310 /* Define all load_store insns. */
311 LDSTall (ldrs, 4, 1, 0, "f");
312 LDSTall (ldrd, 4, 1, 1, "d");
313 LDSTall (ldr32, 5, 1, 0, "fx");
314 LDSTall (ldr64, 5, 1, 1, "dx");
315 LDSTall (strs, 4, 0, 0, "f");
316 LDSTall (strd, 4, 0, 1, "d");
317 LDSTall (str32, 5, 0, 0, "fx");
318 LDSTall (str64, 5, 0, 1, "dx");
319
320 /* Create the load_store insn group. */
321 func *load_store_insns[] = {
322 insns_LDSTall (ldrs), insns_LDSTall (ldrd),
323 insns_LDSTall (ldr32), insns_LDSTall (ldr64),
324 insns_LDSTall (strs), insns_LDSTall (strd),
325 insns_LDSTall (str32), insns_LDSTall (str64),
326 0
327 };
328
329 /* Define all move insns. */
330 MVf (sr, rs, 2);
331 MVd (dlr, rdl, 0);
332 MVd (dhr, rdh, 1);
333 MVdx (64lr, r64l, 0);
334 MVdx (64hr, r64h, 1);
335 MVfxa (al32, 32al, 0);
336 MVfxa (am32, 32am, 1);
337 MVfxa (ah32, 32ah, 2);
338 MVfxa (a32, 32a, 3);
339 MVdxa (a64, 64a, 4);
340 MCRC2 (mvsc32, 6, 0, 1, 5, dspsc, mvreg ("fx", 16));
341 MCRC2 (mv32sc, 6, 0, 0, 5, mvreg ("fx", 0), dspsc);
342 CDP2 (cpys, , 4, 0, 0, "f", "f");
343 CDP2 (cpyd, , 4, 0, 1, "d", "d");
344
345 /* Create the move insns group. */
346 func *move_insns[] = {
347 insns_MV (sr, rs), insns_MV (dlr, rdl), insns_MV (dhr, rdh),
348 insns_MV (64lr, r64l), insns_MV (64hr, r64h),
349 insns_MV (al32, 32al), insns_MV (am32, 32am), insns_MV (ah32, 32ah),
350 insns_MV (a32, 32a), insns_MV (a64, 64a),
351 insn (mvsc32), insn (mv32sc), insn (cpys), insn (cpyd),
352 0
353 };
354
355 /* Define all conversion insns. */
356 CDP2 (cvtsd, , 4, 0, 3, "d", "f");
357 CDP2 (cvtds, , 4, 0, 2, "f", "d");
358 CDP2 (cvt32s, , 4, 0, 4, "f", "fx");
359 CDP2 (cvt32d, , 4, 0, 5, "d", "fx");
360 CDP2 (cvt64s, , 4, 0, 6, "f", "dx");
361 CDP2 (cvt64d, , 4, 0, 7, "d", "dx");
362 CDP2 (cvts32, , 5, 1, 4, "fx", "f");
363 CDP2 (cvtd32, , 5, 1, 5, "fx", "d");
364 CDP2 (truncs32, , 5, 1, 6, "fx", "f");
365 CDP2 (truncd32, , 5, 1, 7, "fx", "d");
366
367 /* Create the conv insns group. */
368 func *conv_insns[] = {
369 insn (cvtsd), insn (cvtds), insn (cvt32s), insn (cvt32d),
370 insn (cvt64s), insn (cvt64d), insn (cvts32), insn (cvtd32),
371 insn (truncs32), insn (truncd32),
372 0
373 };
374
375 /* Define all shift insns. */
376 MCRC3 (rshl32, 5, 0, 0, 2, mvreg ("fx", 16), mvreg ("fx", 0), armreg(12));
377 MCRC3 (rshl64, 5, 0, 0, 3, mvreg ("dx", 16), mvreg ("dx", 0), armreg(12));
378 CDP2_imm7 (sh32, 5, 0, "fx", "fx");
379 CDP2_imm7 (sh64, 5, 2, "dx", "dx");
380
381 /* Create the shift insns group. */
382 func *shift_insns[] = {
383 insn (rshl32), insn (rshl64),
384 insn (sh32), insn (sh64),
385 0
386 };
387
388 /* Define all comparison insns. */
389 MCRC3 (cmps, 4, 0, 1, 4, armreg (12), mvreg ("f", 16), mvreg ("f", 0));
390 MCRC3 (cmpd, 4, 0, 1, 5, armreg (12), mvreg ("d", 16), mvreg ("d", 0));
391 MCRC3 (cmp32, 5, 0, 1, 4, armreg (12), mvreg ("fx", 16), mvreg ("fx", 0));
392 MCRC3 (cmp64, 5, 0, 1, 5, armreg (12), mvreg ("dx", 16), mvreg ("dx", 0));
393
394 /* Create the comp insns group. */
395 func *comp_insns[] = {
396 insn (cmps), insn (cmpd),
397 insn (cmp32), insn (cmp64),
398 0
399 };
400
401 /* Define all floating-point arithmetic insns. */
402 CDP2f (abs, 3, 0);
403 CDP2d (abs, 3, 1);
404 CDP2f (neg, 3, 2);
405 CDP2d (neg, 3, 3);
406 CDP3f (add, 3, 4);
407 CDP3d (add, 3, 5);
408 CDP3f (sub, 3, 6);
409 CDP3d (sub, 3, 7);
410 CDP3f (mul, 1, 0);
411 CDP3d (mul, 1, 1);
412
413 /* Create the fp-arith insns group. */
414 func *fp_arith_insns[] = {
415 CDPfp_insns (abs), CDPfp_insns (neg),
416 CDPfp_insns (add), CDPfp_insns (sub), CDPfp_insns (mul),
417 0
418 };
419
420 /* Define all integer arithmetic insns. */
421 CDP2fx (abs, 3, 0);
422 CDP2dx (abs, 3, 1);
423 CDP2fx (neg, 3, 2);
424 CDP2dx (neg, 3, 3);
425 CDP3fx (add, 3, 4);
426 CDP3dx (add, 3, 5);
427 CDP3fx (sub, 3, 6);
428 CDP3dx (sub, 3, 7);
429 CDP3fx (mul, 1, 0);
430 CDP3dx (mul, 1, 1);
431 CDP3fx (mac, 1, 2);
432 CDP3fx (msc, 1, 3);
433
434 /* Create the int-arith insns group. */
435 func *int_arith_insns[] = {
436 CDPx_insns (abs), CDPx_insns (neg),
437 CDPx_insns (add), CDPx_insns (sub), CDPx_insns (mul),
438 insn (mac32), insn (msc32),
439 0
440 };
441
442 /* Define all accumulator arithmetic insns. */
443 CDP41A (madd32, 0);
444 CDP41A (msub32, 1);
445 CDP42A (madda32, 2);
446 CDP42A (msuba32, 3);
447
448 /* Create the acc-arith insns group. */
449 func *acc_arith_insns[] = {
450 insn (madd32), insn (msub32),
451 insn (madda32), insn (msuba32),
452 0
453 };
454
455 /* Create the set of all groups. */
456 group_t
457 groups[] = {
458 { "load_store", load_store_insns },
459 { "move", move_insns },
460 { "conv", conv_insns },
461 { "shift", shift_insns },
462 { "comp", comp_insns },
463 { "fp_arith", fp_arith_insns },
464 { "int_arith", int_arith_insns },
465 { "acc_arith", acc_arith_insns },
466 { 0 }
467 };
468
469 int
470 main(int argc, char *argv[])
471 {
472 FILE *as_in = stdout, *dis_out = stderr;
473
474 /* Check whether we're filtering insns. */
475 if (argc > 1)
476 skip_list = argv + 1;
477
478 /* Output assembler header. */
479 fputs ("\t.text\n"
480 "\t.align\n",
481 as_in);
482 /* Output comments for the testsuite-driver and the initial
483 * disassembler output. */
484 fputs ("#objdump: -dr --prefix-address --show-raw-insn\n"
485 "#name: Maverick\n"
486 "#as: -marm9e\n"
487 "\n"
488 "# Test the instructions of Maverick\n"
489 "\n"
490 ".*: +file format.*arm.*\n"
491 "\n"
492 "Disassembly of section .text:\n",
493 dis_out);
494
495 /* Now emit all (selected) insns. */
496 output_groups (groups, as_in, dis_out);
497
498 exit (0);
499 }
This page took 0.044937 seconds and 5 git commands to generate.