xref: /openbmc/qemu/target/hexagon/README (revision bf616ce4)
1Hexagon is Qualcomm's very long instruction word (VLIW) digital signal
2processor(DSP).  We also support Hexagon Vector eXtensions (HVX).  HVX
3is a wide vector coprocessor designed for high performance computer vision,
4image processing, machine learning, and other workloads.
5
6The following versions of the Hexagon core are supported
7    Scalar core: v73
8    https://developer.qualcomm.com/downloads/qualcomm-hexagon-v73-programmers-reference-manual-rev-aa
9    HVX extension: v73
10    https://developer.qualcomm.com/downloads/qualcomm-hexagon-v73-hvx-programmers-reference-manual-rev-aa
11
12We presented an overview of the project at the 2019 KVM Forum.
13    https://kvmforum2019.sched.com/event/Tmwc/qemu-hexagon-automatic-translation-of-the-isa-manual-pseudcode-to-tiny-code-instructions-of-a-vliw-architecture-niccolo-izzo-revng-taylor-simpson-qualcomm-innovation-center
14
15*** Tour of the code ***
16
17The qemu-hexagon implementation is a combination of qemu and the Hexagon
18architecture library (aka archlib).  The three primary directories with
19Hexagon-specific code are
20
21    qemu/target/hexagon
22        This has all the instruction and packet semantics
23    qemu/target/hexagon/imported
24        These files are imported with very little modification from archlib
25        *.idef                  Instruction semantics definition
26        macros.def              Mapping of macros to instruction attributes
27        encode*.def             Encoding patterns for each instruction
28        iclass.def              Instruction class definitions used to determine
29                                legal VLIW slots for each instruction
30    qemu/target/hexagon/idef-parser
31        Parser that, given the high-level definitions of an instruction,
32        produces a C function generating equivalent tiny code instructions.
33        See README.rst.
34    qemu/linux-user/hexagon
35        Helpers for loading the ELF file and making Linux system calls,
36        signals, etc
37
38We start with scripts that generate a bunch of include files.  This
39is a two step process.  The first step is to use the C preprocessor to expand
40macros inside the architecture definition files.  This is done in
41target/hexagon/gen_semantics.c.  This step produces
42    <BUILD_DIR>/target/hexagon/semantics_generated.pyinc.
43That file is consumed by the following python scripts to produce the indicated
44header files in <BUILD_DIR>/target/hexagon
45        gen_opcodes_def.py              -> opcodes_def_generated.h.inc
46        gen_op_regs.py                  -> op_regs_generated.h.inc
47        gen_printinsn.py                -> printinsn_generated.h.inc
48        gen_op_attribs.py               -> op_attribs_generated.h.inc
49        gen_helper_protos.py            -> helper_protos_generated.h.inc
50        gen_shortcode.py                -> shortcode_generated.h.inc
51        gen_tcg_funcs.py                -> tcg_funcs_generated.c.inc
52        gen_tcg_func_table.py           -> tcg_func_table_generated.c.inc
53        gen_helper_funcs.py             -> helper_funcs_generated.c.inc
54        gen_idef_parser_funcs.py        -> idef_parser_input.h
55        gen_analyze_funcs.py            -> analyze_funcs_generated.c.inc
56
57Qemu helper functions have 3 parts
58    DEF_HELPER declaration indicates the signature of the helper
59    gen_helper_<NAME> will generate a TCG call to the helper function
60    The helper implementation
61
62Here's an example of the A2_add instruction.
63    Instruction tag        A2_add
64    Assembly syntax        "Rd32=add(Rs32,Rt32)"
65    Instruction semantics  "{ RdV=RsV+RtV;}"
66
67By convention, the operands are identified by letter
68    RdV is the destination register
69    RsV, RtV are source registers
70
71The generator uses the operand naming conventions (see large comment in
72hex_common.py) to determine the signature of the helper function.  Here are the
73results for A2_add
74
75helper_protos_generated.h.inc
76    DEF_HELPER_3(A2_add, s32, env, s32, s32)
77
78tcg_funcs_generated.c.inc
79    static void generate_A2_add(
80                    CPUHexagonState *env,
81                    DisasContext *ctx,
82                    Insn *insn,
83                    Packet *pkt)
84    {
85        TCGv RdV = tcg_temp_new();
86        const int RdN = insn->regno[0];
87        TCGv RsV = hex_gpr[insn->regno[1]];
88        TCGv RtV = hex_gpr[insn->regno[2]];
89        gen_helper_A2_add(RdV, tcg_env, RsV, RtV);
90        gen_log_reg_write(ctx, RdN, RdV);
91    }
92
93helper_funcs_generated.c.inc
94    int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV)
95    {
96        uint32_t slot __attribute__((unused)) = 4;
97        int32_t RdV = 0;
98        { RdV=RsV+RtV;}
99        return RdV;
100    }
101
102Note that generate_A2_add updates the disassembly context to be processed
103when the packet commits (see "Packet Semantics" below).
104
105The generator checks for fGEN_TCG_<tag> macro.  This allows us to generate
106TCG code instead of a call to the helper.  If defined, the macro takes 1
107argument.
108    C semantics (aka short code)
109
110This allows the code generator to override the auto-generated code.  In some
111cases this is necessary for correct execution.  We can also override for
112faster emulation.  For example, calling a helper for add is more expensive
113than generating a TCG add operation.
114
115The gen_tcg.h file has any overrides. For example, we could write
116    #define fGEN_TCG_A2_add(GENHLPR, SHORTCODE) \
117        tcg_gen_add_tl(RdV, RsV, RtV)
118
119The instruction semantics C code relies heavily on macros.  In cases where the
120C semantics are specified only with macros, we can override the default with
121the short semantics option and #define the macros to generate TCG code.  One
122example is L2_loadw_locked:
123    Instruction tag        L2_loadw_locked
124    Assembly syntax        "Rd32=memw_locked(Rs32)"
125    Instruction semantics  "{ fEA_REG(RsV); fLOAD_LOCKED(1,4,u,EA,RdV) }"
126
127In gen_tcg.h, we use the shortcode
128#define fGEN_TCG_L2_loadw_locked(SHORTCODE) \
129    SHORTCODE
130
131There are also cases where we brute force the TCG code generation.
132Instructions with multiple definitions are examples.  These require special
133handling because qemu helpers can only return a single value.
134
135For HVX vectors, the generator behaves slightly differently.  The wide vectors
136won't fit in a TCGv or TCGv_i64, so we pass TCGv_ptr variables to pass the
137address to helper functions.  Here's an example for an HVX vector-add-word
138istruction.
139    static void generate_V6_vaddw(DisasContext *ctx)
140    {
141        Insn *insn __attribute__((unused)) = ctx->insn;
142        const int VdN = insn->regno[0];
143        const intptr_t VdV_off =
144            ctx_future_vreg_off(ctx, VdN, 1, true);
145        TCGv_ptr VdV = tcg_temp_new_ptr();
146        tcg_gen_addi_ptr(VdV, tcg_env, VdV_off);
147        const int VuN = insn->regno[1];
148        const intptr_t VuV_off =
149            vreg_src_off(ctx, VuN);
150        TCGv_ptr VuV = tcg_temp_new_ptr();
151        const int VvN = insn->regno[2];
152        const intptr_t VvV_off =
153            vreg_src_off(ctx, VvN);
154        TCGv_ptr VvV = tcg_temp_new_ptr();
155        tcg_gen_addi_ptr(VuV, tcg_env, VuV_off);
156        tcg_gen_addi_ptr(VvV, tcg_env, VvV_off);
157        gen_helper_V6_vaddw(tcg_env, VdV, VuV, VvV);
158    }
159
160Notice that we also generate a variable named <operand>_off for each operand of
161the instruction.  This makes it easy to override the instruction semantics with
162functions from tcg-op-gvec.h.  Here's the override for this instruction.
163    #define fGEN_TCG_V6_vaddw(SHORTCODE) \
164        tcg_gen_gvec_add(MO_32, VdV_off, VuV_off, VvV_off, \
165                         sizeof(MMVector), sizeof(MMVector))
166
167Finally, we notice that the override doesn't use the TCGv_ptr variables, so
168we don't generate them when an override is present.  Here is what we generate
169when the override is present.
170    static void generate_V6_vaddw(DisasContext *ctx)
171    {
172        Insn *insn __attribute__((unused)) = ctx->insn;
173        const int VdN = insn->regno[0];
174        const intptr_t VdV_off =
175            ctx_future_vreg_off(ctx, VdN, 1, true);
176        const int VuN = insn->regno[1];
177        const intptr_t VuV_off =
178            vreg_src_off(ctx, VuN);
179        const int VvN = insn->regno[2];
180        const intptr_t VvV_off =
181            vreg_src_off(ctx, VvN);
182        fGEN_TCG_V6_vaddw({ fHIDE(int i;) fVFOREACH(32, i) { VdV.w[i] = VuV.w[i] + VvV.w[i] ; } });
183    }
184
185We also generate an analyze_<tag> function for each instruction.  Currently,
186these functions record the writes to registers by calling ctx_log_*.  During
187gen_start_packet, we invoke the analyze_<tag> function for each instruction in
188the packet, and we mark the implicit writes.  After the analysis is performed,
189we initialize the result register for each of the predicated assignments.
190
191In addition to instruction semantics, we use a generator to create the decode
192tree.  This generation is a four step process.
193Step 1 is to run target/hexagon/gen_dectree_import.c to produce
194    <BUILD_DIR>/target/hexagon/iset.py
195Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
196    <BUILD_DIR>/target/hexagon/normal_decode_generated
197    <BUILD_DIR>/target/hexagon/hvx_decode_generated
198    <BUILD_DIR>/target/hexagon/subinsn_*_decode_generated
199Step 3 is to process the above files with QEMU's decodetree.py to produce
200    <BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
201Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
202    <BUILD_DIR>/target/hexagon/decodetree_trans_funcs_generated.c.inc
203
204*** Key Files ***
205
206cpu.h
207
208This file contains the definition of the CPUHexagonState struct.  It is the
209runtime information for each thread and contains stuff like the GPR and
210predicate registers.
211
212macros.h
213mmvec/macros.h
214
215The Hexagon arch lib relies heavily on macros for the instruction semantics.
216This is a great advantage for qemu because we can override them for different
217purposes.  You will also notice there are sometimes two definitions of a macro.
218The QEMU_GENERATE variable determines whether we want the macro to generate TCG
219code.  If QEMU_GENERATE is not defined, we want the macro to generate vanilla
220C code that will work in the helper implementation.
221
222translate.c
223
224The functions in this file generate TCG code for a translation block.  Some
225important functions in this file are
226
227    gen_start_packet - initialize the data structures for packet semantics
228    gen_commit_packet - commit the register writes, stores, etc for a packet
229    decode_and_translate_packet - disassemble a packet and generate code
230
231genptr.c
232gen_tcg.h
233
234These files create a function for each instruction.  It is mostly composed of
235fGEN_TCG_<tag> definitions followed by including tcg_funcs_generated.c.inc.
236
237op_helper.c
238
239This file contains the implementations of all the helpers.  There are a few
240general purpose helpers, but most of them are generated by including
241helper_funcs_generated.c.inc.  There are also several helpers used for debugging.
242
243
244*** Packet Semantics ***
245
246VLIW packet semantics differ from serial semantics in that all input operands
247are read, then the operations are performed, then all the results are written.
248For example, this packet performs a swap of registers r0 and r1
249    { r0 = r1; r1 = r0 }
250Note that the result is different if the instructions are executed serially.
251
252Packet semantics dictate that we defer any changes of state until the entire
253packet is committed.  We record the results of each instruction in a side data
254structure, and update the visible processor state when we commit the packet.
255
256The data structures are divided between the runtime state and the translation
257context.
258
259During the TCG generation (see translate.[ch]), we use the DisasContext to
260track what needs to be done during packet commit.  Here are the relevant
261fields
262
263    reg_log            list of registers written
264    reg_log_idx        index into ctx_reg_log
265    pred_log           list of predicates written
266    pred_log_idx       index into ctx_pred_log
267    store_width        width of stores (indexed by slot)
268
269During runtime, the following fields in CPUHexagonState (see cpu.h) are used
270
271    new_value             new value of a given register
272    reg_written           boolean indicating if register was written
273    new_pred_value        new value of a predicate register
274    pred_written          boolean indicating if predicate was written
275    mem_log_stores        record of the stores (indexed by slot)
276
277For Hexagon Vector eXtensions (HVX), the following fields are used
278    VRegs                       Vector registers
279    future_VRegs                Registers to be stored during packet commit
280    tmp_VRegs                   Temporary registers *not* stored during commit
281    QRegs                       Q (vector predicate) registers
282    future_QRegs                Registers to be stored during packet commit
283
284*** Debugging ***
285
286You can turn on a lot of debugging by changing the HEX_DEBUG macro to 1 in
287internal.h.  This will stream a lot of information as it generates TCG and
288executes the code.
289
290To track down nasty issues with Hexagon->TCG generation, we compare the
291execution results with actual hardware running on a Hexagon Linux target.
292Run qemu with the "-d cpu" option.  Then, we can diff the results and figure
293out where qemu and hardware behave differently.
294
295The stacks are located at different locations.  We handle this by changing
296env->stack_adjust in translate.c.  First, set this to zero and run qemu.
297Then, change env->stack_adjust to the difference between the two stack
298locations.  Then rebuild qemu and run again. That will produce a very
299clean diff.
300
301Here are some handy places to set breakpoints
302
303    At the call to gen_start_packet for a given PC (note that the line number
304        might change in the future)
305        br translate.c:602 if ctx->base.pc_next == 0xdeadbeef
306    The helper function for each instruction is named helper_<TAG>, so here's
307        an example that will set a breakpoint at the start
308        br helper_A2_add
309    If you have the HEX_DEBUG macro set, the following will be useful
310        At the start of execution of a packet for a given PC
311            br helper_debug_start_packet if env->gpr[41] == 0xdeadbeef
312        At the end of execution of a packet for a given PC
313            br helper_debug_commit_end if this_PC == 0xdeadbeef
314