OSDN Git Service

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