1*f5c631daSSadaf Ebrahimi#!/usr/bin/env python3 2*f5c631daSSadaf Ebrahimi 3*f5c631daSSadaf Ebrahimi# Copyright 2016, VIXL authors 4*f5c631daSSadaf Ebrahimi# All rights reserved. 5*f5c631daSSadaf Ebrahimi# 6*f5c631daSSadaf Ebrahimi# Redistribution and use in source and binary forms, with or without 7*f5c631daSSadaf Ebrahimi# modification, are permitted provided that the following conditions are met: 8*f5c631daSSadaf Ebrahimi# 9*f5c631daSSadaf Ebrahimi# * Redistributions of source code must retain the above copyright notice, 10*f5c631daSSadaf Ebrahimi# this list of conditions and the following disclaimer. 11*f5c631daSSadaf Ebrahimi# * Redistributions in binary form must reproduce the above copyright notice, 12*f5c631daSSadaf Ebrahimi# this list of conditions and the following disclaimer in the documentation 13*f5c631daSSadaf Ebrahimi# and/or other materials provided with the distribution. 14*f5c631daSSadaf Ebrahimi# * Neither the name of ARM Limited nor the names of its contributors may be 15*f5c631daSSadaf Ebrahimi# used to endorse or promote products derived from this software without 16*f5c631daSSadaf Ebrahimi# specific prior written permission. 17*f5c631daSSadaf Ebrahimi# 18*f5c631daSSadaf Ebrahimi# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 19*f5c631daSSadaf Ebrahimi# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20*f5c631daSSadaf Ebrahimi# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21*f5c631daSSadaf Ebrahimi# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22*f5c631daSSadaf Ebrahimi# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*f5c631daSSadaf Ebrahimi# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24*f5c631daSSadaf Ebrahimi# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25*f5c631daSSadaf Ebrahimi# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26*f5c631daSSadaf Ebrahimi# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*f5c631daSSadaf Ebrahimi# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*f5c631daSSadaf Ebrahimi 29*f5c631daSSadaf Ebrahimi""" 30*f5c631daSSadaf EbrahimiGenerating tests 31*f5c631daSSadaf Ebrahimi================ 32*f5c631daSSadaf Ebrahimi 33*f5c631daSSadaf EbrahimiFrom the VIXL toplevel directory run: 34*f5c631daSSadaf Ebrahimi 35*f5c631daSSadaf Ebrahimi $ ./tools/generate_tests.py 36*f5c631daSSadaf Ebrahimi 37*f5c631daSSadaf EbrahimiThe script assumes that `clang-format-4.0` is in the current path. If it isn't, 38*f5c631daSSadaf Ebrahimiyou can provide your own: 39*f5c631daSSadaf Ebrahimi 40*f5c631daSSadaf Ebrahimi $ ./tools/generate_tests.py --clang-format /patch/to/clang-format 41*f5c631daSSadaf Ebrahimi 42*f5c631daSSadaf EbrahimiOnce the script has finished, it will have generated test files, as many as 43*f5c631daSSadaf Ebrahimipresent in the `default_config_files` list. For example: 44*f5c631daSSadaf Ebrahimi 45*f5c631daSSadaf Ebrahimi- test/aarch32/test-assembler-cond-rd-rn-immediate-a32.cc 46*f5c631daSSadaf Ebrahimi- test/aarch32/test-assembler-cond-rd-rn-rm-a32.cc 47*f5c631daSSadaf Ebrahimi- test/aarch32/test-assembler-cond-rd-rn-rm-q-a32.cc 48*f5c631daSSadaf Ebrahimi- test/aarch32/test-assembler-cond-rd-rn-rm-ge-a32.cc 49*f5c631daSSadaf Ebrahimi 50*f5c631daSSadaf EbrahimiBecause these test cases need traces in order to build, the script will have 51*f5c631daSSadaf Ebrahimigenerated placeholder trace files in `test/aarch32/traces/`. If you look at them 52*f5c631daSSadaf Ebrahimiyou'll see they are basically empty: 53*f5c631daSSadaf Ebrahimi 54*f5c631daSSadaf Ebrahimi $ cat test/aarch32/traces/sim-cond-rd-rn-immediate-adc-a32.h 55*f5c631daSSadaf Ebrahimi static const TestResult *kReferenceAdc = NULL; 56*f5c631daSSadaf Ebrahimi 57*f5c631daSSadaf EbrahimiSo of course, we can now build the test cases but running them will crash. We 58*f5c631daSSadaf Ebrahimineed to re-generate traces with real hardware; the test cases do not support 59*f5c631daSSadaf Ebrahimirunning in the simulator just yet. 60*f5c631daSSadaf Ebrahimi 61*f5c631daSSadaf EbrahimiGenerating traces 62*f5c631daSSadaf Ebrahimi================= 63*f5c631daSSadaf Ebrahimi 64*f5c631daSSadaf EbrahimiYou need to have either compiled natively for ARM, or cross-compiled 65*f5c631daSSadaf Ebrahimi`test-runner`. The traces can then be generated in the same way as with VIXL64. 66*f5c631daSSadaf EbrahimiNote that it takes a few minutes to generate everything. 67*f5c631daSSadaf Ebrahimi 68*f5c631daSSadaf Ebrahimi ./tools/generate_simulator_traces.py --runner /path/to/test-runner \ 69*f5c631daSSadaf Ebrahimi --aarch32-only 70*f5c631daSSadaf Ebrahimi 71*f5c631daSSadaf EbrahimiYou can now rebuild everything. If it all goes well, running the new tests 72*f5c631daSSadaf Ebrahimishould pass. 73*f5c631daSSadaf Ebrahimi 74*f5c631daSSadaf EbrahimiTest configuration format 75*f5c631daSSadaf Ebrahimi========================= 76*f5c631daSSadaf Ebrahimi 77*f5c631daSSadaf EbrahimiTODO: Write a simple and well documented complete example configuration file and 78*f5c631daSSadaf Ebrahimi mention it here. 79*f5c631daSSadaf Ebrahimi 80*f5c631daSSadaf EbrahimiThe underlying `test_generator` framework reads JSON description files and 81*f5c631daSSadaf Ebrahimigenerates tests according to them. These files live in `test/aarch32/config` by 82*f5c631daSSadaf Ebrahimidefault, but you may provide your own files with the `--config-files FILE ...` 83*f5c631daSSadaf Ebrahimiflag. The JSON format was extended to support C++ like one-line comments. 84*f5c631daSSadaf Ebrahimi 85*f5c631daSSadaf EbrahimiEach configuration file will serve to generate one or more test files, 86*f5c631daSSadaf Ebrahimiwe even use its file name to choose the name of the test: 87*f5c631daSSadaf Ebrahimi 88*f5c631daSSadaf Ebrahimi test/aarch32/config/cond-rd-rn-immediate-a32.json 89*f5c631daSSadaf Ebrahimi `-> test/aarch32/test-simulator-cond-rd-rn-immediate-a32.cc 90*f5c631daSSadaf Ebrahimi `-> test/aarch32/test-assembler-cond-rd-rn-immediate-a32.cc 91*f5c631daSSadaf Ebrahimi 92*f5c631daSSadaf EbrahimiIn addition to these test configuration files, we also provide a JSON 93*f5c631daSSadaf Ebrahimidescription with shared information. This information represents data types that 94*f5c631daSSadaf Ebrahimiinstructions use and lives in `test/aarch32/config/data-types.json`. 95*f5c631daSSadaf Ebrahimi 96*f5c631daSSadaf EbrahimiData types description 97*f5c631daSSadaf Ebrahimi---------------------- 98*f5c631daSSadaf Ebrahimi 99*f5c631daSSadaf EbrahimiWe refer to two kinds of data types: `operand` and `input`. 100*f5c631daSSadaf Ebrahimi 101*f5c631daSSadaf EbrahimiAn `operand` represents an argument passed to the macro-assembler to generate an 102*f5c631daSSadaf Ebrahimiinstruction. For example, a register or an immediate are operands. We can think 103*f5c631daSSadaf Ebrahimiof it as "assemble-time" data. 104*f5c631daSSadaf Ebrahimi 105*f5c631daSSadaf EbrahimiAs opposed to `operands`, an `input` represents data passed to an instruction at 106*f5c631daSSadaf Ebrahimiruntime. For example, it will be the value you write to a register before 107*f5c631daSSadaf Ebrahimiexecuting the instruction under test. 108*f5c631daSSadaf Ebrahimi 109*f5c631daSSadaf EbrahimiThe `data-types.json` file has the following structure: 110*f5c631daSSadaf Ebrahimi 111*f5c631daSSadaf Ebrahimi~~~ 112*f5c631daSSadaf Ebrahimi{ 113*f5c631daSSadaf Ebrahimi "operands": [ 114*f5c631daSSadaf Ebrahimi // List of operand types. 115*f5c631daSSadaf Ebrahimi ], 116*f5c631daSSadaf Ebrahimi "inputs": [ 117*f5c631daSSadaf Ebrahimi // List of input types. 118*f5c631daSSadaf Ebrahimi ] 119*f5c631daSSadaf Ebrahimi} 120*f5c631daSSadaf Ebrahimi~~~ 121*f5c631daSSadaf Ebrahimi 122*f5c631daSSadaf EbrahimiEach operand is described with the following structure: 123*f5c631daSSadaf Ebrahimi 124*f5c631daSSadaf Ebrahimi~~~ 125*f5c631daSSadaf Ebrahimi{ 126*f5c631daSSadaf Ebrahimi // Unique name for this operand type. 127*f5c631daSSadaf Ebrahimi "name": "AllRegistersButPC", 128*f5c631daSSadaf Ebrahimi // C++ type used by VIXL to represent this operand. 129*f5c631daSSadaf Ebrahimi "type": "Register", 130*f5c631daSSadaf Ebrahimi // List of possible variants. 131*f5c631daSSadaf Ebrahimi "variants": [ 132*f5c631daSSadaf Ebrahimi "r0", 133*f5c631daSSadaf Ebrahimi "r1", 134*f5c631daSSadaf Ebrahimi "r2", 135*f5c631daSSadaf Ebrahimi "r3", 136*f5c631daSSadaf Ebrahimi "r4", 137*f5c631daSSadaf Ebrahimi "r5", 138*f5c631daSSadaf Ebrahimi "r6", 139*f5c631daSSadaf Ebrahimi "r7", 140*f5c631daSSadaf Ebrahimi "r8", 141*f5c631daSSadaf Ebrahimi "r9", 142*f5c631daSSadaf Ebrahimi "r10", 143*f5c631daSSadaf Ebrahimi "r11", 144*f5c631daSSadaf Ebrahimi "r12", 145*f5c631daSSadaf Ebrahimi "r13", 146*f5c631daSSadaf Ebrahimi "r14" 147*f5c631daSSadaf Ebrahimi ], 148*f5c631daSSadaf Ebrahimi // Default variant to use. 149*f5c631daSSadaf Ebrahimi "default": "r0" 150*f5c631daSSadaf Ebrahimi} 151*f5c631daSSadaf Ebrahimi~~~ 152*f5c631daSSadaf Ebrahimi 153*f5c631daSSadaf EbrahimiThe "name" field of the operand will be used by test configuration files in 154*f5c631daSSadaf Ebrahimiorder to specify what kind of operands an instruction takes. The "type" field 155*f5c631daSSadaf Ebrahimisimply tells the generator what C++ type should be generated, e.g. "Condition", 156*f5c631daSSadaf Ebrahimi"Register", "uint32_t", "ShiftType", ...etc. 157*f5c631daSSadaf Ebrahimi 158*f5c631daSSadaf EbrahimiInputs are described in a very similar way: 159*f5c631daSSadaf Ebrahimi 160*f5c631daSSadaf Ebrahimi~~~ 161*f5c631daSSadaf Ebrahimi{ 162*f5c631daSSadaf Ebrahimi // Unique name for this input type. 163*f5c631daSSadaf Ebrahimi "name": "Register", 164*f5c631daSSadaf Ebrahimi // Python type from `test_generator.data_types` to use to generate C++ code 165*f5c631daSSadaf Ebrahimi // for this input. 166*f5c631daSSadaf Ebrahimi "type": "Register", 167*f5c631daSSadaf Ebrahimi // List of possible values. 168*f5c631daSSadaf Ebrahimi "values": [ 169*f5c631daSSadaf Ebrahimi "0x00000000", 170*f5c631daSSadaf Ebrahimi "0xffffffff", 171*f5c631daSSadaf Ebrahimi "0xabababab", 172*f5c631daSSadaf Ebrahimi "0x5a5a5a5a" 173*f5c631daSSadaf Ebrahimi ], 174*f5c631daSSadaf Ebrahimi // Default value. 175*f5c631daSSadaf Ebrahimi "default": "0xabababab" 176*f5c631daSSadaf Ebrahimi} 177*f5c631daSSadaf Ebrahimi~~~ 178*f5c631daSSadaf Ebrahimi 179*f5c631daSSadaf EbrahimiThe "name" field has the same purpose as for operands. The "type" field however, 180*f5c631daSSadaf Ebrahimiis the name of a Python class in `test_generator.data_types`. The type will 181*f5c631daSSadaf Ebrahimispecify what C++ code to generate in order to load and record the input value, 182*f5c631daSSadaf Ebrahimie.g. how to load a value into a register, how to read and record it. 183*f5c631daSSadaf Ebrahimi 184*f5c631daSSadaf EbrahimiWhen adding more tests, one may have to create new data types in this file. For 185*f5c631daSSadaf Ebrahimiexample, when we want to test an instruction with a different set of registers. 186*f5c631daSSadaf EbrahimiIf adding new input types which need different C++ code to load and record them, 187*f5c631daSSadaf Ebrahimione will have to add it to `test_generator.data_types` and override the 188*f5c631daSSadaf Ebrahimi`Epilogue` and `Prologue` methods. 189*f5c631daSSadaf Ebrahimi 190*f5c631daSSadaf EbrahimiTest configuration 191*f5c631daSSadaf Ebrahimi------------------ 192*f5c631daSSadaf Ebrahimi 193*f5c631daSSadaf EbrahimiOnce we have all the data types we need described, we need test configuration 194*f5c631daSSadaf Ebrahimifiles to describe what instructions to test and with what `inputs` and 195*f5c631daSSadaf Ebrahimi`operands` they take. 196*f5c631daSSadaf Ebrahimi 197*f5c631daSSadaf EbrahimiThese files have the following structure: 198*f5c631daSSadaf Ebrahimi 199*f5c631daSSadaf Ebrahimi~~~ 200*f5c631daSSadaf Ebrahimi{ 201*f5c631daSSadaf Ebrahimi "mnemonics": [ 202*f5c631daSSadaf Ebrahimi // List of instruction mnemonics to use. These must correspond to 203*f5c631daSSadaf Ebrahimi // `MacroAssembler` methods. 204*f5c631daSSadaf Ebrahimi ], 205*f5c631daSSadaf Ebrahimi "description": { 206*f5c631daSSadaf Ebrahimi "operands": [ 207*f5c631daSSadaf Ebrahimi // List of operands the instruction takes. 208*f5c631daSSadaf Ebrahimi ], 209*f5c631daSSadaf Ebrahimi "inputs: [ 210*f5c631daSSadaf Ebrahimi // List of inputs the instruction can be affected by. 211*f5c631daSSadaf Ebrahimi ] 212*f5c631daSSadaf Ebrahimi }, 213*f5c631daSSadaf Ebrahimi // List of files to generate. 214*f5c631daSSadaf Ebrahimi "test-files": [ 215*f5c631daSSadaf Ebrahimi { 216*f5c631daSSadaf Ebrahimi "type": "assembler", 217*f5c631daSSadaf Ebrahimi "mnemonics": [ 218*f5c631daSSadaf Ebrahimi // Optional list of instruction mnemonics to use, overriding the 219*f5c631daSSadaf Ebrahimi // top-level list. 220*f5c631daSSadaf Ebrahimi ], 221*f5c631daSSadaf Ebrahimi "test-cases": [ 222*f5c631daSSadaf Ebrahimi // List of test cases for "assembler" tests, see below for 223*f5c631daSSadaf Ebrahimi // details. 224*f5c631daSSadaf Ebrahimi ] 225*f5c631daSSadaf Ebrahimi }, 226*f5c631daSSadaf Ebrahimi { 227*f5c631daSSadaf Ebrahimi "type": "simulator", 228*f5c631daSSadaf Ebrahimi "test-cases": [ 229*f5c631daSSadaf Ebrahimi // List of test cases for "simulator" tests, see below for 230*f5c631daSSadaf Ebrahimi // details. 231*f5c631daSSadaf Ebrahimi ] 232*f5c631daSSadaf Ebrahimi } 233*f5c631daSSadaf Ebrahimi ] 234*f5c631daSSadaf Ebrahimi} 235*f5c631daSSadaf Ebrahimi~~~ 236*f5c631daSSadaf Ebrahimi 237*f5c631daSSadaf Ebrahimi- List of operands: 238*f5c631daSSadaf Ebrahimi 239*f5c631daSSadaf EbrahimiThe operand list describes the actual argument to the `MacroAssembler` method. 240*f5c631daSSadaf EbrahimiFor example, if we take instruction in the form 241*f5c631daSSadaf Ebrahimi"XXX.cond rd rn rm shift #amount": 242*f5c631daSSadaf Ebrahimi 243*f5c631daSSadaf EbrahimiWe want to generate C++ code as such: 244*f5c631daSSadaf Ebrahimi 245*f5c631daSSadaf Ebrahimi~~~ 246*f5c631daSSadaf EbrahimiCondition cond = ...; 247*f5c631daSSadaf EbrahimiRegister rd = ...; 248*f5c631daSSadaf EbrahimiRegister rn = ...; 249*f5c631daSSadaf EbrahimiRegister rm = ...; 250*f5c631daSSadaf EbrahimiShiftType type = ...; 251*f5c631daSSadaf Ebrahimiuint32_t amount = ...; 252*f5c631daSSadaf EbrahimiOperand op(rm, type, amount); 253*f5c631daSSadaf Ebrahimi 254*f5c631daSSadaf Ebrahimi__ Xxx(cond, rd, rn, op); 255*f5c631daSSadaf Ebrahimi~~~ 256*f5c631daSSadaf Ebrahimi 257*f5c631daSSadaf EbrahimiWe will have the following operand list: 258*f5c631daSSadaf Ebrahimi 259*f5c631daSSadaf Ebrahimi~~~ 260*f5c631daSSadaf Ebrahimi"operands": [ 261*f5c631daSSadaf Ebrahimi { 262*f5c631daSSadaf Ebrahimi "name": "cond", 263*f5c631daSSadaf Ebrahimi "type": "Condition" 264*f5c631daSSadaf Ebrahimi }, 265*f5c631daSSadaf Ebrahimi { 266*f5c631daSSadaf Ebrahimi "name": "rd", 267*f5c631daSSadaf Ebrahimi "type": "AllRegistersButPC" 268*f5c631daSSadaf Ebrahimi }, 269*f5c631daSSadaf Ebrahimi { 270*f5c631daSSadaf Ebrahimi "name": "rn", 271*f5c631daSSadaf Ebrahimi "type": "AllRegistersButPC" 272*f5c631daSSadaf Ebrahimi }, 273*f5c631daSSadaf Ebrahimi { 274*f5c631daSSadaf Ebrahimi "name": "op", 275*f5c631daSSadaf Ebrahimi "wrapper": "Operand", 276*f5c631daSSadaf Ebrahimi "operands": [ 277*f5c631daSSadaf Ebrahimi { 278*f5c631daSSadaf Ebrahimi "name": "rm", 279*f5c631daSSadaf Ebrahimi "operand": "AllRegistersButPC" 280*f5c631daSSadaf Ebrahimi }, 281*f5c631daSSadaf Ebrahimi { 282*f5c631daSSadaf Ebrahimi "name": "type", 283*f5c631daSSadaf Ebrahimi "operand": "Shift" 284*f5c631daSSadaf Ebrahimi }, 285*f5c631daSSadaf Ebrahimi { 286*f5c631daSSadaf Ebrahimi "name": "amount", 287*f5c631daSSadaf Ebrahimi "operand": "ImmediateShiftAmount" 288*f5c631daSSadaf Ebrahimi } 289*f5c631daSSadaf Ebrahimi ] 290*f5c631daSSadaf Ebrahimi } 291*f5c631daSSadaf Ebrahimi] 292*f5c631daSSadaf Ebrahimi~~~ 293*f5c631daSSadaf Ebrahimi 294*f5c631daSSadaf EbrahimiThe "name" field represents the identifier of the operand and will be used as a 295*f5c631daSSadaf Ebrahimivariable name in the generated code. The "type" field corresponds to an operand 296*f5c631daSSadaf Ebrahimitype described in the `data-types.json` file as described above. 297*f5c631daSSadaf Ebrahimi 298*f5c631daSSadaf EbrahimiWe can see that we've wrapped the last three operands into an "op" 299*f5c631daSSadaf Ebrahimiwrapper object. This allows us to tell the generator to wrap these 300*f5c631daSSadaf Ebrahimioperands into a `Operand` C++ object. 301*f5c631daSSadaf Ebrahimi 302*f5c631daSSadaf Ebrahimi- List of inputs: 303*f5c631daSSadaf Ebrahimi 304*f5c631daSSadaf EbrahimiThis structure is similar to the operand list, but this time it describes what 305*f5c631daSSadaf Ebrahimiinput data the instructions may be affected by at runtime. If we take the same 306*f5c631daSSadaf Ebrahimiexample as above, we will have the following list: 307*f5c631daSSadaf Ebrahimi 308*f5c631daSSadaf Ebrahimi~~~ 309*f5c631daSSadaf Ebrahimi"inputs": [ 310*f5c631daSSadaf Ebrahimi { 311*f5c631daSSadaf Ebrahimi "name": "apsr", 312*f5c631daSSadaf Ebrahimi "type": "NZCV" 313*f5c631daSSadaf Ebrahimi }, 314*f5c631daSSadaf Ebrahimi { 315*f5c631daSSadaf Ebrahimi "name": "rd", 316*f5c631daSSadaf Ebrahimi "type": "Register" 317*f5c631daSSadaf Ebrahimi }, 318*f5c631daSSadaf Ebrahimi { 319*f5c631daSSadaf Ebrahimi "name": "rn", 320*f5c631daSSadaf Ebrahimi "type": "Register" 321*f5c631daSSadaf Ebrahimi }, 322*f5c631daSSadaf Ebrahimi { 323*f5c631daSSadaf Ebrahimi "name": "rm", 324*f5c631daSSadaf Ebrahimi "type": "Register" 325*f5c631daSSadaf Ebrahimi } 326*f5c631daSSadaf Ebrahimi] 327*f5c631daSSadaf Ebrahimi~~~ 328*f5c631daSSadaf Ebrahimi 329*f5c631daSSadaf EbrahimiThis will specify what C++ code to generate before and after emitting the 330*f5c631daSSadaf Ebrahimiinstruction under test. The C++ code will set and record register values for 331*f5c631daSSadaf Ebrahimiexample. See `test_generator.data_types` for more details. 332*f5c631daSSadaf Ebrahimi 333*f5c631daSSadaf Ebrahimi- Test files and test cases: 334*f5c631daSSadaf Ebrahimi 335*f5c631daSSadaf EbrahimiUp until now, we've only just described the environment in which instructions 336*f5c631daSSadaf Ebrahimican operate. We need to express what files we want generating, what instructions 337*f5c631daSSadaf Ebrahimiwe want to test and what we want them to do. 338*f5c631daSSadaf Ebrahimi 339*f5c631daSSadaf EbrahimiAs previously mentioned, a configuration file can control the generation of 340*f5c631daSSadaf Ebrahimiseveral test files. We will generate one file per element in the "test-files" 341*f5c631daSSadaf Ebrahimiarray: 342*f5c631daSSadaf Ebrahimi 343*f5c631daSSadaf Ebrahimi~~~ 344*f5c631daSSadaf Ebrahimi"test-files": [ 345*f5c631daSSadaf Ebrahimi { 346*f5c631daSSadaf Ebrahimi "type": "assembler", 347*f5c631daSSadaf Ebrahimi "test-cases": [ 348*f5c631daSSadaf Ebrahimi // List of test cases for "assembler" tests, see below for 349*f5c631daSSadaf Ebrahimi // details. 350*f5c631daSSadaf Ebrahimi ] 351*f5c631daSSadaf Ebrahimi }, 352*f5c631daSSadaf Ebrahimi { 353*f5c631daSSadaf Ebrahimi "type": "assembler", 354*f5c631daSSadaf Ebrahimi "name": "special-case", 355*f5c631daSSadaf Ebrahimi "mnemonics": [ 356*f5c631daSSadaf Ebrahimi // Override the top-level list with a subset of instructions concerned 357*f5c631daSSadaf Ebrahimi // with this special case. 358*f5c631daSSadaf Ebrahimi ], 359*f5c631daSSadaf Ebrahimi "test-cases": [ 360*f5c631daSSadaf Ebrahimi // List of test cases for "assembler" tests, see below for 361*f5c631daSSadaf Ebrahimi // details. 362*f5c631daSSadaf Ebrahimi ] 363*f5c631daSSadaf Ebrahimi }, 364*f5c631daSSadaf Ebrahimi { 365*f5c631daSSadaf Ebrahimi "type": "simulator", 366*f5c631daSSadaf Ebrahimi "test-cases": [ 367*f5c631daSSadaf Ebrahimi // List of test cases for "simulator" tests, see below for 368*f5c631daSSadaf Ebrahimi // details. 369*f5c631daSSadaf Ebrahimi ] 370*f5c631daSSadaf Ebrahimi } 371*f5c631daSSadaf Ebrahimi] 372*f5c631daSSadaf Ebrahimi~~~ 373*f5c631daSSadaf Ebrahimi 374*f5c631daSSadaf EbrahimiAbove, we've decided to generate three tests: a "simulator" test and two 375*f5c631daSSadaf Ebrahimi"assembler" tests. The resulting files will have names with the following 376*f5c631daSSadaf Ebrahimipattern. 377*f5c631daSSadaf Ebrahimi 378*f5c631daSSadaf Ebrahimi - "test/aarch32/test-assembler-{configuration name}-a32.cc" 379*f5c631daSSadaf Ebrahimi - "test/aarch32/test-assembler-{configuration name}-special-case-a32.cc" 380*f5c631daSSadaf Ebrahimi - "test/aarch32/test-simulator-{configuration name}-a32.cc" 381*f5c631daSSadaf Ebrahimi 382*f5c631daSSadaf EbrahimiThe "type" field describes the kind of testing we want to do, these types are 383*f5c631daSSadaf Ebrahimirecognized by the generator and, at the moment, can be one of "simulator", 384*f5c631daSSadaf Ebrahimi"assembler", "macro-assembler" and "assembler-negative". Simulator tests will 385*f5c631daSSadaf Ebrahimirun each instruction and record the changes while assembler tests will only 386*f5c631daSSadaf Ebrahimirecord the code buffer and never execute anything. MacroAssembler tests 387*f5c631daSSadaf Ebrahimicurrently only generate code to check that the MacroAssembler does not crash; 388*f5c631daSSadaf Ebrahimithe output itself is not yet tested. Because you may want to generate more than 389*f5c631daSSadaf Ebrahimione test of the same type, as we are doing in the example, we need a way to 390*f5c631daSSadaf Ebrahimidifferentiate them. You may use the optional "name" field for this. Negative 391*f5c631daSSadaf Ebrahimiassembler tests check that the instructions described are not allowed, which 392*f5c631daSSadaf Ebrahimimeans that an exception is raised when VIXL is built in negative testing mode. 393*f5c631daSSadaf Ebrahimi 394*f5c631daSSadaf EbrahimiFinally, we describe how to test the instruction by declaring a list of test 395*f5c631daSSadaf Ebrahimicases with the "test-cases" field. 396*f5c631daSSadaf Ebrahimi 397*f5c631daSSadaf EbrahimiHere is an example of what we can express: 398*f5c631daSSadaf Ebrahimi~~~ 399*f5c631daSSadaf Ebrahimi[ 400*f5c631daSSadaf Ebrahimi // Generate all combinations of instructions where "rd" an "rn" are the same 401*f5c631daSSadaf Ebrahimi // register and "cond" and "rm" are just the default. 402*f5c631daSSadaf Ebrahimi // For example: 403*f5c631daSSadaf Ebrahimi // __ Xxx(al, r0, r0, r0); 404*f5c631daSSadaf Ebrahimi // __ Xxx(al, r1, r1, r0); 405*f5c631daSSadaf Ebrahimi // __ Xxx(al, r2, r2, r0); 406*f5c631daSSadaf Ebrahimi // ... 407*f5c631daSSadaf Ebrahimi // __ Xxx(al, r12, r12, r0); 408*f5c631daSSadaf Ebrahimi // __ Xxx(al, r13, r13, r0); 409*f5c631daSSadaf Ebrahimi // __ Xxx(al, r14, r14, r0); 410*f5c631daSSadaf Ebrahimi // 411*f5c631daSSadaf Ebrahimi // For each of the instructions above, run them with a different value in "rd" 412*f5c631daSSadaf Ebrahimi // and "rn". 413*f5c631daSSadaf Ebrahimi { 414*f5c631daSSadaf Ebrahimi "name": "RdIsRn", 415*f5c631daSSadaf Ebrahimi "operands": [ 416*f5c631daSSadaf Ebrahimi "rd", "rn" 417*f5c631daSSadaf Ebrahimi ], 418*f5c631daSSadaf Ebrahimi "operand-filter": "rd == rn", 419*f5c631daSSadaf Ebrahimi "inputs": [ 420*f5c631daSSadaf Ebrahimi "rd", "rn" 421*f5c631daSSadaf Ebrahimi ], 422*f5c631daSSadaf Ebrahimi "input-filter": "rd == rn" 423*f5c631daSSadaf Ebrahimi }, 424*f5c631daSSadaf Ebrahimi // Generate all combinations of instructions with different condition codes. 425*f5c631daSSadaf Ebrahimi // For example: 426*f5c631daSSadaf Ebrahimi // __ Xxx(eq, r0, r0, r0); 427*f5c631daSSadaf Ebrahimi // __ Xxx(ne, r0, r0, r0); 428*f5c631daSSadaf Ebrahimi // __ Xxx(cs, r0, r0, r0); 429*f5c631daSSadaf Ebrahimi // ... 430*f5c631daSSadaf Ebrahimi // __ Xxx(gt, r0, r0, r0); 431*f5c631daSSadaf Ebrahimi // __ Xxx(le, r0, r0, r0); 432*f5c631daSSadaf Ebrahimi // __ Xxx(al, r0, r0, r0); 433*f5c631daSSadaf Ebrahimi // 434*f5c631daSSadaf Ebrahimi // For each of the instructions above, run them against all combinations of 435*f5c631daSSadaf Ebrahimi // NZCV bits. 436*f5c631daSSadaf Ebrahimi { 437*f5c631daSSadaf Ebrahimi "name": "ConditionVersusNZCV", 438*f5c631daSSadaf Ebrahimi "operands": [ 439*f5c631daSSadaf Ebrahimi "cond" 440*f5c631daSSadaf Ebrahimi ], 441*f5c631daSSadaf Ebrahimi "inputs": [ 442*f5c631daSSadaf Ebrahimi "apsr" 443*f5c631daSSadaf Ebrahimi ] 444*f5c631daSSadaf Ebrahimi }, 445*f5c631daSSadaf Ebrahimi // We are interested in testing that the Q bit gets set and cleared, so we've 446*f5c631daSSadaf Ebrahimi // limited the instruction generation to a single instruction and instead have 447*f5c631daSSadaf Ebrahimi // stressed the values put in "rn" and "rm". 448*f5c631daSSadaf Ebrahimi // 449*f5c631daSSadaf Ebrahimi // So for this instruction, we choose to run it will all combinations of 450*f5c631daSSadaf Ebrahimi // values in "rn" and "rm". Additionally, we include "qbit" in the inputs, 451*f5c631daSSadaf Ebrahimi // which will make the test set or clear it before executing the instruction. 452*f5c631daSSadaf Ebrahimi // Note that "qbit" needs to be declared as an input in the instruction 453*f5c631daSSadaf Ebrahimi // description (see "List of inputs" section). 454*f5c631daSSadaf Ebrahimi { 455*f5c631daSSadaf Ebrahimi "name": "Qbit", 456*f5c631daSSadaf Ebrahimi "operands": [ 457*f5c631daSSadaf Ebrahimi "rn", "rm" 458*f5c631daSSadaf Ebrahimi ], 459*f5c631daSSadaf Ebrahimi "inputs": [ 460*f5c631daSSadaf Ebrahimi "qbit", "rn", "rm" 461*f5c631daSSadaf Ebrahimi ], 462*f5c631daSSadaf Ebrahimi "operand-filter": "rn != rm'", 463*f5c631daSSadaf Ebrahimi "operand-limit": 1 464*f5c631daSSadaf Ebrahimi }, 465*f5c631daSSadaf Ebrahimi // Generate 10 random instructions with all different registers but use the 466*f5c631daSSadaf Ebrahimi // default condition. 467*f5c631daSSadaf Ebrahimi // For example: 468*f5c631daSSadaf Ebrahimi // __ Xxx(al, r5, r1, r0); 469*f5c631daSSadaf Ebrahimi // __ Xxx(al, r8, r9, r7); 470*f5c631daSSadaf Ebrahimi // __ Xxx(al, r9, r1, r2); 471*f5c631daSSadaf Ebrahimi // __ Xxx(al, r0, r6, r2); 472*f5c631daSSadaf Ebrahimi // __ Xxx(al, r11, r9, r11); 473*f5c631daSSadaf Ebrahimi // __ Xxx(al, r14, r2, r11); 474*f5c631daSSadaf Ebrahimi // __ Xxx(al, r8, r2, r5); 475*f5c631daSSadaf Ebrahimi // __ Xxx(al, r10, r0, r1); 476*f5c631daSSadaf Ebrahimi // __ Xxx(al, r11, r2, r7); 477*f5c631daSSadaf Ebrahimi // __ Xxx(al, r2, r6, r1); 478*f5c631daSSadaf Ebrahimi // 479*f5c631daSSadaf Ebrahimi // For each instruction, feed it 200 different combination of values in the 480*f5c631daSSadaf Ebrahimi // three registers. 481*f5c631daSSadaf Ebrahimi { 482*f5c631daSSadaf Ebrahimi "name": "RegisterSimulatorTest", 483*f5c631daSSadaf Ebrahimi "operands": [ 484*f5c631daSSadaf Ebrahimi "rd", "rn", "rm" 485*f5c631daSSadaf Ebrahimi ], 486*f5c631daSSadaf Ebrahimi "inputs": [ 487*f5c631daSSadaf Ebrahimi "rd", "rn", "rm" 488*f5c631daSSadaf Ebrahimi ], 489*f5c631daSSadaf Ebrahimi "operand-limit": 10, 490*f5c631daSSadaf Ebrahimi "input-limit": 200 491*f5c631daSSadaf Ebrahimi } 492*f5c631daSSadaf Ebrahimi] 493*f5c631daSSadaf Ebrahimi~~~ 494*f5c631daSSadaf Ebrahimi 495*f5c631daSSadaf EbrahimiAssembler test cases are much simpler, here are some examples: 496*f5c631daSSadaf Ebrahimi~~~ 497*f5c631daSSadaf Ebrahimi// Generate 2000 random instructions out of all possible operand combinations. 498*f5c631daSSadaf Ebrahimi{ 499*f5c631daSSadaf Ebrahimi "name": "LotsOfRandomInstructions", 500*f5c631daSSadaf Ebrahimi "operands": [ 501*f5c631daSSadaf Ebrahimi "cond", "rd", "rn", "rm" 502*f5c631daSSadaf Ebrahimi ], 503*f5c631daSSadaf Ebrahimi "operand-limit": 2000 504*f5c631daSSadaf Ebrahimi}, 505*f5c631daSSadaf Ebrahimi// Same as above but limit the test to 200 instructions where rd == rn. 506*f5c631daSSadaf Ebrahimi{ 507*f5c631daSSadaf Ebrahimi "name": "RdIsRn", 508*f5c631daSSadaf Ebrahimi "operands": [ 509*f5c631daSSadaf Ebrahimi "cond", "rd", "rn", "rm" 510*f5c631daSSadaf Ebrahimi ], 511*f5c631daSSadaf Ebrahimi "operand-filter": "rd == rn", 512*f5c631daSSadaf Ebrahimi "operand-limit": 200 513*f5c631daSSadaf Ebrahimi} 514*f5c631daSSadaf Ebrahimi~~~ 515*f5c631daSSadaf Ebrahimi 516*f5c631daSSadaf EbrahimiAs can be expected, assembler test do not have the notion of "inputs". 517*f5c631daSSadaf Ebrahimi 518*f5c631daSSadaf EbrahimiHere are details about each field. Note that all of them except for "name" are 519*f5c631daSSadaf Ebrahimioptional. 520*f5c631daSSadaf Ebrahimi 521*f5c631daSSadaf Ebrahimi * "name": 522*f5c631daSSadaf Ebrahimi 523*f5c631daSSadaf Ebrahimi A unique name should be given to the test case, it will be used to give the 524*f5c631daSSadaf Ebrahimi generated C++ `const Input[]` array a name. 525*f5c631daSSadaf Ebrahimi 526*f5c631daSSadaf Ebrahimi * "operands": 527*f5c631daSSadaf Ebrahimi 528*f5c631daSSadaf Ebrahimi List of operand names that we are interested in testing. The generator will 529*f5c631daSSadaf Ebrahimi lookup the list of variants for each operand and build the product of all of 530*f5c631daSSadaf Ebrahimi them. It will then choose the default variant for the operands not specified 531*f5c631daSSadaf Ebrahimi here. 532*f5c631daSSadaf Ebrahimi 533*f5c631daSSadaf Ebrahimi * "operand-filter": 534*f5c631daSSadaf Ebrahimi 535*f5c631daSSadaf Ebrahimi As you would expect, the product of all operand variants may be huge. To 536*f5c631daSSadaf Ebrahimi prevent this, you may specify a Python expression to filter the list. 537*f5c631daSSadaf Ebrahimi 538*f5c631daSSadaf Ebrahimi * "operand-limit": 539*f5c631daSSadaf Ebrahimi 540*f5c631daSSadaf Ebrahimi We can potentially obtain a *massive* set of variants of instructions, as we 541*f5c631daSSadaf Ebrahimi are computing a product of operand variants in "operands". This field allows 542*f5c631daSSadaf Ebrahimi us to limit this by choosing a random sample from the computed variants. 543*f5c631daSSadaf Ebrahimi Note that this is a seeded pseudo-random sample, and the seed corresponds to 544*f5c631daSSadaf Ebrahimi the test case description. The same test case description will always 545*f5c631daSSadaf Ebrahimi generate the same code. 546*f5c631daSSadaf Ebrahimi 547*f5c631daSSadaf Ebrahimi * "inputs": 548*f5c631daSSadaf Ebrahimi 549*f5c631daSSadaf Ebrahimi This is exactly the same as "operands" but for inputs. 550*f5c631daSSadaf Ebrahimi 551*f5c631daSSadaf Ebrahimi * "input-filter": 552*f5c631daSSadaf Ebrahimi 553*f5c631daSSadaf Ebrahimi Ditto. 554*f5c631daSSadaf Ebrahimi 555*f5c631daSSadaf Ebrahimi * "input-limit": 556*f5c631daSSadaf Ebrahimi 557*f5c631daSSadaf Ebrahimi Ditto. 558*f5c631daSSadaf Ebrahimi 559*f5c631daSSadaf EbrahimiHere is an example of the C++ code that will be generated for a given test case. 560*f5c631daSSadaf EbrahimiFor simplicity, let's generate tests for an instruction with only `NZCV` and two 561*f5c631daSSadaf Ebrahimiregisters as inputs. 562*f5c631daSSadaf Ebrahimi 563*f5c631daSSadaf EbrahimiFor the following test case, which will target encodings where `rd` and `rn` are 564*f5c631daSSadaf Ebrahimithe same registers: 565*f5c631daSSadaf Ebrahimi 566*f5c631daSSadaf Ebrahimi~~~ 567*f5c631daSSadaf Ebrahimi{ 568*f5c631daSSadaf Ebrahimi "name": "RdIsRn", 569*f5c631daSSadaf Ebrahimi "operands": [ 570*f5c631daSSadaf Ebrahimi "rd", "rn" 571*f5c631daSSadaf Ebrahimi ], 572*f5c631daSSadaf Ebrahimi "operand-filter": "rd == rn", 573*f5c631daSSadaf Ebrahimi "inputs": [ 574*f5c631daSSadaf Ebrahimi "rd", "rn" 575*f5c631daSSadaf Ebrahimi ], 576*f5c631daSSadaf Ebrahimi "input-filter": "rd == rn" 577*f5c631daSSadaf Ebrahimi}, 578*f5c631daSSadaf Ebrahimi~~~ 579*f5c631daSSadaf Ebrahimi 580*f5c631daSSadaf EbrahimiIt will generate the following input array. 581*f5c631daSSadaf Ebrahimi 582*f5c631daSSadaf Ebrahimi~~~ 583*f5c631daSSadaf Ebrahimi// apsr, rd, rn 584*f5c631daSSadaf Ebrahimistatic const Inputs kRdIsRn[] = {{NoFlag, 0x00000000, 0x00000000}, 585*f5c631daSSadaf Ebrahimi {NoFlag, 0xffffffff, 0xffffffff}, 586*f5c631daSSadaf Ebrahimi {NoFlag, 0xabababab, 0xabababab}, 587*f5c631daSSadaf Ebrahimi {NoFlag, 0x5a5a5a5a, 0x5a5a5a5a}}; 588*f5c631daSSadaf Ebrahimi~~~ 589*f5c631daSSadaf Ebrahimi 590*f5c631daSSadaf EbrahimiWe can see that the default apsr value was chosen (NoFlag), as apsr is not in 591*f5c631daSSadaf Ebrahimithe list of "inputs". 592*f5c631daSSadaf Ebrahimi 593*f5c631daSSadaf EbrahimiIt will also generate a list of instructions to test: 594*f5c631daSSadaf Ebrahimi 595*f5c631daSSadaf Ebrahimi~~~ 596*f5c631daSSadaf Ebrahimistatic const TestLoopData kTests[] = { 597*f5c631daSSadaf Ebrahimi {{al, r1, r1, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"}, 598*f5c631daSSadaf Ebrahimi {{al, r2, r2, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"}, 599*f5c631daSSadaf Ebrahimi {{al, r8, r8, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"}, 600*f5c631daSSadaf Ebrahimi {{al, r9, r9, 0x000000ab}, ARRAY_SIZE(kRdIsRn), kRdIsRn, "RdIsRn"}, 601*f5c631daSSadaf Ebrahimi}; 602*f5c631daSSadaf Ebrahimi~~~ 603*f5c631daSSadaf Ebrahimi 604*f5c631daSSadaf EbrahimiAs a result, the new test we will assemble each instructions in "mnemonics" with 605*f5c631daSSadaf Ebrahimiall of the operands described in `kTests` above. And each instruction will be 606*f5c631daSSadaf Ebrahimiexecuted and passed all inputs in `kRdIsRn`. 607*f5c631daSSadaf Ebrahimi""" 608*f5c631daSSadaf Ebrahimi 609*f5c631daSSadaf Ebrahimiimport subprocess 610*f5c631daSSadaf Ebrahimiimport argparse 611*f5c631daSSadaf Ebrahimiimport string 612*f5c631daSSadaf Ebrahimiimport re 613*f5c631daSSadaf Ebrahimiimport multiprocessing 614*f5c631daSSadaf Ebrahimiimport functools 615*f5c631daSSadaf Ebrahimi 616*f5c631daSSadaf Ebrahimiimport test_generator.parser 617*f5c631daSSadaf Ebrahimi 618*f5c631daSSadaf Ebrahimi 619*f5c631daSSadaf Ebrahimidefault_config_files = [ 620*f5c631daSSadaf Ebrahimi # A32 and T32 tests 621*f5c631daSSadaf Ebrahimi 'test/aarch32/config/rd-rn-rm.json', 622*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-dt-drt-drd-drn-drm-float.json', 623*f5c631daSSadaf Ebrahimi 624*f5c631daSSadaf Ebrahimi # A32 specific tests 625*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-const-a32.json', 626*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-a32.json', 627*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to31-a32.json', 628*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to32-a32.json', 629*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-shift-rs-a32.json', 630*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-ror-amount-a32.json', 631*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-a32.json', 632*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-pc-a32.json', 633*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-rm-a32.json', 634*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-const-a32.json', 635*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-a32.json', 636*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to31-a32.json', 637*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to32-a32.json', 638*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-rs-a32.json', 639*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-ror-amount-a32.json', 640*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-memop-immediate-512-a32.json', 641*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-memop-immediate-8192-a32.json', 642*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-memop-rs-a32.json', 643*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-memop-rs-shift-amount-1to31-a32.json', 644*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-memop-rs-shift-amount-1to32-a32.json', 645*f5c631daSSadaf Ebrahimi 646*f5c631daSSadaf Ebrahimi # T32 specific tests 647*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-t32.json', 648*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-rm-t32.json', 649*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rdlow-rnlow-rmlow-t32.json', 650*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-const-t32.json', 651*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-pc-operand-imm12-t32.json', 652*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-imm12-t32.json', 653*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-pc-operand-imm8-t32.json', 654*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-sp-operand-imm8-t32.json', 655*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rdlow-rnlow-operand-immediate-t32.json', 656*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-sp-sp-operand-imm7-t32.json', 657*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-t32.json', 658*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to31-t32.json', 659*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-shift-amount-1to32-t32.json', 660*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-rn-operand-rm-ror-amount-t32.json', 661*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-const-t32.json', 662*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-imm16-t32.json', 663*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rdlow-operand-imm8-t32.json', 664*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to31-t32.json', 665*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-amount-1to32-t32.json', 666*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-shift-rs-t32.json', 667*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-ror-amount-t32.json', 668*f5c631daSSadaf Ebrahimi 'test/aarch32/config/cond-rd-operand-rn-t32.json', 669*f5c631daSSadaf Ebrahimi] 670*f5c631daSSadaf Ebrahimi 671*f5c631daSSadaf Ebrahimi 672*f5c631daSSadaf Ebrahimi# Link a test type with a template file. 673*f5c631daSSadaf Ebrahimitemplate_files = { 674*f5c631daSSadaf Ebrahimi 'simulator': "test/aarch32/config/template-simulator-aarch32.cc.in", 675*f5c631daSSadaf Ebrahimi 'assembler': "test/aarch32/config/template-assembler-aarch32.cc.in", 676*f5c631daSSadaf Ebrahimi 'macro-assembler': "test/aarch32/config/template-macro-assembler-aarch32.cc.in", 677*f5c631daSSadaf Ebrahimi 'assembler-negative': "test/aarch32/config/template-assembler-negative-aarch32.cc.in", 678*f5c631daSSadaf Ebrahimi} 679*f5c631daSSadaf Ebrahimi 680*f5c631daSSadaf Ebrahimi 681*f5c631daSSadaf Ebrahimidef BuildOptions(): 682*f5c631daSSadaf Ebrahimi result = argparse.ArgumentParser( 683*f5c631daSSadaf Ebrahimi description = 'Test generator for AArch32.', 684*f5c631daSSadaf Ebrahimi formatter_class=argparse.ArgumentDefaultsHelpFormatter) 685*f5c631daSSadaf Ebrahimi result.add_argument('--config-files', nargs='+', 686*f5c631daSSadaf Ebrahimi default=default_config_files, 687*f5c631daSSadaf Ebrahimi metavar='FILE', 688*f5c631daSSadaf Ebrahimi help='Configuration files, each will generate a test file.') 689*f5c631daSSadaf Ebrahimi result.add_argument('--clang-format', 690*f5c631daSSadaf Ebrahimi default='clang-format-4.0', help='Path to clang-format.') 691*f5c631daSSadaf Ebrahimi result.add_argument('--jobs', '-j', type=int, metavar='N', 692*f5c631daSSadaf Ebrahimi default=multiprocessing.cpu_count(), 693*f5c631daSSadaf Ebrahimi help='Allow N jobs at once') 694*f5c631daSSadaf Ebrahimi result.add_argument('--skip-traces', action='store_true', 695*f5c631daSSadaf Ebrahimi help='Skip generation of placeholder traces.') 696*f5c631daSSadaf Ebrahimi return result.parse_args() 697*f5c631daSSadaf Ebrahimi 698*f5c631daSSadaf Ebrahimi 699*f5c631daSSadaf Ebrahimidef DoNotEditComment(template_file): 700*f5c631daSSadaf Ebrahimi # We rely on `clang-format` to wrap this comment to 80 characters. 701*f5c631daSSadaf Ebrahimi return """ 702*f5c631daSSadaf Ebrahimi// ----------------------------------------------------------------------------- 703*f5c631daSSadaf Ebrahimi// This file is auto generated from the {} template file using tools/generate_tests.py. 704*f5c631daSSadaf Ebrahimi// 705*f5c631daSSadaf Ebrahimi// PLEASE DO NOT EDIT. 706*f5c631daSSadaf Ebrahimi// ----------------------------------------------------------------------------- 707*f5c631daSSadaf Ebrahimi """.format(template_file) 708*f5c631daSSadaf Ebrahimi 709*f5c631daSSadaf Ebrahimidef GenerateTest(generator, clang_format, skip_traces): 710*f5c631daSSadaf Ebrahimi template_file = template_files[generator.test_type] 711*f5c631daSSadaf Ebrahimi generated_file = "" 712*f5c631daSSadaf Ebrahimi with open(template_file, "r") as f: 713*f5c631daSSadaf Ebrahimi # Strip out comments starting with three forward slashes before creating the 714*f5c631daSSadaf Ebrahimi # string.Template object. 715*f5c631daSSadaf Ebrahimi template = string.Template(re.sub("\/\/\/.*", "", f.read())) 716*f5c631daSSadaf Ebrahimi 717*f5c631daSSadaf Ebrahimi # The `generator` object has methods generating strings to fill the template. 718*f5c631daSSadaf Ebrahimi generated_file = template.substitute({ 719*f5c631daSSadaf Ebrahimi # Add a top comment stating this file is auto-generated. 720*f5c631daSSadaf Ebrahimi 'do_not_edit_comment': DoNotEditComment(template_file), 721*f5c631daSSadaf Ebrahimi 722*f5c631daSSadaf Ebrahimi # List of mnemonics. 723*f5c631daSSadaf Ebrahimi 'instruction_list_declaration': generator.InstructionListDeclaration(), 724*f5c631daSSadaf Ebrahimi 725*f5c631daSSadaf Ebrahimi # Declarations. 726*f5c631daSSadaf Ebrahimi 'operand_list_declaration': generator.OperandDeclarations(), 727*f5c631daSSadaf Ebrahimi 'input_declarations': generator.InputDeclarations(), 728*f5c631daSSadaf Ebrahimi 729*f5c631daSSadaf Ebrahimi # Definitions. 730*f5c631daSSadaf Ebrahimi 'input_definitions': generator.InputDefinitions(), 731*f5c631daSSadaf Ebrahimi 'test_case_definitions': generator.TestCaseDefinitions(), 732*f5c631daSSadaf Ebrahimi 733*f5c631daSSadaf Ebrahimi # Include traces. 734*f5c631daSSadaf Ebrahimi 'include_trace_files': generator.IncludeTraceFiles(), 735*f5c631daSSadaf Ebrahimi 736*f5c631daSSadaf Ebrahimi # Define a typedef for the MacroAssembler method. 737*f5c631daSSadaf Ebrahimi 'macroassembler_method_args': generator.MacroAssemblerMethodArgs(), 738*f5c631daSSadaf Ebrahimi 739*f5c631daSSadaf Ebrahimi # Generate code to switch instruction set. 740*f5c631daSSadaf Ebrahimi 'macroassembler_set_isa': generator.MacroAssemblerSetISA(), 741*f5c631daSSadaf Ebrahimi 742*f5c631daSSadaf Ebrahimi # Generate code to emit instructions. 743*f5c631daSSadaf Ebrahimi 'code_instantiate_operands': generator.CodeInstantiateOperands(), 744*f5c631daSSadaf Ebrahimi 'code_prologue': generator.CodePrologue(), 745*f5c631daSSadaf Ebrahimi 'code_epilogue': generator.CodeEpilogue(), 746*f5c631daSSadaf Ebrahimi 'code_parameter_list': generator.CodeParameterList(), 747*f5c631daSSadaf Ebrahimi 748*f5c631daSSadaf Ebrahimi # Generate code to trace the execution and print C++. 749*f5c631daSSadaf Ebrahimi 'trace_print_outputs': generator.TracePrintOutputs(), 750*f5c631daSSadaf Ebrahimi 751*f5c631daSSadaf Ebrahimi # Generate code to compare the results against a trace. 752*f5c631daSSadaf Ebrahimi 'check_instantiate_results': generator.CheckInstantiateResults(), 753*f5c631daSSadaf Ebrahimi 'check_instantiate_inputs': generator.CheckInstantiateInputs(), 754*f5c631daSSadaf Ebrahimi 'check_instantiate_references': generator.CheckInstantiateReferences(), 755*f5c631daSSadaf Ebrahimi 'check_results_against_references': 756*f5c631daSSadaf Ebrahimi generator.CheckResultsAgainstReferences(), 757*f5c631daSSadaf Ebrahimi 'check_print_input': generator.CheckPrintInput(), 758*f5c631daSSadaf Ebrahimi 'check_print_expected': generator.CheckPrintExpected(), 759*f5c631daSSadaf Ebrahimi 'check_print_found': generator.CheckPrintFound(), 760*f5c631daSSadaf Ebrahimi 761*f5c631daSSadaf Ebrahimi 'test_isa': generator.TestISA(), 762*f5c631daSSadaf Ebrahimi 'test_name': generator.TestName(), 763*f5c631daSSadaf Ebrahimi 'isa_guard': generator.GetIsaGuard() 764*f5c631daSSadaf Ebrahimi }) 765*f5c631daSSadaf Ebrahimi # Create the test case and pipe it through `clang-format` before writing it. 766*f5c631daSSadaf Ebrahimi with open( 767*f5c631daSSadaf Ebrahimi "test/aarch32/test-{}-{}-{}.cc".format(generator.test_type, 768*f5c631daSSadaf Ebrahimi generator.test_name, 769*f5c631daSSadaf Ebrahimi generator.test_isa), 770*f5c631daSSadaf Ebrahimi "w") as f: 771*f5c631daSSadaf Ebrahimi proc = subprocess.Popen([clang_format], stdin=subprocess.PIPE, 772*f5c631daSSadaf Ebrahimi stdout=subprocess.PIPE) 773*f5c631daSSadaf Ebrahimi out, _ = proc.communicate(generated_file.encode()) 774*f5c631daSSadaf Ebrahimi f.write(out.decode()) 775*f5c631daSSadaf Ebrahimi if not skip_traces: 776*f5c631daSSadaf Ebrahimi # Write placeholder trace files into 'test/aarch32/traces/'. 777*f5c631daSSadaf Ebrahimi generator.WriteEmptyTraces("test/aarch32/traces/") 778*f5c631daSSadaf Ebrahimi print("Generated {} {} test for \"{}\".".format(generator.test_isa.upper(), 779*f5c631daSSadaf Ebrahimi generator.test_type, 780*f5c631daSSadaf Ebrahimi generator.test_name)) 781*f5c631daSSadaf Ebrahimi 782*f5c631daSSadaf Ebrahimiif __name__ == '__main__': 783*f5c631daSSadaf Ebrahimi args = BuildOptions() 784*f5c631daSSadaf Ebrahimi 785*f5c631daSSadaf Ebrahimi # Each file in `args.config_files` populates a `Generator` object. 786*f5c631daSSadaf Ebrahimi generators = test_generator.parser.Parse('test/aarch32/config/data-types.json', 787*f5c631daSSadaf Ebrahimi args.config_files) 788*f5c631daSSadaf Ebrahimi 789*f5c631daSSadaf Ebrahimi # Call the `GenerateTest` function for each generator object in parallel. This 790*f5c631daSSadaf Ebrahimi # will use as many processes as defined by `-jN`, which defaults to 1. 791*f5c631daSSadaf Ebrahimi with multiprocessing.Pool(processes=args.jobs) as pool: 792*f5c631daSSadaf Ebrahimi pool.map(functools.partial(GenerateTest, clang_format=args.clang_format, 793*f5c631daSSadaf Ebrahimi skip_traces=args.skip_traces), 794*f5c631daSSadaf Ebrahimi generators) 795