target/hexagon: Add handlers for guest/sysreg r/w
This commit provides handlers to generate TCG for guest and system register reads and writes. They will be leveraged by a future commit. Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:28 UTC
6e158c05741d43c4317ecf86599070902acae0cf
1 file changed
+151
target/hexagon/genptr.c
+151
@@ -23,6 +23,7 @@
23
#include "exec/helper-gen.h"
24
#include "insn.h"
25
#include "opcodes.h"
26
+#include "sys_macros.h"
27
#include "translate.h"
28
#define QEMU_GENERATE /* Used internally by macros.h */
29
#include "macros.h"
@@ -120,6 +121,156 @@ TCGv get_result_pred(DisasContext *ctx, int pnum)
121
}
122
}
123
124
+#ifndef CONFIG_USER_ONLY
125
+G_GNUC_UNUSED
126
+static bool greg_writable(int rnum, bool pair)
127
+{
128
+ if (pair) {
129
+ if (rnum < HEX_GREG_G3) {
130
+ return true;
131
+ }
132
+ qemu_log_mask(LOG_UNIMP,
133
+ "Warning: ignoring write to guest register pair G%d:%d\n",
134
+ rnum + 1, rnum);
135
+ } else {
136
+ if (rnum <= HEX_GREG_G3) {
137
+ return true;
138
+ }
139
+ qemu_log_mask(LOG_UNIMP,
140
+ "Warning: ignoring write to guest register G%d\n", rnum);
141
+ }
142
+ return false;
143
+}
144
+
145
+G_GNUC_UNUSED
146
+static void check_greg_impl(int rnum, bool pair)
147
+{
148
+ if (pair && (!greg_implemented(rnum) || !greg_implemented(rnum + 1))) {
149
+ qemu_log_mask(LOG_UNIMP,
150
+ "Warning: guest register pair G%d:%d is unimplemented or "
151
+ "reserved. Read will yield 0.\n",
152
+ rnum + 1, rnum);
153
+ } else if (!pair && !greg_implemented(rnum)) {
154
+ qemu_log_mask(LOG_UNIMP,
155
+ "Warning: guest register G%d is unimplemented or reserved."
156
+ " Read will yield 0.\n", rnum);
157
+ }
158
+}
159
+
160
+G_GNUC_UNUSED
161
+static inline void gen_log_greg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
162
+{
163
+ tcg_gen_mov_i32(ctx->greg_new_value[rnum], val);
164
+}
165
+
166
+G_GNUC_UNUSED
167
+static void gen_log_greg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
168
+{
169
+ TCGv_i32 val32 = tcg_temp_new_i32();
170
+
171
+ /* Low word */
172
+ tcg_gen_extrl_i64_i32(val32, val);
173
+ gen_log_greg_write(ctx, rnum, val32);
174
+
175
+ /* High word */
176
+ tcg_gen_extrh_i64_i32(val32, val);
177
+ gen_log_greg_write(ctx, rnum + 1, val32);
178
+}
179
+
180
+static const uint32_t sreg_immut_masks[NUM_SREGS] = {
181
+ [HEX_SREG_STID] = 0xff00ff00,
182
+ [HEX_SREG_ELR] = 0x00000003,
183
+ [HEX_SREG_SSR] = 0x00008000,
184
+ [HEX_SREG_CCR] = 0x10e0ff24,
185
+ [HEX_SREG_HTID] = IMMUTABLE,
186
+ [HEX_SREG_IMASK] = 0xffff0000,
187
+ [HEX_SREG_GEVB] = 0x000000ff,
188
+};
189
+
190
+G_GNUC_UNUSED
191
+static void gen_log_sreg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
192
+{
193
+ const uint32_t reg_mask = sreg_immut_masks[rnum];
194
+
195
+ if (reg_mask != IMMUTABLE) {
196
+ if (rnum < HEX_SREG_GLB_START) {
197
+ gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask);
198
+ if (ctx->need_commit || rnum == HEX_SREG_SSR) {
199
+ tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
200
+ } else {
201
+ tcg_gen_mov_i32(hex_t_sreg[rnum], val);
202
+ }
203
+ } else {
204
+ gen_helper_sreg_write_masked(tcg_env, tcg_constant_i32(rnum), val);
205
+ }
206
+ }
207
+}
208
+
209
+G_GNUC_UNUSED
210
+static void gen_log_sreg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
211
+{
212
+ TCGv_i32 val32 = tcg_temp_new_i32();
213
+
214
+ /* Low word */
215
+ tcg_gen_extrl_i64_i32(val32, val);
216
+ gen_log_sreg_write(ctx, rnum, val32);
217
+
218
+ /* High word */
219
+ tcg_gen_extrh_i64_i32(val32, val);
220
+ gen_log_sreg_write(ctx, rnum + 1, val32);
221
+}
222
+
223
+G_GNUC_UNUSED
224
+static void gen_read_sreg(TCGv_i32 dst, int reg_num)
225
+{
226
+ if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA) {
227
+ gen_helper_sreg_read(dst, tcg_env, tcg_constant_i32(reg_num));
228
+ } else {
229
+ tcg_gen_mov_i32(dst, hex_t_sreg[reg_num]);
230
+ }
231
+}
232
+
233
+G_GNUC_UNUSED
234
+static void gen_read_sreg_pair(TCGv_i64 dst, int reg_num)
235
+{
236
+ if (reg_num < HEX_SREG_GLB_START) {
237
+ if (reg_num + 1 == HEX_SREG_BADVA) {
238
+ TCGv_i32 badva = tcg_temp_new_i32();
239
+ gen_helper_sreg_read(badva, tcg_env,
240
+ tcg_constant_i32(HEX_SREG_BADVA));
241
+ tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num], badva);
242
+ } else {
243
+ tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num],
244
+ hex_t_sreg[reg_num + 1]);
245
+ }
246
+ } else {
247
+ gen_helper_sreg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
248
+ }
249
+}
250
+
251
+G_GNUC_UNUSED
252
+static void gen_read_greg(TCGv_i32 dst, int reg_num)
253
+{
254
+ if (reg_num <= HEX_GREG_G3) {
255
+ tcg_gen_mov_i32(dst, hex_greg[reg_num]);
256
+ } else {
257
+ gen_helper_greg_read(dst, tcg_env, tcg_constant_i32(reg_num));
258
+ }
259
+}
260
+
261
+G_GNUC_UNUSED
262
+static void gen_read_greg_pair(TCGv_i64 dst, int reg_num)
263
+{
264
+ if (reg_num == HEX_GREG_G0 || reg_num == HEX_GREG_G2) {
265
+ tcg_gen_concat_i32_i64(dst, hex_greg[reg_num],
266
+ hex_greg[reg_num + 1]);
267
+ } else {
268
+ gen_helper_greg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
269
+ }
270
+}
271
+#endif
272
+
273
+
274
void gen_pred_write(DisasContext *ctx, int pnum, TCGv val)
275
{
276
TCGv pred = get_result_pred(ctx, pnum);