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