1 /* Copyright (C) 2000, 2003 Free Software Foundation
2 Contributed by Alexandre Oliva <aoliva@cygnus.com>
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.
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.
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. */
18 /* Generator of tests for Maverick.
20 See the following file for usage and documentation. */
21 #include "../all/test-gen.c"
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. */
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"
37 /* The various types of registers: ARM's registers, Maverick's
38 f/d/fx/dx registers, Maverick's accumulators and Maverick's
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))
47 literal ("dspsc"), tick_random
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
57 arm_cond (func_arg
* arg
, insn_data
* data
)
58 #define arm_cond { arm_cond }
60 static const char conds
[16][3] =
62 "eq", "ne", "cs", "cc",
63 "mi", "pl", "vs", "vc",
64 "hi", "ls", "ge", "lt",
67 unsigned val
= get_bits (4u);
69 data
->as_in
= data
->dis_out
= strdup (conds
[val
]);
71 data
->dis_out
= strdup ("");
72 data
->bits
= (val
== 15 ? 14 : val
) << 28;
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. */
81 off8s (func_arg
* arg
, insn_data
* data
)
82 #define off8s { off8s }
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. */
96 while (val
== -1 || val
== 0);
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;
110 sprintf (value
, ", #%i", val
);
111 data
->as_in
= data
->dis_out
= strdup (value
);
112 data
->bits
= (val
>> 2) | (1 << 23);
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. */
123 imm7 (func_arg
*arg
, insn_data
*data
)
124 #define imm7 { imm7 }
126 int val
= get_bits (7s
);
129 data
->bits
= (val
& 0x0f) | (2 * (val
& 0x70));
130 sprintf (value
, "#%i", val
);
131 data
->as_in
= data
->dis_out
= strdup (value
);
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
143 #define mv_insn(insname, insnvar, word, funcs...) \
144 define_insn (insname ## insnvar, \
146 insn_bits (insname, word), \
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, \
166 /* Define all variants of an LDR or STR instruction, namely,
167 pre-indexed without write-back, pre-indexed with write-back and
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)
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)
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
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))
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")
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")
195 /* Define a float CDP instruction with two operands. */
196 #define CDP2f(insname, opcode1, opcode2) \
197 CDP2 (insname, s, 4, opcode1, opcode2, "f", "f")
199 /* Define a double CDP instruction with two operands. */
200 #define CDP2d(insname, opcode1, opcode2) \
201 CDP2 (insname, d, 4, opcode1, opcode2, "d", "d")
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, \
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
213 #define CDPfp_insns(insname) \
214 insn (insname ## s), insn (insname ## d)
215 #define CDPx_insns(insname) \
216 insn (insname ## 32), insn (insname ## 64)
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)
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")
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")
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")
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")
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))
248 /* Define a CDP4 instruction with one accumulator operands. */
249 #define CDP41A(insname, opcode1) \
250 CDP4 (insname, opcode1, mvreg ("fx", 12), "fx", "fx")
252 /* Define a CDP4 instruction with two accumulator operands. */
253 #define CDP42A(insname, opcode1) \
254 CDP4 (insname, opcode1, acreg (12), "fx", "fx")
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)
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))
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))
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)
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))
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))
288 /* Define move insns between a float DSP register and an ARM
290 #define MVf(nameAD, nameDA, opcode2) \
291 MVDSPARM (nameAD, 4, opcode2, "f"); \
292 MVARMDSP (nameDA, 4, opcode2, "f")
294 /* Define move insns between a double DSP register and an ARM
296 #define MVd(nameAD, nameDA, opcode2) \
297 MVDSPARM (nameAD, 4, opcode2, "d"); \
298 MVARMDSP (nameDA, 4, opcode2, "d")
300 /* Define move insns between a 32-bit integer DSP register and an ARM
302 #define MVfx(nameAD, nameDA, opcode2) \
303 MVDSPARM (nameAD, 5, opcode2, "fx"); \
304 MVARMDSP (nameDA, 5, opcode2, "fx")
306 /* Define move insns between a 64-bit integer DSP register and an ARM
308 #define MVdx(nameAD, nameDA, opcode2) \
309 MVDSPARM (nameAD, 5, opcode2, "dx"); \
310 MVARMDSP (nameDA, 5, opcode2, "dx")
312 /* Define move insns between a 32-bit DSP register and a DSP
314 #define MVfxa(nameFA, nameAF, opcode2) \
315 MVDSPACC (nameFA, opcode2, "fx"); \
316 MVACCDSP (nameAF, opcode2, "fx")
318 /* Define move insns between a 64-bit DSP register and a DSP
320 #define MVdxa(nameDA, nameAD, opcode2) \
321 MVDSPACC (nameDA, opcode2, "dx"); \
322 MVACCDSP (nameAD, opcode2, "dx")
324 /* Produce the insn identifiers for a pair of mv insns. */
325 #define insns_MV(name1, name2) \
326 insn (mv ## name1), insn (mv ## name2)
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, \
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");
346 /* Create the load_store insn group. */
347 func
*load_store_insns
[] =
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
),
356 /* Define all move insns. */
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);
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");
372 /* Create the move insns group. */
373 func
* move_insns
[] =
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
),
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");
395 /* Create the conv insns group. */
396 func
* conv_insns
[] =
398 insn (cvtsd
), insn (cvtds
), insn (cvt32s
), insn (cvt32d
),
399 insn (cvt64s
), insn (cvt64d
), insn (cvts32
), insn (cvtd32
),
400 insn (truncs32
), insn (truncd32
),
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");
410 /* Create the shift insns group. */
411 func
*shift_insns
[] =
413 insn (rshl32
), insn (rshl64
),
414 insn (sh32
), insn (sh64
),
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));
424 /* Create the comp insns group. */
427 insn (cmps
), insn (cmpd
),
428 insn (cmp32
), insn (cmp64
),
432 /* Define all floating-point arithmetic insns. */
444 /* Create the fp-arith insns group. */
445 func
*fp_arith_insns
[] =
447 CDPfp_insns (abs
), CDPfp_insns (neg
),
448 CDPfp_insns (add
), CDPfp_insns (sub
), CDPfp_insns (mul
),
452 /* Define all integer arithmetic insns. */
466 /* Create the int-arith insns group. */
467 func
* int_arith_insns
[] =
469 CDPx_insns (abs
), CDPx_insns (neg
),
470 CDPx_insns (add
), CDPx_insns (sub
), CDPx_insns (mul
),
471 insn (mac32
), insn (msc32
),
475 /* Define all accumulator arithmetic insns. */
481 /* Create the acc-arith insns group. */
482 func
* acc_arith_insns
[] =
484 insn (madd32
), insn (msub32
),
485 insn (madda32
), insn (msuba32
),
489 /* Create the set of all groups. */
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
},
504 main (int argc
, char *argv
[])
506 FILE *as_in
= stdout
, *dis_out
= stderr
;
508 /* Check whether we're filtering insns. */
510 skip_list
= argv
+ 1;
512 /* Output assembler header. */
516 /* Output comments for the testsuite-driver and the initial
517 disassembler output. */
518 fputs ("#objdump: -dr --prefix-address --show-raw-insn\n"
520 "#as: -mcpu=ep9312\n"
522 "# Test the instructions of the Cirrus Maverick floating point co-processor\n"
524 ".*: +file format.*arm.*\n"
526 "Disassembly of section .text:\n",
529 /* Now emit all (selected) insns. */
530 output_groups (groups
, as_in
, dis_out
);
This page took 0.050557 seconds and 4 git commands to generate.