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