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