How to add custom instructions (ISE) to Trimaran
This guide is incomplete at the moment. With the project evolving, more comprehensive and detailed instructions will be gradually patched. Currently, only custom instructions up to 4 inputs and 4 outputs are supported, with minimum modification to the original Trimaran code.1. Generate custom instructions in Elcor.
This step involves adding an extra stage to Elcor, before instruction scheduling and register allocation stages, in order to identify suitable subgraphs for custom instructions, and then replace the subgraphs with custom operations.
ISE identification code is under elcor/src/ISE.
Other files to be modified:
elcor/src/Graph:
opcode.h: define the opcode. In enum type IR_ROOT_OPCODE, define a new root opcode:
ROOT_CUSTOM32 = 191,
In enum type Opcode, define a new opcode in terms of root opcode:
CUSTOM32_W = ROOT_CUSTOM32,
opcode.cpp: Instruction name (a string) and its opcode (a macro value) should be bounded in two maps el_string_to_opcode_map and el_opcode_to_string_map, in one of the map initialization functions. Here, we add custom instruction bounding in el_init_elcor_opcode_maps_arithmetic():
el_string_to_opcode_map.bind("CUSTOM32_W", CUSTOM32_W);
el_opcode_to_string_map.bind(CUSTOM32_W, "CUSTOM32_W");
elcor/src/Main:
el_driver_init.cpp: insert a global switch variable "El_do_custom_instruction = 1;" to turn on/off ISE phase.
processor_function.cpp: Insert "#include "ise_main.h" " at the beginning, which provides definitions of functions of the ISE code.
Insert a call to "ise_main(f);" before instruction scheduling function "El_collect_pre_processing_stats(f);" to enter the ISE phase.
Modify GNUmakdfile under elcor/src in order to find the ISE code and produce corresponding libraries for ISE.
Modify elcor/includes/makelinks, add links to header files of the ISE code. Any changes on existence of header files require executing "makelinks" manually again.
After adding or removing files to Elcor source (mainly we refer to elcor/ISE) and modifying corresponding places in GNUmakefile, "make depend" need to be issued in order to generate dependency files under each source directory (".dependences"), otherwise, modifying the new .cpp file won't cause recompilation.
2. Append new machine description (mdes) sections for the custom instructions.
Machine description defines the format, resource usage, and timing for each instruction (operation and operands), and is the information database where Trimaran instruction scheduler refers to. Note that you do not need to define the detailed semantics of a custom instruction in the machine description file. Instead, you define "Scheduling_Alternative" which groups instructions with the same semantics but different resource usages (e.g., encoding, reservation table, timing); "Scheduling_Alternative" is used by the instruction scheduler to choose an appropriate instruction for an operation to minimize the schedule length. In most cases, a custom operation corresponds to only one custom instruction, i.e., only one "Scheduling_Alternative". Execution semantics of a custom instruction is defined in the Simu (Simulator).
High level machine description file (*.hmdes) need to be compiled using "hc" compiler to low level correspondence (*.lmdes).
3. Generate Rebel form.
The Simu uses Rebel form to simulate execution of test programs.
4. Modify Simu.
(a). Define the semantics of custom instructions in "PD_ops.h" and "PD_int_arith_ops.c" (if you want to put the function definition there). The simulator actually calls the functions defined here to "execute" the instructions. If you observe the "binary" generated from Elcor to Simulatable source code (the "urbenchmark.O_el.simu.c.tbls" file), the function name appears in the fifth field of each instruction.
(b). Add custom instructions in "PD_ops.list" for the dissembler (if you ever want to use it).
Step (a) and (b) assure the Simulator understand how to execute a custom instruction, but yet we are not able to convert the Rebel form to the Simulatable source code. Step (c) fills this code gen gap.
(c). Modify "opcode.h" and "opcode.cpp" under elcor/src/Graph directory. In "opcode.h", add custom instruction opcode (digit) to IR_ROOT_OPCODE and Op_code section. In "opcode.cpp", bind custom instruction opcode with corresponding custom instruction name in function "el_init_elcor_opcode_maps_arithmatic()" (if u want, in this function...). This binding will let the code gen recognize the custom instructions appearing in the Rebel form.