xref: /openbmc/qemu/target/hexagon/README (revision 824cac68)
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: v67
8    https://developer.qualcomm.com/downloads/qualcomm-hexagon-v67-programmer-s-reference-manual
9    HVX extension: v66
10    https://developer.qualcomm.com/downloads/qualcomm-hexagon-v66-hvx-programmer-s-reference-manual
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
56Qemu helper functions have 3 parts
57    DEF_HELPER declaration indicates the signature of the helper
58    gen_helper_<NAME> will generate a TCG call to the helper function
59    The helper implementation
60
61Here's an example of the A2_add instruction.
62    Instruction tag        A2_add
63    Assembly syntax        "Rd32=add(Rs32,Rt32)"
64    Instruction semantics  "{ RdV=RsV+RtV;}"
65
66By convention, the operands are identified by letter
67    RdV is the destination register
68    RsV, RtV are source registers
69
70The generator uses the operand naming conventions (see large comment in
71hex_common.py) to determine the signature of the helper function.  Here are the
72results for A2_add
73
74helper_protos_generated.h.inc
75    DEF_HELPER_3(A2_add, s32, env, s32, s32)
76
77tcg_funcs_generated.c.inc
78    static void generate_A2_add(
79                    CPUHexagonState *env,
80                    DisasContext *ctx,
81                    Insn *insn,
82                    Packet *pkt)
83    {
84        TCGv RdV = tcg_temp_local_new();
85        const int RdN = insn->regno[0];
86        TCGv RsV = hex_gpr[insn->regno[1]];
87        TCGv RtV = hex_gpr[insn->regno[2]];
88        gen_helper_A2_add(RdV, cpu_env, RsV, RtV);
89        gen_log_reg_write(RdN, RdV);
90        ctx_log_reg_write(ctx, RdN);
91        tcg_temp_free(RdV);
92    }
93
94helper_funcs_generated.c.inc
95    int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV)
96    {
97        uint32_t slot __attribute__((unused)) = 4;
98        int32_t RdV = 0;
99        { RdV=RsV+RtV;}
100        return RdV;
101    }
102
103Note that generate_A2_add updates the disassembly context to be processed
104when the packet commits (see "Packet Semantics" below).
105
106The generator checks for fGEN_TCG_<tag> macro.  This allows us to generate
107TCG code instead of a call to the helper.  If defined, the macro takes 1
108argument.
109    C semantics (aka short code)
110
111This allows the code generator to override the auto-generated code.  In some
112cases this is necessary for correct execution.  We can also override for
113faster emulation.  For example, calling a helper for add is more expensive
114than generating a TCG add operation.
115
116The gen_tcg.h file has any overrides. For example, we could write
117    #define fGEN_TCG_A2_add(GENHLPR, SHORTCODE) \
118        tcg_gen_add_tl(RdV, RsV, RtV)
119
120The instruction semantics C code relies heavily on macros.  In cases where the
121C semantics are specified only with macros, we can override the default with
122the short semantics option and #define the macros to generate TCG code.  One
123example is L2_loadw_locked:
124    Instruction tag        L2_loadw_locked
125    Assembly syntax        "Rd32=memw_locked(Rs32)"
126    Instruction semantics  "{ fEA_REG(RsV); fLOAD_LOCKED(1,4,u,EA,RdV) }"
127
128In gen_tcg.h, we use the shortcode
129#define fGEN_TCG_L2_loadw_locked(SHORTCODE) \
130    SHORTCODE
131
132There are also cases where we brute force the TCG code generation.
133Instructions with multiple definitions are examples.  These require special
134handling because qemu helpers can only return a single value.
135
136For HVX vectors, the generator behaves slightly differently.  The wide vectors
137won't fit in a TCGv or TCGv_i64, so we pass TCGv_ptr variables to pass the
138address to helper functions.  Here's an example for an HVX vector-add-word
139istruction.
140    static void generate_V6_vaddw(
141                    CPUHexagonState *env,
142                    DisasContext *ctx,
143                    Insn *insn,
144                    Packet *pkt)
145    {
146        const int VdN = insn->regno[0];
147        const intptr_t VdV_off =
148            ctx_future_vreg_off(ctx, VdN, 1, true);
149        TCGv_ptr VdV = tcg_temp_local_new_ptr();
150        tcg_gen_addi_ptr(VdV, cpu_env, VdV_off);
151        const int VuN = insn->regno[1];
152        const intptr_t VuV_off =
153            vreg_src_off(ctx, VuN);
154        TCGv_ptr VuV = tcg_temp_local_new_ptr();
155        const int VvN = insn->regno[2];
156        const intptr_t VvV_off =
157            vreg_src_off(ctx, VvN);
158        TCGv_ptr VvV = tcg_temp_local_new_ptr();
159        tcg_gen_addi_ptr(VuV, cpu_env, VuV_off);
160        tcg_gen_addi_ptr(VvV, cpu_env, VvV_off);
161        TCGv slot = tcg_constant_tl(insn->slot);
162        gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV, slot);
163        tcg_temp_free(slot);
164        gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
165        ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
166        tcg_temp_free_ptr(VdV);
167        tcg_temp_free_ptr(VuV);
168        tcg_temp_free_ptr(VvV);
169    }
170
171Notice that we also generate a variable named <operand>_off for each operand of
172the instruction.  This makes it easy to override the instruction semantics with
173functions from tcg-op-gvec.h.  Here's the override for this instruction.
174    #define fGEN_TCG_V6_vaddw(SHORTCODE) \
175        tcg_gen_gvec_add(MO_32, VdV_off, VuV_off, VvV_off, \
176                         sizeof(MMVector), sizeof(MMVector))
177
178Finally, we notice that the override doesn't use the TCGv_ptr variables, so
179we don't generate them when an override is present.  Here is what we generate
180when the override is present.
181    static void generate_V6_vaddw(
182                    CPUHexagonState *env,
183                    DisasContext *ctx,
184                    Insn *insn,
185                    Packet *pkt)
186    {
187        const int VdN = insn->regno[0];
188        const intptr_t VdV_off =
189            ctx_future_vreg_off(ctx, VdN, 1, true);
190        const int VuN = insn->regno[1];
191        const intptr_t VuV_off =
192            vreg_src_off(ctx, VuN);
193        const int VvN = insn->regno[2];
194        const intptr_t VvV_off =
195            vreg_src_off(ctx, VvN);
196        fGEN_TCG_V6_vaddw({ fHIDE(int i;) fVFOREACH(32, i) { VdV.w[i] = VuV.w[i] + VvV.w[i] ; } });
197        gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
198        ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
199    }
200
201In addition to instruction semantics, we use a generator to create the decode
202tree.  This generation is also a two step process.  The first step is to run
203target/hexagon/gen_dectree_import.c to produce
204    <BUILD_DIR>/target/hexagon/iset.py
205This file is imported by target/hexagon/dectree.py to produce
206    <BUILD_DIR>/target/hexagon/dectree_generated.h.inc
207
208*** Key Files ***
209
210cpu.h
211
212This file contains the definition of the CPUHexagonState struct.  It is the
213runtime information for each thread and contains stuff like the GPR and
214predicate registers.
215
216macros.h
217mmvec/macros.h
218
219The Hexagon arch lib relies heavily on macros for the instruction semantics.
220This is a great advantage for qemu because we can override them for different
221purposes.  You will also notice there are sometimes two definitions of a macro.
222The QEMU_GENERATE variable determines whether we want the macro to generate TCG
223code.  If QEMU_GENERATE is not defined, we want the macro to generate vanilla
224C code that will work in the helper implementation.
225
226translate.c
227
228The functions in this file generate TCG code for a translation block.  Some
229important functions in this file are
230
231    gen_start_packet - initialize the data structures for packet semantics
232    gen_commit_packet - commit the register writes, stores, etc for a packet
233    decode_and_translate_packet - disassemble a packet and generate code
234
235genptr.c
236gen_tcg.h
237
238These files create a function for each instruction.  It is mostly composed of
239fGEN_TCG_<tag> definitions followed by including tcg_funcs_generated.c.inc.
240
241op_helper.c
242
243This file contains the implementations of all the helpers.  There are a few
244general purpose helpers, but most of them are generated by including
245helper_funcs_generated.c.inc.  There are also several helpers used for debugging.
246
247
248*** Packet Semantics ***
249
250VLIW packet semantics differ from serial semantics in that all input operands
251are read, then the operations are performed, then all the results are written.
252For exmaple, this packet performs a swap of registers r0 and r1
253    { r0 = r1; r1 = r0 }
254Note that the result is different if the instructions are executed serially.
255
256Packet semantics dictate that we defer any changes of state until the entire
257packet is committed.  We record the results of each instruction in a side data
258structure, and update the visible processor state when we commit the packet.
259
260The data structures are divided between the runtime state and the translation
261context.
262
263During the TCG generation (see translate.[ch]), we use the DisasContext to
264track what needs to be done during packet commit.  Here are the relevant
265fields
266
267    reg_log            list of registers written
268    reg_log_idx        index into ctx_reg_log
269    pred_log           list of predicates written
270    pred_log_idx       index into ctx_pred_log
271    store_width        width of stores (indexed by slot)
272
273During runtime, the following fields in CPUHexagonState (see cpu.h) are used
274
275    new_value             new value of a given register
276    reg_written           boolean indicating if register was written
277    new_pred_value        new value of a predicate register
278    pred_written          boolean indicating if predicate was written
279    mem_log_stores        record of the stores (indexed by slot)
280
281For Hexagon Vector eXtensions (HVX), the following fields are used
282    VRegs                       Vector registers
283    future_VRegs                Registers to be stored during packet commit
284    tmp_VRegs                   Temporary registers *not* stored during commit
285    VRegs_updated               Mask of predicated vector writes
286    QRegs                       Q (vector predicate) registers
287    future_QRegs                Registers to be stored during packet commit
288    QRegs_updated               Mask of predicated vector writes
289
290*** Debugging ***
291
292You can turn on a lot of debugging by changing the HEX_DEBUG macro to 1 in
293internal.h.  This will stream a lot of information as it generates TCG and
294executes the code.
295
296To track down nasty issues with Hexagon->TCG generation, we compare the
297execution results with actual hardware running on a Hexagon Linux target.
298Run qemu with the "-d cpu" option.  Then, we can diff the results and figure
299out where qemu and hardware behave differently.
300
301The stacks are located at different locations.  We handle this by changing
302env->stack_adjust in translate.c.  First, set this to zero and run qemu.
303Then, change env->stack_adjust to the difference between the two stack
304locations.  Then rebuild qemu and run again. That will produce a very
305clean diff.
306
307Here are some handy places to set breakpoints
308
309    At the call to gen_start_packet for a given PC (note that the line number
310        might change in the future)
311        br translate.c:602 if ctx->base.pc_next == 0xdeadbeef
312    The helper function for each instruction is named helper_<TAG>, so here's
313        an example that will set a breakpoint at the start
314        br helper_A2_add
315    If you have the HEX_DEBUG macro set, the following will be useful
316        At the start of execution of a packet for a given PC
317            br helper_debug_start_packet if env->gpr[41] == 0xdeadbeef
318        At the end of execution of a packet for a given PC
319            br helper_debug_commit_end if env->this_PC == 0xdeadbeef
320