User templates

Some users need user-specific decoder codes or some codes to support decoders like constant tables. The mcdecoder allows users to define user-specific code templates to generate those codes. This is called user templates.

To use user templates, follow the steps below:

  1. Add user-defined data to an MC description

  2. Create user-defined template files

  3. Generate codes with the created template

Here’s a tutorial for user templates.

1. Add user-defined data to an MC description

First, you may need to add some user-specific data to your MC description file. If you don’t need any additional information than MC description specification, you can skip this step. You can use extras or field_extras to define user-defined data. They take any structure, so you can define the structure of your own. See MC description specification for more details.

Make arm.yaml that contains the following content.

arm.yaml
machine:
  byteorder: little
  extras:
    # User-defined data for the machine
    arch_type: arm
instructions:
  - name: add_1
    format: xxxx:cond|00|1|0100|x:S|xxxx:Rn|xxxx:Rd|xxxx xxxx xxxx:imm12
    extras:
      # User-defined data for the instruction 'add_1'
      clocks: 10
    field_extras:
      Rn: {type: register} # User-defined data for the field 'Rn'
      Rd: {type: register} # User-defined data for the field 'Rd'
      imm12: {type: immediate} # User-defined data for the field 'imm12'
  - name: push_1
    format: xxxx:cond|1001 00|1|0|1101|xxxx xxxx xxxx xxxx:register_list
    # No user-defined data are defined for the instruction 'push_1'
decoder:
  namespace: arm
extras:
  # User-defined data for the global scope
  compiler: gcc

2. Create user-defined template files

Second, you must define user-defined templates. The mcdecoder uses Jinja2 syntax for templates. See Template Designer Documentation to understand the template syntax.

You can use template variables in your template, such as instruction_decoders (decoder information about instructions) or ns (namespace prefix) to access information about decoders and user-defined data. See Template variable specification for more details.

You need to make a directory and put your template files in it. Generated files will have the same names as those of template files. If you use template variables in the names of template files, the names will be generated in the same way as the contents of generated files.

This time, make templates directory and create the following template files.

templates/{{ns}}constants.h
{# Example usage of user-defined data for the global scope and the machine #}
/*
 * This file is generated for:
 *   - Compiler: {{ extras.compiler }}
 *   - Architecture: {{ machine.extras.arch_type }}
 */

{%- for inst in instructions -%}
    {%- for field in inst.fields -%}
        {# Example usage of user-defined data for fields #}
        {# Check if the attribute 'type' exists #}
        {%- if field.extras.type -%}
            #define FIELD_REG_TYPE_{{ inst.name }}_{{ field.name }} "{{field.extras.type}}"
        {%- endif -%}
    {%- endfor %}
{%- endfor -%}

extern uint8 CLOCKS[];
templates/{{ns}}constants.c
{# Example usage of user-defined data for the global scope and the machine #}
/*
 * This file is generated for:
 *   - Compiler: {{ extras.compiler }}
 *   - Architecture: {{ machine.extras.arch_type }}
 */
#include "{{ ns }}constants.h"

const uint8 CLOCKS[] = {
    {%- for inst in instructions -%}
        {# Example usage of user-defined data for instructions #}
        {# Check if the attribute 'clocks' exists #}
        {%- if inst.extras.clocks -%}
            {{ inst.extras.clocks }}, /* {{ inst.name }} */
        {%- else -%}
            0, /* {{ inst.name }} */
        {%- endif -%}
    {%- endfor %}
};

3. Generate codes with the created template

Finally, you must run a command to generate with the template. Use mcdecoder generate command and --template option to specify the template. See Command line option specification for more details.

Run the command below:

mcdecoder generate --template templates --output out arm.yaml

And the generated files will be:

out/arm_constants.h

/*
 * This file is generated for:
 *   - Compiler: gcc
 *   - Architecture: arm
 */
        
        
        #define FIELD_REG_TYPE_add_1_Rn "register"
        #define FIELD_REG_TYPE_add_1_Rd "register"
        #define FIELD_REG_TYPE_add_1_imm12 "immediate"
        
        extern uint8 CLOCKS[];
out/arm_constants.c

/*
 * This file is generated for:
 *   - Compiler: gcc
 *   - Architecture: arm
 */
#include "arm_constants.h"

const uint8 CLOCKS[] = {
        10, /* add_1 */
        0, /* push_1 */
};

You can see example files in this tutorial in github.

What’s next?