blob: 21f4db6fbd2e7a1af906ca907479615d149e3785 [file] [log] [blame]
Song Gaof8da88d2022-06-06 20:42:53 +08001/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * LoongArch emulation for QEMU - main translation routines.
4 *
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
6 */
7
8#include "qemu/osdep.h"
9#include "cpu.h"
10#include "tcg/tcg-op.h"
Song Gao57b4f1a2023-05-04 20:27:30 +080011#include "tcg/tcg-op-gvec.h"
Richard Hendersond654e922023-04-01 21:11:29 -070012#include "exec/translation-block.h"
Song Gaof8da88d2022-06-06 20:42:53 +080013#include "exec/translator.h"
14#include "exec/helper-proto.h"
15#include "exec/helper-gen.h"
Song Gaof8da88d2022-06-06 20:42:53 +080016#include "exec/log.h"
17#include "qemu/qemu-print.h"
Song Gaod578ca62022-06-06 20:43:00 +080018#include "fpu/softfloat.h"
Song Gaof8da88d2022-06-06 20:42:53 +080019#include "translate.h"
20#include "internals.h"
Song Gao008a3b12023-09-14 10:25:59 +080021#include "vec.h"
Song Gaof8da88d2022-06-06 20:42:53 +080022
23/* Global register indices */
24TCGv cpu_gpr[32], cpu_pc;
25static TCGv cpu_lladdr, cpu_llval;
Song Gaof8da88d2022-06-06 20:42:53 +080026
Richard Hendersond53106c2023-03-31 10:37:04 -070027#define HELPER_H "helper.h"
28#include "exec/helper-info.c.inc"
29#undef HELPER_H
30
Xiaojuan Yang5b1dedf2022-06-06 20:43:15 +080031#define DISAS_STOP DISAS_TARGET_0
32#define DISAS_EXIT DISAS_TARGET_1
33#define DISAS_EXIT_UPDATE DISAS_TARGET_2
Song Gaof8da88d2022-06-06 20:42:53 +080034
Song Gao57b4f1a2023-05-04 20:27:30 +080035static inline int vec_full_offset(int regno)
36{
37 return offsetof(CPULoongArchState, fpr[regno]);
38}
39
Song Gaof5ce2c82023-09-14 10:26:39 +080040static inline int vec_reg_offset(int regno, int index, MemOp mop)
41{
42 const uint8_t size = 1 << mop;
43 int offs = index * size;
44
45 if (HOST_BIG_ENDIAN && size < 8 ) {
46 offs ^= (8 - size);
47 }
48
49 return offs + vec_full_offset(regno);
50}
51
Song Gao57b4f1a2023-05-04 20:27:30 +080052static inline void get_vreg64(TCGv_i64 dest, int regno, int index)
53{
Richard Hendersonad75a512023-09-13 16:37:36 -070054 tcg_gen_ld_i64(dest, tcg_env,
Song Gao57b4f1a2023-05-04 20:27:30 +080055 offsetof(CPULoongArchState, fpr[regno].vreg.D(index)));
56}
57
58static inline void set_vreg64(TCGv_i64 src, int regno, int index)
59{
Richard Hendersonad75a512023-09-13 16:37:36 -070060 tcg_gen_st_i64(src, tcg_env,
Song Gao57b4f1a2023-05-04 20:27:30 +080061 offsetof(CPULoongArchState, fpr[regno].vreg.D(index)));
62}
63
Song Gao143d6782022-06-06 20:42:54 +080064static inline int plus_1(DisasContext *ctx, int x)
65{
66 return x + 1;
67}
68
Song Gao843b6272023-05-04 20:28:07 +080069static inline int shl_1(DisasContext *ctx, int x)
70{
71 return x << 1;
72}
73
Song Gaobb791742022-06-06 20:42:57 +080074static inline int shl_2(DisasContext *ctx, int x)
75{
76 return x << 2;
77}
78
Song Gao843b6272023-05-04 20:28:07 +080079static inline int shl_3(DisasContext *ctx, int x)
80{
81 return x << 3;
82}
83
Song Gaod578ca62022-06-06 20:43:00 +080084/*
85 * LoongArch the upper 32 bits are undefined ("can be any value").
86 * QEMU chooses to nanbox, because it is most likely to show guest bugs early.
87 */
88static void gen_nanbox_s(TCGv_i64 out, TCGv_i64 in)
89{
90 tcg_gen_ori_i64(out, in, MAKE_64BIT_MASK(32, 32));
91}
92
Song Gaof8da88d2022-06-06 20:42:53 +080093void generate_exception(DisasContext *ctx, int excp)
94{
95 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
Richard Hendersonad75a512023-09-13 16:37:36 -070096 gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp));
Song Gaof8da88d2022-06-06 20:42:53 +080097 ctx->base.is_jmp = DISAS_NORETURN;
98}
99
100static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
101{
Jiajie Chen7033c0e2023-08-22 09:13:55 +0200102 if (ctx->va32) {
103 dest = (uint32_t) dest;
104 }
105
Song Gaof8da88d2022-06-06 20:42:53 +0800106 if (translator_use_goto_tb(&ctx->base, dest)) {
107 tcg_gen_goto_tb(n);
108 tcg_gen_movi_tl(cpu_pc, dest);
109 tcg_gen_exit_tb(ctx->base.tb, n);
110 } else {
111 tcg_gen_movi_tl(cpu_pc, dest);
112 tcg_gen_lookup_and_goto_ptr();
113 }
114}
115
116static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
117 CPUState *cs)
118{
119 int64_t bound;
Richard Hendersonb77af262023-09-13 17:22:49 -0700120 CPULoongArchState *env = cpu_env(cs);
Song Gaof8da88d2022-06-06 20:42:53 +0800121 DisasContext *ctx = container_of(dcbase, DisasContext, base);
122
123 ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
Rui Wangc8885b82022-11-07 10:45:25 +0800124 ctx->plv = ctx->base.tb->flags & HW_FLAGS_PLV_MASK;
Rui Wangb4bda202022-11-04 12:05:16 +0800125 if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) {
Rui Wangc8885b82022-11-07 10:45:25 +0800126 ctx->mem_idx = ctx->plv;
Rui Wangb4bda202022-11-04 12:05:16 +0800127 } else {
Rui Wangc8885b82022-11-07 10:45:25 +0800128 ctx->mem_idx = MMU_IDX_DA;
Rui Wangb4bda202022-11-04 12:05:16 +0800129 }
Song Gaof8da88d2022-06-06 20:42:53 +0800130
131 /* Bound the number of insns to execute to those left on the page. */
132 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
133 ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
Song Gao143d6782022-06-06 20:42:54 +0800134
Song Gao57b4f1a2023-05-04 20:27:30 +0800135 if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LSX)) {
136 ctx->vl = LSX_LEN;
137 }
138
Song Gao269ca39a2023-09-14 10:26:02 +0800139 if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LASX)) {
140 ctx->vl = LASX_LEN;
141 }
142
Jiajie Chen39665822023-08-22 09:13:50 +0200143 ctx->la64 = is_la64(env);
144 ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0;
145
Song Gao143d6782022-06-06 20:42:54 +0800146 ctx->zero = tcg_constant_tl(0);
Song Gaoc0c04612023-08-22 09:19:52 +0200147
148 ctx->cpucfg1 = env->cpucfg[1];
Song Gao95e2ca22023-08-22 09:19:55 +0200149 ctx->cpucfg2 = env->cpucfg[2];
Song Gaof8da88d2022-06-06 20:42:53 +0800150}
151
152static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
153{
154}
155
156static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
157{
158 DisasContext *ctx = container_of(dcbase, DisasContext, base);
159
160 tcg_gen_insn_start(ctx->base.pc_next);
161}
162
Song Gao143d6782022-06-06 20:42:54 +0800163/*
164 * Wrappers for getting reg values.
165 *
166 * The $zero register does not have cpu_gpr[0] allocated -- we supply the
167 * constant zero as a source, and an uninitialized sink as destination.
168 *
169 * Further, we may provide an extension for word operations.
170 */
Song Gao143d6782022-06-06 20:42:54 +0800171static TCGv gpr_src(DisasContext *ctx, int reg_num, DisasExtend src_ext)
172{
173 TCGv t;
174
175 if (reg_num == 0) {
176 return ctx->zero;
177 }
178
179 switch (src_ext) {
180 case EXT_NONE:
181 return cpu_gpr[reg_num];
182 case EXT_SIGN:
Richard Henderson60a7e252023-02-24 19:05:39 -1000183 t = tcg_temp_new();
Song Gao143d6782022-06-06 20:42:54 +0800184 tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]);
185 return t;
186 case EXT_ZERO:
Richard Henderson60a7e252023-02-24 19:05:39 -1000187 t = tcg_temp_new();
Song Gao143d6782022-06-06 20:42:54 +0800188 tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]);
189 return t;
190 }
191 g_assert_not_reached();
192}
193
194static TCGv gpr_dst(DisasContext *ctx, int reg_num, DisasExtend dst_ext)
195{
196 if (reg_num == 0 || dst_ext) {
Richard Henderson60a7e252023-02-24 19:05:39 -1000197 return tcg_temp_new();
Song Gao143d6782022-06-06 20:42:54 +0800198 }
199 return cpu_gpr[reg_num];
200}
201
202static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext)
203{
204 if (reg_num != 0) {
205 switch (dst_ext) {
206 case EXT_NONE:
207 tcg_gen_mov_tl(cpu_gpr[reg_num], t);
208 break;
209 case EXT_SIGN:
210 tcg_gen_ext32s_tl(cpu_gpr[reg_num], t);
211 break;
212 case EXT_ZERO:
213 tcg_gen_ext32u_tl(cpu_gpr[reg_num], t);
214 break;
215 default:
216 g_assert_not_reached();
217 }
218 }
219}
220
Song Gao4854bbb2023-05-04 20:28:09 +0800221static TCGv get_fpr(DisasContext *ctx, int reg_num)
222{
223 TCGv t = tcg_temp_new();
Richard Hendersonad75a512023-09-13 16:37:36 -0700224 tcg_gen_ld_i64(t, tcg_env,
Song Gao4854bbb2023-05-04 20:28:09 +0800225 offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0)));
226 return t;
227}
228
229static void set_fpr(int reg_num, TCGv val)
230{
Richard Hendersonad75a512023-09-13 16:37:36 -0700231 tcg_gen_st_i64(val, tcg_env,
Song Gao4854bbb2023-05-04 20:28:09 +0800232 offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0)));
233}
234
Jiajie Chen34423c02023-08-22 09:13:51 +0200235static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend)
236{
237 TCGv temp = NULL;
238
Jiajie Chen7033c0e2023-08-22 09:13:55 +0200239 if (addend || ctx->va32) {
Jiajie Chen34423c02023-08-22 09:13:51 +0200240 temp = tcg_temp_new();
Jiajie Chen7033c0e2023-08-22 09:13:55 +0200241 }
242 if (addend) {
Jiajie Chen34423c02023-08-22 09:13:51 +0200243 tcg_gen_add_tl(temp, base, addend);
244 base = temp;
245 }
Jiajie Chen7033c0e2023-08-22 09:13:55 +0200246 if (ctx->va32) {
247 tcg_gen_ext32u_tl(temp, base);
248 base = temp;
249 }
Jiajie Chen34423c02023-08-22 09:13:51 +0200250 return base;
251}
252
Jiajie Chenc5af6622023-08-22 09:13:52 +0200253static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs)
254{
255 TCGv addend = ofs ? tcg_constant_tl(ofs) : NULL;
256 return make_address_x(ctx, base, addend);
257}
258
Jiajie Chen5a7ce252023-08-22 09:13:53 +0200259static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr)
260{
Jiajie Chen64962692023-08-22 09:19:50 +0200261 if (ctx->va32) {
262 addr = (int32_t)addr;
263 }
Jiajie Chen5a7ce252023-08-22 09:13:53 +0200264 return addr;
265}
266
Song Gao143d6782022-06-06 20:42:54 +0800267#include "decode-insns.c.inc"
268#include "insn_trans/trans_arith.c.inc"
Song Gao63cfcd42022-06-06 20:42:55 +0800269#include "insn_trans/trans_shift.c.inc"
Song Gaoad08cb32022-06-06 20:42:56 +0800270#include "insn_trans/trans_bit.c.inc"
Song Gaobb791742022-06-06 20:42:57 +0800271#include "insn_trans/trans_memory.c.inc"
Song Gao94b02d52022-06-06 20:42:58 +0800272#include "insn_trans/trans_atomic.c.inc"
Song Gao8708a042022-06-06 20:42:59 +0800273#include "insn_trans/trans_extra.c.inc"
Song Gaod578ca62022-06-06 20:43:00 +0800274#include "insn_trans/trans_farith.c.inc"
Song Gao9b741072022-06-06 20:43:01 +0800275#include "insn_trans/trans_fcmp.c.inc"
Song Gao7c1f8872022-06-06 20:43:02 +0800276#include "insn_trans/trans_fcnv.c.inc"
Song Gaob7dabd52022-06-06 20:43:03 +0800277#include "insn_trans/trans_fmov.c.inc"
Song Gaoe616bdf2022-06-06 20:43:04 +0800278#include "insn_trans/trans_fmemory.c.inc"
Song Gaoee86bd52022-06-06 20:43:05 +0800279#include "insn_trans/trans_branch.c.inc"
Xiaojuan Yang5b1dedf2022-06-06 20:43:15 +0800280#include "insn_trans/trans_privileged.c.inc"
Song Gao1dc33f22023-09-14 10:25:49 +0800281#include "insn_trans/trans_vec.c.inc"
Song Gao143d6782022-06-06 20:42:54 +0800282
Song Gaof8da88d2022-06-06 20:42:53 +0800283static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
284{
Richard Hendersonb77af262023-09-13 17:22:49 -0700285 CPULoongArchState *env = cpu_env(cs);
Song Gaof8da88d2022-06-06 20:42:53 +0800286 DisasContext *ctx = container_of(dcbase, DisasContext, base);
287
tanhongzeec28dd62023-03-30 20:46:00 +0800288 ctx->opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next);
Song Gaof8da88d2022-06-06 20:42:53 +0800289
290 if (!decode(ctx, ctx->opcode)) {
291 qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. "
292 TARGET_FMT_lx ": 0x%x\n",
293 ctx->base.pc_next, ctx->opcode);
294 generate_exception(ctx, EXCCODE_INE);
295 }
296
Song Gaof8da88d2022-06-06 20:42:53 +0800297 ctx->base.pc_next += 4;
Jiajie Chen7033c0e2023-08-22 09:13:55 +0200298
299 if (ctx->va32) {
300 ctx->base.pc_next = (uint32_t)ctx->base.pc_next;
301 }
Song Gaof8da88d2022-06-06 20:42:53 +0800302}
303
304static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
305{
306 DisasContext *ctx = container_of(dcbase, DisasContext, base);
307
308 switch (ctx->base.is_jmp) {
309 case DISAS_STOP:
310 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
311 tcg_gen_lookup_and_goto_ptr();
312 break;
313 case DISAS_TOO_MANY:
314 gen_goto_tb(ctx, 0, ctx->base.pc_next);
315 break;
316 case DISAS_NORETURN:
317 break;
Xiaojuan Yang5b1dedf2022-06-06 20:43:15 +0800318 case DISAS_EXIT_UPDATE:
319 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
320 QEMU_FALLTHROUGH;
321 case DISAS_EXIT:
322 tcg_gen_exit_tb(NULL, 0);
323 break;
Song Gaof8da88d2022-06-06 20:42:53 +0800324 default:
325 g_assert_not_reached();
326 }
327}
328
329static void loongarch_tr_disas_log(const DisasContextBase *dcbase,
330 CPUState *cpu, FILE *logfile)
331{
332 qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
333 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
334}
335
336static const TranslatorOps loongarch_tr_ops = {
337 .init_disas_context = loongarch_tr_init_disas_context,
338 .tb_start = loongarch_tr_tb_start,
339 .insn_start = loongarch_tr_insn_start,
340 .translate_insn = loongarch_tr_translate_insn,
341 .tb_stop = loongarch_tr_tb_stop,
342 .disas_log = loongarch_tr_disas_log,
343};
344
Richard Henderson597f9b22023-01-28 15:19:22 -1000345void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
Richard Henderson306c8722022-08-11 13:48:03 -0700346 target_ulong pc, void *host_pc)
Song Gaof8da88d2022-06-06 20:42:53 +0800347{
348 DisasContext ctx;
349
Richard Henderson306c8722022-08-11 13:48:03 -0700350 translator_loop(cs, tb, max_insns, pc, host_pc,
351 &loongarch_tr_ops, &ctx.base);
Song Gaof8da88d2022-06-06 20:42:53 +0800352}
353
354void loongarch_translate_init(void)
355{
356 int i;
357
358 cpu_gpr[0] = NULL;
359 for (i = 1; i < 32; i++) {
Richard Hendersonad75a512023-09-13 16:37:36 -0700360 cpu_gpr[i] = tcg_global_mem_new(tcg_env,
Song Gaof8da88d2022-06-06 20:42:53 +0800361 offsetof(CPULoongArchState, gpr[i]),
362 regnames[i]);
363 }
364
Richard Hendersonad75a512023-09-13 16:37:36 -0700365 cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPULoongArchState, pc), "pc");
366 cpu_lladdr = tcg_global_mem_new(tcg_env,
Song Gaof8da88d2022-06-06 20:42:53 +0800367 offsetof(CPULoongArchState, lladdr), "lladdr");
Richard Hendersonad75a512023-09-13 16:37:36 -0700368 cpu_llval = tcg_global_mem_new(tcg_env,
Song Gaof8da88d2022-06-06 20:42:53 +0800369 offsetof(CPULoongArchState, llval), "llval");
370}