1 Hexagon is Qualcomm's very long instruction word (VLIW) digital signal
2 processor(DSP). We also support Hexagon Vector eXtensions (HVX). HVX
3 is a wide vector coprocessor designed for high performance computer vision,
4 image processing, machine learning, and other workloads.
6 The following versions of the Hexagon core are supported
8 https://developer.qualcomm.com/downloads/qualcomm-hexagon-v67-programmer-s-reference-manual
10 https://developer.qualcomm.com/downloads/qualcomm-hexagon-v66-hvx-programmer-s-reference-manual
12 We 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
15 *** Tour of the code ***
17 The qemu-hexagon implementation is a combination of qemu and the Hexagon
18 architecture library (aka archlib). The three primary directories with
19 Hexagon-specific code are
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,
34 We start with scripts that generate a bunch of include files. This
35 is a two step process. The first step is to use the C preprocessor to expand
36 macros inside the architecture definition files. This is done in
37 target/hexagon/gen_semantics.c. This step produces
38 <BUILD_DIR>/target/hexagon/semantics_generated.pyinc.
39 That file is consumed by the following python scripts to produce the indicated
40 header 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
51 Qemu 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
56 Here'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;}"
61 By convention, the operands are identified by letter
62 RdV is the destination register
63 RsV, RtV are source registers
65 The generator uses the operand naming conventions (see large comment in
66 hex_common.py) to determine the signature of the helper function. Here are the
69 helper_protos_generated.h.inc
70 DEF_HELPER_3(A2_add, s32, env, s32, s32)
72 tcg_funcs_generated.c.inc
73 static void generate_A2_add(
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);
89 helper_funcs_generated.c.inc
90 int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV)
92 uint32_t slot __attribute__((unused)) = 4;
98 Note that generate_A2_add updates the disassembly context to be processed
99 when the packet commits (see "Packet Semantics" below).
101 The generator checks for fGEN_TCG_<tag> macro. This allows us to generate
102 TCG code instead of a call to the helper. If defined, the macro takes 1
104 C semantics (aka short code)
106 This allows the code generator to override the auto-generated code. In some
107 cases this is necessary for correct execution. We can also override for
108 faster emulation. For example, calling a helper for add is more expensive
109 than generating a TCG add operation.
111 The 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)
115 The instruction semantics C code relies heavily on macros. In cases where the
116 C semantics are specified only with macros, we can override the default with
117 the short semantics option and #define the macros to generate TCG code. One
118 example 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) }"
123 In gen_tcg.h, we use the shortcode
124 #define fGEN_TCG_L2_loadw_locked(SHORTCODE) \
127 There are also cases where we brute force the TCG code generation.
128 Instructions with multiple definitions are examples. These require special
129 handling because qemu helpers can only return a single value.
131 For HVX vectors, the generator behaves slightly differently. The wide vectors
132 won't fit in a TCGv or TCGv_i64, so we pass TCGv_ptr variables to pass the
133 address to helper functions. Here's an example for an HVX vector-add-word
135 static void generate_V6_vaddw(
136 CPUHexagonState *env,
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);
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);
166 Notice that we also generate a variable named <operand>_off for each operand of
167 the instruction. This makes it easy to override the instruction semantics with
168 functions 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))
173 Finally, we notice that the override doesn't use the TCGv_ptr variables, so
174 we don't generate them when an override is present. Here is what we generate
175 when the override is present.
176 static void generate_V6_vaddw(
177 CPUHexagonState *env,
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);
196 In addition to instruction semantics, we use a generator to create the decode
197 tree. This generation is also a two step process. The first step is to run
198 target/hexagon/gen_dectree_import.c to produce
199 <BUILD_DIR>/target/hexagon/iset.py
200 This file is imported by target/hexagon/dectree.py to produce
201 <BUILD_DIR>/target/hexagon/dectree_generated.h.inc
207 This file contains the definition of the CPUHexagonState struct. It is the
208 runtime information for each thread and contains stuff like the GPR and
214 The Hexagon arch lib relies heavily on macros for the instruction semantics.
215 This is a great advantage for qemu because we can override them for different
216 purposes. You will also notice there are sometimes two definitions of a macro.
217 The QEMU_GENERATE variable determines whether we want the macro to generate TCG
218 code. If QEMU_GENERATE is not defined, we want the macro to generate vanilla
219 C code that will work in the helper implementation.
223 The functions in this file generate TCG code for a translation block. Some
224 important functions in this file are
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
233 These files create a function for each instruction. It is mostly composed of
234 fGEN_TCG_<tag> definitions followed by including tcg_funcs_generated.c.inc.
238 This file contains the implementations of all the helpers. There are a few
239 general purpose helpers, but most of them are generated by including
240 helper_funcs_generated.c.inc. There are also several helpers used for debugging.
243 *** Packet Semantics ***
245 VLIW packet semantics differ from serial semantics in that all input operands
246 are read, then the operations are performed, then all the results are written.
247 For exmaple, this packet performs a swap of registers r0 and r1
249 Note that the result is different if the instructions are executed serially.
251 Packet semantics dictate that we defer any changes of state until the entire
252 packet is committed. We record the results of each instruction in a side data
253 structure, and update the visible processor state when we commit the packet.
255 The data structures are divided between the runtime state and the translation
258 During the TCG generation (see translate.[ch]), we use the DisasContext to
259 track what needs to be done during packet commit. Here are the relevant
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)
268 During runtime, the following fields in CPUHexagonState (see cpu.h) are used
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)
276 For 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
287 You can turn on a lot of debugging by changing the HEX_DEBUG macro to 1 in
288 internal.h. This will stream a lot of information as it generates TCG and
291 To track down nasty issues with Hexagon->TCG generation, we compare the
292 execution results with actual hardware running on a Hexagon Linux target.
293 Run qemu with the "-d cpu" option. Then, we can diff the results and figure
294 out where qemu and hardware behave differently.
296 The stacks are located at different locations. We handle this by changing
297 env->stack_adjust in translate.c. First, set this to zero and run qemu.
298 Then, change env->stack_adjust to the difference between the two stack
299 locations. Then rebuild qemu and run again. That will produce a very
302 Here are some handy places to set breakpoints
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
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