From 521f90293ab02ad3744d8d510b3f63b2a3f1af5e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 8 Aug 2024 11:17:57 -0700 Subject: [PATCH 001/109] target/hexagon: Fix badva reference, delete CAUSE The BADVA reg is referred to with the wrong identifier. The CAUSE reg field of SSR is not yet modeled, we will dump the SSR in a subsequent commit. Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 0b7fc98f6ce1..9ebed4dd86e1 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -216,8 +216,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags) qemu_fprintf(f, " cs0 = 0x00000000\n"); qemu_fprintf(f, " cs1 = 0x00000000\n"); #else - print_reg(f, env, HEX_REG_CAUSE); - print_reg(f, env, HEX_REG_BADVA); + print_reg(f, env, HEX_SREG_BADVA); print_reg(f, env, HEX_REG_CS0); print_reg(f, env, HEX_REG_CS1); #endif From 1cb87d47089528162c95e955eef68526b8dc5c5c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 19:50:15 -0700 Subject: [PATCH 002/109] target/hexagon: Add missing A_CALL attr, hintjumpr to multi_cof Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 758e5fd12dfe..e60e8efabc93 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -247,7 +247,11 @@ def need_next_PC(tag): def need_pkt_has_multi_cof(tag): - return "A_COF" in attribdict[tag] + if "A_JUMP" in attribdict[tag] or "A_CALL" in attribdict[tag]: + if tag == "J4_hintjumpr": + return False + return True + return False def need_pkt_need_commit(tag): From 736cebe981273f4d5ac61576aec16b05d8b35792 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 17:59:23 -0700 Subject: [PATCH 003/109] target/hexagon: Add System/Guest register definitions Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 140 +++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index e60e8efabc93..a800c8d50371 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -1013,6 +1013,136 @@ def analyze_write(self, f, tag, regno): ctx_log_qreg_write(ctx, {self.reg_num}, insn_has_hvx_helper); """)) +class GuestRegister(Register): + def gen_check_impl(self, f, regno): + if self.is_written(): + f.write(code_fmt(f"""\ + if (!greg_writable(insn->regno[{regno}], + {str(self.is_pair()).lower()})) {{ + return; + }} + """)) + else: + f.write(code_fmt(f"""\ +check_greg_impl(insn->regno[{regno}], {str(self.is_pair()).lower()}); + """)) + +class GuestDest(GuestRegister, Single, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + self.gen_check_impl(f, regno) + f.write(code_fmt(f"""\ + TCGv {self.reg_tcg()} = tcg_temp_new(); + gen_read_greg({self.reg_tcg()}, {self.reg_num}); + """)) + def log_write(self, f, tag): + f.write(code_fmt(f"""\ + gen_log_greg_write(ctx, {self.reg_num}, {self.reg_tcg()}); + """)) + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_greg_write(ctx, {self.reg_num}); + """)) + +class GuestSource(GuestRegister, Single, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno); + self.gen_check_impl(f, regno) + f.write(code_fmt(f"""\ + TCGv {self.reg_tcg()} = tcg_temp_new(); + gen_read_greg({self.reg_tcg()}, {self.reg_num}); + """)) + def analyze_read(self, f, regno): + f.write(code_fmt(f"""\ + // const int {self.reg_num} = insn->regno[{regno}]; + """)) + +class GuestPairDest(GuestRegister, Pair, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + self.gen_check_impl(f, regno) + f.write(code_fmt(f"""\ + TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64(); + gen_read_greg_pair({self.reg_tcg()}, {self.reg_num}); + """)) + def log_write(self, f, tag): + f.write(code_fmt(f"""\ + gen_log_greg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()}); + """)) + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_greg_write_pair(ctx, {self.reg_num}); + """)) + +class GuestPairSource(GuestRegister, Pair, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + self.gen_check_impl(f, regno) + f.write(code_fmt(f"""\ + TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64(); + gen_read_greg_pair({self.reg_tcg()}, {self.reg_num}); + """)) + def analyze_read(self, f, regno): + f.write(code_fmt(f"""\ + // const int {self.reg_num} = insn->regno[{regno}]; + """)) + +class SystemDest(Register, Single, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + TCGv {self.reg_tcg()} = tcg_temp_new(); + gen_read_sreg({self.reg_tcg()}, {self.reg_num}); + """)) + def log_write(self, f, tag): + f.write(code_fmt(f"""\ + gen_log_sreg_write(ctx, {self.reg_num}, {self.reg_tcg()}); + """)) + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_sreg_write(ctx, {self.reg_num}); + """)) + +class SystemSource(Register, Single, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno); + f.write(code_fmt(f"""\ + TCGv {self.reg_tcg()} = tcg_temp_new(); + gen_read_sreg({self.reg_tcg()}, {self.reg_num}); + """)) + def analyze_read(self, f, regno): + f.write(code_fmt(f"""\ + // const int {self.reg_num} = insn->regno[{regno}]; + """)) + +class SystemPairDest(Register, Pair, Dest): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64(); + gen_read_sreg_pair({self.reg_tcg()}, {self.reg_num}); + """)) + def log_write(self, f, tag): + f.write(code_fmt(f"""\ + gen_log_sreg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()}); + """)) + def analyze_write(self, f, tag, regno): + f.write(code_fmt(f"""\ + ctx_log_sreg_write_pair(ctx, {self.reg_num}); + """)) + +class SystemPairSource(Register, Pair, OldSource): + def decl_tcg(self, f, tag, regno): + self.decl_reg_num(f, regno) + f.write(code_fmt(f"""\ + TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64(); + gen_read_sreg_pair({self.reg_tcg()}, {self.reg_num}); + """)) + def analyze_read(self, f, regno): + f.write(code_fmt(f"""\ + // const int {self.reg_num} = insn->regno[{regno}]; + """)) + def init_registers(): regs = { GprDest("R", "d"), @@ -1059,6 +1189,16 @@ def init_registers(): QRegSource("Q", "u"), QRegSource("Q", "v"), QRegReadWrite("Q", "x"), + + # system regs + GuestDest("G", "d"), + GuestSource("G", "s"), + GuestPairDest("G", "dd"), + GuestPairSource("G", "ss"), + SystemDest("S", "d"), + SystemSource("S", "s"), + SystemPairDest("S", "dd"), + SystemPairSource("S", "ss"), } for reg in regs: registers[f"{reg.regtype}{reg.regid}"] = reg From 64d295497161f7b106c52129cc674797a86f97bb Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 18:12:15 -0700 Subject: [PATCH 004/109] target/hexagon: Add some utility functions for sysemu Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index a800c8d50371..1df9795fe7d0 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -33,6 +33,41 @@ overrides = {} # tags with helper overrides idef_parser_enabled = {} # tags enabled for idef-parser + +def is_sysemu_tag(tag): + return "A_PRIV" in attribdict[tag] or "A_GUEST" in attribdict[tag] + + +def tag_ignore(tag): + tag_skips = ( + "Y6_diag", + "Y6_diag0", + "Y6_diag1", + ) + attr_skips = ( + "A_FAKEINSN", + "A_MAPPING", + ) + return tag in tag_skips or \ + any(attr in attribdict[tag] for attr in attr_skips) + + +def get_sys_tags(): + return sorted( + tag for tag in frozenset(tags) if is_sysemu_tag(tag) + ) + + +def get_user_tags(): + return sorted( + tag for tag in frozenset(tags) if not is_sysemu_tag(tag) + ) + + +def get_all_tags(): + return get_user_tags() + get_sys_tags() + + # We should do this as a hash for performance, # but to keep order let's keep it as a list. def uniquify(seq): From de05b227a4d8e1214f6edc57127bc70133f670ae Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 16:15:39 -0500 Subject: [PATCH 005/109] target/hexagon: Make gen_exception_end_tb non-static Signed-off-by: Brian Cain --- target/hexagon/translate.c | 9 ++++----- target/hexagon/translate.h | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index fe7858703c8c..2e9a934fc6c1 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -185,13 +185,12 @@ static void gen_end_tb(DisasContext *ctx) ctx->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_end_tb(DisasContext *ctx, int excp) +void hex_gen_exception_end_tb(DisasContext *ctx, int excp) { gen_exec_counters(ctx); tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC); gen_exception_raw(excp); ctx->base.is_jmp = DISAS_NORETURN; - } static int read_packet_words(CPUHexagonState *env, DisasContext *ctx, @@ -558,7 +557,7 @@ static void gen_insn(DisasContext *ctx) ctx->insn->generate(ctx); mark_store_width(ctx); } else { - gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE); + hex_gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_OPCODE); } } @@ -912,7 +911,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx) nwords = read_packet_words(env, ctx, words); if (!nwords) { - gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_PACKET); + hex_gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_PACKET); return; } @@ -927,7 +926,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx) gen_commit_packet(ctx); ctx->base.pc_next += pkt.encod_pkt_size_in_bytes; } else { - gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_PACKET); + hex_gen_exception_end_tb(ctx, HEX_CAUSE_INVALID_PACKET); } } diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index d251e2233fda..2bd125297a82 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -281,6 +281,8 @@ extern TCGv hex_vstore_addr[VSTORES_MAX]; extern TCGv hex_vstore_size[VSTORES_MAX]; extern TCGv hex_vstore_pending[VSTORES_MAX]; +void hex_gen_exception_end_tb(DisasContext *ctx, int excp); + void process_store(DisasContext *ctx, int slot_num); FIELD(PROBE_PKT_SCALAR_STORE_S0, MMU_IDX, 0, 2) From 31efbf2ae453fc834bf5463d11cd443f701b2782 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 18:16:03 -0700 Subject: [PATCH 006/109] target/hexagon: Guard system insts Signed-off-by: Brian Cain --- target/hexagon/gen_analyze_funcs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/hexagon/gen_analyze_funcs.py b/target/hexagon/gen_analyze_funcs.py index 3ac7cc2cfe57..df4a5bbbde26 100755 --- a/target/hexagon/gen_analyze_funcs.py +++ b/target/hexagon/gen_analyze_funcs.py @@ -42,6 +42,14 @@ def gen_analyze_func(f, tag, regs, imms): f.write(f"static void analyze_{tag}(DisasContext *ctx)\n") f.write("{\n") + if hex_common.tag_ignore(tag): + f.write("}\n\n") + return + + if ("A_PRIV" in hex_common.attribdict[tag] or + "A_GUEST" in hex_common.attribdict[tag]): + f.write("#ifndef CONFIG_USER_ONLY\n") + f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n") if (hex_common.is_hvx_insn(tag)): if hex_common.has_hvx_helper(tag): @@ -74,6 +82,10 @@ def gen_analyze_func(f, tag, regs, imms): if reg.is_written(): reg.analyze_write(f, tag, regno) + if ("A_PRIV" in hex_common.attribdict[tag] or + "A_GUEST" in hex_common.attribdict[tag]): + f.write("#endif /* !CONFIG_USER_ONLY */\n") + f.write("}\n\n") From 87b2699e0606cc43c03a8fa11439daffab53a591 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 18:56:07 -0700 Subject: [PATCH 007/109] target/hexagon: Switch to tag_ignore(), generate via get_{user,sys}_tags() Signed-off-by: Brian Cain --- target/hexagon/gen_helper_funcs.py | 21 +++++++++------------ target/hexagon/gen_helper_protos.py | 23 ++++++++++++----------- target/hexagon/gen_idef_parser_funcs.py | 2 ++ target/hexagon/gen_op_attribs.py | 2 +- target/hexagon/gen_opcodes_def.py | 5 ++++- target/hexagon/gen_tcg_func_table.py | 14 ++------------ 6 files changed, 30 insertions(+), 37 deletions(-) diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py index c1f806ac4b25..dd8ab6059855 100755 --- a/target/hexagon/gen_helper_funcs.py +++ b/target/hexagon/gen_helper_funcs.py @@ -109,26 +109,23 @@ def main(): tagimms = hex_common.get_tagimms() with open(args.out, "w") as f: - for tag in hex_common.tags: - ## Skip the priv instructions - if "A_PRIV" in hex_common.attribdict[tag]: + for tag in hex_common.get_user_tags(): + if hex_common.tag_ignore(tag): continue - ## Skip the guest instructions - if "A_GUEST" in hex_common.attribdict[tag]: - continue - ## Skip the diag instructions - if tag == "Y6_diag": - continue - if tag == "Y6_diag0": + if hex_common.skip_qemu_helper(tag): continue - if tag == "Y6_diag1": + if hex_common.is_idef_parser_enabled(tag): continue + gen_helper_function(f, tag, tagregs, tagimms) + + f.write("#if !defined(CONFIG_USER_ONLY)\n") + for tag in hex_common.get_sys_tags(): if hex_common.skip_qemu_helper(tag): continue if hex_common.is_idef_parser_enabled(tag): continue - gen_helper_function(f, tag, tagregs, tagimms) + f.write("#endif\n") if __name__ == "__main__": diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py index 77f8e0a6a322..59c8bdd05c0f 100755 --- a/target/hexagon/gen_helper_protos.py +++ b/target/hexagon/gen_helper_protos.py @@ -59,27 +59,28 @@ def main(): tagimms = hex_common.get_tagimms() with open(args.out, "w") as f: - for tag in hex_common.tags: - ## Skip the priv instructions - if "A_PRIV" in hex_common.attribdict[tag]: + for tag in hex_common.get_user_tags(): + if hex_common.tag_ignore(tag): continue - ## Skip the guest instructions - if "A_GUEST" in hex_common.attribdict[tag]: - continue - ## Skip the diag instructions - if tag == "Y6_diag": - continue - if tag == "Y6_diag0": + + if hex_common.skip_qemu_helper(tag): continue - if tag == "Y6_diag1": + if hex_common.is_idef_parser_enabled(tag): continue + gen_helper_prototype(f, tag, tagregs, tagimms) + + f.write("#if !defined(CONFIG_USER_ONLY)\n") + for tag in hex_common.get_sys_tags(): + if hex_common.tag_ignore(tag): + continue if hex_common.skip_qemu_helper(tag): continue if hex_common.is_idef_parser_enabled(tag): continue gen_helper_prototype(f, tag, tagregs, tagimms) + f.write("#endif\n") if __name__ == "__main__": diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py index 2f6e826f76d6..32bce9b00286 100644 --- a/target/hexagon/gen_idef_parser_funcs.py +++ b/target/hexagon/gen_idef_parser_funcs.py @@ -60,6 +60,8 @@ def main(): f.write('#include "macros.h.inc"\n\n') for tag in hex_common.tags: + if hex_common.tag_ignore(tag): + continue ## Skip the priv instructions if "A_PRIV" in hex_common.attribdict[tag]: continue diff --git a/target/hexagon/gen_op_attribs.py b/target/hexagon/gen_op_attribs.py index bbbb02df3a23..94dd1f876b21 100755 --- a/target/hexagon/gen_op_attribs.py +++ b/target/hexagon/gen_op_attribs.py @@ -38,7 +38,7 @@ def main(): ## Generate all the attributes associated with each instruction ## with open(args.out, "w") as f: - for tag in hex_common.tags: + for tag in hex_common.get_all_tags(): f.write( f"OP_ATTRIB({tag},ATTRIBS(" f'{",".join(sorted(hex_common.attribdict[tag]))}))\n' diff --git a/target/hexagon/gen_opcodes_def.py b/target/hexagon/gen_opcodes_def.py index 94a19ff412e2..17ba3f9db95e 100755 --- a/target/hexagon/gen_opcodes_def.py +++ b/target/hexagon/gen_opcodes_def.py @@ -37,7 +37,10 @@ def main(): ## Generate a list of all the opcodes ## with open(args.out, "w") as f: - for tag in hex_common.tags: + for tag in hex_common.get_user_tags(): + f.write(f"OPCODE({tag}),\n") + + for tag in hex_common.get_sys_tags(): f.write(f"OPCODE({tag}),\n") diff --git a/target/hexagon/gen_tcg_func_table.py b/target/hexagon/gen_tcg_func_table.py index 299a39b1aa02..70c8db5c44c8 100755 --- a/target/hexagon/gen_tcg_func_table.py +++ b/target/hexagon/gen_tcg_func_table.py @@ -41,19 +41,9 @@ def main(): f.write("#define HEXAGON_FUNC_TABLE_H\n\n") f.write("const SemanticInsn opcode_genptr[XX_LAST_OPCODE] = {\n") + for tag in hex_common.tags: - ## Skip the priv instructions - if "A_PRIV" in hex_common.attribdict[tag]: - continue - ## Skip the guest instructions - if "A_GUEST" in hex_common.attribdict[tag]: - continue - ## Skip the diag instructions - if tag == "Y6_diag": - continue - if tag == "Y6_diag0": - continue - if tag == "Y6_diag1": + if hex_common.tag_ignore(tag): continue f.write(f" [{tag}] = generate_{tag},\n") From 368dd869e0adda06f73433f655915e641d48a1b8 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 19:07:25 -0700 Subject: [PATCH 008/109] target/hexagon: Guard system insts, switch to tag_ignore() Signed-off-by: Brian Cain --- target/hexagon/cpu_bits.h | 2 ++ target/hexagon/gen_tcg_funcs.py | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index ff596e2a94c9..6582bb4f16fc 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -37,6 +37,8 @@ enum hex_cause { HEX_CAUSE_PC_NOT_ALIGNED = 0x01e, HEX_CAUSE_PRIV_NO_UREAD = 0x024, HEX_CAUSE_PRIV_NO_UWRITE = 0x025, + HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a, + HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b, }; #define PACKET_WORDS_MAX 4 diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index c2ba91ddc044..65bfa046b867 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -21,7 +21,7 @@ import re import string import hex_common - +from textwrap import dedent ## ## Generate the TCG code to call the helper @@ -50,6 +50,18 @@ def gen_tcg_func(f, tag, regs, imms): f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n") + if "A_PRIV" in hex_common.attribdict[tag]: + f.write(dedent("""\ +#ifdef CONFIG_USER_ONLY + hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_SINSN); +#else +""")) + if "A_GUEST" in hex_common.attribdict[tag]: + f.write(dedent("""\ +#ifdef CONFIG_USER_ONLY + hex_gen_exception_end_tb(ctx, HEX_CAUSE_PRIV_USER_NO_GINSN); +#else +""")) if hex_common.need_ea(tag): f.write(" TCGv EA G_GNUC_UNUSED = tcg_temp_new();\n") @@ -97,6 +109,11 @@ def gen_tcg_func(f, tag, regs, imms): if reg.is_written(): reg.log_write(f, tag) + if ( + "A_PRIV" in hex_common.attribdict[tag] + or "A_GUEST" in hex_common.attribdict[tag] + ): + f.write("#endif /* CONFIG_USER_ONLY */\n") f.write("}\n\n") @@ -121,18 +138,7 @@ def main(): f.write('#include "idef-generated-emitter.h.inc"\n\n') for tag in hex_common.tags: - ## Skip the priv instructions - if "A_PRIV" in hex_common.attribdict[tag]: - continue - ## Skip the guest instructions - if "A_GUEST" in hex_common.attribdict[tag]: - continue - ## Skip the diag instructions - if tag == "Y6_diag": - continue - if tag == "Y6_diag0": - continue - if tag == "Y6_diag1": + if hex_common.tag_ignore(tag): continue gen_def_tcg_func(f, tag, tagregs, tagimms) From 8c2e641b1be44b2460801edf4bf3948baee42c04 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 19:19:03 -0700 Subject: [PATCH 009/109] target/hexagon: Add sysemu instructions triggering need_next_PC, multi-cof Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 1df9795fe7d0..571e96eac6a3 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -278,11 +278,13 @@ def need_PC(tag): def need_next_PC(tag): - return "A_CALL" in attribdict[tag] + return "A_CALL" in attribdict[tag] or tag == "J2_trap0" or tag == "J2_trap1" def need_pkt_has_multi_cof(tag): - if "A_JUMP" in attribdict[tag] or "A_CALL" in attribdict[tag]: + if ("A_JUMP" in attribdict[tag] + or "A_CALL" in attribdict[tag] + or tag == "J2_rte"): if tag == "J4_hintjumpr": return False return True From ce5058f772704760e11891c6185c5f6750b702c0 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 17 May 2024 19:37:30 -0700 Subject: [PATCH 010/109] target/hexagon: Add is_pair() method to scalars Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 571e96eac6a3..785b522b1f19 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -407,12 +407,16 @@ def helper_proto_type(self): return "s32" def helper_arg_type(self): return "int32_t" + def is_pair(self): + return False class Pair(Scalar): def helper_proto_type(self): return "s64" def helper_arg_type(self): return "int64_t" + def is_pair(self): + return True class Hvx: def is_scalar_reg(self): From c6fd603e2ffccaadb2be53f0b6fe977a8f3fcfb9 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Tue, 7 Nov 2023 17:03:13 -0800 Subject: [PATCH 011/109] gdb-xml: Add gdb-xml for hexagon sysemu Signed-off-by: Brian Cain --- gdb-xml/hexagon-sys.xml | 116 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 gdb-xml/hexagon-sys.xml diff --git a/gdb-xml/hexagon-sys.xml b/gdb-xml/hexagon-sys.xml new file mode 100644 index 000000000000..70256c1d39c6 --- /dev/null +++ b/gdb-xml/hexagon-sys.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e976e8e9c88ac6e8634821b79bcec7b4d58d4b8c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 19 May 2024 21:52:51 -0500 Subject: [PATCH 012/109] target/hexagon: Add memory order definition Signed-off-by: Brian Cain --- target/hexagon/cpu-param.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 71b4a9b83ec2..051b60a5b155 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -24,4 +24,9 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +/* + * Hexagon processors have a strong memory model. + */ +#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL) + #endif From 7220f128e1412b4b07937457dde1690967766059 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 19 May 2024 21:54:00 -0500 Subject: [PATCH 013/109] target/hexagon: Add a placeholder fp exception Signed-off-by: Brian Cain --- target/hexagon/arch.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index d053d6848715..87c2f6a53f6c 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -208,6 +208,11 @@ void arch_fpop_start(CPUHexagonState *env) * model it in qemu user mode. */ #define RAISE_FP_EXCEPTION do {} while (0) +#else + /* + * To be implemented. + */ +#define RAISE_FP_EXCEPTION do { g_assert_not_reached(); } while (0) #endif #define SOFTFLOAT_TEST_FLAG(FLAG, MYF, MYE) \ From c0bbdbdb6b67b20c2fb8952bc7ef7713b0cf1682 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 19 May 2024 21:52:11 -0500 Subject: [PATCH 014/109] target/hexagon: Define page size for sysemu Signed-off-by: Brian Cain --- target/hexagon/cpu-param.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 051b60a5b155..bc157d6b7ea7 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -18,7 +18,11 @@ #ifndef HEXAGON_CPU_PARAM_H #define HEXAGON_CPU_PARAM_H +#ifdef CONFIG_USER_ONLY #define TARGET_PAGE_BITS 16 /* 64K pages */ +#else +#define TARGET_PAGE_BITS 12 /* 4K pages */ +#endif #define TARGET_LONG_BITS 32 #define TARGET_PHYS_ADDR_SPACE_BITS 36 From f18e9bd59a15092dfb955f02af4f32fcad417fe2 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 14:27:37 -0500 Subject: [PATCH 015/109] target/hexagon: Add guest, system reg number defs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These registers are defined in the Qualcomm Hexagon V71 Programmer's Reference Manual - https://docs.qualcomm.com/bundle/publicresource/80-N2040-51_REV_AB_Hexagon_V71_ProgrammerS_Reference_Manual.pdf Refer to §11.9.1 SYSTEM GUEST, §11.9.2 SYSTEM MONITOR. Signed-off-by: Brian Cain --- target/hexagon/cpu.h | 5 ++ target/hexagon/hex_regs.h | 115 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 79e60d4bfa1b..20ea0adccad9 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -20,6 +20,11 @@ #include "fpu/softfloat-types.h" +#define NUM_GREGS 32 +#define GREG_WRITES_MAX 32 +#define NUM_SREGS 64 +#define SREG_WRITES_MAX 64 + #include "cpu-qom.h" #include "exec/cpu-defs.h" #include "hex_regs.h" diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h index bddfc28021c6..ea8c62eba9ce 100644 --- a/target/hexagon/hex_regs.h +++ b/target/hexagon/hex_regs.h @@ -81,4 +81,119 @@ enum { HEX_REG_UTIMERHI = 63, }; +#ifndef CONFIG_USER_ONLY + +#define HEX_GREG_VALUES \ + DECL_HEX_GREG(G0, 0) \ + DECL_HEX_GREG(GELR, 0) \ + DECL_HEX_GREG(G1, 1) \ + DECL_HEX_GREG(GSR, 1) \ + DECL_HEX_GREG(G2, 2) \ + DECL_HEX_GREG(GOSP, 2) \ + DECL_HEX_GREG(G3, 3) \ + DECL_HEX_GREG(GBADVA, 3) \ + DECL_HEX_GREG(GCYCLE_1T, 10) \ + DECL_HEX_GREG(GCYCLE_2T, 11) \ + DECL_HEX_GREG(GCYCLE_3T, 12) \ + DECL_HEX_GREG(GCYCLE_4T, 13) \ + DECL_HEX_GREG(GCYCLE_5T, 14) \ + DECL_HEX_GREG(GCYCLE_6T, 15) \ + DECL_HEX_GREG(GPMUCNT4, 16) \ + DECL_HEX_GREG(GPMUCNT5, 17) \ + DECL_HEX_GREG(GPMUCNT6, 18) \ + DECL_HEX_GREG(GPMUCNT7, 19) \ + DECL_HEX_GREG(GPCYCLELO, 24) \ + DECL_HEX_GREG(GPCYCLEHI, 25) \ + DECL_HEX_GREG(GPMUCNT0, 26) \ + DECL_HEX_GREG(GPMUCNT1, 27) \ + DECL_HEX_GREG(GPMUCNT2, 28) \ + DECL_HEX_GREG(GPMUCNT3, 29) \ + DECL_HEX_GREG_DONE + +#define DECL_HEX_GREG_DONE +#define DECL_HEX_GREG(name, val) HEX_GREG_ ##name = val, +enum hex_greg { + HEX_GREG_VALUES +}; +#undef DECL_HEX_GREG +#undef DECL_HEX_GREG_DONE + +#define DECL_HEX_GREG_DONE 0 +#define DECL_HEX_GREG(_, val) (1 << val) | +static inline bool greg_implemented(enum hex_greg greg) +{ +#if NUM_GREGS > 32 +#error "NUM_GREGS too large for greg_implemented(): update `impl_bitmap`" +#endif + static int32_t impl_bitmap = HEX_GREG_VALUES; + return impl_bitmap & (1 << greg); +} +#undef DECL_HEX_GREG +#undef DECL_HEX_GREG_DONE + +#endif /* CONFIG_USER_ONLY */ + +enum { + HEX_SREG_SGP0 = 0, + HEX_SREG_SGP1 = 1, + HEX_SREG_STID = 2, + HEX_SREG_ELR = 3, + HEX_SREG_BADVA0 = 4, + HEX_SREG_BADVA1 = 5, + HEX_SREG_SSR = 6, + HEX_SREG_CCR = 7, + HEX_SREG_HTID = 8, + HEX_SREG_BADVA = 9, + HEX_SREG_IMASK = 10, + HEX_SREG_GEVB = 11, + HEX_SREG_GLB_START = 16, + HEX_SREG_EVB = 16, + HEX_SREG_MODECTL = 17, + HEX_SREG_SYSCFG = 18, + HEX_SREG_IPENDAD = 20, + HEX_SREG_VID = 21, + HEX_SREG_VID1 = 22, + HEX_SREG_BESTWAIT = 23, + HEX_SREG_IEL = 24, + HEX_SREG_SCHEDCFG = 25, + HEX_SREG_IAHL = 26, + HEX_SREG_CFGBASE = 27, + HEX_SREG_DIAG = 28, + HEX_SREG_REV = 29, + HEX_SREG_PCYCLELO = 30, + HEX_SREG_PCYCLEHI = 31, + HEX_SREG_ISDBST = 32, + HEX_SREG_ISDBCFG0 = 33, + HEX_SREG_ISDBCFG1 = 34, + HEX_SREG_LIVELOCK = 35, + HEX_SREG_BRKPTPC0 = 36, + HEX_SREG_BRKPTCFG0 = 37, + HEX_SREG_BRKPTPC1 = 38, + HEX_SREG_BRKPTCFG1 = 39, + HEX_SREG_ISDBMBXIN = 40, + HEX_SREG_ISDBMBXOUT = 41, + HEX_SREG_ISDBEN = 42, + HEX_SREG_ISDBGPR = 43, + HEX_SREG_PMUCNT4 = 44, + HEX_SREG_PMUCNT5 = 45, + HEX_SREG_PMUCNT6 = 46, + HEX_SREG_PMUCNT7 = 47, + HEX_SREG_PMUCNT0 = 48, + HEX_SREG_PMUCNT1 = 49, + HEX_SREG_PMUCNT2 = 50, + HEX_SREG_PMUCNT3 = 51, + HEX_SREG_PMUEVTCFG = 52, + HEX_SREG_PMUSTID0 = 53, + HEX_SREG_PMUEVTCFG1 = 54, + HEX_SREG_PMUSTID1 = 55, + HEX_SREG_TIMERLO = 56, + HEX_SREG_TIMERHI = 57, + HEX_SREG_PMUCFG = 58, + HEX_SREG_S59 = 59, + HEX_SREG_S60 = 60, + HEX_SREG_S61 = 61, + HEX_SREG_S62 = 62, + HEX_SREG_S63 = 63, +}; + #endif From 0451994dbab59cc08224194461cc38b4ae941152 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 28 May 2024 22:09:54 -0500 Subject: [PATCH 016/109] target/hexagon: Add guest, system reg number state Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 23 +++++++++++++++++++++++ target/hexagon/cpu.h | 10 ++++++++++ 2 files changed, 33 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 9ebed4dd86e1..25137cf2699e 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -287,6 +287,14 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); /* Default NaN value: sign bit set, all frac bits set */ set_float_default_nan_pattern(0b11111111, &env->fp_status); + +#ifndef CONFIG_USER_ONLY + if (cs->cpu_index == 0) { + memset(env->g_sreg, 0, sizeof(target_ulong) * NUM_SREGS); + } + memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); + memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); +#endif } static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info) @@ -312,6 +320,21 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) qemu_init_vcpu(cs); cpu_reset(cs); +#ifndef CONFIG_USER_ONLY + if (cs->cpu_index == 0) { + env->g_sreg = g_new0(target_ulong, NUM_SREGS); + } else { + CPUState *cpu0_s = NULL; + CPUHexagonState *env0 = NULL; + CPU_FOREACH(cpu0_s) { + assert(cpu0_s->cpu_index == 0); + env0 = &(HEXAGON_CPU(cpu0_s)->env); + + break; + } + env->g_sreg = env0->g_sreg; + } +#endif mcc->parent_realize(dev, errp); } diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 20ea0adccad9..1da73deb90c0 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -82,6 +82,16 @@ typedef struct CPUArchState { target_ulong stack_start; uint8_t slot_cancelled; + +#ifndef CONFIG_USER_ONLY + /* Some system registers are per thread and some are global. */ + target_ulong t_sreg[NUM_SREGS]; + target_ulong t_sreg_written[NUM_SREGS]; + target_ulong *g_sreg; + + target_ulong greg[NUM_GREGS]; + target_ulong greg_written[NUM_GREGS]; +#endif target_ulong new_value_usr; MemLog mem_log_stores[STORES_MAX]; From b7fff0af5107bf9c90df92976cb35121dc5e8874 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 17:28:56 -0500 Subject: [PATCH 017/109] target/hexagon: Add TCG values for sreg, greg Signed-off-by: Brian Cain --- target/hexagon/translate.c | 7 +++++++ target/hexagon/translate.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 2e9a934fc6c1..71c137be308f 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -61,6 +61,13 @@ TCGv hex_vstore_addr[VSTORES_MAX]; TCGv hex_vstore_size[VSTORES_MAX]; TCGv hex_vstore_pending[VSTORES_MAX]; +#ifndef CONFIG_USER_ONLY +TCGv hex_greg[NUM_GREGS]; +TCGv hex_t_sreg[NUM_SREGS]; +TCGv_ptr hex_g_sreg_ptr; +TCGv hex_g_sreg[NUM_SREGS]; +#endif + static const char * const hexagon_prednames[] = { "p0", "p1", "p2", "p3" }; diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 2bd125297a82..f611c854dcbd 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -280,6 +280,13 @@ extern TCGv_i64 hex_llsc_val_i64; extern TCGv hex_vstore_addr[VSTORES_MAX]; extern TCGv hex_vstore_size[VSTORES_MAX]; extern TCGv hex_vstore_pending[VSTORES_MAX]; +#ifndef CONFIG_USER_ONLY +extern TCGv hex_greg[NUM_GREGS]; +extern TCGv hex_t_sreg[NUM_SREGS]; +extern TCGv_ptr hex_g_sreg_ptr; +extern TCGv hex_g_sreg[NUM_SREGS]; +#endif + void hex_gen_exception_end_tb(DisasContext *ctx, int excp); From 7ad9f918158acc9c74687aa24e584cbf42097915 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 16:27:30 -0500 Subject: [PATCH 018/109] target/hexagon: Add guest/sys reg writes to DC Signed-off-by: Brian Cain --- target/hexagon/translate.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index f611c854dcbd..0eaa3db03e81 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -39,6 +39,14 @@ typedef struct DisasContext { int reg_log_idx; DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS); DECLARE_BITMAP(predicated_regs, TOTAL_PER_THREAD_REGS); +#ifndef CONFIG_USER_ONLY + int greg_log[GREG_WRITES_MAX]; + int greg_log_idx; + int sreg_log[SREG_WRITES_MAX]; + int sreg_log_idx; + TCGv t_sreg_new_value[NUM_SREGS]; + TCGv greg_new_value[NUM_GREGS]; +#endif int preg_log[PRED_WRITES_MAX]; int preg_log_idx; DECLARE_BITMAP(pregs_written, NUM_PREGS); @@ -79,6 +87,34 @@ typedef struct DisasContext { bool is_gather_store_insn(DisasContext *ctx); +#ifndef CONFIG_USER_ONLY +static inline void ctx_log_greg_write(DisasContext *ctx, int rnum) +{ + if (rnum <= HEX_GREG_G3) { + ctx->greg_log[ctx->greg_log_idx] = rnum; + ctx->greg_log_idx++; + } +} + +static inline void ctx_log_greg_write_pair(DisasContext *ctx, int rnum) +{ + ctx_log_greg_write(ctx, rnum); + ctx_log_greg_write(ctx, rnum + 1); +} + +static inline void ctx_log_sreg_write(DisasContext *ctx, int rnum) +{ + ctx->sreg_log[ctx->sreg_log_idx] = rnum; + ctx->sreg_log_idx++; +} + +static inline void ctx_log_sreg_write_pair(DisasContext *ctx, int rnum) +{ + ctx_log_sreg_write(ctx, rnum); + ctx_log_sreg_write(ctx, rnum + 1); +} +#endif + static inline void ctx_log_pred_write(DisasContext *ctx, int pnum) { if (!test_bit(pnum, ctx->pregs_written)) { From 2809f855956cef531a7a5afd59edc6e397fa313c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 17:04:25 -0500 Subject: [PATCH 019/109] target/hexagon: Add imported macro, attr defs for sysemu Signed-off-by: Brian Cain --- target/hexagon/attribs_def.h.inc | 414 +++++++++++++++++++-- target/hexagon/imported/macros.def | 558 +++++++++++++++++++++++++++++ 2 files changed, 942 insertions(+), 30 deletions(-) mode change 100755 => 100644 target/hexagon/imported/macros.def diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index 9e3a05f88281..e6523a739b10 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -19,20 +19,41 @@ DEF_ATTRIB(AA_DUMMY, "Dummy Zeroth Attribute", "", "") /* Misc */ +DEF_ATTRIB(FAKEINSN, "Not a real instruction", "", "") +DEF_ATTRIB(MAPPING, "Not real -- asm mapped", "", "") +DEF_ATTRIB(CONDMAPPING, "Not real -- mapped based on values", "", "") DEF_ATTRIB(EXTENSION, "Extension instruction", "", "") +DEF_ATTRIB(SHARED_EXTENSION, "Shared extension instruction", "", "") +DEF_ATTRIB(CABAC, + "Cabac Instruction. Used in conjuction with QDSP6_CABAC_PRESENT", "", + "") +DEF_ATTRIB(EXPERIMENTAL, "This may not work correctly not supported by RTL.", + "", "") DEF_ATTRIB(PRIV, "Not available in user or guest mode", "", "") DEF_ATTRIB(GUEST, "Not available in user mode", "", "") DEF_ATTRIB(FPOP, "Floating Point Operation", "", "") +DEF_ATTRIB(FPDOUBLE, "Double-precision Floating Point Operation", "", "") +DEF_ATTRIB(FPSINGLE, "Single-precision Floating Point Operation", "", "") +DEF_ATTRIB(SFMAKE, "Single Float Make", "", "") +DEF_ATTRIB(DFMAKE, "Single Float Make", "", "") + +DEF_ATTRIB(NO_TIMING_LOG, "Does not get logged to the timing model", "", "") DEF_ATTRIB(EXTENDABLE, "Immediate may be extended", "", "") +DEF_ATTRIB(EXT_UPPER_IMMED, "Extend upper case immediate", "", "") +DEF_ATTRIB(EXT_LOWER_IMMED, "Extend lower case immediate", "", "") +DEF_ATTRIB(MUST_EXTEND, "Immediate must be extended", "", "") +DEF_ATTRIB(NA_NT, "Non-Allocating Non-Temporal instruction", "", "") +DEF_ATTRIB(INVPRED, "The predicate is inverted for true/false sense", "", "") DEF_ATTRIB(ARCHV2, "V2 architecture", "", "") DEF_ATTRIB(ARCHV3, "V3 architecture", "", "") DEF_ATTRIB(ARCHV4, "V4 architecture", "", "") DEF_ATTRIB(ARCHV5, "V5 architecture", "", "") +DEF_ATTRIB(PACKED, "Packable instruction", "", "") DEF_ATTRIB(SUBINSN, "sub-instruction", "", "") /* Load and Store attributes */ @@ -46,21 +67,48 @@ DEF_ATTRIB(MEMSIZE_4B, "Memory width is 4 bytes", "", "") DEF_ATTRIB(MEMSIZE_8B, "Memory width is 8 bytes", "", "") DEF_ATTRIB(SCALAR_LOAD, "Load is scalar", "", "") DEF_ATTRIB(SCALAR_STORE, "Store is scalar", "", "") -DEF_ATTRIB(REGWRSIZE_1B, "Memory width is 1 byte", "", "") -DEF_ATTRIB(REGWRSIZE_2B, "Memory width is 2 bytes", "", "") -DEF_ATTRIB(REGWRSIZE_4B, "Memory width is 4 bytes", "", "") -DEF_ATTRIB(REGWRSIZE_8B, "Memory width is 8 bytes", "", "") +DEF_ATTRIB(REGWRSIZE_1B, "ETM Memory width is 1 byte", "", "") +DEF_ATTRIB(REGWRSIZE_2B, "ETM Memory width is 2 bytes", "", "") +DEF_ATTRIB(REGWRSIZE_4B, "ETM Memory width is 4 bytes", "", "") +DEF_ATTRIB(REGWRSIZE_8B, "ETM Memory width is 8 bytes", "", "") DEF_ATTRIB(MEMLIKE, "Memory-like instruction", "", "") DEF_ATTRIB(MEMLIKE_PACKET_RULES, "follows Memory-like packet rules", "", "") +DEF_ATTRIB(CACHEOP, "Cache operation", "", "") +DEF_ATTRIB(COPBYADDRESS, "Cache operation by address", "", "") +DEF_ATTRIB(COPBYIDX, "Cache operation by index", "", "") DEF_ATTRIB(RELEASE, "Releases a lock", "", "") DEF_ATTRIB(ACQUIRE, "Acquires a lock", "", "") +DEF_ATTRIB(LLSC, "load-locked/store-conditional instruction", "", "") DEF_ATTRIB(RLS_INNER, "Store release inner visibility", "", "") +DEF_ATTRIB(RLS_OUTER, "Store release outer visibility", "", "") DEF_ATTRIB(RLS_ALL_THREAD, "Store release among all threads", "", "") DEF_ATTRIB(RLS_SAME_THREAD, "Store release with the same thread", "", "") +/* Load and Store Addressing Mode Attributes */ +DEF_ATTRIB(EA_REG_ONLY, "EA = input register only", "", "") +DEF_ATTRIB(EA_IMM_ONLY, "EA = immediate only", "", "") +DEF_ATTRIB(EA_REG_PLUS_IMM, "EA = register plus immediate", "", "") +DEF_ATTRIB(EA_REG_PLUS_REGSCALED, "EA = register plus scaled register", "", "") +DEF_ATTRIB(EA_IMM_PLUS_REGSCALED, "EA = immediate plus scaled register", "", "") +DEF_ATTRIB(EA_BREV_REG, "EA = bit-reversed input register", "", "") +DEF_ATTRIB(EA_GP_IMM, "EA = GP plus immediate (unless extended)", "", "") +DEF_ATTRIB(EA_PAGECROSS, "EA calculation can have a Page Cross Stall", "", "") + +DEF_ATTRIB(PM_ANY, "Post Modify", "", "") +DEF_ATTRIB(PM_I, "Post Modify by Immediate", "", "") +DEF_ATTRIB(PM_M, "Post Modify by M register", "", "") +DEF_ATTRIB(PM_CIRI, "Post Modify with Circular Addressing by immediate", "", "") +DEF_ATTRIB(PM_CIRR, "Post Modify with Circular Addressing by I field", "", "") + +DEF_ATTRIB(VMEM, "VMEM-type", "", "") +DEF_ATTRIB(VBUF, "Touches the VBUF", "", "") +DEF_ATTRIB(VDBG, "Vector debugging instruction", "", "") + /* V6 Vector attributes */ DEF_ATTRIB(CVI, "Executes on the HVX extension", "", "") +DEF_ATTRIB(NT_VMEM, "Non-temporal memory access", "", "") +DEF_ATTRIB(VMEMU, "Unaligned memory access", "", "") DEF_ATTRIB(CVI_NEW, "New value memory instruction executes on HVX", "", "") DEF_ATTRIB(CVI_VM, "Memory instruction executes on HVX", "", "") @@ -69,109 +117,415 @@ DEF_ATTRIB(CVI_VP_VS, "Double vector permute/shft insn executes on HVX", "", "") DEF_ATTRIB(CVI_VX, "Multiply instruction executes on HVX", "", "") DEF_ATTRIB(CVI_VX_DV, "Double vector multiply insn executes on HVX", "", "") DEF_ATTRIB(CVI_VS, "Shift instruction executes on HVX", "", "") -DEF_ATTRIB(CVI_VS_3SRC, "This shift needs to borrow a source register", "", "") +DEF_ATTRIB( + CVI_VS_3SRC, + "This shift instruction needs to borrow a source register from the VP slot", + "", "") DEF_ATTRIB(CVI_VS_VX, "Permute/shift and multiply insn executes on HVX", "", "") DEF_ATTRIB(CVI_VA, "ALU instruction executes on HVX", "", "") +DEF_ATTRIB(CVI_VA_2SRC, + "This alu instruction executes on multimedia vector engine and " + "requires two vectro sources", + "", "") DEF_ATTRIB(CVI_VA_DV, "Double vector alu instruction executes on HVX", "", "") DEF_ATTRIB(CVI_4SLOT, "Consumes all the vector execution resources", "", "") DEF_ATTRIB(CVI_TMP, "Transient Memory Load not written to register", "", "") DEF_ATTRIB(CVI_REMAP, "Register Renaming not written to register file", "", "") +DEF_ATTRIB(CVI_TMP_SRC, "Transient reassign", "", "") +DEF_ATTRIB(CVI_EXTRACT, "HVX Extract Instruction that goes through L2", "", "") +DEF_ATTRIB(CVI_EARLY, "HVX instructions that require early sources", "", "") +DEF_ATTRIB(CVI_LATE, "HVX insn that always require late sources", "", "") +DEF_ATTRIB(CVI_VV_LATE, "HVX insn that always require late Vv source", "", "") +DEF_ATTRIB(CVI_REQUIRES_TMPLOAD, ".tmp load must be included in packet", "", "") +DEF_ATTRIB(CVI_PUMP_2X, "Goes through the pipeline twice", "", "") +DEF_ATTRIB(CVI_PUMP_4X, "Goes through the pipeline four times", "", "") DEF_ATTRIB(CVI_GATHER, "CVI Gather operation", "", "") DEF_ATTRIB(CVI_SCATTER, "CVI Scatter operation", "", "") DEF_ATTRIB(CVI_SCATTER_RELEASE, "CVI Store Release for scatter", "", "") +DEF_ATTRIB(CVI_GATHER_RELEASE, "CVI Store Release for gather", "", "") DEF_ATTRIB(CVI_TMP_DST, "CVI instruction that doesn't write a register", "", "") +DEF_ATTRIB(CVI_SCATTER_WORD_ACC, "CVI Scatter Word Accum (second pass)", "", "") +DEF_ATTRIB(CVI_SCATTER_ACC, "CVI Scatter Accumulate", "", "") +DEF_ATTRIB(CVI_VX_VSRC0_IS_DST, + "For the assembler to handle the special case of non-linear " + "instructions with Vxx specified both as src and dst in syntax ", + "", "") + +DEF_ATTRIB(CVI_VX_ACC_FWD, "VX Accumulator Forwarding", "", "") + +DEF_ATTRIB(CVI_VX_NO_TMP_LD, + "VX Accumulator renaming not allowed from tmp load instruction", "", + "") + +DEF_ATTRIB(RESTRICT_CVI_NOVP, + "Instructions with this attribute are assigned to the original " + "shift unit and can not be assigned to the shift/permute unit", + "", "") + +DEF_ATTRIB(CVI_GATHER_ADDR_2B, "CVI Scatter/Gather address is halfword", "", "") +DEF_ATTRIB(CVI_GATHER_ADDR_4B, "CVI Scatter/Gather address is word", "", "") + +DEF_ATTRIB(VFETCH, "memory fetch op to L2 for a single vector", "", "") + DEF_ATTRIB(CVI_SLOT23, "Can execute in slot 2 or slot 3 (HVX)", "", "") -DEF_ATTRIB(VTCM_ALLBANK_ACCESS, "Allocates in all VTCM schedulers.", "", "") +DEF_ATTRIB(HVX_FLT, "This a floating point HVX instruction.", "", "") + +DEF_ATTRIB( + VTCM_ALLBANK_ACCESS, + "This instruction allocates in all VTCM schedulers due to a region access.", + "", "") +DEF_ATTRIB(XUMINOR, "XU minor SMTable instruction", "", "") + +DEF_ATTRIB(SYNC_MARKER, "This instruction needs a sync marker.", "", "") + /* Change-of-flow attributes */ DEF_ATTRIB(JUMP, "Jump-type instruction", "", "") +DEF_ATTRIB(DIRECT, "Uses an PC-relative immediate field", "", "") DEF_ATTRIB(INDIRECT, "Absolute register jump", "", "") +DEF_ATTRIB(CJUMP, "Conditional jump", "", "") DEF_ATTRIB(CALL, "Function call instruction", "", "") +DEF_ATTRIB(RET, "Function return instruction", "", "") +DEF_ATTRIB(PERM, "Permute instruction", "", "") DEF_ATTRIB(COF, "Change-of-flow instruction", "", "") DEF_ATTRIB(HINTED_COF, "This instruction is a hinted change-of-flow", "", "") DEF_ATTRIB(CONDEXEC, "May be cancelled by a predicate", "", "") +DEF_ATTRIB(DOTOLD, "Uses a predicate generated in a previous packet", "", "") +DEF_ATTRIB(DOTNEW, "Uses a predicate generated in the same packet", "", "") DEF_ATTRIB(DOTNEWVALUE, "Uses a register value generated in this pkt", "", "") DEF_ATTRIB(NEWCMPJUMP, "Compound compare and jump", "", "") DEF_ATTRIB(NVSTORE, "New-value store", "", "") DEF_ATTRIB(MEMOP, "memop", "", "") -DEF_ATTRIB(ROPS_2, "Compound instruction worth 2 RISC-ops", "", "") -DEF_ATTRIB(ROPS_3, "Compound instruction worth 3 RISC-ops", "", "") +DEF_ATTRIB(ROPS_2, "Compound instruction worth 2 wimpy RISC-ops", "", "") +DEF_ATTRIB(ROPS_3, "Compound instruction worth 3 wimpy RISC-ops", "", "") /* access to implicit registers */ DEF_ATTRIB(IMPLICIT_WRITES_LR, "Writes the link register", "", "UREG.LR") +DEF_ATTRIB(IMPLICIT_READS_LR, "Reads the link register", "UREG.LR", "") +DEF_ATTRIB(IMPLICIT_READS_LC0, "Reads loop count for loop 0", "UREG.LC0", "") +DEF_ATTRIB(IMPLICIT_READS_LC1, "Reads loop count for loop 1", "UREG.LC1", "") +DEF_ATTRIB(IMPLICIT_READS_SA0, "Reads start address for loop 0", "UREG.SA0", "") +DEF_ATTRIB(IMPLICIT_READS_SA1, "Reads start address for loop 1", "UREG.SA1", "") +DEF_ATTRIB(IMPLICIT_WRITES_PC, "Writes the program counter", "", "UREG.PC") +DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the program counter", "UREG.PC", "") DEF_ATTRIB(IMPLICIT_WRITES_SP, "Writes the stack pointer", "", "UREG.SP") +DEF_ATTRIB(IMPLICIT_READS_SP, "Reads the stack pointer", "UREG.SP", "") DEF_ATTRIB(IMPLICIT_WRITES_FP, "Writes the frame pointer", "", "UREG.FP") +DEF_ATTRIB(IMPLICIT_READS_FP, "Reads the frame pointer", "UREG.FP", "") +DEF_ATTRIB(IMPLICIT_WRITES_GP, "Writes the GP register", "", "UREG.GP") +DEF_ATTRIB(IMPLICIT_READS_GP, "Reads the GP register", "UREG.GP", "") DEF_ATTRIB(IMPLICIT_WRITES_LC0, "Writes loop count for loop 0", "", "UREG.LC0") DEF_ATTRIB(IMPLICIT_WRITES_LC1, "Writes loop count for loop 1", "", "UREG.LC1") DEF_ATTRIB(IMPLICIT_WRITES_SA0, "Writes start addr for loop 0", "", "UREG.SA0") DEF_ATTRIB(IMPLICIT_WRITES_SA1, "Writes start addr for loop 1", "", "UREG.SA1") +DEF_ATTRIB(IMPLICIT_WRITES_R00, "Writes Register 0", "", "UREG.R00") DEF_ATTRIB(IMPLICIT_WRITES_P0, "Writes Predicate 0", "", "UREG.P0") DEF_ATTRIB(IMPLICIT_WRITES_P1, "Writes Predicate 1", "", "UREG.P1") DEF_ATTRIB(IMPLICIT_WRITES_P2, "Writes Predicate 1", "", "UREG.P2") DEF_ATTRIB(IMPLICIT_WRITES_P3, "May write Predicate 3", "", "UREG.P3") -DEF_ATTRIB(IMPLICIT_READS_PC, "Reads the PC register", "", "") -DEF_ATTRIB(IMPLICIT_READS_P0, "Reads the P0 register", "", "") -DEF_ATTRIB(IMPLICIT_READS_P1, "Reads the P1 register", "", "") -DEF_ATTRIB(IMPLICIT_READS_P2, "Reads the P2 register", "", "") -DEF_ATTRIB(IMPLICIT_READS_P3, "Reads the P3 register", "", "") +DEF_ATTRIB(IMPLICIT_READS_R00, "Reads Register 0", "UREG.R00", "") +DEF_ATTRIB(IMPLICIT_READS_P0, "Reads Predicate 0", "UREG.P0", "") +DEF_ATTRIB(IMPLICIT_READS_P1, "Reads Predicate 1", "UREG.P1", "") +DEF_ATTRIB(IMPLICIT_READS_P3, "Reads Predicate 3", "UREG.P3", "") +DEF_ATTRIB(IMPLICIT_READS_Q3, "Reads Vector Predicate 3", "UREG.Q3", "") +DEF_ATTRIB(IMPLICIT_READS_CS, "Reads the CS/M register", "UREG.CS", "") +DEF_ATTRIB(IMPLICIT_READS_FRAMEKEY, "Reads FRAMEKEY", "UREG.FRAMEKEY", "") +DEF_ATTRIB(IMPLICIT_READS_FRAMELIMIT, "Reads FRAMELIMIT", "UREG.FRAMELIMIT", "") +DEF_ATTRIB(IMPLICIT_READS_ELR, "Reads the ELR register", "MREG.ELR", "") +DEF_ATTRIB(IMPLICIT_READS_SGP0, "Reads the SGP0 register", "MREG.SGP0", "") +DEF_ATTRIB(IMPLICIT_READS_SGP1, "Reads the SGP1 register", "MREG.SGP1", "") +DEF_ATTRIB(IMPLICIT_WRITES_SGP0, "Reads the SGP0 register", "", "MREG.SGP0") +DEF_ATTRIB(IMPLICIT_WRITES_SGP1, "Reads the SGP1 register", "", "MREG.SGP1") +DEF_ATTRIB(IMPLICIT_WRITES_STID_PRIO_ANYTHREAD, "Reads", "", "MREG.STID.PRIO") +DEF_ATTRIB(IMPLICIT_WRITES_SRBIT, "Writes the OVF bit", "", "UREG.SR.OVF") +DEF_ATTRIB(IMPLICIT_WRITES_FPFLAGS, "May write FP flags", "", "UREG.SR.FPFLAGS") +DEF_ATTRIB(IMPLICIT_WRITES_LPCFG, "Writes the loop config", "", "UREG.SR.LPCFG") +DEF_ATTRIB(IMPLICIT_WRITES_CVBITS, "Writes the CV flags", "", "UREG.SR.CV") +DEF_ATTRIB(IMPLICIT_READS_FPRND, "May read FP rnd mode", "UREG.SR.FPRND", "") +DEF_ATTRIB(IMPLICIT_READS_SSR, "May read SSR values", "MREG.SSR", "") +DEF_ATTRIB(IMPLICIT_READS_CCR, "May read CCR values", "MREG.CCR", "") +DEF_ATTRIB(IMPLICIT_WRITES_CCR, "May write CCR values", "", "MREG.CCR") +DEF_ATTRIB(IMPLICIT_WRITES_SSR, "May write SSR values", "", "MREG.SSR") +DEF_ATTRIB(IMPLICIT_READS_GELR, "May read GELR values", "GREG.GELR", "") +DEF_ATTRIB(IMPLICIT_READS_GEVB, "May read GEVB values", "MREG.GEVB", "") +DEF_ATTRIB(IMPLICIT_READS_GSR, "May read GSR values", "GREG.GSR", "") +DEF_ATTRIB(IMPLICIT_READS_GOSP, "May read GOSP values", "GREG.GOSP", "") +DEF_ATTRIB(IMPLICIT_WRITES_GELR, "May write GELR values", "", "GREG.GELR") +DEF_ATTRIB(IMPLICIT_WRITES_GSR, "May write GSR values", "", "GREG.GSR") +DEF_ATTRIB(IMPLICIT_WRITES_GOSP, "May write GOSP values", "", "GREG.GOSP") +DEF_ATTRIB(IMPLICIT_READS_IPENDAD_IPEND, "May read", "MREG.IPENDAD.IPEND", "") +DEF_ATTRIB(IMPLICIT_WRITES_IPENDAD_IPEND, "May write", "", "MREG.IPENDAD.IPEND") +DEF_ATTRIB(IMPLICIT_READS_IPENDAD_IAD, "May read", "MREG.IPENDAD.IAD", "") +DEF_ATTRIB(IMPLICIT_WRITES_IPENDAD_IAD, "May write", "", "MREG.IPENDAD.IAD") +DEF_ATTRIB(IMPLICIT_WRITES_IMASK_ANYTHREAD, "May write", "", "MREG.IMASK") +DEF_ATTRIB(IMPLICIT_READS_IMASK_ANYTHREAD, "May read", "MREG.IMASK", "") +DEF_ATTRIB(IMPLICIT_READS_SYSCFG_K0LOCK, "May read", "MREG.SYSCFG.K0LOCK", "") +DEF_ATTRIB(IMPLICIT_WRITES_SYSCFG_K0LOCK, "May write", "", "MREG.SYSCFG.K0LOCK") +DEF_ATTRIB(IMPLICIT_READS_SYSCFG_TLBLOCK, "May read", "MREG.SYSCFG.TLBLOCK", "") +DEF_ATTRIB(IMPLICIT_WRITES_SYSCFG_TLBLOCK, "May wr", "", "MREG.SYSCFG.TLBLOCK") +DEF_ATTRIB(IMPLICIT_WRITES_SYSCFG_GCA, "May write", "", "MREG.SYSCFG.GCA") +DEF_ATTRIB(IMPLICIT_READS_SYSCFG_GCA, "May read", "MREG.SYSCFG.GCA", "") DEF_ATTRIB(IMPLICIT_WRITES_USR, "May write USR", "", "") -DEF_ATTRIB(IMPLICIT_READS_SP, "Reads the SP register", "", "") + +/* Other things the instruction does */ +DEF_ATTRIB(ACC, "Has a multiply", "", "") +DEF_ATTRIB(MPY, "Has a multiply", "", "") +DEF_ATTRIB(SATURATE, "Does signed saturation", "", "") +DEF_ATTRIB(USATURATE, "Does unsigned saturation", "", "") +DEF_ATTRIB(CIRCADDR, "Uses circular addressing mode", "", "") +DEF_ATTRIB(BREVADDR, "Uses bit reverse addressing mode", "", "") +DEF_ATTRIB(BIDIRSHIFTL, "Uses a bidirectional shift left", "", "") +DEF_ATTRIB(BIDIRSHIFTR, "Uses a bidirectional shift right", "", "") +DEF_ATTRIB(BRANCHADDER, "Contains a PC-plus-immediate operation.", "", "") +DEF_ATTRIB(CRSLOT23, "Can execute in slot 2 or slot 3 (CR)", "", "") DEF_ATTRIB(COMMUTES, "The operation is communitive", "", "") DEF_ATTRIB(DEALLOCRET, "dealloc_return", "", "") DEF_ATTRIB(DEALLOCFRAME, "deallocframe", "", "") -DEF_ATTRIB(CRSLOT23, "Can execute in slot 2 or slot 3 (CR)", "", "") +/* Instruction Types */ + +DEF_ATTRIB(IT_ALU, "ALU type", "", "") +DEF_ATTRIB(IT_ALU_ADDSUB, "ALU add or subtract type", "", "") +DEF_ATTRIB(IT_ALU_MINMAX, "ALU MIN or MAX type", "", "") +DEF_ATTRIB(IT_ALU_MOVE, "ALU data movement type", "", "") +DEF_ATTRIB(IT_ALU_LOGICAL, "ALU logical operation type", "", "") +DEF_ATTRIB(IT_ALU_SHIFT, "ALU shift operation type", "", "") +DEF_ATTRIB(IT_ALU_SHIFT_AND_OP, "ALU shift and additional op type", "", "") +DEF_ATTRIB(IT_ALU_CMP, "ALU compare operation type", "", "") + +DEF_ATTRIB(IT_LOAD, "Loads from memory", "", "") +DEF_ATTRIB(IT_STORE, "Stores to memory", "", "") + +DEF_ATTRIB(IT_MPY, "Multiply type", "", "") +DEF_ATTRIB(IT_MPY_32, "32-bit Multiply type", "", "") + +DEF_ATTRIB(IT_COF, "Change-of-flow type", "", "") +DEF_ATTRIB(IT_HWLOOP, "Sets up hardware loop registers", "", "") + +DEF_ATTRIB(IT_MISC, "misc instruction type", "", "") + DEF_ATTRIB(IT_NOP, "nop instruction", "", "") DEF_ATTRIB(IT_EXTENDER, "constant extender instruction", "", "") +/* Exceptions the instruction can generate */ + +DEF_ATTRIB(EXCEPTION_TLB, "Can generate a TLB Miss Exception", "", "") +DEF_ATTRIB(EXCEPTION_ACCESS, "Can generate Access Violation Exception", "", "") +DEF_ATTRIB(EXCEPTION_SWI, "Software Interrupt (trap) exception", "", "") + + +/* Documentation Notes */ +DEF_ATTRIB(NOTE_ARCHV2, "Only available in the V2 architecture", "", "") + +DEF_ATTRIB(NOTE_PACKET_PC, "The PC is the addr of the start of the pkt", "", "") + +DEF_ATTRIB(NOTE_PACKET_NPC, "Next PC is the address following pkt", "", "") + +DEF_ATTRIB(NOTE_CONDITIONAL, "can be conditionally executed", "", "") + +DEF_ATTRIB(NOTE_NEWVAL_SLOT0, "New-value oprnd must execute on slot 0", "", "") + +DEF_ATTRIB(NOTE_RELATIVE_ADDRESS, "A PC-relative address is formed", "", "") + +DEF_ATTRIB(NOTE_LA_RESTRICT, "Cannot be in the last pkt of a HW loop", "", "") + +DEF_ATTRIB(NOTE_OOBVSHIFT, "Possible shift overflow", "", "") +DEF_ATTRIB(NOTE_BIDIRSHIFT, "Bidirectional shift", "", "") + +DEF_ATTRIB(NOTE_CVFLAGS, "Sets the Carry and Overflow flags in USR.", "", "") +DEF_ATTRIB(NOTE_SR_OVF_WHEN_SATURATING, "Might set OVF bit", "", "") +DEF_ATTRIB(NOTE_STNT, + "Non Temporal Data. The :nt appendix is a hint to the " + "microarchitecture indicating that the life of the cache line is " + "short. This information is used throughout the cache hierarchy to " + "make replacement and allocation decisions.", + "", "") +DEF_ATTRIB(NOTE_PRIV, "Monitor-level feature", "", "") +DEF_ATTRIB(NOTE_GUEST, "Guest-level feature", "", "") +DEF_ATTRIB(NOTE_NOPACKET, "solo instruction", "", "") +DEF_ATTRIB(NOTE_AXOK, "May only be grouped with ALU32 or non-FP XTYPE.", "", "") +DEF_ATTRIB(NOTE_NOSLOT1, "Packet with this insn must have slot 1 empty", "", "") +DEF_ATTRIB(NOTE_SLOT1_AOK, "Packet must have slot 1 empty or ALU32", "", "") +DEF_ATTRIB(NOTE_NOSLOT01, "Packet must have both slot 1 and 2 empty", "", "") +DEF_ATTRIB(NOTE_NEEDS_MEMLD, "Must be grouped with a memory load", "", "") +DEF_ATTRIB(NOTE_LATEPRED, "The predicate can not be used as a .new", "", "") +DEF_ATTRIB(NOTE_COMPAT_ACCURACY, "In the future accuracy may increase", "", "") +DEF_ATTRIB(NOTE_NVSLOT0, "Can execute only in slot 0 (ST)", "", "") +DEF_ATTRIB(NOTE_DEPRECATED, "Will be deprecated in a future version.", "", "") +DEF_ATTRIB(NOTE_NONAPALIV1, "may not work correctly in Napali V1.", "", "") +DEF_ATTRIB(NOTE_NOLAHAINAV1, "This may not work correctly in Lahaina V1.", "", + "") +DEF_ATTRIB(NOTE_BADTAG_UNDEF, "Undefined if a tag is non-present", "", "") +DEF_ATTRIB(NOTE_NOSLOT2_MPY, "Packet cannot have a slot 2 multiply", "", "") +DEF_ATTRIB(NOTE_HVX_ONLY, "Only available on a core with HVX.", "", "") + +DEF_ATTRIB(NOTE_NOCOF_RESTRICT, "Cannot be grouped with any COF", "", "") +DEF_ATTRIB(NOTE_BRANCHADDER_MAX1, "One PC-plus-offset calculation", "", "") + +DEF_ATTRIB(NOTE_CRSLOT23, "Execute on either slot2 or slot3 (CR)", "", "") +DEF_ATTRIB(NOTE_EXTENSION_AUDIO, "Hexagon audio extensions", "", "") +DEF_ATTRIB(NOTE_FETCHNT, + "Non Temporal Data Cache Prefetch. The :nt appendix is a hint to " + "the microarchitecture indicating that the life of the cache line " + "fetched is short. This information is used throughout the cache " + "hierarchy to make replacement and allocation decisions.", + "", "") +DEF_ATTRIB(NOTE_VECX_V67, "This instruction is only available on V67", "", "") + +DEF_ATTRIB(NOTE_NOVP, + "This instruction cannot be paired with a HVX permute instruction", + "", "") +DEF_ATTRIB(NOTE_VA_UNARY, + "If a packet contains this instruction and a HVX ALU op then the " + "ALU OP must be unary.", + "", "") + + +/* V6 MMVector Notes for Documentation */ +DEF_ATTRIB(NOTE_ANY_RESOURCE, "Can use any HVX resource.", "", "") +DEF_ATTRIB(NOTE_ANY2_RESOURCE, "Uses any pair of the HVX resources", "", "") +DEF_ATTRIB(NOTE_PERMUTE_RESOURCE, "Uses the HVX permute resource.", "", "") +DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "") +DEF_ATTRIB(NOTE_MPY_RESOURCE, "Uses a HVX multiply resource.", "", "") +DEF_ATTRIB(NOTE_MPYDV_RESOURCE, "Uses both HVX multiply resources.", "", "") +DEF_ATTRIB(NOTE_NT_VMEM, "Non-temporal hint to the micro-architecture", "", "") +DEF_ATTRIB(NOTE_ALL_RESOURCE, "Uses all HVX resources.", "", "") +DEF_ATTRIB(NOTE_VMEM, "Immediates are in multiples of vector length.", "", "") +DEF_ATTRIB(NOTE_ANY_VS_VX_RESOURCE, "Consumes two resources", "", "") + +DEF_ATTRIB(NOTE_RT8, "Input scalar register Rt is limited to R0-R7", "", "") + +DEF_ATTRIB(NOTE_MX, "This is in-memory matrix multiply instruction.", "", "") +DEF_ATTRIB(NOTE_VX_ACC_FWD, + "The accumulator (Vxx) source of this instruction must be generate " + "in the previous packet to avoid a stall. The accumulator cannot " + "come from a .tmp operation.", + "", "") +DEF_ATTRIB(NOTE_TMP_NO_VX, + "The tmp load instruction destination register cannot be an " + "accumulator register.", + "", "") + +DEF_ATTRIB( + NOTE_NO_ECC, + "ECC is not supported for scatter and gather instructions. Enabling ECC " + "with unprotected access instructions result in undetermined behavior.", + "", "") + +/* FP8 instructions */ +DEF_ATTRIB(HVX_FP8, "HVX FP8 extension instruction", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_8, "HVX IEEE FP extension instruction: 8-bit output", + "", "") + /* Restrictions to make note of */ +DEF_ATTRIB(RESTRICT_LOOP_LA, "Cannot be in the last packet of a loop", "", "") +DEF_ATTRIB(RESTRICT_NEEDS_MEMLD, "Must be grouped with a load", "", "") DEF_ATTRIB(RESTRICT_COF_MAX1, "One change-of-flow per packet", "", "") DEF_ATTRIB(RESTRICT_NOPACKET, "Not allowed in a packet", "", "") +DEF_ATTRIB(RESTRICT_NOSRMOVE, "Do not write SR in the same packet", "", "") DEF_ATTRIB(RESTRICT_SLOT0ONLY, "Must execute on slot0", "", "") DEF_ATTRIB(RESTRICT_SLOT1ONLY, "Must execute on slot1", "", "") DEF_ATTRIB(RESTRICT_SLOT2ONLY, "Must execute on slot2", "", "") DEF_ATTRIB(RESTRICT_SLOT3ONLY, "Must execute on slot3", "", "") +DEF_ATTRIB(RESTRICT_NOSLOT2_MPY, "A packet cannot have a slot 2 mpy", "", "") DEF_ATTRIB(RESTRICT_NOSLOT1, "No slot 1 instruction in parallel", "", "") +DEF_ATTRIB(RESTRICT_SLOT1_AOK, "Slot 1 insn must be empty or A-type", "", "") +DEF_ATTRIB(RESTRICT_NOSLOT01, "No slot 0 or 1 instructions in parallel", "", "") +DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "") +DEF_ATTRIB(RESTRICT_NOSLOT0_LOAD, "Packet must not have a slot 1 load", "", "") +DEF_ATTRIB(RESTRICT_NOCOF, "Cannot be grouped with any COF", "", "") +DEF_ATTRIB(RESTRICT_BRANCHADDER_MAX1, "One PC-plus-offset calculation", "", "") DEF_ATTRIB(RESTRICT_PREFERSLOT0, "Try to encode into slot 0", "", "") +DEF_ATTRIB(RESTRICT_SINGLE_MEM_FIRST, "Single memory op must be last", "", "") DEF_ATTRIB(RESTRICT_PACKET_AXOK, "May exist with A-type or X-type", "", "") +DEF_ATTRIB(RESTRICT_PACKET_SOMEREGS_OK, "Relaxed grouping rules", "", "") +DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") + +DEF_ATTRIB(PAIR_1OF2, "For assembler", "", "") +DEF_ATTRIB(PAIR_2OF2, "For assembler", "", "") +DEF_ATTRIB(NOTE_MX_PAIR, + "Weights and Activations need to be paired in a packet.", "", "") +DEF_ATTRIB(NOTE_RESTRICT_CVI_NOVP, + "This instruction cannot use the permute/shift resource", "", "") + +/* Performance based preferences */ +DEF_ATTRIB(PREFER_SLOT3, "Complex XU prefering slot3", "", "") + +DEF_ATTRIB(RELAX_COF_1ST, "COF can be fisrt in assembly order", "", "") +DEF_ATTRIB(RELAX_COF_2ND, "COF can be second in assembly order", "", "") DEF_ATTRIB(ICOP, "Instruction cache op", "", "") +DEF_ATTRIB(INTRINSIC_RETURNS_UNSIGNED, "Intrinsic returns an unsigned", "", "") + +DEF_ATTRIB(PRED_BIT_1, "The branch uses bit 1 as the prediction bit", "", "") +DEF_ATTRIB(PRED_BIT_4, "The branch uses bit 4 as the prediction bit", "", "") +DEF_ATTRIB(PRED_BIT_8, "The branch uses bit 8 as the prediction bit", "", "") +DEF_ATTRIB(PRED_BIT_12, "The branch uses bit 12 as the prediction bit", "", "") +DEF_ATTRIB(PRED_BIT_13, "The branch uses bit 13 as the prediction bit", "", "") +DEF_ATTRIB(PRED_BIT_7, "The branch uses bit 7 as the prediction bit", "", "") +DEF_ATTRIB(HWLOOP0_SETUP, "Sets up HW loop0", "", "") +DEF_ATTRIB(HWLOOP1_SETUP, "Sets up HW loop1", "", "") DEF_ATTRIB(HWLOOP0_END, "Ends HW loop0", "", "") DEF_ATTRIB(HWLOOP1_END, "Ends HW loop1", "", "") DEF_ATTRIB(RET_TYPE, "return type", "", "") +DEF_ATTRIB(HINTJR, "hintjr type", "", "") DEF_ATTRIB(DCZEROA, "dczeroa type", "", "") +DEF_ATTRIB(ICTAGOP, "ictag op type", "", "") DEF_ATTRIB(ICFLUSHOP, "icflush op type", "", "") DEF_ATTRIB(DCFLUSHOP, "dcflush op type", "", "") +DEF_ATTRIB(DCTAGOP, "dctag op type", "", "") DEF_ATTRIB(L2FLUSHOP, "l2flush op type", "", "") +DEF_ATTRIB(L2TAGOP, "l2tag op type", "", "") DEF_ATTRIB(DCFETCH, "dcfetch type", "", "") +DEF_ATTRIB(BIMODAL_BRANCH, "Updates the bimodal branch predictor", "", "") +DEF_ATTRIB(VECINSN, "Long Vector Instruction", "", "") +DEF_ATTRIB(MEMSIZE_32B, "Memory width is 32 bytes", "", "") +DEF_ATTRIB(FOUR_PHASE, "Four Phase Instruction", "", "") DEF_ATTRIB(L2FETCH, "Instruction is l2fetch type", "", "") +DEF_ATTRIB(PREDUSE_BSB, "Instructions need back-skip-back scheduling", "", "") DEF_ATTRIB(ICINVA, "icinva", "", "") DEF_ATTRIB(DCCLEANINVA, "dccleaninva", "", "") +DEF_ATTRIB(EXTENSION_AUDIO, "audio extension", "", "") + +DEF_ATTRIB(MEMCPY, "memcpy or dma-type instruction", "", "") DEF_ATTRIB(NO_INTRINSIC, "Don't generate an intrisic", "", "") -/* Documentation Notes */ -DEF_ATTRIB(NOTE_CONDITIONAL, "can be conditionally executed", "", "") -DEF_ATTRIB(NOTE_NEWVAL_SLOT0, "New-value oprnd must execute on slot 0", "", "") -DEF_ATTRIB(NOTE_PRIV, "Monitor-level feature", "", "") -DEF_ATTRIB(NOTE_NOPACKET, "solo instruction", "", "") -DEF_ATTRIB(NOTE_AXOK, "May only be grouped with ALU32 or non-FP XTYPE.", "", "") -DEF_ATTRIB(NOTE_LATEPRED, "The predicate can not be used as a .new", "", "") -DEF_ATTRIB(NOTE_NVSLOT0, "Can execute only in slot 0 (ST)", "", "") -DEF_ATTRIB(NOTE_NOVP, "Cannot be paired with a HVX permute instruction", "", "") -DEF_ATTRIB(NOTE_VA_UNARY, "Combined with HVX ALU op (must be unary)", "", "") +DEF_ATTRIB(NO_XML, "Don't generate a XML docs for this instruction", "", "") -/* V6 MMVector Notes for Documentation */ -DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "") -/* Restrictions to make note of */ -DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "") -DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") +DEF_ATTRIB(DMA, "User-DMA instruction", "", "") +DEF_ATTRIB(VERIF_DMASTEP, + "Hiphop needs to step dma prior to executing this packet", "", "") +DEF_ATTRIB(VERIF_DMATICK, + "DMA gets a tick in verif mode for this instruction after a commit", + "", "") + +DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "") +DEF_ATTRIB(NOTE_HVX_IEEE_FP, + "Only supported on the HVX cores with the IEEE FP extension", "", "") + +DEF_ATTRIB(HVX_IEEE_FP_DV_ONE, + "HVX IEEE FP extension instruction - dual pipes: P2 and P3 - output " + "only on P2", + "", "") +DEF_ATTRIB(HVX_IEEE_FP_ACC, "HVX IEEE FP accumulate instruction", "", "") +DEF_ATTRIB(HVX_IEEE_BF, + "HVX IEEE BF extension instruction: 16-bit bfloat input", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_BF, + "HVX IEEE FP extension instruction: 16-bit bfloat output", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_16, + "HVX IEEE FP extension instruction: 16-bit output", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_32, + "HVX IEEE FP extension instruction: 32-bit output", "", "") +DEF_ATTRIB(HVX_IEEE_FP_BINARY_LATE, + "HVX IEEE FP extension instruction: Both inputs can arrive late", "", + "") /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/imported/macros.def b/target/hexagon/imported/macros.def old mode 100755 new mode 100644 index 4bbcfdd5e194..f24f89f36126 --- a/target/hexagon/imported/macros.def +++ b/target/hexagon/imported/macros.def @@ -353,6 +353,12 @@ DEF_MACRO( () ) +DEF_MACRO( + fREAD_SSR, /* read SSR register */ + (READ_RREG(REG_SSR)), /* behavior */ + () +) + DEF_MACRO( fWRITE_LR, /* write lr */ WRITE_RREG(REG_LR,A), /* behavior */ @@ -371,12 +377,36 @@ DEF_MACRO( (A_IMPLICIT_WRITES_SP) ) +DEF_MACRO( + fWRITE_GOSP, /* write gosp */ + WRITE_RREG(REG_GOSP,A), /* behavior */ + (A_IMPLICIT_WRITES_GOSP) +) + DEF_MACRO( fREAD_SP, /* read stack pointer */ (READ_RREG(REG_SP)), /* behavior */ () ) +DEF_MACRO( + fREAD_GOSP, /* read guest other stack pointer */ + (READ_RREG(REG_GOSP)), /* behavior */ + () +) + +DEF_MACRO( + fREAD_GELR, /* read guest other stack pointer */ + (READ_RREG(REG_GELR)), /* behavior */ + () +) + +DEF_MACRO( + fREAD_GEVB, /* read guest other stack pointer */ + (READ_RREG(REG_GEVB)), /* behavior */ + () +) + DEF_MACRO( fREAD_CSREG, /* read CS register */ (READ_RREG(REG_CSA+N)), /* behavior */ @@ -570,6 +600,11 @@ DEF_MACRO( WRITE_PREG(3,VAL), /* behavior */ (A_IMPLICIT_WRITES_P3) ) +DEF_MACRO( + fWRITE_P3_LATE, /* write Predicate 0 */ + {WRITE_PREG(3,VAL); fHIDE(MARK_LATE_PRED_WRITE(3))} , /* behavior */ + (A_IMPLICIT_WRITES_P3,A_RESTRICT_LATEPRED) +) DEF_MACRO( fPART1, /* write Predicate 0 */ @@ -660,6 +695,7 @@ DEF_MACRO( ((size8s_t)((size2s_t)(A))), /* optional attributes */ ) + DEF_MACRO( fCAST2_8u, /* macro name */ ((size8u_t)((size2u_t)(A))), @@ -1532,18 +1568,209 @@ DEF_MACRO(fECHO, /* OS interface and stop/wait */ /********************************************/ +DEF_MACRO(RUNNABLE_THREADS_MAX, + (thread->processor_ptr->runnable_threads_max), + () +) + +DEF_MACRO(THREAD_IS_ON, + ((PROC->arch_proc_options->thread_enable_mask>>TNUM) & 0x1), + () +) + +DEF_MACRO(THREAD_EN_MASK, + ((PROC->arch_proc_options->thread_enable_mask)), + () +) + + + +DEF_MACRO(READ_IMASK, + (((TH) >= (thread->processor_ptr->runnable_threads_max)) ? 0 : (thread->processor_ptr->thread[TH]->Regs[REG_IMASK])), + () +) +DEF_MACRO(WRITE_IMASK, + if ((TH) < (thread->processor_ptr->runnable_threads_max)) { thread->processor_ptr->thread[TH]->Regs[REG_IMASK]=(VAL & reg_mutability[REG_IMASK] ); }, + (A_IMPLICIT_WRITES_IMASK_ANYTHREAD) +) + + +DEF_MACRO(WRITE_PRIO, + { + if ((TH) < (thread->processor_ptr->runnable_threads_max)) { + size4u_t tid_reg = thread->processor_ptr->thread[TH]->Regs[REG_TID]; + fINSERT_BITS(tid_reg, reg_field_info[STID_PRIO].width, reg_field_info[STID_PRIO].offset, VAL); + LOG_OTHER_THREAD_REG_WRITE(thread,REG_TID,tid_reg,TH); + } + }, + (A_IMPLICIT_WRITES_STID_PRIO_ANYTHREAD) +) + + +DEF_MACRO(DO_IASSIGNW, + { + int i; + int intbitpos = ((REG>>16)&0xF); + for (i=0;iprocessor_ptr->arch_proc_options->thread_enable_mask>>i) & 0x1)) { + fINSERT_BITS(thread->processor_ptr->thread[i]->Regs[REG_IMASK],1, intbitpos, (REG>>i) & 1); + } + } + }, + (A_IMPLICIT_WRITES_IMASK_ANYTHREAD) +) + + + + +DEF_MACRO(fDO_NMI, + { + int i; + for (i=0;iprocessor_ptr->arch_proc_options->thread_enable_mask>>i) & 0x1) ) { + if (SREG & (1<processor_ptr->thread[i]); + } + } + } + }, +) + +DEF_MACRO(fDO_TRACE, + { + fHIDE(HEX_CALLBACK(thread->processor_ptr->options->trace_callback, + thread->system_ptr,thread->processor_ptr, + thread->threadId,SREG);) + }, +) + +DEF_MACRO(DO_IASSIGNR, + { + int i; + int result=0; + int intbitpos = ((SREG>>16)&0xF); + for (i=0;iprocessor_ptr->arch_proc_options->thread_enable_mask>>i) & 0x1)) { + result |= (((thread->processor_ptr->thread[i]->Regs[REG_IMASK]>>intbitpos)&1)<processor_ptr->options->swi_callback, + thread->system_ptr,thread->processor_ptr, + thread->threadId,REG)); + LOG_GLOBAL_REG_WRITE(REG_IPEND,(GLOBAL_REG_READ(REG_IPEND) | (REG & GLOBAL_REG_READ(REG_IEL)))); + }, + (A_EXCEPTION_SWI) +) + +DEF_MACRO(DO_CSWI, + LOG_GLOBAL_REG_WRITE(REG_IPEND,GLOBAL_REG_READ(REG_IPEND) & ~((REG) & GLOBAL_REG_READ(REG_IEL)));, + () +) + +DEF_MACRO(DO_CIAD, + sys_ciad(thread,VAL); LOG_GLOBAL_REG_WRITE(REG_IAD,GLOBAL_REG_READ(REG_IAD) & ~(VAL));, + (A_EXCEPTION_SWI) +) + +DEF_MACRO(DO_SIAD, + sys_siad(thread,VAL); LOG_GLOBAL_REG_WRITE(REG_IAD,GLOBAL_REG_READ(REG_IAD) | (VAL));, + (A_EXCEPTION_SWI) +) + +DEF_MACRO(fBREAK, + {isdb_brkpt_insn(thread->processor_ptr,thread->threadId);}, + () +) + DEF_MACRO(fPAUSE, {sys_pause(thread, insn->slot, IMM);}, () ) + DEF_MACRO(fTRAP, warn("Trap NPC=%x ",fREAD_NPC()); warn("Trap exception, PCYCLE=%lld TYPE=%d NPC=%x IMM=0x%x",thread->processor_ptr->pstats[pcycles],TRAPTYPE,fREAD_NPC(),IMM); register_trap_exception(thread,fREAD_NPC(),TRAPTYPE,IMM);, + (A_EXCEPTION_SWI) +) + +DEF_MACRO(fINTERNAL_CLEAR_SAMEPAGE, + /* force re-xlate at next fetch, refresh of in_user_mode, etc */ + /* Permissions change too... */ + sys_utlb_invalidate(thread->processor_ptr,thread), + /* NOTHING */ +) + +DEF_MACRO(fCLEAR_RTE_EX, + { + fLOG_REG_FIELD(SSR,SSR_EX,0); + fINTERNAL_CLEAR_SAMEPAGE(); + }, + () +) + +DEF_MACRO(fTLB_LOCK_AVAILABLE, + (fREAD_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_TLBLOCK) == 0), () ) +DEF_MACRO(fK0_LOCK_AVAILABLE, + (fREAD_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_K0LOCK) == 0), + () +) + +DEF_MACRO(fSET_TLB_LOCK, + { + if (fTLB_LOCK_AVAILABLE()) { + fLOG_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_TLBLOCK,1); + } else { + sys_waiting_for_tlb_lock(thread); + } + }, + () +) + +DEF_MACRO(fSET_K0_LOCK, + { + if (fK0_LOCK_AVAILABLE() && sys_k0lock_queue_ready(thread)) { + warn("k0lock: T%d: PC=0x%x: PCycle=%lld",thread->threadId,thread->Regs[REG_PC],thread->processor_ptr->pstats[pcycles]); + fLOG_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_K0LOCK,1); + } else { + warn("k0lock_waiting: T%d: PC=0x%x: PCycle=%lld",thread->threadId,thread->Regs[REG_PC],thread->processor_ptr->pstats[pcycles]); + sys_waiting_for_k0_lock(thread); + } + }, + () +) + +DEF_MACRO(fCLEAR_TLB_LOCK, + { + int i; + fLOG_GLOBAL_REG_FIELD(SYSCONF,SYSCFG_TLBLOCK,0); + for (i = 0; i < RUNNABLE_THREADS_MAX; i++) { + if(( (thread->processor_ptr->arch_proc_options->thread_enable_mask>>i) & 0x1)) { + thread->processor_ptr->thread[i]->cu_tlb_lock_waiting = 0; + } + } + }, + () +) + +DEF_MACRO(fCLEAR_K0_LOCK, + do { + warn("k0unlock: T%d: PC=0x%x: Pcycle=%lld",thread->threadId,thread->Regs[REG_PC], thread->processor_ptr->pstats[pcycles]); + sys_initiate_clear_k0_lock(thread); + } while (0), + () +) + DEF_MACRO(fALIGN_REG_FIELD_VALUE, ((VAL)<processor_ptr->global_regs[REG_##REG], + reg_field_info[FIELD].width, + reg_field_info[FIELD].offset,VAL), +) + +DEF_MACRO(fLOG_GLOBAL_REG_FIELD, + LOG_MASKED_GLOBAL_REG_WRITE(REG_##REG, + fALIGN_REG_FIELD_VALUE(FIELD,VAL), + fGET_REG_FIELD_MASK(FIELD)), + () +) + DEF_MACRO(fREAD_REG_FIELD, fEXTRACTU_BITS(thread->Regs[REG_##REG], reg_field_info[FIELD].width, @@ -1561,6 +1808,13 @@ DEF_MACRO(fREAD_REG_FIELD, /* ATTRIBS */ ) +DEF_MACRO(fREAD_GLOBAL_REG_FIELD, + fEXTRACTU_BITS(thread->processor_ptr->global_regs[REG_##REG], + reg_field_info[FIELD].width, + reg_field_info[FIELD].offset), + /* ATTRIBS */ +) + DEF_MACRO(fGET_FIELD, fEXTRACTU_BITS(VAL, reg_field_info[FIELD].width, @@ -1576,6 +1830,185 @@ DEF_MACRO(fSET_FIELD, /* ATTRIBS */ ) +DEF_MACRO(fSET_RUN_MODE_NOW, + {thread->processor_ptr->global_regs[REG_MODECTL] |= (1<last_commit_cycle = thread->processor_ptr->pcycle_counter; + sys_recalc_num_running_threads(thread->processor_ptr);}, +) + +DEF_MACRO(fIN_DEBUG_MODE, + (thread->debug_mode || (fREAD_GLOBAL_REG_FIELD(ISDBST,ISDBST_DEBUGMODE) & 1<debug_mode), + () +) + + +DEF_MACRO(fIN_DEBUG_MODE_WARN, + { + if (fREAD_GLOBAL_REG_FIELD(ISDBST,ISDBST_DEBUGMODE) & 1<processor_ptr); + } while (0), + /* NOTHING */ +) + +DEF_MACRO(fGET_RUN_MODE, + ((thread->processor_ptr->global_regs[REG_MODECTL]>>TNUM)&0x1), +) + +DEF_MACRO(fSET_WAIT_MODE, + {fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_W, + fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_W) | 1<<(TNUM))}, + /* NOTHING */ +) + +DEF_MACRO(fCLEAR_WAIT_MODE, + {thread->processor_ptr->global_regs[REG_MODECTL] &= ~(1<<(TNUM+16)); + thread->last_commit_cycle = thread->processor_ptr->pcycle_counter; + sys_recalc_num_running_threads(thread->processor_ptr);}, +) + +DEF_MACRO(fGET_WAIT_MODE, + ((thread->processor_ptr->global_regs[REG_MODECTL]>>(TNUM+16))&0x1), +) + + +DEF_MACRO(fRESET_THREAD, + register_reset_interrupt(T,NUM), +) + +DEF_MACRO(fREAD_CURRENT_EVB, + (GLOBAL_REG_READ(REG_EVB)), + /* nothing */ +) + +DEF_MACRO(fREAD_ELR, + READ_RREG(REG_ELR), + () +) + +DEF_MACRO(fPOW2_HELP_ROUNDUP, + ((VAL) | ((VAL) >> 1) | ((VAL) >> 2) | ((VAL) >> 4) | ((VAL) >> 8) | ((VAL) >> 16)), + () +) + +DEF_MACRO(fPOW2_ROUNDUP, + fPOW2_HELP_ROUNDUP((VAL)-1)+1, + () +) + +DEF_MACRO(fTLB_IDXMASK, + ((INDEX) & (fPOW2_ROUNDUP(fCAST4u(thread->processor_ptr->arch_proc_options->jtlb_size)) - 1)), + () +) + +DEF_MACRO(fTLB_NONPOW2WRAP, + (((INDEX) >= thread->processor_ptr->arch_proc_options->jtlb_size) ? ((INDEX) - thread->processor_ptr->arch_proc_options->jtlb_size) : (INDEX)), + /* ATTRIBS */ +) + +DEF_MACRO(fTLBW, + do {size4u_t __myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX)); + TLB_REG_WRITE(__myidx,VALUE); + fHIDE(HEX_CALLBACK(thread->processor_ptr->options->tlbw_callback,thread->system_ptr,thread->processor_ptr,thread->threadId,__myidx);) + fHIDE(sys_tlb_write(thread,__myidx,VALUE);)} while (0), + /* ATTRIBS */ +) + +DEF_MACRO(fTLB_ENTRY_OVERLAP, + fHIDE( (sys_check_overlap(thread,VALUE)!=-2) ), + /* ATTRIBS */ +) + +DEF_MACRO(fTLB_ENTRY_OVERLAP_IDX, + fHIDE(sys_check_overlap(thread,VALUE)), + /* ATTRIBS */ +) + + +DEF_MACRO(fTLBR, + TLB_REG_READ(fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX))), + /* ATTRIBS */ +) + +DEF_MACRO(fTLBP, + tlb_lookup(thread,((TLBHI)>>12),((TLBHI)<<12),1), + /* attribs */ +) + + + +DEF_MACRO(READ_SGP0, + READ_RREG(REG_SGP), + () +) + +DEF_MACRO(READ_SGP1, + READ_RREG(REG_SGP+1), + () +) + +DEF_MACRO(READ_SGP10, + READ_RREG_PAIR(REG_SGP), + () +) + +DEF_MACRO(READ_UGP, + READ_RREG(REG_UGP), +) + +DEF_MACRO(WRITE_SGP0, + WRITE_RREG(REG_SGP,VAL), + (A_IMPLICIT_WRITES_SGP0) +) + +DEF_MACRO(WRITE_SGP1, + WRITE_RREG(REG_SGP+1,VAL), + (A_IMPLICIT_WRITES_SGP1) +) + +DEF_MACRO(WRITE_SGP10, + WRITE_RREG_PAIR(REG_SGP,VAL), + (A_IMPLICIT_WRITES_SGP0,A_IMPLICIT_WRITES_SGP1) +) + +DEF_MACRO(WRITE_UGP, + WRITE_RREG(REG_UGP,VAL), +) + +DEF_MACRO(fSTART, + fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_E, fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_E) | (((REG & ((1<processor_ptr))), + () +) + +DEF_MACRO(fRESUME, + fLOG_GLOBAL_REG_FIELD(MODECTL,MODECTL_W, + fREAD_GLOBAL_REG_FIELD(MODECTL,MODECTL_W) & (~(REG))), + () +) + +DEF_MACRO(fGET_TNUM, + thread->threadId, + () +) + /********************************************/ /* Cache Management */ /********************************************/ @@ -1602,6 +2035,11 @@ DEF_MACRO(fISYNC, ) +DEF_MACRO(fICFETCH, + , + () +) + DEF_MACRO(fDCFETCH, sys_dcfetch(thread, (REG), insn->slot), (A_MEMLIKE) @@ -1615,6 +2053,34 @@ DEF_MACRO(fICINVA, (A_ICINVA) ) +DEF_MACRO(fDCTAGR, + ({DST=sys_dctagr(thread, INDEX, insn->slot,DSTREGNO);})/* FIXME */, + () +) + +DEF_MACRO(fDCTAGW, + (sys_dctagw(thread, INDEX, PART2, insn->slot)), + () +) +DEF_MACRO(fICTAGR, + ({DST=sys_ictagr(thread, INDEX, insn->slot,REGNO);}), + () +) + +DEF_MACRO(fICDATAR, + ({DST=sys_icdatar(thread, INDEX, insn->slot);}), + () +) + +DEF_MACRO(fICTAGW, + (sys_ictagw(thread, INDEX, PART2, insn->slot)), + () +) +DEF_MACRO(fICDATAW, + ({ fHIDE(); }), + () +) + DEF_MACRO(fL2FETCH, sys_l2fetch(thread, ADDR,HEIGHT,WIDTH,STRIDE,FLAGS, insn->slot), (A_MEMLIKE,A_L2FETCH) @@ -1635,6 +2101,12 @@ DEF_MACRO(fDCZEROA, (A_MEMLIKE) ) +DEF_MACRO(fDCINVA, + sys_dcinva(thread, (REG)), + (A_MEMLIKE) +) + + DEF_MACRO(fCHECKFORPRIV, {sys_check_privs(thread); if (EXCEPTION_DETECTED) return; }, () @@ -1645,6 +2117,16 @@ DEF_MACRO(fCHECKFORGUEST, () ) +DEF_MACRO(fTAKEN_INTERRUPT_EDGECLEAR, + { proc->global_regs[REG_IPEND] &= ~(INT_NUMTOMASK(intnum) & proc->global_regs[REG_IEL]); }, + () +) + +DEF_MACRO(fSET_IAD, + { sys_siad(thread,INT_NUMTOMASK(intnum)); thread->processor_ptr->global_regs[REG_IAD] |= INT_NUMTOMASK(intnum); }, + () +) + DEF_MACRO(fBRANCH_SPECULATE_STALL, { sys_speculate_branch_stall(thread, insn->slot, JUMP_COND(JUMP_PRED_SET), @@ -1664,3 +2146,79 @@ DEF_MACRO(IV1DEAD, , () ) + +DEF_MACRO(fIN_MONITOR_MODE, + sys_in_monitor_mode(thread), + () +) + +DEF_MACRO(fIN_USER_MODE, + sys_in_user_mode(thread), + () +) + +DEF_MACRO(fIN_GUEST_MODE, + sys_in_guest_mode(thread), + () +) + +DEF_MACRO(fGRE_ENABLED, + fREAD_REG_FIELD(CCR,CCR_GRE), + () +) + +DEF_MACRO(fGTE_ENABLED, + fREAD_REG_FIELD(CCR,CCR_GRE), + () +) + +DEF_MACRO(fTRAP1_VIRTINSN, + ((fIN_GUEST_MODE()) + && (fGRE_ENABLED()) + && ( ((IMM) == 1) + || ((IMM) == 3) + || ((IMM) == 4) + || ((IMM) == 6))), + () +) + +DEF_MACRO(fVIRTINSN_RTE, + do { + thread->trap1_info = TRAP1_VIRTINSN_RTE; + fLOG_REG_FIELD(SSR,SSR_SS,fREAD_REG_FIELD(GSR,GSR_SS)); + fLOG_REG_FIELD(CCR,CCR_GIE,fREAD_REG_FIELD(GSR,GSR_IE)); + fLOG_REG_FIELD(SSR,SSR_GM,!fREAD_REG_FIELD(GSR,GSR_UM)); + fBRANCH((fREAD_GELR() & -4),COF_TYPE_RTE); + fINTERNAL_CLEAR_SAMEPAGE(); + } while (0), + (A_IMPLICIT_WRITES_CCR,A_IMPLICIT_WRITES_SSR) +) + +DEF_MACRO(fVIRTINSN_SETIE, + do { + fLOG_REG_FIELD(CCR,CCR_GIE,(REG) & 1); + REG = fREAD_REG_FIELD(CCR,CCR_GIE); + thread->trap1_info = TRAP1_VIRTINSN_SETIE; + } while (0), + (A_IMPLICIT_WRITES_CCR) +) + +DEF_MACRO(fVIRTINSN_GETIE, + { + thread->trap1_info = TRAP1_VIRTINSN_GETIE; + REG = fREAD_REG_FIELD(CCR,CCR_GIE); + }, + () +) + +DEF_MACRO(fVIRTINSN_SPSWAP, + do { + if (fREAD_REG_FIELD(GSR,GSR_UM)) { + size4u_t TEMP = REG; + REG = fREAD_GOSP(); + fWRITE_GOSP(TEMP); + thread->trap1_info = TRAP1_VIRTINSN_SPSWAP; + } + } while (0), + (A_IMPLICIT_WRITES_GOSP) +) From ade7eeccbc0644a0342df83d37467318bb7f7022 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 8 Sep 2024 18:52:49 -0700 Subject: [PATCH 020/109] target/hexagon: Define DC states Signed-off-by: Brian Cain --- target/hexagon/cpu_bits.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 6582bb4f16fc..5d26815eb9bc 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -41,6 +41,13 @@ enum hex_cause { HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b, }; +enum data_cache_state { + HEX_DC_STATE_INVALID = 0x0, + HEX_DC_STATE_VALID = 0x1, + HEX_DC_STATE_RESERVED = 0x2, + HEX_DC_STATE_UNUSED_WT = 0x3, +}; + #define PACKET_WORDS_MAX 4 static inline uint32_t parse_bits(uint32_t encoding) From b961c8e39fce980e40236701a64135513d960b4f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 17:04:51 -0500 Subject: [PATCH 021/109] FIXME: target/hexagon: Add new macro definitions for sysemu FIXME: this commit contains FIXMEs Signed-off-by: Brian Cain --- target/hexagon/macros.h | 28 ++++- target/hexagon/op_helper.c | 1 + target/hexagon/sys_macros.h | 238 ++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 target/hexagon/sys_macros.h diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index ee3d4c88e7bd..6e4a3a16970c 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -537,9 +537,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #ifdef CONFIG_USER_ONLY #define fFRAMECHECK(ADDR, EA) do { } while (0) /* Not modelled in linux-user */ -#else -/* System mode not implemented yet */ -#define fFRAMECHECK(ADDR, EA) g_assert_not_reached(); #endif #ifdef QEMU_GENERATE @@ -630,8 +627,18 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #define fCONSTLL(A) A##LL #define fECHO(A) (A) -#define fTRAP(TRAPTYPE, IMM) helper_raise_exception(env, HEX_EXCP_TRAP0) +#ifdef CONFIG_USER_ONLY +#define fTRAP(TRAPTYPE, IMM) \ + do { \ + hexagon_raise_exception_err(env, HEX_EVENT_TRAP0, PC); \ + } while (0) +#endif + +#define fDO_TRACE(SREG) +#define fBREAK() +#define fUNPAUSE() #define fPAUSE(IMM) +#define fDCFETCH(REG) #define fALIGN_REG_FIELD_VALUE(FIELD, VAL) \ ((VAL) << reg_field_info[FIELD].offset) @@ -648,10 +655,23 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) ctx->dczero_addr = tcg_temp_new(); \ tcg_gen_mov_tl(ctx->dczero_addr, (REG)); \ } while (0) +#else +#define fDCZEROA(REG) ((void) REG) #endif #define fBRANCH_SPECULATE_STALL(DOTNEWVAL, JUMP_COND, SPEC_DIR, HINTBITNUM, \ STRBITNUM) /* Nothing */ +#ifdef CONFIG_USER_ONLY +/* + * This macro can only be true in guest mode. + * In user mode, the 4 VIRTINSN's can't be reached + */ +#define fTRAP1_VIRTINSN(IMM) (false) +#define fVIRTINSN_SPSWAP(IMM, REG) g_assert_not_reached() +#define fVIRTINSN_GETIE(IMM, REG) g_assert_not_reached() +#define fVIRTINSN_SETIE(IMM, REG) g_assert_not_reached() +#define fVIRTINSN_RTE(IMM, REG) g_assert_not_reached() +#endif #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6da8db8ea5c5..4feec232983a 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "internal.h" #include "macros.h" +#include "sys_macros.h" #include "arch.h" #include "hex_arch_types.h" #include "fma_emu.h" diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h new file mode 100644 index 000000000000..6c9bb0a147ba --- /dev/null +++ b/target/hexagon/sys_macros.h @@ -0,0 +1,238 @@ +/* + * Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-clause + */ + +#ifndef HEXAGON_SYS_MACROS_H +#define HEXAGON_SYS_MACROS_H + +/* + * Macro definitions for Hexagon system mode + */ + +#ifndef CONFIG_USER_ONLY + +#define READ_SREG(NUM) ARCH_GET_SYSTEM_REG(env, NUM) +#define READ_SGP0() ARCH_GET_SYSTEM_REG(env, HEX_SREG_SGP0) +#define READ_SGP1() ARCH_GET_SYSTEM_REG(env, HEX_SREG_SGP1) +#define READ_SGP10() ((uint64_t)ARCH_GET_SYSTEM_REG(env, HEX_SREG_SGP0) | \ + ((uint64_t)ARCH_GET_SYSTEM_REG(env, HEX_SREG_SGP1) << 32)) + +#define WRITE_SREG(NUM, VAL) log_sreg_write(env, NUM, VAL, slot) +#define WRITE_SGP0(VAL) log_sreg_write(env, HEX_SREG_SGP0, VAL, slot) +#define WRITE_SGP1(VAL) log_sreg_write(env, HEX_SREG_SGP1, VAL, slot) +#define WRITE_SGP10(VAL) \ + do { \ + log_sreg_write(env, HEX_SREG_SGP0, (VAL) & 0xFFFFFFFF, slot); \ + log_sreg_write(env, HEX_SREG_SGP1, (VAL) >> 32, slot); \ + } while (0) + +#ifdef QEMU_GENERATE +#define GET_SSR_FIELD(RES, FIELD) \ + GET_FIELD(RES, FIELD, hex_t_sreg[HEX_SREG_SSR]) +#else + +#define GET_SSR_FIELD(FIELD, REGIN) \ + (uint32_t)GET_FIELD(FIELD, REGIN) +#define GET_SYSCFG_FIELD(FIELD, REGIN) \ + (uint32_t)GET_FIELD(FIELD, REGIN) +#define SET_SYSTEM_FIELD(ENV, REG, FIELD, VAL) \ + do { \ + uint32_t regval = ARCH_GET_SYSTEM_REG(ENV, REG); \ + fINSERT_BITS(regval, reg_field_info[FIELD].width, \ + reg_field_info[FIELD].offset, (VAL)); \ + ARCH_SET_SYSTEM_REG(ENV, REG, regval); \ + } while (0) +#define SET_SSR_FIELD(ENV, FIELD, VAL) \ + SET_SYSTEM_FIELD(ENV, HEX_SREG_SSR, FIELD, VAL) +#define SET_SYSCFG_FIELD(ENV, FIELD, VAL) \ + SET_SYSTEM_FIELD(ENV, HEX_SREG_SYSCFG, FIELD, VAL) + +#define CCR_FIELD_SET(ENV, FIELD) \ + (!!GET_FIELD(FIELD, ARCH_GET_SYSTEM_REG(ENV, HEX_SREG_CCR))) + +/* + * Direct-to-guest is not implemented yet, continuing would cause unexpected + * behavior, so we abort. + */ +#define ASSERT_DIRECT_TO_GUEST_UNSET(ENV, EXCP) \ + do { \ + switch (EXCP) { \ + case HEX_EVENT_TRAP0: \ + g_assert(!CCR_FIELD_SET(ENV, CCR_GTE)); \ + break; \ + case HEX_EVENT_IMPRECISE: \ + case HEX_EVENT_PRECISE: \ + case HEX_EVENT_FPTRAP: \ + g_assert(!CCR_FIELD_SET(ENV, CCR_GEE)); \ + break; \ + default: \ + if ((EXCP) >= HEX_EVENT_INT0) { \ + g_assert(!CCR_FIELD_SET(ENV, CCR_GIE)); \ + } \ + break; \ + } \ + } while (0) +#endif + +#define fREAD_ELR() (READ_SREG(HEX_SREG_ELR)) + +#define fLOAD_PHYS(NUM, SIZE, SIGN, SRC1, SRC2, DST) { \ + const uintptr_t rs = ((unsigned long)(unsigned)(SRC1)) & 0x7ff; \ + const uintptr_t rt = ((unsigned long)(unsigned)(SRC2)) << 11; \ + const uintptr_t addr = rs + rt; \ + cpu_physical_memory_read(addr, &DST, sizeof(uint32_t)); \ +} + +#define fPOW2_HELP_ROUNDUP(VAL) \ + ((VAL) | \ + ((VAL) >> 1) | \ + ((VAL) >> 2) | \ + ((VAL) >> 4) | \ + ((VAL) >> 8) | \ + ((VAL) >> 16)) +#define fPOW2_ROUNDUP(VAL) (fPOW2_HELP_ROUNDUP((VAL) - 1) + 1) + +#define fFRAMECHECK(ADDR, EA) g_assert_not_reached(); + +#define fTRAP(TRAPTYPE, IMM) \ + register_trap_exception(env, TRAPTYPE, IMM, PC) + +#define fVIRTINSN_SPSWAP(IMM, REG) +#define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; } +#define fVIRTINSN_SETIE(IMM, REG) +#define fVIRTINSN_RTE(IMM, REG) +#define fGRE_ENABLED() GET_FIELD(CCR_GRE, READ_SREG(HEX_SREG_CCR)) +#define fTRAP1_VIRTINSN(IMM) \ + (fGRE_ENABLED() && \ + (((IMM) == 1) || ((IMM) == 3) || ((IMM) == 4) || ((IMM) == 6))) + +/* Not modeled in qemu */ + +#define MARK_LATE_PRED_WRITE(RNUM) +#define fICINVIDX(REG) +#define fICKILL() +#define fDCKILL() +#define fL2KILL() +#define fL2UNLOCK() +#define fL2CLEAN() +#define fL2CLEANINV() +#define fL2CLEANPA(REG) +#define fL2CLEANINVPA(REG) +#define fL2CLEANINVIDX(REG) +#define fL2CLEANIDX(REG) +#define fL2INVIDX(REG) +#define fL2TAGR(INDEX, DST, DSTREG) +#define fL2UNLOCKA(VA) ((void) VA) +#define fL2TAGW(INDEX, PART2) +#define fDCCLEANIDX(REG) +#define fDCCLEANINVIDX(REG) + +/* Always succeed: */ +#define fL2LOCKA(EA, PDV, PDN) ((void) EA, PDV = 0xFF) +#define fCLEAR_RTE_EX() \ + do { \ + uint32_t tmp = 0; \ + tmp = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); \ + fINSERT_BITS(tmp, reg_field_info[SSR_EX].width, \ + reg_field_info[SSR_EX].offset, 0); \ + log_sreg_write(env, HEX_SREG_SSR, tmp, slot); \ + } while (0) + +#define fDCINVIDX(REG) +#define fDCINVA(REG) do { REG = REG; } while (0) /* Nothing to do in qemu */ + +#define fSET_TLB_LOCK() g_assert_not_reached() +#define fCLEAR_TLB_LOCK() g_assert_not_reached() + +#define fSET_K0_LOCK() g_assert_not_reached() +#define fCLEAR_K0_LOCK() g_assert_not_reached() + +#define fTLB_IDXMASK(INDEX) \ + ((INDEX) & (fPOW2_ROUNDUP(fCAST4u(env_archcpu(env)->num_tlbs)) - 1)) + +#define fTLB_NONPOW2WRAP(INDEX) \ + (((INDEX) >= env_archcpu(env)->num_tlbs) ? \ + ((INDEX) - env_archcpu(env)->num_tlbs) : \ + (INDEX)) + + +#define fTLBW(INDEX, VALUE) \ + hex_tlbw(env, (INDEX), (VALUE)) +#define fTLBW_EXTENDED(INDEX, VALUE) \ + hex_tlbw(env, (INDEX), (VALUE)) +#define fTLB_ENTRY_OVERLAP(VALUE) \ + (hex_tlb_check_overlap(env, VALUE, -1) != -2) +#define fTLB_ENTRY_OVERLAP_IDX(VALUE) \ + hex_tlb_check_overlap(env, VALUE, -1) +#define fTLBR(INDEX) \ + (env->hex_tlb->entries[fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX))]) +#define fTLBR_EXTENDED(INDEX) \ + (env->hex_tlb->entries[fTLB_NONPOW2WRAP(fTLB_IDXMASK(INDEX))]) +#define fTLBP(TLBHI) \ + hex_tlb_lookup(env, ((TLBHI) >> 12), ((TLBHI) << 12)) +#define iic_flush_cache(p) + +#define fIN_DEBUG_MODE(TNUM) \ + ((GET_FIELD(ISDBST_DEBUGMODE, ARCH_GET_SYSTEM_REG(env, HEX_SREG_ISDBST)) \ + & (0x1 << (TNUM))) != 0) + +#define fIN_DEBUG_MODE_NO_ISDB(TNUM) false +#define fIN_DEBUG_MODE_WARN(TNUM) false + +#ifdef QEMU_GENERATE + +/* + * Read tags back as zero for now: + * + * tag value in RD[31:10] for 32k, RD[31:9] for 16k + */ +#define fICTAGR(RS, RD, RD2) \ + do { \ + RD = ctx->zero; \ + } while (0) +#define fICTAGW(RS, RD) +#define fICDATAR(RS, RD) \ + do { \ + RD = ctx->zero; \ + } while (0) +#define fICDATAW(RS, RD) + +#define fDCTAGW(RS, RT) +/* tag: RD[23:0], state: RD[30:29] */ +#define fDCTAGR(INDEX, DST, DST_REG_NUM) \ + do { \ + DST = ctx->zero; \ + } while (0) +#else + +/* + * Read tags back as zero for now: + * + * tag value in RD[31:10] for 32k, RD[31:9] for 16k + */ +#define fICTAGR(RS, RD, RD2) \ + do { \ + RD = 0x00; \ + } while (0) +#define fICTAGW(RS, RD) +#define fICDATAR(RS, RD) \ + do { \ + RD = 0x00; \ + } while (0) +#define fICDATAW(RS, RD) + +#define fDCTAGW(RS, RT) +/* tag: RD[23:0], state: RD[30:29] */ +#define fDCTAGR(INDEX, DST, DST_REG_NUM) \ + do { \ + DST = HEX_DC_STATE_INVALID | 0x00; \ + } while (0) +#endif + +#endif + +#define NUM_TLB_REGS(x) (env_archcpu(env)->num_tlbs) + +#endif From 7ad78aef4853170fd0cacacb9c1c958767aa445a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 17:05:26 -0500 Subject: [PATCH 022/109] 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. Signed-off-by: Brian Cain --- target/hexagon/genptr.c | 159 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 2c5e15cfcf6f..488d0b4b978b 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -23,6 +23,7 @@ #include "exec/helper-gen.h" #include "insn.h" #include "opcodes.h" +#include "sys_macros.h" #include "translate.h" #define QEMU_GENERATE /* Used internally by macros.h */ #include "macros.h" @@ -128,6 +129,164 @@ TCGv get_result_pred(DisasContext *ctx, int pnum) } } +#ifndef CONFIG_USER_ONLY +G_GNUC_UNUSED +static bool greg_writable(int rnum, bool pair) +{ + if (pair) { + if (rnum < HEX_GREG_G3) { + return true; + } + qemu_log_mask(LOG_UNIMP, + "Warning: ignoring write to guest register pair G%d:%d\n", + rnum + 1, rnum); + } else { + if (rnum <= HEX_GREG_G3) { + return true; + } + qemu_log_mask(LOG_UNIMP, + "Warning: ignoring write to guest register G%d\n", rnum); + } + return false; +} + +G_GNUC_UNUSED +static void check_greg_impl(int rnum, bool pair) +{ + if (pair && (!greg_implemented(rnum) || !greg_implemented(rnum + 1))) { + qemu_log_mask(LOG_UNIMP, + "Warning: guest register pair G%d:%d is unimplemented or " + "reserved. Read will yield 0.\n", + rnum + 1, rnum); + } else if (!pair && !greg_implemented(rnum)) { + qemu_log_mask(LOG_UNIMP, + "Warning: guest register G%d is unimplemented or reserved." + " Read will yield 0.\n", rnum); + } +} + +G_GNUC_UNUSED +static inline void gen_log_greg_write(DisasContext *ctx, int rnum, TCGv val) +{ + tcg_gen_mov_tl(ctx->greg_new_value[rnum], val); +} + +G_GNUC_UNUSED +static void gen_log_greg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val) +{ + TCGv val32 = tcg_temp_new(); + + /* Low word */ + tcg_gen_extrl_i64_i32(val32, val); + gen_log_greg_write(ctx, rnum, val32); + + /* High word */ + tcg_gen_extrh_i64_i32(val32, val); + gen_log_greg_write(ctx, rnum + 1, val32); +} + +static const target_ulong sreg_immut_masks[NUM_SREGS] = { + [HEX_SREG_STID] = 0xff00ff00, + [HEX_SREG_ELR] = 0x00000003, + [HEX_SREG_SSR] = 0x00008000, + [HEX_SREG_CCR] = 0x10e0ff24, + [HEX_SREG_HTID] = IMMUTABLE, + [HEX_SREG_IMASK] = 0xffff0000, + [HEX_SREG_GEVB] = 0x000000ff, + [HEX_SREG_EVB] = 0x000000ff, + [HEX_SREG_MODECTL] = IMMUTABLE, + [HEX_SREG_SYSCFG] = 0x80001c00, + [HEX_SREG_IPENDAD] = IMMUTABLE, + [HEX_SREG_VID] = 0xfc00fc00, + [HEX_SREG_VID1] = 0xfc00fc00, + [HEX_SREG_BESTWAIT] = 0xfffffe00, + [HEX_SREG_SCHEDCFG] = 0xfffffef0, + [HEX_SREG_CFGBASE] = IMMUTABLE, + [HEX_SREG_REV] = IMMUTABLE, + [HEX_SREG_ISDBST] = IMMUTABLE, + [HEX_SREG_ISDBCFG0] = 0xe0000000, + [HEX_SREG_BRKPTPC0] = 0x00000003, + [HEX_SREG_BRKPTCFG0] = 0xfc007000, + [HEX_SREG_BRKPTPC1] = 0x00000003, + [HEX_SREG_BRKPTCFG1] = 0xfc007000, + [HEX_SREG_ISDBMBXIN] = IMMUTABLE, + [HEX_SREG_ISDBEN] = 0xfffffffe, + [HEX_SREG_TIMERLO] = IMMUTABLE, + [HEX_SREG_TIMERHI] = IMMUTABLE, +}; + +G_GNUC_UNUSED +static void gen_log_sreg_write(DisasContext *ctx, int rnum, TCGv val) +{ + const target_ulong reg_mask = sreg_immut_masks[rnum]; + + if (reg_mask != IMMUTABLE) { + if (rnum < HEX_SREG_GLB_START) { + gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask); + tcg_gen_mov_tl(ctx->t_sreg_new_value[rnum], val); + } else { + gen_masked_reg_write(val, hex_g_sreg[rnum], reg_mask); + gen_helper_sreg_write(tcg_env, tcg_constant_i32(rnum), val); + } + } +} + +G_GNUC_UNUSED +static void gen_log_sreg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val) +{ + TCGv val32 = tcg_temp_new(); + + /* Low word */ + tcg_gen_extrl_i64_i32(val32, val); + gen_log_sreg_write(ctx, rnum, val32); + + /* High word */ + tcg_gen_extrh_i64_i32(val32, val); + gen_log_sreg_write(ctx, rnum + 1, val32); +} + +G_GNUC_UNUSED +static void gen_read_sreg(TCGv dst, int reg_num) +{ + if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA) { + gen_helper_sreg_read(dst, tcg_env, tcg_constant_i32(reg_num)); + } else { + tcg_gen_mov_tl(dst, hex_t_sreg[reg_num]); + } +} + +G_GNUC_UNUSED +static void gen_read_sreg_pair(TCGv_i64 dst, int reg_num) +{ + if (reg_num < HEX_SREG_GLB_START) { + if (reg_num + 1 == HEX_SREG_BADVA) { + TCGv badva = tcg_temp_new(); + gen_helper_sreg_read(badva, tcg_env, + tcg_constant_tl(HEX_SREG_BADVA)); + tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num], badva); + } else { + tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num], + hex_t_sreg[reg_num + 1]); + } + } else { + gen_helper_sreg_read_pair(dst, tcg_env, tcg_constant_tl(reg_num)); + } +} + +G_GNUC_UNUSED +static void gen_read_greg(TCGv dst, int reg_num) +{ + gen_helper_greg_read(dst, tcg_env, tcg_constant_tl(reg_num)); +} + +G_GNUC_UNUSED +static void gen_read_greg_pair(TCGv_i64 dst, int reg_num) +{ + gen_helper_greg_read_pair(dst, tcg_env, tcg_constant_tl(reg_num)); +} +#endif + + void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) { TCGv pred = get_result_pred(ctx, pnum); From 79ccf993404624c31436b0a9c651e22a0e71a73a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 20 May 2024 17:54:50 -0500 Subject: [PATCH 023/109] target/hexagon: Add placeholder greg/sreg r/w helpers Signed-off-by: Brian Cain --- target/hexagon/helper.h | 9 +++++++++ target/hexagon/op_helper.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index f8baa599c88c..fddbd99a197d 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -107,3 +107,12 @@ DEF_HELPER_4(probe_noshuf_load, void, env, i32, int, int) DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int) DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int) + +#if !defined(CONFIG_USER_ONLY) +DEF_HELPER_2(sreg_read, i32, env, i32) +DEF_HELPER_2(sreg_read_pair, i64, env, i32) +DEF_HELPER_2(greg_read, i32, env, i32) +DEF_HELPER_2(greg_read_pair, i64, env, i32) +DEF_HELPER_3(sreg_write, void, env, i32, i32) +DEF_HELPER_3(sreg_write_pair, void, env, i32, i64) +#endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 4feec232983a..ccd806836cf7 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1315,6 +1315,40 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) } } +#ifndef CONFIG_USER_ONLY +void HELPER(sreg_write)(CPUHexagonState *env, uint32_t reg, uint32_t val) +{ + g_assert_not_reached(); +} + +void HELPER(sreg_write_pair)(CPUHexagonState *env, uint32_t reg, uint64_t val) + +{ + g_assert_not_reached(); +} + +uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} + +uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} + +uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} + +uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} +#endif + + /* These macros can be referenced in the generated helper functions */ #define warn(...) /* Nothing */ #define fatal(...) g_assert_not_reached(); From e43d4f11678f10f52204660233fe1a01556123f6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 8 Sep 2024 12:15:28 -0700 Subject: [PATCH 024/109] target/hexagon: Add vmstate representation Signed-off-by: Brian Cain --- target/hexagon/machine.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 target/hexagon/machine.c diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c new file mode 100644 index 000000000000..5f654d84b8eb --- /dev/null +++ b/target/hexagon/machine.c @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2023-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "migration/cpu.h" +#include "cpu.h" + + +const VMStateDescription vmstate_hexagon_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_CPU(), + VMSTATE_UINTTL_ARRAY(env.gpr, HexagonCPU, TOTAL_PER_THREAD_REGS), + VMSTATE_UINTTL_ARRAY(env.pred, HexagonCPU, NUM_PREGS), + VMSTATE_UINTTL_ARRAY(env.t_sreg, HexagonCPU, NUM_SREGS), + VMSTATE_UINTTL_ARRAY(env.t_sreg_written, HexagonCPU, NUM_SREGS), + VMSTATE_UINTTL_ARRAY(env.greg, HexagonCPU, NUM_GREGS), + VMSTATE_UINTTL_ARRAY(env.greg_written, HexagonCPU, NUM_GREGS), + VMSTATE_END_OF_LIST() + }, +}; + From cd9ce8bf16baff9fb9d9924ed228b3355dc5111e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 30 Apr 2024 08:13:36 -0700 Subject: [PATCH 025/109] docs: Add hexagon sysemu docs Signed-off-by: Brian Cain --- MAINTAINERS | 2 + docs/devel/hexagon-sys.rst | 106 +++++++++++++++++++++++++++++++++ docs/devel/index-internals.rst | 1 + docs/system/hexagon/cdsp.rst | 10 ++++ docs/system/target-hexagon.rst | 100 +++++++++++++++++++++++++++++++ docs/system/targets.rst | 1 + 6 files changed, 220 insertions(+) create mode 100644 docs/devel/hexagon-sys.rst create mode 100644 docs/system/hexagon/cdsp.rst create mode 100644 docs/system/target-hexagon.rst diff --git a/MAINTAINERS b/MAINTAINERS index 2101b5121756..2b882047e16f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -237,6 +237,8 @@ F: disas/hexagon.c F: configs/targets/hexagon-linux-user/default.mak F: docker/dockerfiles/debian-hexagon-cross.docker F: gdb-xml/hexagon*.xml +F: docs/system/target-hexagon.rst +F: docs/devel/hexagon-sys.rst T: git https://github.com/quic/qemu.git hex-next Hexagon idef-parser diff --git a/docs/devel/hexagon-sys.rst b/docs/devel/hexagon-sys.rst new file mode 100644 index 000000000000..3972261a2bbe --- /dev/null +++ b/docs/devel/hexagon-sys.rst @@ -0,0 +1,106 @@ +.. _Hexagon-System-arch: + +Hexagon System Architecture +=========================== + +The hexagon architecture has some unique elements which are described here. + +Interrupts +---------- +When interrupts arrive at a Hexagon DSP core, they are priority-steered to +be handled by an eligible hardware thread with the lowest priority. + +Memory +------ +Each hardware thread has an ``SSR.ASID`` field that contains its Address +Space Identifier. This value is catenated with a 32-bit virtual address - +the MMU can then resolve this extended virtual address to a physical address. + +TLBs +---- +The format of a TLB entry is shown below. + +.. note:: + The Small Core DSPs have a different TLB format which is not yet + supported. + +.. admonition:: Diagram + + .. code:: text + + 6 5 4 3 + 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |v|g|x|A|A| | | + |a|l|P|1|0| ASID | Virtual Page | + |l|b| | | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + 3 2 1 0 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | | | | + |x|w|r|u|Cacheab| Physical Page |S| + | | | | | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +* ASID: the address-space identifier +* A1, A0: the behavior of these cache line attributes are not modeled by QEMU. +* xP: the extra-physical bit is the most significant physical address bit. +* S: the S bit and the LSBs of the physical page indicate the page size +* val: this is the 'valid' bit, when set it indicates that page matching + should consider this entry. + +.. list-table:: Page sizes + :widths: 25 25 50 + :header-rows: 1 + + * - S-bit + - Phys page LSBs + - Page size + * - 1 + - N/A + - 4kb + * - 0 + - 0b1 + - 16kb + * - 0 + - 0b10 + - 64kb + * - 0 + - 0b100 + - 256kb + * - 0 + - 0b1000 + - 1MB + * - 0 + - 0b10000 + - 4MB + * - 0 + - 0b100000 + - 16MB + +* glb: if the global bit is set, the ASID is not considered when matching + TLBs. +* Cacheab: the cacheability attributes of TLBs are not modeled, these bits + are ignored. +* RWX: read-, write-, execute-, enable bits. Indicates if user programs + are permitted to read/write/execute the given page. +* U: indicates if user programs can access this page. + +Scheduler +--------- +The Hexagon system architecture has a feature to assist the guest OS +task scheduler. The guest OS can enable this feature by setting +``SCHEDCFG.EN``. The ``BESTWAIT`` register is programmed by the guest OS +to indicate the priority of the highest priority task waiting to run on a +hardware thread. The reschedule interrupt is triggered when any hardware +thread's priority in ``STID.PRIO`` is worse than the ``BESTWAIT``. When +it is triggered, the ``BESTWAIT.PRIO`` value is reset to 0x1ff. + +HVX Coprocessor +--------------- +The Supervisor Status Register field ``SSR.XA`` binds a DSP hardware thread +to one of the eight possible HVX contexts. The guest OS is responsible for +managing this resource. diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index ab9fbc448263..0480b3a7dc61 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -12,6 +12,7 @@ Details about QEMU's various subsystems including how to add features to them. block-coroutine-wrapper clocks ebpf_rss + hexagon-sys migration/index multi-process reset diff --git a/docs/system/hexagon/cdsp.rst b/docs/system/hexagon/cdsp.rst new file mode 100644 index 000000000000..f755fbe0a5ba --- /dev/null +++ b/docs/system/hexagon/cdsp.rst @@ -0,0 +1,10 @@ +Compute DSP +=========== + +A Hexagon CDSP is designed as a computation offload device for an SoC. The +``V66G_1024`` machine contains: + +* L2VIC interrupt controller +* QTimer timer device + +This machine will support any Hexagon CPU, but will default to ``v66``. diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst new file mode 100644 index 000000000000..e12a93d15d4f --- /dev/null +++ b/docs/system/target-hexagon.rst @@ -0,0 +1,100 @@ +.. _Hexagon-System-emulator: + +Hexagon System emulator +----------------------- + +Use the ``qemu-system-hexagon`` executable to simulate a 32-bit Hexagon +machine. + +Hexagon Machines +================ + +Hexagon DSPs are suited to various functions and generally appear in a +"DSP subsystem" of a larger system-on-chip (SoC). + +Hexagon DSPs are often included in a subsystem that looks like the diagram +below. Instructions are loaded into DDR before the DSP is brought out of +reset and the first instructions are fetched from DDR via the EVB/reset vector. + +In a real system, a TBU/SMMU would normally arbitrate AXI accesses but +we don't have a need to model that for QEMU. + +Hexagon DSP cores use simultaneous multithreading (SMT) with as many as 8 +hardware threads. + +.. admonition:: Diagram + + .. code:: text + + AHB (local) bus AXI (global) bus + │ │ + │ │ + ┌─────────┐ │ ┌─────────────────┐ │ + │ L2VIC ├──┤ │ │ │ + │ ├──┼───────► ├───────┤ + └─────▲───┘ │ │ Hexagon DSP │ │ + │ │ │ │ │ ┌─────┐ + │ │ │ N threads │ │ │ DDR │ + │ ├───────┤ │ │ │ │ + ┌────┴──┐ │ │ │ ├────────┤ │ + │QTimer ├───┤ │ │ │ │ │ + │ │ │ │ │ │ │ │ + └───────┘ │ │ ┌─────────┐ │ │ │ │ + │ │ ┌─────────┐│ │ │ │ │ + ┌───────┐ │ │ │ HVX xM ││ │ │ │ │ + │QDSP6SS├───┤ │ │ │┘ │ │ │ │ + └───────┘ │ │ └─────────┘ │ │ └─────┘ + │ │ │ │ + ┌───────┐ │ └─────────────────┘ │ + │ CSR ├───┤ + └───────┘ │ ┌──────┐ ┌───────────┐ + │ │ TCM │ │ VTCM │ + │ │ │ │ + └──────┘ │ │ + │ │ + │ │ + │ │ + └───────────┘ + +Components +---------- +Other than l2vic and HVX, the components below are not implemented in QEMU. + +* L2VIC: the L2 vectored interrupt controller. Supports 1024 input + interrupts, edge- or level-triggered. The core ISA has system registers + ``VID``, ``VID1`` which read through to the L2VIC device. +* QTimer: ARMSSE-based programmable timer device. Its interrupts are + wired to the L2VIC. System registers ``TIMER``, ``UTIMER`` read + through to the QTimer device. +* QDSP6SS: DSP subsystem features, accessible to the entire SoC, including + DSP NMI, watchdog, reset, etc. +* CSR: Configuration/Status Registers. +* TCM: DSP-exclusive tightly-coupled memory. This memory can be used for + DSPs when isolated from DDR and in some bootstrapping modes. +* VTCM: DSP-exclusive vector tightly-coupled memory. This memory is accessed + by some HVX instructions. +* HVX: the vector coprocessor supports 64 and 128-byte vector registers. + 64-byte mode is not implemented in QEMU. + + +Bootstrapping +------------- +Hexagon systems do not generally have access to a block device. So, for +QEMU the typical use case involves loading a binary or ELF file into memory +and executing from the indicated start address:: + + $ qemu-system-hexagon -kernel ./prog -append 'arg1 arg2' + +Semihosting +----------- +Hexagon supports a semihosting interface similar to other architectures'. +The ``trap0`` instruction can activate these semihosting calls so that the +guest software can access the host console and filesystem. Semihosting +is not yet implemented in QEMU hexagon. + + +Hexagon Features +================ +.. toctree:: + hexagon/cdsp + diff --git a/docs/system/targets.rst b/docs/system/targets.rst index 224fadae71c4..e6dcdb9d4161 100644 --- a/docs/system/targets.rst +++ b/docs/system/targets.rst @@ -29,3 +29,4 @@ Contents: target-sparc64 target-i386 target-xtensa + target-hexagon From 8bb107c278714f352f772558a2ae4e6ab9cfc7f6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 8 Jul 2024 18:51:06 -0700 Subject: [PATCH 026/109] FIXME: docs: Add hexagon VM info FIXME: this commit contains FIXMEs Signed-off-by: Brian Cain --- MAINTAINERS | 1 + docs/devel/hexagon-vm.rst | 190 +++++++++++++++++++++++++++++++++ docs/devel/index-internals.rst | 1 + docs/system/target-hexagon.rst | 11 ++ 4 files changed, 203 insertions(+) create mode 100644 docs/devel/hexagon-vm.rst diff --git a/MAINTAINERS b/MAINTAINERS index 2b882047e16f..4d1ffb4ba93f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -239,6 +239,7 @@ F: docker/dockerfiles/debian-hexagon-cross.docker F: gdb-xml/hexagon*.xml F: docs/system/target-hexagon.rst F: docs/devel/hexagon-sys.rst +F: docs/devel/hexagon-vm.rst T: git https://github.com/quic/qemu.git hex-next Hexagon idef-parser diff --git a/docs/devel/hexagon-vm.rst b/docs/devel/hexagon-vm.rst new file mode 100644 index 000000000000..fb16d56d59de --- /dev/null +++ b/docs/devel/hexagon-vm.rst @@ -0,0 +1,190 @@ +Hexagon Virtual Machine +======================= + +The hexagon virtual machine is a hypervisor that can partition a single +Hexagon DSP among multiple guest operating systems, and abstracts the +specific details of a DSP architectural revision for the sake of consistency +among generations. + +Events +------ + +The guest operating system should register the Guest Event Vector Base +via the ``vmsetvec`` virtual instruction at system startup. The vector table +and handlers are determined by the guest OS. + +Guests return from event handlers with ``vmrte``. This instruction will restore +the mode (user versus guest), interrupt enable state, PC, SP. + +.. list-table:: Event types + :header-rows: 1 + + * - Number + - Name + - Description + - Maskable + - Detail + * - 0 + - Reserved + - + - + - + * - 1 + - Machine check event + - unrecoverable VM state + - No + - execution terminates if unhandled + * - 2 + - General exception + - internal hardware or software exception + - No + - + * - 3-4 + - Reserved + - + - + - + * - 5 + - ``trap0`` + - ``trap0`` instruction + - No + - + * - 6 + - Reserved + - + - + - + * - 7 + - Interrupt + - external interrupts + - Yes + - increasing interrupt numbers have descending priority + +Startup +------- +In order to transition to user-mode, the guest OS must set the ``UM`` bit in +the guest status register and specify the address to start executing in +user mode in the guest event link register. + +Virtual Instructions +-------------------- + +.. list-table:: Virtual Instructions + :header-rows: 1 + + * - Instruction + - Behavior + - Operand + - Input + - Output + * - vmversion + - returns the VM version + - 0x0 + - requested VM version + - provided VM version + * - vmrte + - return from event + - 0x1 + - Event info in g3:0 + - N/A + * - vmsetvec + - set event vector + - 0x2 + - r0 is set to vector table addr + - r0 is 0 on success, 1 otherwise + * - vmsetie + - set interrupt enabled + - 0x3 + - r0 is set to 1 to enable, 0 to disable + - previous IE bit is stored as LSB of r0 + * - vmgetie + - get interrupt enabled + - 0x4 + - N/A + - current IE bit is stored as LSB of r0 + * - vmintop + - interrupt operation + - 0x5 + - r0 = Interrupt Op, r1-r4: Depends on Op + - r0 - value depends on operation + * - vmclrmap + - clear virtual memory map + - 0xa + - r0 = Interrupt Op, r1-r4: Depends on Op + - r0 - value depends on operation + * - vmnewmap + - set new virtual memory map + - 0xb + - + r0 contains logical address of new segment table + + r1 = type of translations: 0 indicates a logical address of a zero-terminated linear list, 1 indicates a set of page tables. + - r0 contains 0 on success, otherwise negative error code + * - vmcache + - VM cache control: not modeled + - 0xd + - + r0 contains the operation to be performed + + r1 = Starting virtual address + + r2 contains the length in bytes + - r0 contains 0 on success, otherwise -1. Cache behavior is not modeled so this operation always succeeds. + * - vmgettime + - Get virtual machine time + - 0xe + - N/A + - r0 contains the least significant 32 bits of timestamp, r1 contains the most significant 32 bits of timestamp + * - vmsettime + - Set virtual machine time + - 0xf + - r0 contains the least significant 32 bits of timestamp, r1 contains the most significant 32 bits of timestamp + - N/A + * - vmwait + - wait for interrupt + - 0x10 + - N/A + - r0 contains the interrupt number of the interrupt waking the guest + * - vmyield + - voluntarily yield VM task + - 0x11 + - N/A + - N/A + * - vmstart + - Create new virtual processor instance + - 0x12 + - r0 contains the starting execution address, r1 contains the starting stack pointer + - r0 contains the Virtual processor number of new virtual processor on success, otherwise -1 + * - vmstop + - terminate current virtual processor instance + - 0x13 + - N/A + - N/A + * - vmvpid + - get the virtual processor ID + - 0x14 + - N/A + - r0 contains the virtual processor number of virtual processor executing the instruction + * - vmsetregs + - Set guest registers + - 0x15 + - r0-3 hold g0-3 values + - N/A + * - vmgetregs + - Get guest registers + - 0x16 + - N/A + - r0-3 hold g0-3 values + * - vmtimerop + - perform an operation on a system timer + - 0x18 + - + getfreq = 0 + + getres = 1 + + gettime = 2 + + gettimeout = 3 + + settimeout = 4 + + deltatimeout = 5 + - r0 contains result of the timer operation call + * - vmgetinfo + - Get system info + - 0x1a + - Index of the system info parameter: + + + build_id = 0 + + info_boot_flags = 1 + - value of the indicated system info parameter diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index 0480b3a7dc61..01db83c93f11 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -13,6 +13,7 @@ Details about QEMU's various subsystems including how to add features to them. clocks ebpf_rss hexagon-sys + hexagon-vm migration/index multi-process reset diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst index e12a93d15d4f..8daaee02884a 100644 --- a/docs/system/target-hexagon.rst +++ b/docs/system/target-hexagon.rst @@ -92,6 +92,17 @@ The ``trap0`` instruction can activate these semihosting calls so that the guest software can access the host console and filesystem. Semihosting is not yet implemented in QEMU hexagon. +Hexagon Virtual Machine +----------------------- + +The hexagon virtual machine is a hypervisor that can partition a single +Hexagon DSP among multiple guest operating systems, and abstracts the +specific details of a DSP architectural revision for the sake of consistency +among generations. + +[minivm](https://github.com/quic/hexagonMVM) is a reference implementation +of this VM interface. + Hexagon Features ================ From 5836715c073ecce2e96af35e7d0505f01d530ca6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 25 Oct 2024 23:20:05 -0500 Subject: [PATCH 027/109] docs/system: Add hexagon CPU emulation Signed-off-by: Brian Cain --- docs/system/hexagon/emulation.rst | 16 ++++++++++++++++ docs/system/target-hexagon.rst | 1 + 2 files changed, 17 insertions(+) create mode 100644 docs/system/hexagon/emulation.rst diff --git a/docs/system/hexagon/emulation.rst b/docs/system/hexagon/emulation.rst new file mode 100644 index 000000000000..03a6092a1281 --- /dev/null +++ b/docs/system/hexagon/emulation.rst @@ -0,0 +1,16 @@ +.. _Hexagon Emulation: + +Hexagon CPU architecture support +================================ + +QEMU's TCG emulation includes support for v65, v66, v67, v68, v69, v71, v73. +It also has support for the following architecture extensions: + +- HVX (Hexagon Vector eXtensions) + +For information on the specifics of the HVX extension, please refer +to the `Qualcomm Hexagon V69 HVX Programmer's Reference Manual +`_. + +.. code-block:: bash + diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst index 8daaee02884a..894337a533cd 100644 --- a/docs/system/target-hexagon.rst +++ b/docs/system/target-hexagon.rst @@ -107,5 +107,6 @@ of this VM interface. Hexagon Features ================ .. toctree:: + hexagon/emulation hexagon/cdsp From b8946482bca25bab182a12243a38d98a8dbe8b68 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 26 May 2024 19:11:55 -0500 Subject: [PATCH 028/109] target/hexagon: Make A_PRIV, "J2_trap*" insts need_env() Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 785b522b1f19..a98bde5caf22 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -250,7 +250,9 @@ def need_env(tag): "A_LOAD" in attribdict[tag] or "A_CVI_GATHER" in attribdict[tag] or "A_CVI_SCATTER" in attribdict[tag] or - "A_IMPLICIT_WRITES_USR" in attribdict[tag]) + "A_IMPLICIT_WRITES_USR" in attribdict[tag] or + "A_PRIV" in attribdict[tag] or + "J2_trap" in tag) def need_slot(tag): From 95f9dac63aa4475a0ad9f4ac211f0bc2468ae333 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 23 May 2024 21:42:44 -0500 Subject: [PATCH 029/109] target/hexagon: Define register fields for system regs Define the register fields for ssr, schedcfg, stid, bestwait, ccr, modectl, imask, ipendad. Define the fields for TLB entries. Signed-off-by: Brian Cain --- target/hexagon/reg_fields_def.h.inc | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/target/hexagon/reg_fields_def.h.inc b/target/hexagon/reg_fields_def.h.inc index f2a58d486c55..156a3514e77d 100644 --- a/target/hexagon/reg_fields_def.h.inc +++ b/target/hexagon/reg_fields_def.h.inc @@ -39,3 +39,99 @@ DEF_REG_FIELD(USR_FPDBZE, 26, 1) DEF_REG_FIELD(USR_FPOVFE, 27, 1) DEF_REG_FIELD(USR_FPUNFE, 28, 1) DEF_REG_FIELD(USR_FPINPE, 29, 1) + +DEF_REG_FIELD(IPENDAD_IAD, 16, 16) +DEF_REG_FIELD(IPENDAD_IPEND, 0, 16) + +DEF_REG_FIELD(SCHEDCFG_EN, 8, 1) +DEF_REG_FIELD(SCHEDCFG_INTNO, 0, 4) +DEF_REG_FIELD(BESTWAIT_PRIO, 0, 10) + + +/* PTE (aka TLB entry) fields */ +DEF_REG_FIELD(PTE_PPD, 0, 24) +DEF_REG_FIELD(PTE_C, 24, 4) +DEF_REG_FIELD(PTE_U, 28, 1) +DEF_REG_FIELD(PTE_R, 29, 1) +DEF_REG_FIELD(PTE_W, 30, 1) +DEF_REG_FIELD(PTE_X, 31, 1) +DEF_REG_FIELD(PTE_VPN, 32, 20) +DEF_REG_FIELD(PTE_ASID, 52, 7) +DEF_REG_FIELD(PTE_ATR0, 59, 1) +DEF_REG_FIELD(PTE_ATR1, 60, 1) +DEF_REG_FIELD(PTE_PA35, 61, 1) +DEF_REG_FIELD(PTE_G, 62, 1) +DEF_REG_FIELD(PTE_V, 63, 1) + +/* SYSCFG fields */ +DEF_REG_FIELD(SYSCFG_MMUEN, 0, 1) +DEF_REG_FIELD(SYSCFG_ICEN, 1, 1) +DEF_REG_FIELD(SYSCFG_DCEN, 2, 1) +DEF_REG_FIELD(SYSCFG_ISDBTRUSTED, 3, 1) +DEF_REG_FIELD(SYSCFG_GIE, 4, 1) +DEF_REG_FIELD(SYSCFG_ISDBREADY, 5, 1) +DEF_REG_FIELD(SYSCFG_PCYCLEEN, 6, 1) +DEF_REG_FIELD(SYSCFG_V2X, 7, 1) +DEF_REG_FIELD(SYSCFG_IGNOREDABORT, 8, 1) +DEF_REG_FIELD(SYSCFG_PM, 9, 1) +DEF_REG_FIELD(SYSCFG_TLBLOCK, 11, 1) +DEF_REG_FIELD(SYSCFG_K0LOCK, 12, 1) +DEF_REG_FIELD(SYSCFG_BQ, 13, 1) +DEF_REG_FIELD(SYSCFG_PRIO, 14, 1) +DEF_REG_FIELD(SYSCFG_DMT, 15, 1) +DEF_REG_FIELD(SYSCFG_L2CFG, 16, 3) +DEF_REG_FIELD(SYSCFG_ITCM, 19, 1) +DEF_REG_FIELD(SYSCFG_L2NWA, 21, 1) +DEF_REG_FIELD(SYSCFG_L2NRA, 22, 1) +DEF_REG_FIELD(SYSCFG_L2WB, 23, 1) +DEF_REG_FIELD(SYSCFG_L2P, 24, 1) +DEF_REG_FIELD(SYSCFG_SLVCTL0, 25, 2) +DEF_REG_FIELD(SYSCFG_SLVCTL1, 27, 2) +DEF_REG_FIELD(SYSCFG_L2PARTSIZE, 29, 2) +DEF_REG_FIELD(SYSCFG_L2GCA, 31, 1) + +/* SSR fields */ +DEF_REG_FIELD(SSR_CAUSE, 0, 8) +DEF_REG_FIELD(SSR_ASID, 8, 7) +DEF_REG_FIELD(SSR_UM, 16, 1) +DEF_REG_FIELD(SSR_EX, 17, 1) +DEF_REG_FIELD(SSR_IE, 18, 1) +DEF_REG_FIELD(SSR_GM, 19, 1) +DEF_REG_FIELD(SSR_V0, 20, 1) +DEF_REG_FIELD(SSR_V1, 21, 1) +DEF_REG_FIELD(SSR_BVS, 22, 1) +DEF_REG_FIELD(SSR_CE, 23, 1) +DEF_REG_FIELD(SSR_PE, 24, 1) +DEF_REG_FIELD(SSR_BP, 25, 1) +DEF_REG_FIELD(SSR_XE2, 26, 1) +DEF_REG_FIELD(SSR_XA, 27, 3) +DEF_REG_FIELD(SSR_SS, 30, 1) +DEF_REG_FIELD(SSR_XE, 31, 1) + +/* misc registers */ +DEF_REG_FIELD(IMASK_MASK, 0, 16) + +DEF_REG_FIELD(STID_PRIO, 16, 8) +DEF_REG_FIELD(STID_STID, 0, 8) + +/* MODECTL fields */ +DEF_REG_FIELD(MODECTL_E, 0, 8) +DEF_REG_FIELD(MODECTL_W, 16, 8) + +DEF_REG_FIELD(CCR_L1ICP, 0, 2) +DEF_REG_FIELD(CCR_L1DCP, 3, 2) +DEF_REG_FIELD(CCR_L2CP, 6, 2) + +DEF_REG_FIELD(CCR_HFI, 16, 1) +DEF_REG_FIELD(CCR_HFD, 17, 1) +DEF_REG_FIELD(CCR_HFIL2, 18, 1) +DEF_REG_FIELD(CCR_HFDL2, 19, 1) +DEF_REG_FIELD(CCR_SFD, 20, 1) + +DEF_REG_FIELD(CCR_GIE, 24, 1) +DEF_REG_FIELD(CCR_GTE, 25, 1) +DEF_REG_FIELD(CCR_GEE, 26, 1) +DEF_REG_FIELD(CCR_GRE, 27, 1) +DEF_REG_FIELD(CCR_VV1, 29, 1) +DEF_REG_FIELD(CCR_VV2, 30, 1) +DEF_REG_FIELD(CCR_VV3, 31, 1) From 404f998820f836b81fb47ca0ac343a538eada6de Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 24 May 2024 17:50:51 -0500 Subject: [PATCH 030/109] FIXME this unused fixes some errs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FIXME: Can we avoid this UNUSED? Or if not, can we explain why we generate these? Error that we see without this change: In file included from ../target/hexagon/translate.c:40: target/hexagon/analyze_funcs_generated.c.inc: In function ‘analyze_Y2_tfrscrr’: target/hexagon/analyze_funcs_generated.c.inc:16748:15: error: unused variable ‘SsN’ [-Werror=unused-variable] 16748 | const int SsN = insn->regno[1]; | ^~~ target/hexagon/analyze_funcs_generated.c.inc: In function ‘analyze_Y4_tfrscpp’: target/hexagon/analyze_funcs_generated.c.inc:16771:15: error: unused variable ‘SssN’ [-Werror=unused-variable] 16771 | const int SssN = insn->regno[1]; | ^~~~ target/hexagon/analyze_funcs_generated.c.inc: In function ‘analyze_G4_tfrgcrr’: target/hexagon/analyze_funcs_generated.c.inc:16794:15: error: unused variable ‘GsN’ [-Werror=unused-variable] 16794 | const int GsN = insn->regno[1]; | ^~~ target/hexagon/analyze_funcs_generated.c.inc: In function ‘analyze_G4_tfrgcpp’: target/hexagon/analyze_funcs_generated.c.inc:16817:15: error: unused variable ‘GssN’ [-Werror=unused-variable] 16817 | const int GssN = insn->regno[1]; | ^~~~ Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index a98bde5caf22..3c7568a1f85f 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -382,7 +382,7 @@ def __init__(self, regtype, regid): self.reg_num = f"{regtype}{regid}N" def decl_reg_num(self, f, regno): f.write(code_fmt(f"""\ - const int {self.reg_num} = insn->regno[{regno}]; + const int G_GNUC_UNUSED {self.reg_num} = insn->regno[{regno}]; """)) def idef_arg(self, declared): declared.append(self.reg_tcg()) From 51ddc6c309557820cfdef83b56da58caf9a20a7b Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 27 May 2024 16:49:05 -0500 Subject: [PATCH 031/109] target/hexagon: Add TCG overrides for break,unpause,fetchbo,dczeroa These instructions are modeled as nops: break: this hardware breakpoint instruction is used with the in-silicon debugger feature, this is not modeled. unpause: this instruction is used to resume hardware threads that are stalled by pause instructions. pause is modeled as a nop, or in RR mode as an EXCP_YIELD. This instruction is safe to ignore. Since cache/prefetch functions are not modeled, dczero and fetchbo are safe to ignore. Signed-off-by: Brian Cain --- target/hexagon/gen_tcg.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 8a3b801287c7..71f8a0e2d084 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -488,6 +488,7 @@ /* dczeroa clears the 32 byte cache line at the address given */ #define fGEN_TCG_Y2_dczeroa(SHORTCODE) SHORTCODE +#define fGEN_TCG_Y2_dczeroa_nt(SHORTCODE) SHORTCODE /* In linux-user mode, these are not modelled, suppress compiler warning */ #define fGEN_TCG_Y2_dcinva(SHORTCODE) \ @@ -1133,6 +1134,9 @@ RdV, tcg_constant_tl(0)); \ } while (0) +#define fGEN_TCG_Y2_break(SHORTCODE) +#define fGEN_TCG_J2_unpause(SHORTCODE) + #define fGEN_TCG_J2_pause(SHORTCODE) \ do { \ uiV = uiV; \ @@ -1342,6 +1346,11 @@ RsV = RsV; \ uiV = uiV; \ } while (0) +#define fGEN_TCG_Y2_dcfetchbo_nt(SHORTCODE) \ + do { \ + RsV = RsV; \ + uiV = uiV; \ + } while (0) #define fGEN_TCG_L2_loadw_aq(SHORTCODE) SHORTCODE #define fGEN_TCG_L4_loadd_aq(SHORTCODE) SHORTCODE From 3fdb2f0d8627bacc565e989b750234d27f67bea4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 18:34:38 -0700 Subject: [PATCH 032/109] target/hexagon: Implement do_raise_exception() Signed-off-by: Brian Cain --- target/hexagon/internal.h | 5 +++++ target/hexagon/op_helper.c | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 32e96f00d97a..912a8a2c1d94 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -31,4 +31,9 @@ void hexagon_debug(CPUHexagonState *env); extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS]; +void G_NORETURN do_raise_exception(CPUHexagonState *env, + uint32_t exception, + target_ulong PC, + uintptr_t retaddr); + #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index ccd806836cf7..1aa5b32b1f73 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -37,6 +37,26 @@ #define SF_MANTBITS 23 /* Exceptions processing helpers */ +G_NORETURN +void do_raise_exception(CPUHexagonState *env, uint32_t exception, + target_ulong PC, uintptr_t retaddr) +{ + CPUState *cs = env_cpu(env); +#ifdef CONFIG_USER_ONLY + qemu_log_mask(CPU_LOG_INT, "%s: 0x%08x\n", __func__, exception); +#else + qemu_log_mask(CPU_LOG_INT, "%s: 0x%08x, @ %08" PRIx32 "\n", + __func__, exception, PC); + + ASSERT_DIRECT_TO_GUEST_UNSET(env, exception); +#endif + + env->gpr[HEX_REG_PC] = PC; + cs->exception_index = exception; + cpu_loop_exit_restore(cs, retaddr); + cs->halted = false; +} + G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, uintptr_t pc) From 46b7c3654d2758d6b38508dc03b3d4eb1f9431b1 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 May 2024 13:06:36 -0500 Subject: [PATCH 033/109] target/hexagon: Add system reg insns Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 15 +- target/hexagon/imported/encode_pp.def | 213 +++++++++++++++------ target/hexagon/imported/system.idef | 262 +++++++++++++++++++++++--- target/hexagon/macros.h | 2 + 4 files changed, 410 insertions(+), 82 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 3c7568a1f85f..ba78a0f8f0ec 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -1257,11 +1257,18 @@ def init_registers(): for reg in new_regs: new_registers[f"{reg.regtype}{reg.regid}"] = reg +def is_new_reg(tag, regid): + if regid[0] in "NO": + return True + return regid[0] == "P" and \ + f"{regid}N" in semdict[tag] and \ + f"{regid}V" not in semdict[tag] + def get_register(tag, regtype, regid): - if f"{regtype}{regid}V" in semdict[tag]: - return registers[f"{regtype}{regid}"] - else: - return new_registers[f"{regtype}{regid}"] + regid = f"{regtype}{regid}" + is_new = is_new_reg(tag, regid) + reg = new_registers[regid] if is_new else registers[regid] + return reg def helper_ret_type(tag, regs): ## If there is a scalar result, it is the return type diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 0cd30a5e8575..37faf62b1b7e 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ */ /* + * encode32.def * Encodings for 32 bit instructions * */ @@ -341,6 +342,8 @@ DEF_ENC32(L4_pload##TAG##tnew_abs,ICLASS_LD" 1 11 "OPC" iiiii PP110tti 1--ddd DEF_ENC32(L4_pload##TAG##fnew_abs,ICLASS_LD" 1 11 "OPC" iiiii PP111tti 1--ddddd") + + /* 0 000 misc: dealloc,loadw_locked,dcfetch */ STD_LD_ENC(bzw4,"0 101") STD_LD_ENC(bzw2,"0 011") @@ -375,6 +378,7 @@ DEF_ANTICLASS32(ICLASS_LD" 1110 000----- PP------ --------",LD_ADDR_POST_REG) DEF_ENC32(L2_deallocframe, ICLASS_LD" 000 0 000 sssss PP0----- ---ddddd") DEF_ENC32(L4_return, ICLASS_LD" 011 0 000 sssss PP0000-- ---ddddd") + DEF_ENC32(L4_return_t, ICLASS_LD" 011 0 000 sssss PP0100vv ---ddddd") DEF_ENC32(L4_return_f, ICLASS_LD" 011 0 000 sssss PP1100vv ---ddddd") DEF_ENC32(L4_return_tnew_pt, ICLASS_LD" 011 0 000 sssss PP0110vv ---ddddd") @@ -382,15 +386,18 @@ DEF_ENC32(L4_return_fnew_pt, ICLASS_LD" 011 0 000 sssss PP1110vv ---ddddd") DEF_ENC32(L4_return_tnew_pnt, ICLASS_LD" 011 0 000 sssss PP0010vv ---ddddd") DEF_ENC32(L4_return_fnew_pnt, ICLASS_LD" 011 0 000 sssss PP1010vv ---ddddd") -DEF_ENC32(L2_loadw_locked,ICLASS_LD" 001 0 000 sssss PP000--- 000ddddd") - +/** Load Acquire Store Release Encoding **/ +DEF_ENC32(L2_loadw_locked, ICLASS_LD" 001 0 000 sssss PP000--- 000ddddd") +DEF_ENC32(L4_loadd_locked, ICLASS_LD" 001 0 000 sssss PP010--- 000ddddd") DEF_ENC32(L2_loadw_aq, ICLASS_LD" 001 0 000 sssss PP001--- 000ddddd") DEF_ENC32(L4_loadd_aq, ICLASS_LD" 001 0 000 sssss PP011--- 000ddddd") -DEF_ENC32(R6_release_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0011dd") -DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd") + +DEF_ENC32(S2_storew_locked, ICLASS_ST" 000 01 01sssss PP-ttttt ----00dd") +DEF_ENC32(S4_stored_locked, ICLASS_ST" 000 01 11sssss PP0ttttt ----00dd") + DEF_ENC32(S2_storew_rl_at_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --0010dd") DEF_ENC32(S2_storew_rl_st_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --1010dd") @@ -398,13 +405,11 @@ DEF_ENC32(S2_storew_rl_st_vi, ICLASS_ST" 000 01 01sssss PP-ttttt --1010dd") DEF_ENC32(S4_stored_rl_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0010dd") DEF_ENC32(S4_stored_rl_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1010dd") -DEF_ENC32(L4_loadd_locked,ICLASS_LD" 001 0 000 sssss PP010--- 000ddddd") -DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii -01iiiii") -DEF_ENC32(Y2_dcfetchbo, ICLASS_LD" 010 0 000 sssss PP0--iii iiiiiiii") - - - +DEF_ENC32(R6_release_at_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --0011dd") +DEF_ENC32(R6_release_st_vi, ICLASS_ST" 000 01 11sssss PP0ttttt --1011dd") +DEF_EXT_SPACE(EXTRACTW, ICLASS_LD" 001 0 000 iiiii PP0iiiii 001iiiii") +DEF_ENC32(Y2_dcfetchbo, ICLASS_LD" 010 0 000 sssss PP0--iii iiiiiiii") @@ -488,13 +493,17 @@ STD_PST_ENC(rinew, "1 101","10ttt") /* x bus/cache */ /* x store/cache */ DEF_ENC32(S2_allocframe, ICLASS_ST" 000 01 00xxxxx PP000iii iiiiiiii") -DEF_ENC32(S2_storew_locked,ICLASS_ST" 000 01 01sssss PP-ttttt ----00dd") -DEF_ENC32(S4_stored_locked,ICLASS_ST" 000 01 11sssss PP0ttttt ----00dd") +DEF_ENC32(Y5_l2locka, ICLASS_ST" 000 01 11sssss PP1----- ------dd") DEF_ENC32(Y2_dczeroa, ICLASS_ST" 000 01 10sssss PP0----- --------") -DEF_ENC32(Y2_barrier, ICLASS_ST" 100 00 00----- PP------ 000-----") +DEF_ENC32(Y2_barrier, ICLASS_ST" 100 00 00----- PP------ 000-----") DEF_ENC32(Y2_syncht, ICLASS_ST" 100 00 10----- PP------ --------") +DEF_ENC32(Y2_l2kill, ICLASS_ST" 100 00 01----- PP-000-- --------") +DEF_ENC32(Y5_l2gunlock, ICLASS_ST" 100 00 01----- PP-010-- --------") +DEF_ENC32(Y5_l2gclean, ICLASS_ST" 100 00 01----- PP-100-- --------") +DEF_ENC32(Y5_l2gcleaninv, ICLASS_ST" 100 00 01----- PP-110-- --------") +DEF_ENC32(Y2_l2cleaninvidx,ICLASS_ST" 100 00 11sssss PP------ --------") @@ -502,9 +511,34 @@ DEF_ENC32(Y2_dccleana, ICLASS_ST" 000 00 00sssss PP------ --------") DEF_ENC32(Y2_dcinva, ICLASS_ST" 000 00 01sssss PP------ --------") DEF_ENC32(Y2_dccleaninva, ICLASS_ST" 000 00 10sssss PP------ --------") -DEF_ENC32(Y4_l2fetch, ICLASS_ST" 011 00 00sssss PP-ttttt 000-----") +/* Super */ +DEF_ENC32(Y2_dckill, ICLASS_ST" 001 00 00----- PP------ --------") +DEF_ENC32(Y2_dccleanidx, ICLASS_ST" 001 00 01sssss PP------ --------") +DEF_ENC32(Y2_dcinvidx, ICLASS_ST" 001 00 10sssss PP------ --------") +DEF_ENC32(Y2_dccleaninvidx,ICLASS_ST" 001 00 11sssss PP------ --------") + +DEF_ENC32(Y2_dctagw ,ICLASS_ST" 010 00 00sssss PP-ttttt --------") +DEF_ENC32(Y2_dctagr ,ICLASS_ST" 010 00 01sssss PP------ ---ddddd") + +DEF_ENC32(Y4_l2tagw ,ICLASS_ST" 010 00 10sssss PP0ttttt --------") +DEF_ENC32(Y4_l2tagr ,ICLASS_ST" 010 00 11sssss PP------ ---ddddd") + +DEF_ENC32(Y4_l2fetch, ICLASS_ST" 011 00 00sssss PP-ttttt 000-----") +DEF_ENC32(Y5_l2cleanidx, ICLASS_ST" 011 00 01sssss PP------ --------") +DEF_ENC32(Y5_l2invidx, ICLASS_ST" 011 00 10sssss PP------ --------") +DEF_ENC32(Y5_l2unlocka, ICLASS_ST" 011 00 11sssss PP------ --------") DEF_ENC32(Y5_l2fetch, ICLASS_ST" 011 01 00sssss PP-ttttt --------") +DEF_ENC32(Y6_l2gcleanpa, ICLASS_ST" 011 01 01----- PP-ttttt --------") +DEF_ENC32(Y6_l2gcleaninvpa,ICLASS_ST" 011 01 10----- PP-ttttt --------") + + + + + + + + /*******************************/ /* */ /* */ @@ -547,13 +581,23 @@ DEF_ENC32(J2_jumprfnewpt, ICLASS_J" 0011 011sssss PP-11-uu --------") DEF_FIELDROW_DESC32(ICLASS_J" 0100 -------- PP------ --------","[#4] (#u8) ") DEF_ENC32(J2_trap0, ICLASS_J" 0100 00------ PP-iiiii ---iii--") -DEF_ENC32(J2_pause, ICLASS_J" 0100 01------ PP-iiiii ---iii--") +DEF_ENC32(J2_trap1, ICLASS_J" 0100 10-xxxxx PP-iiiii ---iii--") +DEF_ENC32(J2_pause, ICLASS_J" 0100 01----ii PP-iiiii ---iii--") + +DEF_FIELDROW_DESC32(ICLASS_J" 0101 -------- PP------ --------","[#5] Rd=(Rs) ") +DEF_ENC32(Y2_icdatar, ICLASS_J" 0101 101sssss PP------ ---ddddd") +DEF_ENC32(Y2_ictagr, ICLASS_J" 0101 111sssss PP------ ---ddddd") +DEF_ENC32(Y2_ictagw, ICLASS_J" 0101 110sssss PP0ttttt --------") +DEF_ENC32(Y2_icdataw, ICLASS_J" 0101 110sssss PP1ttttt --------") DEF_FIELDROW_DESC32(ICLASS_J" 0110 -------- PP------ --------","[#6] icop(Rs) ") DEF_ENC32(Y2_icinva, ICLASS_J" 0110 110sssss PP000--- --------") +DEF_ENC32(Y2_icinvidx, ICLASS_J" 0110 110sssss PP001--- --------") +DEF_ENC32(Y2_ickill, ICLASS_J" 0110 110----- PP010--- --------") DEF_FIELDROW_DESC32(ICLASS_J" 0111 -------- PP------ --------","[#7] () ") DEF_ENC32(Y2_isync, ICLASS_J" 0111 11000000 PP0---00 00000010") +DEF_ENC32(J2_rte, ICLASS_J" 0111 111----- PP00---- 000-----") /* JUMP */ DEF_FIELDROW_DESC32(ICLASS_J" 100- -------- PP------ --------","[#8,9] PC=(#r22)") @@ -591,7 +635,6 @@ DEF_ENC32(J2_callf, ICLASS_J" 1101 ii1iiiii PPi-0-uu iiiiiii-") /*******************************/ -/* EJP: this has to match what we have in htmldocs.py... so I will call it CJ, we can change it */ DEF_CLASS32(ICLASS_CJ" 0--- -------- PP------ --------",CJ) DEF_FIELDROW_DESC32(ICLASS_CJ" 00-- -------- -------- --------","[#0-3] pd=cmp.xx(R,#u5) ; if ([!]p0.new) jump:[h] #s9:2 ") @@ -738,12 +781,19 @@ DEF_ENC32(J2_jumprltezpt,ICLASS_CR" 0001 11isssss PPi1iiii iiiiiii-") DEF_FIELDROW_DESC32( ICLASS_CR" 0010 -------- PP------ --------","[#2] Cd=Rs ") DEF_ENC32(A2_tfrrcr, ICLASS_CR" 0010 001sssss PP------ ---ddddd") +DEF_ENC32(G4_tfrgrcr, ICLASS_CR" 0010 000sssss PP------ ---ddddd") +DEF_ENC32(Y4_trace, ICLASS_CR" 0010 010sssss PP------ 000-----") +DEF_ENC32(Y6_diag, ICLASS_CR" 0010 010sssss PP------ 001-----") +DEF_ENC32(Y6_diag0, ICLASS_CR" 0010 010sssss PP-ttttt 010-----") +DEF_ENC32(Y6_diag1, ICLASS_CR" 0010 010sssss PP-ttttt 011-----") DEF_FIELDROW_DESC32( ICLASS_CR" 0011 -------- PP------ --------","[#3] Cdd=Rss ") DEF_ENC32(A4_tfrpcp, ICLASS_CR" 0011 001sssss PP------ ---ddddd") +DEF_ENC32(G4_tfrgpcp, ICLASS_CR" 0011 000sssss PP------ ---ddddd") DEF_FIELDROW_DESC32( ICLASS_CR" 1000 -------- PP------ --------","[#8] Rdd=Css ") DEF_ENC32(A4_tfrcpp, ICLASS_CR" 1000 000sssss PP------ ---ddddd") +DEF_ENC32(G4_tfrgcpp, ICLASS_CR" 1000 001sssss PP------ ---ddddd") DEF_FIELDROW_DESC32( ICLASS_CR" 1001 -------- PP------ --------","[#9] (#r8,#U10)") DEF_ENC32(J2_ploop1si, ICLASS_CR" 1001 101IIIII PP-iiiii IIIii-II") @@ -754,6 +804,7 @@ DEF_ENC32(J2_loop1i, ICLASS_CR" 1001 001IIIII PP-iiiii IIIii-II") DEF_FIELDROW_DESC32( ICLASS_CR" 1010 -------- PP------ --------","[#10] Rd=Cs ") DEF_ENC32(A2_tfrcrr, ICLASS_CR" 1010 000sssss PP------ ---ddddd") +DEF_ENC32(G4_tfrgcrr, ICLASS_CR" 1010 001sssss PP------ ---ddddd") DEF_ENC32(C4_addipc, ICLASS_CR" 1010 01001001 PP-iiiii i--ddddd") @@ -776,8 +827,66 @@ DEF_ENC32(C4_and_orn, ICLASS_CR" 1011 1011--ss PP0---tt uu----dd") DEF_ENC32(C4_or_andn, ICLASS_CR" 1011 1101--ss PP0---tt uu----dd") DEF_ENC32(C4_or_orn, ICLASS_CR" 1011 1111--ss PP0---tt uu----dd") -DEF_ENC32(C4_fastcorner9, ICLASS_CR"1011 0000--ss PP1---tt 1--1--dd") -DEF_ENC32(C4_fastcorner9_not, ICLASS_CR"1011 0001--ss PP1---tt 1--1--dd") +DEF_ENC32(C4_fastcorner9, ICLASS_CR"1011 0000--ss PP1---tt 1--1--dd") +DEF_ENC32(C4_fastcorner9_not, ICLASS_CR"1011 0001--ss PP1---tt 1--1--dd") + + + +/* Supervisor CR ops */ +/* Interrupts */ +DEF_FIELDROW_DESC32( ICLASS_CR" 0100 -------- PP------ --------","[#4] (Rs,Pt)") +DEF_ENC32(Y2_swi, ICLASS_CR" 0100 000sssss PP------ 000-----") +DEF_ENC32(Y2_cswi, ICLASS_CR" 0100 000sssss PP------ 001-----") +DEF_ENC32(Y2_iassignw, ICLASS_CR" 0100 000sssss PP------ 010-----") +DEF_ENC32(Y2_ciad, ICLASS_CR" 0100 000sssss PP------ 011-----") +DEF_ENC32(Y2_setimask, ICLASS_CR" 0100 100sssss PP----tt 000-----") +DEF_ENC32(Y2_setprio, ICLASS_CR" 0100 100sssss PP----tt 001-----") +DEF_ENC32(Y4_siad, ICLASS_CR" 0100 100sssss PP------ 011-----") + +DEF_ENC32(Y2_wait, ICLASS_CR" 0100 010sssss PP------ 000-----") +DEF_ENC32(Y2_resume, ICLASS_CR" 0100 010sssss PP------ 001-----") +DEF_ENC32(Y2_stop, ICLASS_CR" 0100 011sssss PP------ 000-----") +DEF_ENC32(Y2_start, ICLASS_CR" 0100 011sssss PP------ 001-----") +DEF_ENC32(Y4_nmi, ICLASS_CR" 0100 011sssss PP------ 010-----") + +DEF_FIELDROW_DESC32( ICLASS_CR" 0101 -------- PP------ --------","[#5] Rx ") +DEF_ENC32(Y2_crswap0, ICLASS_CR" 0101 000xxxxx PP------ --------") +DEF_ENC32(Y4_crswap1, ICLASS_CR" 0101 001xxxxx PP------ --------") + +DEF_FIELDROW_DESC32( ICLASS_CR" 0110 -------- PP------ --------","[#6] Rd=(Rs)") +DEF_ENC32(Y2_getimask, ICLASS_CR" 0110 000sssss PP------ ---ddddd") +DEF_ENC32(Y2_iassignr, ICLASS_CR" 0110 011sssss PP------ ---ddddd") + +DEF_FIELDROW_DESC32( ICLASS_CR" 0111 -------- PP------ --------","[#7] cr=Rs ") +DEF_ENC32(Y2_tfrsrcr, ICLASS_CR" 0111 00-sssss PP------ -ddddddd") + +DEF_FIELDROW_DESC32( ICLASS_CR" 1100 -------- PP------ --------","[#12] ") +DEF_ENC32(Y2_break, ICLASS_CR" 1100 001----- PP------ 000-----") +DEF_ENC32(Y2_tlblock, ICLASS_CR" 1100 001----- PP------ 001-----") +DEF_ENC32(Y2_tlbunlock,ICLASS_CR" 1100 001----- PP------ 010-----") +DEF_ENC32(Y2_k0lock, ICLASS_CR" 1100 001----- PP------ 011-----") +DEF_ENC32(Y2_k0unlock, ICLASS_CR" 1100 001----- PP------ 100-----") +DEF_ENC32(Y2_tlbp, ICLASS_CR" 1100 100sssss PP------ ---ddddd") +DEF_ENC32(Y5_tlboc, ICLASS_CR" 1100 111sssss PP------ ---ddddd") +DEF_ENC32(Y5_tlbasidi, ICLASS_CR" 1100 101sssss PP------ --------") +DEF_ENC32(Y2_tlbr, ICLASS_CR" 1100 010sssss PP------ ---ddddd") +DEF_ENC32(Y2_tlbw, ICLASS_CR" 1100 000sssss PP0ttttt --------") +DEF_ENC32(Y5_ctlbw, ICLASS_CR" 1100 110sssss PP0ttttt ---ddddd") + +DEF_FIELDROW_DESC32( ICLASS_CR" 1101 -------- PP------ --------","[#13] Rxx ") +DEF_ENC32(Y4_crswap10, ICLASS_CR" 1101 10-xxxxx PP------ ---00000") +DEF_ENC32(Y4_tfrspcp, ICLASS_CR" 1101 00-sssss PP------ -ddddddd") + +DEF_FIELDROW_DESC32( ICLASS_CR" 1110 -------- PP------ --------","[#14] Rd=cr ") +DEF_ENC32(Y2_tfrscrr, ICLASS_CR" 1110 1sssssss PP------ ---ddddd") + +DEF_FIELDROW_DESC32( ICLASS_CR" 1111 -------- PP------ --------","[#15] Rdd=Sss ") +DEF_ENC32(Y4_tfrscpp, ICLASS_CR" 1111 0sssssss PP------ ---ddddd") + + + + + @@ -956,9 +1065,9 @@ MPY_ENC(F2_dfmin, "1000","ddddd","0","0","1","1","11") MPY_ENC(F2_dfmax, "1000","ddddd","0","1","0","0","11") MPY_ENC(F2_dfmpyll, "1000","ddddd","0","1","0","1","11") -MPY_ENC(M7_dcmpyrw, "1000","ddddd","0","0","0","1","10") +MPY_ENC(M7_dcmpyrw, "1000","ddddd","0","0","0","1","10") MPY_ENC(M7_dcmpyrwc, "1000","ddddd","0","0","1","1","10") -MPY_ENC(M7_dcmpyiw, "1000","ddddd","0","1","1","0","10") +MPY_ENC(M7_dcmpyiw, "1000","ddddd","0","1","1","0","10") MPY_ENC(M7_dcmpyiwc, "1000","ddddd","0","1","1","1","10") @@ -967,14 +1076,14 @@ DEF_FIELDROW_DESC32(ICLASS_M" 1001 -------- PP------ --------","[#9] Rd=(Rss,Rtt MPY_ENC(M2_vdmpyrs_s0, "1001","ddddd","0","0","0","0","00") MPY_ENC(M2_vdmpyrs_s1, "1001","ddddd","0","0","0","1","00") -MPY_ENC(M7_wcmpyrw, "1001","ddddd","0","0","1","0","00") +MPY_ENC(M7_wcmpyrw, "1001","ddddd","0","0","1","0","00") MPY_ENC(M7_wcmpyrw_rnd, "1001","ddddd","0","0","1","1","00") -MPY_ENC(M7_wcmpyiw, "1001","ddddd","0","1","0","0","00") +MPY_ENC(M7_wcmpyiw, "1001","ddddd","0","1","0","0","00") MPY_ENC(M7_wcmpyiw_rnd, "1001","ddddd","0","1","0","1","00") -MPY_ENC(M7_wcmpyrwc, "1001","ddddd","0","1","1","0","00") +MPY_ENC(M7_wcmpyrwc, "1001","ddddd","0","1","1","0","00") MPY_ENC(M7_wcmpyrwc_rnd, "1001","ddddd","0","1","1","1","00") -MPY_ENC(M7_wcmpyiwc, "1001","ddddd","1","0","0","0","00") +MPY_ENC(M7_wcmpyiwc, "1001","ddddd","1","0","0","0","00") MPY_ENC(M7_wcmpyiwc_rnd, "1001","ddddd","1","0","0","1","00") @@ -1030,10 +1139,10 @@ MPY_ENC(F2_dfmpylh, "1010","xxxxx","0","0","0","0","11") MPY_ENC(F2_dfmpyhh, "1010","xxxxx","0","0","0","1","11") -MPY_ENC(M7_dcmpyrw_acc, "1010","xxxxx","0","0","0","1","10") -MPY_ENC(M7_dcmpyrwc_acc, "1010","xxxxx","0","0","1","1","10") -MPY_ENC(M7_dcmpyiw_acc, "1010","xxxxx","0","1","1","0","10") -MPY_ENC(M7_dcmpyiwc_acc, "1010","xxxxx","1","0","1","0","10") +MPY_ENC(M7_dcmpyrw_acc, "1010","xxxxx","0","0","0","1","10") +MPY_ENC(M7_dcmpyrwc_acc, "1010","xxxxx","0","0","1","1","10") +MPY_ENC(M7_dcmpyiw_acc, "1010","xxxxx","0","1","1","0","10") +MPY_ENC(M7_dcmpyiwc_acc, "1010","xxxxx","1","0","1","0","10") @@ -1063,7 +1172,6 @@ SP_MPY(M2_mpy_sat_rnd, "1100","ddddd","1","1","0") SP_MPY(M2_mpyu, "1100","ddddd","0","0","1") DEF_FIELDROW_DESC32(ICLASS_M" 1101 -------- PP------ --------","[#13] Rd=(Rs,Rt)") -/* EJP: same as mpyi MPY_ENC(M2_mpyui, "1101","ddddd","0","0","1","0","00") */ MPY_ENC(M2_mpyi, "1101","ddddd","0","0","0","0","00") MPY_ENC(M2_mpy_up, "1101","ddddd","0","0","0","0","01") MPY_ENC(M2_mpyu_up, "1101","ddddd","0","0","1","0","01") @@ -1266,7 +1374,6 @@ DEF_ENC32(C2_cmovenewif,ICLASS_ALU2op" 1110 1uu0iiii PP1iiiii iiiddddd") DEF_ENC32(C2_cmoveit, ICLASS_ALU2op" 1110 0uu0iiii PP0iiiii iiiddddd") DEF_ENC32(C2_cmoveif, ICLASS_ALU2op" 1110 1uu0iiii PP0iiiii iiiddddd") - DEF_FIELDROW_DESC32( ICLASS_ALU2op" 1111 -------- PP------ --------","[#15] nop") DEF_ENC32(A2_nop, ICLASS_ALU2op" 1111 -------- PP------ --------") @@ -1408,9 +1515,6 @@ DEF_FIELDROW_DESC32(ICLASS_ALU3op" 1110 -------- PP------ --------","[#14] Rese - - - /*******************************/ /* */ /* */ @@ -1508,7 +1612,6 @@ SH_RRI6_ENC(S6_rol_i_##TAGEND,MAJ4,MIN3,SMOD1 "11",DSTCHARS) DEF_FIELDROW_DESC32(ICLASS_S2op" 0000 -------- PP------ --------","[#0] Rdd=(Rss,#u6)") -/* EJP: there is actually quite a bit of space here, look at the reserved bits */ I6SHIFTTYPES(p, "0000","000","0","ddddd") I5SHIFTTYPES_NOROL(vw, "0000","010","0","ddddd") I4SHIFTTYPES(vh, "0000","100","0","ddddd") @@ -1620,8 +1723,8 @@ SH2_RR_ENC(A2_roundsat, "1000","110","-","001","ddddd") SH_RRI5_ENC(S2_asr_i_svw_trun, "1000","110", "010","ddddd") SH_RRI5_ENC(A4_bitspliti, "1000","110", "100","ddddd") -SH_RRI5_ENC(A7_clip, "1000","110", "101","ddddd") -SH_RRI5_ENC(A7_vclip, "1000","110", "110","ddddd") +SH_RRI5_ENC(A7_clip, "1000","110", "101","ddddd") +SH_RRI5_ENC(A7_vclip, "1000","110", "110","ddddd") SH2_RR_ENC(S4_clbpnorm, "1000","011","-","000","ddddd") @@ -1743,10 +1846,11 @@ SH_RRR_ENC(S2_shuffob, "0001","00-","-","10-","ddddd") SH_RRR_ENC(S2_shuffeh, "0001","00-","-","11-","ddddd") SH_RRR_ENC(S2_shuffoh, "0001","10-","-","000","ddddd") +// 001 SH_RRR_ENC(S2_vtrunewh, "0001","10-","-","010","ddddd") -SH_RRR_ENC(S6_vtrunehb_ppp, "0001","10-","-","011","ddddd") +SH_RRR_ENC(S6_vtrunehb_ppp, "0001","10-","-","011","ddddd") SH_RRR_ENC(S2_vtrunowh, "0001","10-","-","100","ddddd") -SH_RRR_ENC(S6_vtrunohb_ppp, "0001","10-","-","101","ddddd") +SH_RRR_ENC(S6_vtrunohb_ppp, "0001","10-","-","101","ddddd") SH_RRR_ENC(S2_lfsp, "0001","10-","-","110","ddddd") SH_RRR_ENC(S4_vxaddsubw, "0001","01-","-","000","ddddd") @@ -1780,8 +1884,6 @@ SH_RRR_ENC(S4_vrcrotate, "0011","11-","i","11i","ddddd") DEF_FIELDROW_DESC32(ICLASS_S3op" 0100 -------- PP------ --------","[#4] Rd=(Rs,Rt,#u3)") DEF_ENC32(S2_addasl_rrri, ICLASS_S3op" 0100 000 sssss PP0ttttt iiiddddd") - - DEF_FIELDROW_DESC32(ICLASS_S3op" 0101 -------- PP------ --------","[#5] Rd=(Rss,Rt)") SH_RRR_ENC(S2_asr_r_svw_trun, "0101","---","-","010","ddddd") SH_RRR_ENC(M4_cmpyi_wh, "0101","---","-","100","ddddd") @@ -1841,6 +1943,7 @@ DEF_FIELDROW_DESC32(ICLASS_S3op" 1010 -------- PP------ --------","[#10] Rxx=(Rs SH_RRR_ENC(S2_insertp_rp, "1010","0--","0","---","xxxxx") SH_RRR_ENC(M4_xor_xacc, "1010","10-","0","000","xxxxx") + DEF_FIELDROW_DESC32(ICLASS_S3op" 1011 -------- PP------ --------","[#11] Rxx=(Rss,Rt)") RSHIFTTYPES(p_or, "1011","000","-","-","xxxxx") RSHIFTTYPES(p_and, "1011","010","-","-","xxxxx") @@ -1848,19 +1951,19 @@ RSHIFTTYPES(p_nac, "1011","100","-","-","xxxxx") RSHIFTTYPES(p_acc, "1011","110","-","-","xxxxx") RSHIFTTYPES(p_xor, "1011","011","-","-","xxxxx") -SH_RRR_ENCX(A4_vrmaxh, "1011","001","0","001","uuuuu") -SH_RRR_ENCX(A4_vrmaxuh, "1011","001","1","001","uuuuu") -SH_RRR_ENCX(A4_vrmaxw, "1011","001","0","010","uuuuu") -SH_RRR_ENCX(A4_vrmaxuw, "1011","001","1","010","uuuuu") +SH_RRR_ENCX(A4_vrmaxh, "1011","001","0","001","uuuuu") +SH_RRR_ENCX(A4_vrmaxuh, "1011","001","1","001","uuuuu") +SH_RRR_ENCX(A4_vrmaxw, "1011","001","0","010","uuuuu") +SH_RRR_ENCX(A4_vrmaxuw, "1011","001","1","010","uuuuu") -SH_RRR_ENCX(A4_vrminh, "1011","001","0","101","uuuuu") -SH_RRR_ENCX(A4_vrminuh, "1011","001","1","101","uuuuu") -SH_RRR_ENCX(A4_vrminw, "1011","001","0","110","uuuuu") -SH_RRR_ENCX(A4_vrminuw, "1011","001","1","110","uuuuu") +SH_RRR_ENCX(A4_vrminh, "1011","001","0","101","uuuuu") +SH_RRR_ENCX(A4_vrminuh, "1011","001","1","101","uuuuu") +SH_RRR_ENCX(A4_vrminw, "1011","001","0","110","uuuuu") +SH_RRR_ENCX(A4_vrminuw, "1011","001","1","110","uuuuu") -SH_RRR_ENC(S2_vrcnegh, "1011","001","1","111","xxxxx") +SH_RRR_ENC(S2_vrcnegh, "1011","001","1","111","xxxxx") -SH_RRR_ENC(S4_vrcrotate_acc, "1011","101","i","--i","xxxxx") +SH_RRR_ENC(S4_vrcrotate_acc, "1011","101","i","--i","xxxxx") DEF_FIELDROW_DESC32(ICLASS_S3op" 1100 -------- PP------ --------","[#12] Rx=(Rs,Rt)") @@ -1874,11 +1977,6 @@ DEF_FIELDROW_DESC32(ICLASS_S3op" 1101 -------- PP------ --------","[#13] Reserve DEF_FIELDROW_DESC32(ICLASS_S3op" 1110 -------- PP------ --------","[#14] Reserved") -DEF_FIELDROW_DESC32(ICLASS_S3op" 1111 -------- PP------ --------","[#14] User Instruction") - - - - @@ -2129,3 +2227,6 @@ OP_OPI_RI(lsr,"1") DEF_FIELDROW_DESC32(ICLASS_ALU64" 1111 -------- PP------ --------","[#15] Rd=(Rs,Ru,#u6:2)") DEF_ENC32(M4_mpyri_addr_u2, ICLASS_ALU64" 1111 0ii sssss PPiddddd iiiuuuuu") DEF_ENC32(M4_mpyri_addr, ICLASS_ALU64" 1111 1ii sssss PPiddddd iiiuuuuu") + + + diff --git a/target/hexagon/imported/system.idef b/target/hexagon/imported/system.idef index 7c6568e75e42..fd7ef18b3e34 100644 --- a/target/hexagon/imported/system.idef +++ b/target/hexagon/imported/system.idef @@ -25,44 +25,262 @@ /* User->OS interface */ /********************************************/ -Q6INSN(J2_trap0,"trap0(#u8)",ATTRIBS(A_COF), +Q6INSN(J2_trap0,"trap0(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Trap to Operating System", - fTRAP(0,uiV); + fTRAP(0,uiV); ) -Q6INSN(J2_pause,"pause(#u8)",ATTRIBS(A_COF), +Q6INSN(J2_trap1,"trap1(Rx32,#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), +"Trap to Operating System", + /* + * Note: if RxV is not written, we get the same as the input. + * Since trap1 is SOLO, this means the register will effectively not be updated + */ + if (!fTRAP1_VIRTINSN(uiV)) { + fTRAP(1,uiV); + } else if (uiV == 1) { + fVIRTINSN_RTE(uiV,RxV); + } else if (uiV == 3) { + fVIRTINSN_SETIE(uiV,RxV); + } else if (uiV == 4) { + fVIRTINSN_GETIE(uiV,RxV); + } else if (uiV == 6) { + fVIRTINSN_SPSWAP(uiV,RxV); + }) + +Q6INSN(J2_pause,"pause(#u8)",ATTRIBS(A_COF,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Enter low-power state for #u8 cycles",{fPAUSE(uiV);}) -Q6INSN(Y2_icinva,"icinva(Rs32)",ATTRIBS(A_ICOP,A_ICFLUSHOP),"Instruction Cache Invalidate Address",{fEA_REG(RsV); fICINVA(EA);}) +Q6INSN(J2_rte, "rte", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NO_TIMING_LOG), +"Return from Exception", +{ +fHIDE(if((thread->timing_on) && (thread->status & EXEC_STATUS_REPLAY)) { return; }) +fHIDE(CALLBACK(thread->processor_ptr->options->rte_callback, + thread->system_ptr,thread->processor_ptr, + thread->threadId,0);) +fCLEAR_RTE_EX(); +fBRANCH(fREAD_ELR(),COF_TYPE_RTE);}) + + +/********************************************/ +/* Interrupt Management */ +/********************************************/ + +Q6INSN(Y2_swi,"swi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Software Interrupt",{DO_SWI(RsV);}) +Q6INSN(Y2_cswi,"cswi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Cancel Software Interrupt",{DO_CSWI(RsV);}) +Q6INSN(Y2_ciad,"ciad(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Re-enable interrupt in IAD",{DO_CIAD(RsV);}) +Q6INSN(Y4_siad,"siad(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Disable interrupt in IAD",{DO_SIAD(RsV);}) +Q6INSN(Y2_iassignr,"Rd32=iassignr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Read interrupt to thread assignments",{DO_IASSIGNR(RsV,RdV);}) +Q6INSN(Y2_iassignw,"iassignw(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Write interrupt to thread assignments",{DO_IASSIGNW(RsV);}) + + +Q6INSN(Y2_getimask,"Rd32=getimask(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Read imask register of another thread", +{RdV = READ_IMASK(RsV & thread->processor_ptr->thread_system_mask); }) + +Q6INSN(Y2_setimask,"setimask(Pt4,Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Change imask register of another thread", +{fPREDUSE_TIMING();WRITE_IMASK(PtV & thread->processor_ptr->thread_system_mask,RsV); }) + + + +/********************************************/ +/* TLB management */ +/********************************************/ + +Q6INSN(Y2_tlbw,"tlbw(Rss32,Rt32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), +"Write TLB entry", {fTLBW(RtV,RssV);}) + +Q6INSN(Y5_ctlbw,"Rd32=ctlbw(Rss32,Rt32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), +"Conditional Write TLB entry", +{ + if (fTLB_ENTRY_OVERLAP( (1LL<<63) | RssV )) { + RdV=fTLB_ENTRY_OVERLAP_IDX( (1LL<<63) | RssV); + } else { + fTLBW(RtV,RssV); + RdV=0x80000000; + } +}) + +Q6INSN(Y5_tlboc,"Rd32=tlboc(Rss32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), +"TLB overlap check", +{ + if (fTLB_ENTRY_OVERLAP( (1LL<<63) | RssV )) { + RdV=fTLB_ENTRY_OVERLAP_IDX( (1LL<<63) | RssV); + } else { + RdV=0x80000000; + } +}) + +Q6INSN(Y2_tlbr,"Rdd32=tlbr(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Read TLB entry", +{RddV = fTLBR(RsV);}) + +Q6INSN(Y2_tlbp,"Rd32=tlbp(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Probe TLB", {RdV=fTLBP(RsV);}) + +Q6INSN(Y5_tlbasidi,"tlbinvasid(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Invalidate ASID", +{ + fHIDE(int i;) + fHIDE(unsigned int NUM_TLB_ENTRIES = NUM_TLB_REGS(thread->processor_ptr);) + for (i = 0; i < NUM_TLB_ENTRIES; i++) { + if ((fGET_FIELD(fTLBR(i),PTE_G) == 0) && + (fGET_FIELD(fTLBR(i),PTE_ASID) == fEXTRACTU_RANGE(RsV,26,20))) { + fTLBW(i,fTLBR(i) & ~(1ULL << 63)); + } + } +}) + +Q6INSN(Y2_tlblock,"tlblock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG), "Lock TLB", +{fSET_TLB_LOCK();}) + +Q6INSN(Y2_tlbunlock,"tlbunlock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Unlock TLB", +{fCLEAR_TLB_LOCK();}) + +Q6INSN(Y2_k0lock,"k0lock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG), "Lock K0", +{fSET_K0_LOCK();}) + +Q6INSN(Y2_k0unlock,"k0unlock", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Unlock K0", +{fCLEAR_K0_LOCK();}) + +/********************************************/ +/* Supervisor Reg Management */ +/********************************************/ + +Q6INSN(Y2_crswap0,"crswap(Rx32,sgp0)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general pointer 0 with GPR", +{fHIDE(size4s_t tmp;) tmp = RxV; RxV = READ_SGP0(); WRITE_SGP0(tmp);}) +Q6INSN(Y4_crswap1,"crswap(Rx32,sgp1)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general pointer 1 with GPR", +{fHIDE(size4s_t tmp;) tmp = RxV; RxV = READ_SGP1(); WRITE_SGP1(tmp);}) + +Q6INSN(Y4_crswap10,"crswap(Rxx32,sgp1:0)",ATTRIBS(A_PRIV,A_NOTE_PRIV), "Swap system general purpose 0/1 with GPR Pair", +{fHIDE(size8s_t tmp;) tmp = RxxV; RxxV=READ_SGP10(); WRITE_SGP10(tmp);}) + +Q6INSN(Y2_tfrscrr,"Rd32=Ss128",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer Supervisor Reg to GPR", {RdV=SsV;}) +Q6INSN(Y2_tfrsrcr,"Sd128=Rs32",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer GPR to Supervisor Reg", {SdV=RsV;}) +Q6INSN(Y4_tfrscpp,"Rdd32=Sss128",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer Supervisor Reg to GPR", {RddV=SssV;}) +Q6INSN(Y4_tfrspcp,"Sdd128=Rss32",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Transfer GPR to Supervisor Reg", {SddV=RssV;}) + +Q6INSN(G4_tfrgcrr,"Rd32=Gs32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer Guest Reg to GPR", {RdV=GsV;}) +Q6INSN(G4_tfrgrcr,"Gd32=Rs32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer GPR to Guest Reg", {GdV=RsV;}) +Q6INSN(G4_tfrgcpp,"Rdd32=Gss32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer Guest Reg to GPR", {RddV=GssV;}) +Q6INSN(G4_tfrgpcp,"Gdd32=Rss32",ATTRIBS(A_GUEST,A_NOTE_GUEST),"Transfer GPR to Guest Reg", {GddV=RssV;}) -Q6INSN(Y2_isync,"isync",ATTRIBS(),"Memory Synchronization",{fISYNC();}) -Q6INSN(Y2_barrier,"barrier",ATTRIBS(A_RESTRICT_SLOT0ONLY),"Memory Barrier",{fBARRIER();}) -Q6INSN(Y2_syncht,"syncht",ATTRIBS(A_RESTRICT_SLOT0ONLY),"Memory Synchronization",{fSYNCH();}) -Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);}) +Q6INSN(Y2_setprio,"setprio(Pt4,Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV),"Change TID Prio of another thread", +{fPREDUSE_TIMING();WRITE_PRIO(PtV & thread->processor_ptr->thread_system_mask,RsV); }) -Q6INSN(Y2_dczeroa,"dczeroa(Rs32)",ATTRIBS(A_STORE,A_RESTRICT_SLOT0ONLY,A_DCZEROA),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);}) -Q6INSN(Y2_dccleana,"dccleana(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Clean Address",{fEA_REG(RsV); fDCCLEANA(EA);}) -Q6INSN(Y2_dccleaninva,"dccleaninva(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Clean and Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);}) -Q6INSN(Y2_dcinva,"dcinva(Rs32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_DCFLUSHOP),"Data Cache Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);}) -Q6INSN(Y4_l2fetch,"l2fetch(Rs32,Rt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY),"L2 Cache Prefetch", +/********************************************/ +/* Power Management / Thread on/off */ +/********************************************/ +Q6INSN(Y6_diag,"diag(Rs32)",ATTRIBS(),"Send value to Diag trace module",{ +}) +Q6INSN(Y6_diag0,"diag0(Rss32,Rtt32)",ATTRIBS(),"Send values of two register to DIAG Trace. Set X=0",{ +}) +Q6INSN(Y6_diag1,"diag1(Rss32,Rtt32)",ATTRIBS(),"Send values of two register to DIAG Trace. Set X=1",{ +}) + + +Q6INSN(Y4_trace,"trace(Rs32)",ATTRIBS(A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK),"Send value to ETM trace",{ + fDO_TRACE(RsV); +}) + +Q6INSN(Y2_stop,"stop(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Stop thread(s)",{ + fHIDE(RsV=RsV;) + if (!fIN_DEBUG_MODE_NO_ISDB(fGET_TNUM())) fCLEAR_RUN_MODE(fGET_TNUM()); +}) + +Q6INSN(Y4_nmi,"nmi(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG),"Raise NMI on thread(s)",{ + fDO_NMI(RsV); +}) + +Q6INSN(Y2_start,"start(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Start thread(s)",fSTART(RsV);) + +Q6INSN(Y2_wait,"wait(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_NO_TIMING_LOG),"Make thread(s) wait",{ + fHIDE(RsV=RsV;) + if (!fIN_DEBUG_MODE(fGET_TNUM())) fSET_WAIT_MODE(fGET_TNUM()); + fIN_DEBUG_MODE_WARN(fGET_TNUM()); +}) + +Q6INSN(Y2_resume,"resume(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Make thread(s) stop waiting",fRESUME(RsV);) + +Q6INSN(Y2_break,"brkpt",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Breakpoint",{fBREAK();}) + + +/********************************************/ +/* Cache Management */ +/********************************************/ + +Q6INSN(Y2_ictagr,"Rd32=ictagr(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Tag Read",{fICTAGR(RsV,RdV,RdN);}) +Q6INSN(Y2_ictagw,"ictagw(Rs32,Rt32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Tag Write",{fICTAGW(RsV,RtV);}) +Q6INSN(Y2_icdataw,"icdataw(Rs32,Rt32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Data Write",{fICDATAW(RsV,RtV);}) +Q6INSN(Y2_icdatar,"Rd32=icdatar(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICTAGOP),"Instruction Cache Data Read",{fICDATAR(RsV, RdV);}) +Q6INSN(Y2_icinva,"icinva(Rs32)",ATTRIBS(A_ICOP,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYADDRESS,A_ICFLUSHOP),"Instruction Cache Invalidate Address",{fEA_REG(RsV); fICINVA(EA);}) +Q6INSN(Y2_icinvidx,"icinvidx(Rs32)",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_ICFLUSHOP),"Instruction Cache Invalidate Index",{fICINVIDX(RsV);}) +Q6INSN(Y2_ickill,"ickill",ATTRIBS(A_ICOP,A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_ICFLUSHOP),"Instruction Cache Invalidate",{fICKILL();}) + +Q6INSN(Y2_isync,"isync",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_NOPACKET),"Memory Synchronization",{fISYNC();}) +Q6INSN(Y2_barrier,"barrier",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK),"Memory Barrier",{fBARRIER();}) +Q6INSN(Y2_syncht,"syncht",ATTRIBS(A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET),"Memory Synchronization",{fSYNCH();}) + + +Q6INSN(Y2_dcfetchbo,"dcfetch(Rs32+#u11:3)",ATTRIBS(A_RESTRICT_PREFERSLOT0,A_DCFETCH,A_RESTRICT_NOSLOT1_STORE),"Data Cache Prefetch",{fEA_RI(RsV,uiV); fDCFETCH(EA);}) +Q6INSN(Y2_dckill,"dckill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_DCFLUSHOP),"Data Cache Invalidate",{fDCKILL();}) + + +Q6INSN(Y2_dczeroa,"dczeroa(Rs32)",ATTRIBS(A_STORE,A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCZEROA),"Zero an aligned 32-byte cacheline",{fEA_REG(RsV); fDCZEROA(EA);}) +Q6INSN(Y2_dccleana,"dccleana(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean Address",{fEA_REG(RsV); fDCCLEANA(EA);}) +Q6INSN(Y2_dccleanidx,"dccleanidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Clean Index",{fDCCLEANIDX(RsV);}) +Q6INSN(Y2_dccleaninva,"dccleaninva(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Clean and Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);}) +Q6INSN(Y2_dccleaninvidx,"dccleaninvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Clean and Invalidate Index",{fDCCLEANINVIDX(RsV);}) +Q6INSN(Y2_dcinva,"dcinva(Rs32)",ATTRIBS(A_RESTRICT_SLOT1_AOK,A_NOTE_SLOT1_AOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYADDRESS,A_DCFLUSHOP),"Data Cache Invalidate Address",{fEA_REG(RsV); fDCCLEANINVA(EA);}) +Q6INSN(Y2_dcinvidx,"dcinvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCFLUSHOP),"Data Cache Invalidate Index",{fDCINVIDX(RsV);}) +Q6INSN(Y2_dctagr,"Rd32=dctagr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_DCTAGOP),"Data Cache Tag Read",{fDCTAGR(RsV,RdV,RdN);}) +Q6INSN(Y2_dctagw,"dctagw(Rs32,Rt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_DCTAGOP),"Data Cache Tag Write",{fDCTAGW(RsV,RtV);}) + + +Q6INSN(Y2_l2kill,"l2kill",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Cache Invalidate",{fL2KILL();}) +Q6INSN(Y4_l2tagw,"l2tagw(Rs32,Rt32)",ATTRIBS(A_PRIV,A_NOTE_BADTAG_UNDEF,A_NOTE_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET,A_CACHEOP,A_COPBYIDX,A_L2TAGOP),"L2 Cache Tag Write",{fL2TAGW(RsV,RtV);}) +Q6INSN(Y4_l2tagr,"Rd32=l2tagr(Rs32)",ATTRIBS(A_PRIV,A_NOTE_BADTAG_UNDEF,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2TAGOP),"L2 Cache Tag Read",{fL2TAGR(RsV,RdV,RdN);}) + +Q6INSN(Y2_l2cleaninvidx,"l2cleaninvidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Clean and Invalidate Index",{fL2CLEANINVIDX(RsV); }) +Q6INSN(Y5_l2cleanidx,"l2cleanidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Clean by Index",{fL2CLEANIDX(RsV); }) +Q6INSN(Y5_l2invidx,"l2invidx(Rs32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_AXOK,A_RESTRICT_PACKET_AXOK,A_RESTRICT_SLOT0ONLY,A_CACHEOP,A_COPBYIDX,A_L2FLUSHOP),"L2 Cache Invalidate by Index",{fL2INVIDX(RsV); }) + + + +Q6INSN(Y4_l2fetch,"l2fetch(Rs32,Rt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"L2 Cache Prefetch", { fL2FETCH(RsV, - (RtV&0xff), /*height*/ - ((RtV>>8)&0xff), /*width*/ - ((RtV>>16)&0xffff), /*stride*/ - 0); /*extra attrib flags*/ + (RtV&0xff), /*height*/ + ((RtV>>8)&0xff), /*width*/ + ((RtV>>16)&0xffff), /*stride*/ + 0); /*extra attrib flags*/ }) -Q6INSN(Y5_l2fetch,"l2fetch(Rs32,Rtt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY),"L2 Cache Prefetch", +Q6INSN(Y5_l2fetch,"l2fetch(Rs32,Rtt32)",ATTRIBS(A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK),"L2 Cache Prefetch", { fL2FETCH(RsV, - fGETUHALF(0,RttV), /*height*/ - fGETUHALF(1,RttV), /*width*/ - fGETUHALF(2,RttV), /*stride*/ - fGETUHALF(3,RttV)); /*flags*/ + fGETUHALF(0,RttV), /*height*/ + fGETUHALF(1,RttV), /*width*/ + fGETUHALF(2,RttV), /*stride*/ + fGETUHALF(3,RttV)); /*flags*/ }) + +Q6INSN(Y5_l2locka,"Pd4=l2locka(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_CACHEOP,A_COPBYADDRESS,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_LATEPRED,A_NOTE_LATEPRED), +"Lock L2 cache line by address", { fEA_REG(RsV); fL2LOCKA(EA,PdV,PdN); fHIDE(MARK_LATE_PRED_WRITE(PdN)) }) + + +Q6INSN(Y5_l2unlocka,"l2unlocka(Rs32)", ATTRIBS(A_PRIV,A_NOTE_PRIV,A_CACHEOP,A_COPBYADDRESS,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK), "UnLock L2 cache line by address", { fEA_REG(RsV); fL2UNLOCKA(EA); }) + + + +Q6INSN(Y5_l2gunlock,"l2gunlock",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Unlock",{fL2UNLOCK();}) + +Q6INSN(Y5_l2gclean,"l2gclean",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean",{fL2CLEAN();}) + +Q6INSN(Y5_l2gcleaninv,"l2gcleaninv",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean and Invalidate",{fL2CLEANINV();}) + +Q6INSN(Y6_l2gcleanpa,"l2gclean(Rtt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean by PA Range",{fL2CLEANPA(RttV);}) + +Q6INSN(Y6_l2gcleaninvpa,"l2gcleaninv(Rtt32)",ATTRIBS(A_PRIV,A_NOTE_PRIV,A_NOTE_NOPACKET,A_RESTRICT_SLOT0ONLY,A_RESTRICT_NOPACKET,A_CACHEOP,A_L2FLUSHOP),"L2 Global Clean and Invalidate by PA Range",{fL2CLEANINVPA(RttV);}) + diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 6e4a3a16970c..b0e9610d98d5 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -675,3 +675,5 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #endif #endif + +#define fPREDUSE_TIMING() From d08ab187631fc0b06a34352c90a4d01cd0189ce0 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 8 Jul 2024 13:28:08 -0700 Subject: [PATCH 034/109] target/hexagon: Add sysemu TCG overrides Define TCG overrides for setprio(), crswap(,sgp{0,1,1:0}). Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 36 +++++++++++++++++++++++++++++++ target/hexagon/cpu_helper.h | 41 ++++++++++++++++++++++++++++++++++++ target/hexagon/gen_tcg_sys.h | 41 ++++++++++++++++++++++++++++++++++++ target/hexagon/genptr.c | 4 ++++ target/hexagon/helper.h | 1 + target/hexagon/hex_common.py | 2 ++ target/hexagon/meson.build | 14 ++++++------ target/hexagon/op_helper.c | 7 ++++++ 8 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 target/hexagon/cpu_helper.c create mode 100644 target/hexagon/cpu_helper.h create mode 100644 target/hexagon/gen_tcg_sys.h diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c new file mode 100644 index 000000000000..dffb5b045c3d --- /dev/null +++ b/target/hexagon/cpu_helper.c @@ -0,0 +1,36 @@ +/* + * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu_helper.h" +#include "system/cpus.h" +#ifdef CONFIG_USER_ONLY +#include "qemu.h" +#include "exec/helper-proto.h" +#else +#include "hw/boards.h" +#include "hw/hexagon/hexagon.h" +#endif +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "qemu/log.h" +#include "tcg/tcg-op.h" +#include "internal.h" +#include "macros.h" +#include "sys_macros.h" +#include "arch.h" + + +#ifndef CONFIG_USER_ONLY + +uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} + + +#endif diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h new file mode 100644 index 000000000000..3aa58c00ea31 --- /dev/null +++ b/target/hexagon/cpu_helper.h @@ -0,0 +1,41 @@ +/* + * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HEXAGON_CPU_HELPER_H +#define HEXAGON_CPU_HELPER_H + +static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, + uint32_t val) +{ + g_assert(reg < TOTAL_PER_THREAD_REGS); + g_assert_not_reached(); +} + +static inline uint32_t arch_get_thread_reg(CPUHexagonState *env, uint32_t reg) +{ + g_assert(reg < TOTAL_PER_THREAD_REGS); + g_assert_not_reached(); +} + +static inline void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, + uint32_t val) +{ + g_assert_not_reached(); +} + +uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg); + +#define ARCH_GET_THREAD_REG(ENV, REG) \ + arch_get_thread_reg(ENV, REG) +#define ARCH_SET_THREAD_REG(ENV, REG, VAL) \ + arch_set_thread_reg(ENV, REG, VAL) +#define ARCH_GET_SYSTEM_REG(ENV, REG) \ + arch_get_system_reg(ENV, REG) +#define ARCH_SET_SYSTEM_REG(ENV, REG, VAL) \ + arch_set_system_reg(ENV, REG, VAL) + +#endif + diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h new file mode 100644 index 000000000000..ba1d2a84c459 --- /dev/null +++ b/target/hexagon/gen_tcg_sys.h @@ -0,0 +1,41 @@ +/* + * Copyright(c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HEXAGON_GEN_TCG_SYS_H +#define HEXAGON_GEN_TCG_SYS_H + +#define fGEN_TCG_Y2_setprio(SHORTCODE) \ + gen_helper_setprio(tcg_env, PtV, RsV) + +#define fGEN_TCG_Y2_crswap0(SHORTCODE) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + tcg_gen_mov_tl(tmp, RxV); \ + tcg_gen_mov_tl(RxV, hex_t_sreg[HEX_SREG_SGP0]); \ + tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP0], tmp); \ + } while (0) + +#define fGEN_TCG_Y4_crswap1(SHORTCODE) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + tcg_gen_mov_tl(tmp, RxV); \ + tcg_gen_mov_tl(RxV, hex_t_sreg[HEX_SREG_SGP1]); \ + tcg_gen_mov_tl(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \ + } while (0) + +#define fGEN_TCG_Y4_crswap10(SHORTCODE) \ + do { \ + g_assert_not_reached(); \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + tcg_gen_mov_i64(tmp, RxxV); \ + tcg_gen_concat_i32_i64(RxxV, \ + hex_t_sreg[HEX_SREG_SGP0], \ + hex_t_sreg[HEX_SREG_SGP1]); \ + tcg_gen_extrl_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP0], tmp); \ + tcg_gen_extrh_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \ + } while (0) + +#endif diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 488d0b4b978b..5554c9515c4d 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -31,6 +31,10 @@ #undef QEMU_GENERATE #include "gen_tcg.h" #include "gen_tcg_hvx.h" +#ifndef CONFIG_USER_ONLY +#include "gen_tcg_sys.h" +#endif + #include "genptr.h" TCGv gen_read_reg(TCGv result, int num) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index fddbd99a197d..146f4f02e415 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -115,4 +115,5 @@ DEF_HELPER_2(greg_read, i32, env, i32) DEF_HELPER_2(greg_read_pair, i64, env, i32) DEF_HELPER_3(sreg_write, void, env, i32, i32) DEF_HELPER_3(sreg_write_pair, void, env, i32, i64) +DEF_HELPER_3(setprio, void, env, i32, i32) #endif diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index ba78a0f8f0ec..3b6cdb3e9688 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -1381,6 +1381,7 @@ def parse_common_args(desc): parser.add_argument("semantics", help="semantics file") parser.add_argument("overrides", help="overrides file") parser.add_argument("overrides_vec", help="vector overrides file") + parser.add_argument("overrides_sys", help="system overrides file") parser.add_argument("out", help="output file") parser.add_argument("--idef-parser", help="file of instructions translated by idef-parser") @@ -1388,6 +1389,7 @@ def parse_common_args(desc): read_semantics_file(args.semantics) read_overrides_file(args.overrides) read_overrides_file(args.overrides_vec) + read_overrides_file(args.overrides_sys) if args.idef_parser: read_idef_parser_enabled_file(args.idef_parser) calculate_attribs() diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index bb4ebaae816e..3ec53010fa02 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -20,6 +20,7 @@ hexagon_ss = ss.source_set() hex_common_py = 'hex_common.py' gen_tcg_h = meson.current_source_dir() / 'gen_tcg.h' gen_tcg_hvx_h = meson.current_source_dir() / 'gen_tcg_hvx.h' +gen_tcg_sys_h = meson.current_source_dir() / 'gen_tcg_sys.h' idef_parser_dir = meson.current_source_dir() / 'idef-parser' # @@ -249,6 +250,7 @@ hexagon_ss.add(files( 'cpu.c', 'translate.c', 'op_helper.c', + 'cpu_helper.c', 'gdbstub.c', 'genptr.c', 'reg_fields.c', @@ -346,12 +348,12 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs # Setup input and dependencies for the next step, this depends on whether or # not idef-parser is enabled helper_dep = [semantics_generated, idef_generated_tcg_c, idef_generated_tcg] - helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, '--idef-parser', idef_generated_list] + helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h, '--idef-parser', idef_generated_list] else # Setup input and dependencies for the next step, this depends on whether or # not idef-parser is enabled helper_dep = [semantics_generated] - helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h] + helper_in = [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h] endif # @@ -365,7 +367,7 @@ helper_protos_generated = custom_target( 'helper_protos_generated.h.inc', output: 'helper_protos_generated.h.inc', depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h], + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'], ) hexagon_ss.add(helper_protos_generated) @@ -374,7 +376,7 @@ helper_funcs_generated = custom_target( 'helper_funcs_generated.c.inc', output: 'helper_funcs_generated.c.inc', depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h], + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'], ) hexagon_ss.add(helper_funcs_generated) @@ -383,7 +385,7 @@ tcg_funcs_generated = custom_target( 'tcg_funcs_generated.c.inc', output: 'tcg_funcs_generated.c.inc', depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h], + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], command: [python, files('gen_tcg_funcs.py'), helper_in, '@OUTPUT@'], ) hexagon_ss.add(tcg_funcs_generated) @@ -392,7 +394,7 @@ analyze_funcs_generated = custom_target( 'analyze_funcs_generated.c.inc', output: 'analyze_funcs_generated.c.inc', depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h], + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'], ) hexagon_ss.add(analyze_funcs_generated) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 1aa5b32b1f73..865e8ebb3cae 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -31,6 +31,7 @@ #include "mmvec/mmvec.h" #include "mmvec/macros.h" #include "op_helper.h" +#include "cpu_helper.h" #include "translate.h" #define SF_BIAS 127 @@ -1366,6 +1367,12 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg) { g_assert_not_reached(); } + +void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio) +{ + g_assert_not_reached(); +} + #endif From 903067de50cfe42f727e9c0910278feef2b6f169 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 12 Sep 2024 07:05:56 -0700 Subject: [PATCH 035/109] target/hexagon: Add implicit attributes to sysemu macros Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 3b6cdb3e9688..20ac3462e256 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -128,8 +128,13 @@ def calculate_attribs(): add_qemu_macro_attrib("fTRAP", "A_IMPLICIT_READS_PC") add_qemu_macro_attrib("fSET_OVERFLOW", "A_IMPLICIT_WRITES_USR") add_qemu_macro_attrib("fSET_LPCFG", "A_IMPLICIT_WRITES_USR") + add_qemu_macro_attrib("fLOAD_LOCKED", "A_LLSC") + add_qemu_macro_attrib("fSTORE_LOCKED", "A_LLSC") + add_qemu_macro_attrib("fCLEAR_RTE_EX", "A_IMPLICIT_WRITES_SSR") add_qemu_macro_attrib("fLOAD", "A_SCALAR_LOAD") add_qemu_macro_attrib("fSTORE", "A_SCALAR_STORE") + add_qemu_macro_attrib("fSET_K0_LOCK", "A_IMPLICIT_READS_PC") + add_qemu_macro_attrib("fSET_TLB_LOCK", "A_IMPLICIT_READS_PC") add_qemu_macro_attrib('fLSBNEW0', 'A_IMPLICIT_READS_P0') add_qemu_macro_attrib('fLSBNEW0NOT', 'A_IMPLICIT_READS_P0') add_qemu_macro_attrib('fREAD_P0', 'A_IMPLICIT_READS_P0') From 49b7120c9d3274f50deac59c3b928f9bc528d7f6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 24 Jul 2024 20:04:46 -0700 Subject: [PATCH 036/109] target/hexagon: Add TCG overrides for int handler insts Define TCG overrides for {c,}swi {c,s}iad, iassign{r,w}, {s,g}etimask instructions. Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_sys.h | 25 ++++++++++++++++++++++ target/hexagon/helper.h | 8 ++++++++ target/hexagon/op_helper.c | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h index ba1d2a84c459..ec63422c5fc8 100644 --- a/target/hexagon/gen_tcg_sys.h +++ b/target/hexagon/gen_tcg_sys.h @@ -7,6 +7,31 @@ #ifndef HEXAGON_GEN_TCG_SYS_H #define HEXAGON_GEN_TCG_SYS_H +/* System mode instructions */ +#define fGEN_TCG_Y2_swi(SHORTCODE) \ + gen_helper_swi(tcg_env, RsV) + +#define fGEN_TCG_Y2_cswi(SHORTCODE) \ + gen_helper_cswi(tcg_env, RsV) + +#define fGEN_TCG_Y2_ciad(SHORTCODE) \ + gen_helper_ciad(tcg_env, RsV) + +#define fGEN_TCG_Y4_siad(SHORTCODE) \ + gen_helper_siad(tcg_env, RsV) + +#define fGEN_TCG_Y2_iassignw(SHORTCODE) \ + gen_helper_iassignw(tcg_env, RsV) + +#define fGEN_TCG_Y2_iassignr(SHORTCODE) \ + gen_helper_iassignr(RdV, tcg_env, RsV) + +#define fGEN_TCG_Y2_getimask(SHORTCODE) \ + gen_helper_getimask(RdV, tcg_env, RsV) + +#define fGEN_TCG_Y2_setimask(SHORTCODE) \ + gen_helper_setimask(tcg_env, PtV, RsV) + #define fGEN_TCG_Y2_setprio(SHORTCODE) \ gen_helper_setprio(tcg_env, PtV, RsV) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 146f4f02e415..2fe4440ddc6e 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -109,6 +109,14 @@ DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int) #if !defined(CONFIG_USER_ONLY) +DEF_HELPER_2(swi, void, env, i32) +DEF_HELPER_2(cswi, void, env, i32) +DEF_HELPER_2(ciad, void, env, i32) +DEF_HELPER_2(siad, void, env, i32) +DEF_HELPER_2(iassignw, void, env, i32) +DEF_HELPER_2(iassignr, i32, env, i32) +DEF_HELPER_2(getimask, i32, env, i32) +DEF_HELPER_3(setimask, void, env, i32, i32) DEF_HELPER_2(sreg_read, i32, env, i32) DEF_HELPER_2(sreg_read_pair, i64, env, i32) DEF_HELPER_2(greg_read, i32, env, i32) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 865e8ebb3cae..575f3fb1635f 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1337,6 +1337,46 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) } #ifndef CONFIG_USER_ONLY +void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) +{ + g_assert_not_reached(); +} + +void HELPER(siad)(CPUHexagonState *env, uint32_t mask) +{ + g_assert_not_reached(); +} + +void HELPER(swi)(CPUHexagonState *env, uint32_t mask) +{ + g_assert_not_reached(); +} + +void HELPER(cswi)(CPUHexagonState *env, uint32_t mask) +{ + g_assert_not_reached(); +} + +void HELPER(iassignw)(CPUHexagonState *env, uint32_t src) +{ + g_assert_not_reached(); +} + +uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src) +{ + g_assert_not_reached(); +} + +uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid) +{ + g_assert_not_reached(); +} + +void HELPER(setimask)(CPUHexagonState *env, uint32_t pred, uint32_t imask) +{ + g_assert_not_reached(); +} + void HELPER(sreg_write)(CPUHexagonState *env, uint32_t reg, uint32_t val) { g_assert_not_reached(); From 17e09dbc86aaaaa2eb34f1da895451975741c4af Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 24 Jul 2024 20:27:34 -0700 Subject: [PATCH 037/109] target/hexagon: Add TCG overrides for thread ctl Define TCG overrides for start, stop, wait, resume instructions. Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_sys.h | 18 ++++++++++++++++++ target/hexagon/helper.h | 4 ++++ target/hexagon/op_helper.c | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h index ec63422c5fc8..a9fd86fca479 100644 --- a/target/hexagon/gen_tcg_sys.h +++ b/target/hexagon/gen_tcg_sys.h @@ -63,4 +63,22 @@ tcg_gen_extrh_i64_i32(ctx->t_sreg_new_value[HEX_SREG_SGP1], tmp); \ } while (0) +#define fGEN_TCG_Y2_wait(SHORTCODE) \ + do { \ + RsV = RsV; \ + gen_helper_wait(tcg_env, tcg_constant_tl(ctx->pkt->pc)); \ + } while (0) + +#define fGEN_TCG_Y2_resume(SHORTCODE) \ + gen_helper_resume(tcg_env, RsV) + +#define fGEN_TCG_Y2_start(SHORTCODE) \ + gen_helper_start(tcg_env, RsV) + +#define fGEN_TCG_Y2_stop(SHORTCODE) \ + do { \ + RsV = RsV; \ + gen_helper_stop(tcg_env); \ + } while (0) + #endif diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 2fe4440ddc6e..ada520bd52ae 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -124,4 +124,8 @@ DEF_HELPER_2(greg_read_pair, i64, env, i32) DEF_HELPER_3(sreg_write, void, env, i32, i32) DEF_HELPER_3(sreg_write_pair, void, env, i32, i64) DEF_HELPER_3(setprio, void, env, i32, i32) +DEF_HELPER_2(start, void, env, i32) +DEF_HELPER_1(stop, void, env) +DEF_HELPER_2(wait, void, env, i32) +DEF_HELPER_2(resume, void, env, i32) #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 575f3fb1635f..09a52843298a 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1367,6 +1367,26 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src) g_assert_not_reached(); } +void HELPER(start)(CPUHexagonState *env, uint32_t imask) +{ + g_assert_not_reached(); +} + +void HELPER(stop)(CPUHexagonState *env) +{ + g_assert_not_reached(); +} + +void HELPER(wait)(CPUHexagonState *env, target_ulong PC) +{ + g_assert_not_reached(); +} + +void HELPER(resume)(CPUHexagonState *env, uint32_t mask) +{ + g_assert_not_reached(); +} + uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid) { g_assert_not_reached(); From 560243f61690c9c4061aebe90c84134a58e3694d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 24 Jul 2024 20:34:02 -0700 Subject: [PATCH 038/109] target/hexagon: Add TCG overrides for rte, nmi Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_sys.h | 19 +++++++++++++++++++ target/hexagon/helper.h | 1 + target/hexagon/op_helper.c | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h index a9fd86fca479..99323f613531 100644 --- a/target/hexagon/gen_tcg_sys.h +++ b/target/hexagon/gen_tcg_sys.h @@ -81,4 +81,23 @@ gen_helper_stop(tcg_env); \ } while (0) +/* + * rte (return from exception) + * Clear the EX bit in SSR + * Jump to ELR + */ +#define fGEN_TCG_J2_rte(SHORTCODE) \ + do { \ + TCGv new_ssr = tcg_temp_new(); \ + tcg_gen_deposit_tl(new_ssr, hex_t_sreg[HEX_SREG_SSR], \ + tcg_constant_tl(0), \ + reg_field_info[SSR_EX].offset, \ + reg_field_info[SSR_EX].width); \ + gen_log_sreg_write(ctx, HEX_SREG_SSR, new_ssr); \ + gen_jumpr(ctx, hex_t_sreg[HEX_SREG_ELR]); \ + } while (0) + +#define fGEN_TCG_Y4_nmi(SHORTCODE) \ + gen_helper_nmi(tcg_env, RsV) + #endif diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index ada520bd52ae..730eaf8b9a0f 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -128,4 +128,5 @@ DEF_HELPER_2(start, void, env, i32) DEF_HELPER_1(stop, void, env) DEF_HELPER_2(wait, void, env, i32) DEF_HELPER_2(resume, void, env, i32) +DEF_HELPER_2(nmi, void, env, i32) #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 09a52843298a..139a0b5ab27c 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1433,6 +1433,10 @@ void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio) g_assert_not_reached(); } +void HELPER(nmi)(CPUHexagonState *env, uint32_t thread_mask) +{ + g_assert_not_reached(); +} #endif From 0c3f47f65510af9d7833f2b36b655aea5cdfb9bf Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 25 Jul 2024 17:17:14 -0700 Subject: [PATCH 039/109] target/hexagon: Add sreg_{read,write} helpers Co-authored-by: Sid Manning Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 1 + target/hexagon/cpu_helper.c | 37 ++++++++++++ target/hexagon/cpu_helper.h | 8 +++ target/hexagon/op_helper.c | 114 ++++++++++++++++++++++++++++++++++-- 4 files changed, 156 insertions(+), 4 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 25137cf2699e..3ac53a7a8cfc 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -321,6 +321,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) qemu_init_vcpu(cs); cpu_reset(cs); #ifndef CONFIG_USER_ONLY + CPUHexagonState *env = cpu_env(cs); if (cs->cpu_index == 0) { env->g_sreg = g_new0(target_ulong, NUM_SREGS); } else { diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index dffb5b045c3d..f7172c812832 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -27,10 +27,47 @@ #ifndef CONFIG_USER_ONLY +uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index) +{ + g_assert_not_reached(); +} + uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg) { g_assert_not_reached(); } +uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env) +{ + g_assert_not_reached(); +} + +uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env) +{ + g_assert_not_reached(); +} + +uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env) +{ + g_assert_not_reached(); +} + +void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, + uint32_t cycles_hi) +{ + g_assert_not_reached(); +} + +void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, + uint32_t cycles_lo) +{ + g_assert_not_reached(); +} + +void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) +{ + g_assert_not_reached(); +} + #endif diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 3aa58c00ea31..4cb000903664 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -7,6 +7,14 @@ #ifndef HEXAGON_CPU_HELPER_H #define HEXAGON_CPU_HELPER_H +uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index); +uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env); +uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env); +uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env); +void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t); +void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t); +void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); + static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) { diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 139a0b5ab27c..84ed72dc5851 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -17,6 +17,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/main-loop.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" @@ -1397,25 +1398,130 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t pred, uint32_t imask) g_assert_not_reached(); } -void HELPER(sreg_write)(CPUHexagonState *env, uint32_t reg, uint32_t val) +static bool handle_pmu_sreg_write(CPUHexagonState *env, uint32_t reg, + uint32_t val) +{ + if (reg == HEX_SREG_PMUSTID0 || reg == HEX_SREG_PMUSTID1 + || reg == HEX_SREG_PMUCFG || reg == HEX_SREG_PMUEVTCFG + || reg == HEX_SREG_PMUEVTCFG1 + || (reg >= HEX_SREG_PMUCNT4 && reg <= HEX_SREG_PMUCNT3)) { + qemu_log_mask(LOG_UNIMP, "PMU registers not yet implemented"); + return true; + } + return false; +} + +static void modify_syscfg(CPUHexagonState *env, uint32_t val) { g_assert_not_reached(); } -void HELPER(sreg_write_pair)(CPUHexagonState *env, uint32_t reg, uint64_t val) +static void hexagon_set_vid(CPUHexagonState *env, uint32_t offset, int val) +{ + g_assert_not_reached(); +} +static uint32_t hexagon_find_last_irq(CPUHexagonState *env, uint32_t vid) { g_assert_not_reached(); } +static void hexagon_read_timer(CPUHexagonState *env, uint32_t *low, + uint32_t *high) +{ + qemu_log_mask(LOG_UNIMP, "reading timer_hi/lo not yet supported\n"); +} + +static inline QEMU_ALWAYS_INLINE void sreg_write(CPUHexagonState *env, + uint32_t reg, uint32_t val) + +{ + g_assert(bql_locked()); + if ((reg == HEX_SREG_VID) || (reg == HEX_SREG_VID1)) { + hexagon_set_vid(env, (reg == HEX_SREG_VID) ? L2VIC_VID_0 : L2VIC_VID_1, + val); + ARCH_SET_SYSTEM_REG(env, reg, val); + } else if (reg == HEX_SREG_SYSCFG) { + modify_syscfg(env, val); + } else if (reg == HEX_SREG_IMASK) { + val = GET_FIELD(IMASK_MASK, val); + ARCH_SET_SYSTEM_REG(env, reg, val); + } else if (reg == HEX_SREG_PCYCLELO) { + hexagon_set_sys_pcycle_count_low(env, val); + } else if (reg == HEX_SREG_PCYCLEHI) { + hexagon_set_sys_pcycle_count_high(env, val); + } else if (!handle_pmu_sreg_write(env, reg, val)) { + if (reg >= HEX_SREG_GLB_START) { + ARCH_SET_SYSTEM_REG(env, reg, val); + } else { + ARCH_SET_SYSTEM_REG(env, reg, val); + } + } +} + +void HELPER(sreg_write)(CPUHexagonState *env, uint32_t reg, uint32_t val) +{ + BQL_LOCK_GUARD(); + sreg_write(env, reg, val); +} + +void HELPER(sreg_write_pair)(CPUHexagonState *env, uint32_t reg, uint64_t val) +{ + BQL_LOCK_GUARD(); + sreg_write(env, reg, val & 0xFFFFFFFF); + sreg_write(env, reg + 1, val >> 32); +} + +static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env, + uint32_t reg) +{ + g_assert(bql_locked()); + if (reg == HEX_SREG_PMUSTID0 || reg == HEX_SREG_PMUSTID1 + || reg == HEX_SREG_PMUCFG || reg == HEX_SREG_PMUEVTCFG + || reg == HEX_SREG_PMUEVTCFG1 + || (reg >= HEX_SREG_PMUCNT4 && reg <= HEX_SREG_PMUCNT3)) { + qemu_log_mask(LOG_UNIMP, "PMU registers not yet implemented"); + return 0; + } + if ((reg == HEX_SREG_VID) || (reg == HEX_SREG_VID1)) { + const uint32_t vid = hexagon_find_last_irq(env, reg); + ARCH_SET_SYSTEM_REG(env, reg, vid); + } else if ((reg == HEX_SREG_TIMERLO) || (reg == HEX_SREG_TIMERHI)) { + uint32_t low = 0; + uint32_t high = 0; + hexagon_read_timer(env, &low, &high); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_TIMERLO, low); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_TIMERHI, high); + } else if (reg == HEX_SREG_BADVA) { + target_ulong ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + if (GET_SSR_FIELD(SSR_BVS, ssr)) { + return ARCH_GET_SYSTEM_REG(env, HEX_SREG_BADVA1); + } + return ARCH_GET_SYSTEM_REG(env, HEX_SREG_BADVA0); + } + return ARCH_GET_SYSTEM_REG(env, reg); +} + uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + return sreg_read(env, reg); } uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + if (reg == HEX_SREG_TIMERLO) { + uint32_t low = 0; + uint32_t high = 0; + hexagon_read_timer(env, &low, &high); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_TIMERLO, low); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_TIMERHI, high); + } else if (reg == HEX_SREG_PCYCLELO) { + return hexagon_get_sys_pcycle_count(env); + } + return (uint64_t)sreg_read(env, reg) | + (((uint64_t)sreg_read(env, reg + 1)) << 32); } uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg) From d82c776167f84e102e8c1024fabe7cccebd923f9 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 9 Aug 2024 16:28:08 -0700 Subject: [PATCH 040/109] target/hexagon: Initialize htid, modectl regs Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 3ac53a7a8cfc..ab5f2915b6a9 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -26,6 +26,7 @@ #include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" #include "exec/gdbstub.h" +#include "cpu_helper.h" static void hexagon_v66_cpu_init(Object *obj) { } static void hexagon_v67_cpu_init(Object *obj) { } @@ -289,11 +290,18 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) set_float_default_nan_pattern(0b11111111, &env->fp_status); #ifndef CONFIG_USER_ONLY + HexagonCPU *cpu = HEXAGON_CPU(cs); + if (cs->cpu_index == 0) { memset(env->g_sreg, 0, sizeof(target_ulong) * NUM_SREGS); } memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); + + if (cs->cpu_index == 0) { + ARCH_SET_SYSTEM_REG(env, HEX_SREG_MODECTL, 0x1); + } + ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); #endif } From f2e343ce4975f4ef82665dd0ee4897b088bc2480 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 9 Aug 2024 19:24:45 -0700 Subject: [PATCH 041/109] target/hexagon: Add locks, id, next_PC to state Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 6 ++++++ target/hexagon/cpu.h | 37 +++++++++++++++++++++++++++++++++++-- target/hexagon/machine.c | 4 ++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index ab5f2915b6a9..19dae5369547 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -302,6 +302,12 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) ARCH_SET_SYSTEM_REG(env, HEX_SREG_MODECTL, 0x1); } ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); + memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); + memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); + env->threadId = cs->cpu_index; + env->tlb_lock_state = HEX_LOCK_UNLOCKED; + env->k0_lock_state = HEX_LOCK_UNLOCKED; + env->next_PC = 0; #endif } diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 1da73deb90c0..ae9f98548440 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -40,9 +40,36 @@ #define PRED_WRITES_MAX 5 /* 4 insns + endloop */ #define VSTORES_MAX 2 -#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU +#ifndef CONFIG_USER_ONLY +#define CPU_INTERRUPT_SWI CPU_INTERRUPT_TGT_INT_0 +#define CPU_INTERRUPT_K0_UNLOCK CPU_INTERRUPT_TGT_INT_1 +#define CPU_INTERRUPT_TLB_UNLOCK CPU_INTERRUPT_TGT_INT_2 + +#define HEX_CPU_MODE_USER 1 +#define HEX_CPU_MODE_GUEST 2 +#define HEX_CPU_MODE_MONITOR 3 + +#define HEX_EXE_MODE_OFF 1 +#define HEX_EXE_MODE_RUN 2 +#define HEX_EXE_MODE_WAIT 3 +#define HEX_EXE_MODE_DEBUG 4 +#endif -#define MMU_USER_IDX 0 +#define MMU_USER_IDX 0 +#ifndef CONFIG_USER_ONLY +#define MMU_GUEST_IDX 1 +#define MMU_KERNEL_IDX 2 + +typedef enum { + HEX_LOCK_UNLOCKED = 0, + HEX_LOCK_WAITING = 1, + HEX_LOCK_OWNER = 2, + HEX_LOCK_QUEUED = 3 +} hex_lock_state_t; +#endif + + +#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU typedef struct { target_ulong va; @@ -91,6 +118,12 @@ typedef struct CPUArchState { target_ulong greg[NUM_GREGS]; target_ulong greg_written[NUM_GREGS]; + + /* This alias of CPUState.cpu_index is used by imported sources: */ + target_ulong threadId; + hex_lock_state_t tlb_lock_state; + hex_lock_state_t k0_lock_state; + target_ulong next_PC; #endif target_ulong new_value_usr; diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c index 5f654d84b8eb..b8da8d1ff1cd 100644 --- a/target/hexagon/machine.c +++ b/target/hexagon/machine.c @@ -21,6 +21,10 @@ const VMStateDescription vmstate_hexagon_cpu = { VMSTATE_UINTTL_ARRAY(env.t_sreg_written, HexagonCPU, NUM_SREGS), VMSTATE_UINTTL_ARRAY(env.greg, HexagonCPU, NUM_GREGS), VMSTATE_UINTTL_ARRAY(env.greg_written, HexagonCPU, NUM_GREGS), + VMSTATE_UINTTL(env.next_PC, HexagonCPU), + VMSTATE_UINTTL(env.tlb_lock_state, HexagonCPU), + VMSTATE_UINTTL(env.k0_lock_state, HexagonCPU), + VMSTATE_UINTTL(env.threadId, HexagonCPU), VMSTATE_END_OF_LIST() }, }; From 7411a69704c2843ef24e74719a07b466e8344460 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 9 Aug 2024 19:29:54 -0700 Subject: [PATCH 042/109] target/hexagon: Add a TLB count property Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 4 ++++ target/hexagon/cpu.h | 1 + target/hexagon/max.h | 13 +++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 target/hexagon/max.h diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 19dae5369547..12d7e601da76 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -27,6 +27,7 @@ #include "tcg/tcg.h" #include "exec/gdbstub.h" #include "cpu_helper.h" +#include "max.h" static void hexagon_v66_cpu_init(Object *obj) { } static void hexagon_v67_cpu_init(Object *obj) { } @@ -51,6 +52,9 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model) } static const Property hexagon_cpu_properties[] = { +#if !defined(CONFIG_USER_ONLY) + DEFINE_PROP_UINT32("num-tlbs", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES), +#endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, qdev_prop_uint32, target_ulong), diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index ae9f98548440..6decbbe70592 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -170,6 +170,7 @@ struct ArchCPU { bool lldb_compat; target_ulong lldb_stack_adjust; bool short_circuit; + uint32_t num_tlbs; }; #include "cpu_bits.h" diff --git a/target/hexagon/max.h b/target/hexagon/max.h new file mode 100644 index 000000000000..fd315f09b6f7 --- /dev/null +++ b/target/hexagon/max.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _MAX_H +#define _MAX_H + +#define MAX_TLB_ENTRIES 320 +#define DTLB_ENTRIES 16 +#define ITLB_ENTRIES 16 + +#endif From ad71d2308d72919df9c865844fb551f8420cddf3 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 16 Aug 2024 09:03:28 -0700 Subject: [PATCH 043/109] target/hexagon: Add {TLB,k0}lock, cause code, wait_next_pc {TLB,k0}lock counts are used to represent the TLB, k0 locks among hardware threads. wait_next_pc represents the program counter to set when resuming from a wait-for-interrupts state. cause_code contains the precise exception cause.This will be used by subsequent commits. Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 4 ++++ target/hexagon/cpu.h | 4 ++++ target/hexagon/machine.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 12d7e601da76..bf098a5211fd 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -311,7 +311,11 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) env->threadId = cs->cpu_index; env->tlb_lock_state = HEX_LOCK_UNLOCKED; env->k0_lock_state = HEX_LOCK_UNLOCKED; + env->tlb_lock_count = 0; + env->k0_lock_count = 0; env->next_PC = 0; + env->wait_next_pc = 0; + env->cause_code = -1; #endif } diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 6decbbe70592..419e62ba141d 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -103,6 +103,7 @@ typedef struct { typedef struct CPUArchState { target_ulong gpr[TOTAL_PER_THREAD_REGS]; target_ulong pred[NUM_PREGS]; + target_ulong cause_code; /* For comparing with LLDB on target - see adjust_stack_ptrs function */ target_ulong last_pc_dumped; @@ -118,11 +119,14 @@ typedef struct CPUArchState { target_ulong greg[NUM_GREGS]; target_ulong greg_written[NUM_GREGS]; + target_ulong wait_next_pc; /* This alias of CPUState.cpu_index is used by imported sources: */ target_ulong threadId; hex_lock_state_t tlb_lock_state; hex_lock_state_t k0_lock_state; + target_ulong tlb_lock_count; + target_ulong k0_lock_count; target_ulong next_PC; #endif target_ulong new_value_usr; diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c index b8da8d1ff1cd..f60e257223da 100644 --- a/target/hexagon/machine.c +++ b/target/hexagon/machine.c @@ -24,7 +24,11 @@ const VMStateDescription vmstate_hexagon_cpu = { VMSTATE_UINTTL(env.next_PC, HexagonCPU), VMSTATE_UINTTL(env.tlb_lock_state, HexagonCPU), VMSTATE_UINTTL(env.k0_lock_state, HexagonCPU), + VMSTATE_UINTTL(env.tlb_lock_count, HexagonCPU), + VMSTATE_UINTTL(env.k0_lock_count, HexagonCPU), VMSTATE_UINTTL(env.threadId, HexagonCPU), + VMSTATE_UINTTL(env.cause_code, HexagonCPU), + VMSTATE_UINTTL(env.wait_next_pc, HexagonCPU), VMSTATE_END_OF_LIST() }, }; From 3243399f97efd9dea7f8df43ebb4f8d6eccb4849 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 16 Aug 2024 09:03:59 -0700 Subject: [PATCH 044/109] target/hexagon: Add stubs for modify_ssr/get_exe_mode Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 8 ++++++++ target/hexagon/cpu_helper.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index f7172c812832..32051dfea394 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -69,5 +69,13 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) g_assert_not_reached(); } +void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old) +{ + g_assert_not_reached(); +} +int get_exe_mode(CPUHexagonState *env) +{ + g_assert_not_reached(); +} #endif diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 4cb000903664..7d851f3c5029 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -14,6 +14,8 @@ uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env); void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t); void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t); void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); +void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old); +int get_exe_mode(CPUHexagonState *env); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) From 2ce28d3d16b62f64721990264b9e92d491b3b13c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 26 Aug 2024 20:44:28 -0700 Subject: [PATCH 045/109] target/hexagon: Add gdb support for sys regs Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 17 ++++++++++++++ target/hexagon/cpu.h | 6 +++++ target/hexagon/gdbstub.c | 47 ++++++++++++++++++++++++++++++++++++++ target/hexagon/internal.h | 4 ++++ target/hexagon/op_helper.c | 16 +++++++++++++ 5 files changed, 90 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index bf098a5211fd..480524b9bbd0 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -29,6 +29,10 @@ #include "cpu_helper.h" #include "max.h" +#ifndef CONFIG_USER_ONLY +#include "sys_macros.h" +#endif + static void hexagon_v66_cpu_init(Object *obj) { } static void hexagon_v67_cpu_init(Object *obj) { } static void hexagon_v68_cpu_init(Object *obj) { } @@ -340,6 +344,12 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) hexagon_hvx_gdb_write_register, gdb_find_static_feature("hexagon-hvx.xml"), 0); +#ifndef CONFIG_USER_ONLY + gdb_register_coprocessor(cs, hexagon_sys_gdb_read_register, + hexagon_sys_gdb_write_register, + gdb_find_static_feature("hexagon-sys.xml"), 0); +#endif + qemu_init_vcpu(cs); cpu_reset(cs); #ifndef CONFIG_USER_ONLY @@ -402,6 +412,13 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->tcg_ops = &hexagon_tcg_ops; } +#ifndef CONFIG_USER_ONLY +uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg) +{ + g_assert_not_reached(); +} +#endif + #define DEFINE_CPU(type_name, initfn) \ { \ .name = type_name, \ diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 419e62ba141d..8aeaf7d2efdd 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -185,6 +185,12 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, uintptr_t pc); +#ifndef CONFIG_USER_ONLY +uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg); +uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg); +void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val); +#endif + static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) { diff --git a/target/hexagon/gdbstub.c b/target/hexagon/gdbstub.c index 12d6b3bbcbb1..1f7e6201da38 100644 --- a/target/hexagon/gdbstub.c +++ b/target/hexagon/gdbstub.c @@ -76,6 +76,53 @@ int hexagon_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) g_assert_not_reached(); } +#ifndef CONFIG_USER_ONLY +int hexagon_sys_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + if (n < NUM_SREGS) { + return gdb_get_regl(mem_buf, hexagon_sreg_read(env, n)); + } + n -= NUM_SREGS; + + if (n < NUM_GREGS) { + return gdb_get_regl(mem_buf, hexagon_greg_read(env, n)); + } + n -= NUM_GREGS; + + n -= TOTAL_PER_THREAD_REGS; + + if (n < NUM_PREGS) { + env->pred[n] = ldtul_p(mem_buf) & 0xff; + return sizeof(uint8_t); + } + + n -= NUM_PREGS; + + g_assert_not_reached(); +} + +int hexagon_sys_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + if (n < NUM_SREGS) { + hexagon_gdb_sreg_write(env, n, ldtul_p(mem_buf)); + return sizeof(target_ulong); + } + n -= NUM_SREGS; + + if (n < NUM_GREGS) { + return env->greg[n] = ldtul_p(mem_buf); + } + n -= NUM_GREGS; + + g_assert_not_reached(); +} +#endif static int gdb_get_vreg(CPUHexagonState *env, GByteArray *mem_buf, int n) { int total = 0; diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 912a8a2c1d94..cd768f19ef0c 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -22,6 +22,10 @@ int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +#ifndef CONFIG_USER_ONLY +int hexagon_sys_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n); +int hexagon_sys_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n); +#endif int hexagon_hvx_gdb_read_register(CPUState *env, GByteArray *mem_buf, int n); int hexagon_hvx_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n); diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 84ed72dc5851..9205826faa02 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1465,6 +1465,17 @@ void HELPER(sreg_write)(CPUHexagonState *env, uint32_t reg, uint32_t val) sreg_write(env, reg, val); } +void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val) +{ + BQL_LOCK_GUARD(); + sreg_write(env, reg, val); + /* + * The above is needed to run special logic for regs like syscfg, but it + * won't set read-only bits. This will: + */ + ARCH_SET_SYSTEM_REG(env, reg, val); +} + void HELPER(sreg_write_pair)(CPUHexagonState *env, uint32_t reg, uint64_t val) { BQL_LOCK_GUARD(); @@ -1508,6 +1519,11 @@ uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg) return sreg_read(env, reg); } +uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg) +{ + return sreg_read(env, reg); +} + uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg) { BQL_LOCK_GUARD(); From 8cc9d4aefffe73191439ebf911e1ed9e2ee846b1 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 26 Aug 2024 13:44:55 -0700 Subject: [PATCH 046/109] FIXME: target/hexagon: Add initial MMU model FIXME: this commit contains FIXMEs Signed-off-by: Brian Cain Co-authored-by: Taylor Simpson Co-authored-by: Michael Lambert --- target/hexagon/cpu.c | 27 +- target/hexagon/cpu.h | 13 + target/hexagon/hex_mmu.c | 535 +++++++++++++++++++++++++++++++++++++ target/hexagon/hex_mmu.h | 30 +++ target/hexagon/internal.h | 3 + target/hexagon/machine.c | 30 +++ target/hexagon/meson.build | 3 +- target/hexagon/translate.c | 2 +- 8 files changed, 640 insertions(+), 3 deletions(-) create mode 100644 target/hexagon/hex_mmu.c create mode 100644 target/hexagon/hex_mmu.h diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 480524b9bbd0..9b785606c626 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -28,6 +28,7 @@ #include "exec/gdbstub.h" #include "cpu_helper.h" #include "max.h" +#include "hex_mmu.h" #ifndef CONFIG_USER_ONLY #include "sys_macros.h" @@ -282,6 +283,18 @@ static void hexagon_restore_state_to_opc(CPUState *cs, cpu_env(cs)->gpr[HEX_REG_PC] = data[0]; } + +#ifndef CONFIG_USER_ONLY +static void mmu_reset(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + if (cs->cpu_index == 0) { + memset(env->hex_tlb, 0, sizeof(*env->hex_tlb)); + } +} +#endif + + static void hexagon_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -309,6 +322,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) if (cs->cpu_index == 0) { ARCH_SET_SYSTEM_REG(env, HEX_SREG_MODECTL, 0x1); } + mmu_reset(env); ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); @@ -340,6 +354,14 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) return; } +#ifndef CONFIG_USER_ONLY + HexagonCPU *cpu = HEXAGON_CPU(cs); + if (cpu->num_tlbs > MAX_TLB_ENTRIES) { + error_setg(errp, "Number of TLBs selected is invalid"); + return; + } +#endif + gdb_register_coprocessor(cs, hexagon_hvx_gdb_read_register, hexagon_hvx_gdb_write_register, gdb_find_static_feature("hexagon-hvx.xml"), 0); @@ -351,9 +373,12 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) #endif qemu_init_vcpu(cs); - cpu_reset(cs); #ifndef CONFIG_USER_ONLY CPUHexagonState *env = cpu_env(cs); + hex_mmu_realize(env); +#endif + cpu_reset(cs); +#ifndef CONFIG_USER_ONLY if (cs->cpu_index == 0) { env->g_sreg = g_new0(target_ulong, NUM_SREGS); } else { diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 8aeaf7d2efdd..d4603b6e0067 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -31,6 +31,8 @@ #include "mmvec/mmvec.h" #include "hw/registerfields.h" +typedef struct CPUHexagonTLBContext CPUHexagonTLBContext; + #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -128,6 +130,7 @@ typedef struct CPUArchState { target_ulong tlb_lock_count; target_ulong k0_lock_count; target_ulong next_PC; + CPUHexagonTLBContext *hex_tlb; #endif target_ulong new_value_usr; @@ -174,12 +177,15 @@ struct ArchCPU { bool lldb_compat; target_ulong lldb_stack_adjust; bool short_circuit; +#ifndef CONFIG_USER_ONLY uint32_t num_tlbs; +#endif }; #include "cpu_bits.h" FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) +FIELD(TB_FLAGS, MMU_INDEX, 1, 3) G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, @@ -191,6 +197,7 @@ uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg); void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val); #endif +#include "exec/cpu-all.h" static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) { @@ -204,6 +211,12 @@ static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, if (*pc & PCALIGN_MASK) { hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0); } +#ifndef CONFIG_USER_ONLY + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, + cpu_mmu_index(env_cpu(env), false)); +#else + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX); +#endif } typedef HexagonCPU ArchCPU; diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c new file mode 100644 index 000000000000..83ed17892452 --- /dev/null +++ b/target/hexagon/hex_mmu.c @@ -0,0 +1,535 @@ +/* + * Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/qemu-print.h" +#include "cpu.h" +#include "system/cpus.h" +#include "internal.h" +#include "exec/exec-all.h" +#include "hex_mmu.h" +#include "cpu_helper.h" +#include "macros.h" +#include "sys_macros.h" +#include "reg_fields.h" + +#define GET_TLB_FIELD(ENTRY, FIELD) \ + ((uint64_t)fEXTRACTU_BITS(ENTRY, reg_field_info[FIELD].width, \ + reg_field_info[FIELD].offset)) + +/* + * PPD (physical page descriptor) is formed by putting the PTE_PA35 field + * in the MSB of the PPD + */ +#define GET_PPD(ENTRY) \ + ((GET_TLB_FIELD((ENTRY), PTE_PPD) | \ + (GET_TLB_FIELD((ENTRY), PTE_PA35) << reg_field_info[PTE_PPD].width))) + +#define NO_ASID (1 << 8) + +typedef enum { + PGSIZE_4K, + PGSIZE_16K, + PGSIZE_64K, + PGSIZE_256K, + PGSIZE_1M, + PGSIZE_4M, + PGSIZE_16M, + PGSIZE_64M, + PGSIZE_256M, + PGSIZE_1G, + NUM_PGSIZE_TYPES +} tlb_pgsize_t; + +static const char *pgsize_str[NUM_PGSIZE_TYPES] = { + "4K", + "16K", + "64K", + "256K", + "1M", + "4M", + "16M", + "64M", + "256M", + "1G" +}; + +#define INVALID_MASK 0xffffffffLL + +static const uint64_t encmask_2_mask[] = { + 0x0fffLL, /* 4k, 0000 */ + 0x3fffLL, /* 16k, 0001 */ + 0xffffLL, /* 64k, 0010 */ + 0x3ffffLL, /* 256k, 0011 */ + 0xfffffLL, /* 1m, 0100 */ + 0x3fffffLL, /* 4m, 0101 */ + 0xffffffLL, /* 16m, 0110 */ + 0x3ffffffLL, /* 64m, 0111 */ + 0xfffffffLL, /* 256m, 1000 */ + 0x3fffffffLL, /* 1g, 1001 */ + INVALID_MASK, /* RSVD, 0111 */ +}; + +static inline int hex_tlb_pgsize(uint64_t entry) +{ + if (entry == 0) { + qemu_log_mask(CPU_LOG_MMU, "%s: Supplied TLB entry was 0!\n", __func__); + return 0; + } + int size = ctz64(entry); + g_assert(size < NUM_PGSIZE_TYPES); + return size; +} + +static inline uint32_t hex_tlb_page_size(uint64_t entry) +{ + return 1 << (TARGET_PAGE_BITS + 2 * hex_tlb_pgsize(GET_PPD(entry))); +} + +static inline uint64_t hex_tlb_phys_page_num(uint64_t entry) +{ + uint32_t ppd = GET_PPD(entry); + return ppd >> 1; +} + +static inline uint64_t hex_tlb_phys_addr(uint64_t entry) +{ + uint64_t pagemask = encmask_2_mask[hex_tlb_pgsize(entry)]; + uint64_t pagenum = hex_tlb_phys_page_num(entry); + uint64_t PA = (pagenum << TARGET_PAGE_BITS) & (~pagemask); + return PA; +} + +static inline uint64_t hex_tlb_virt_addr(uint64_t entry) +{ + return GET_TLB_FIELD(entry, PTE_VPN) << TARGET_PAGE_BITS; +} + +static bool hex_dump_mmu_entry(FILE *f, uint64_t entry) +{ + if (GET_TLB_FIELD(entry, PTE_V)) { + fprintf(f, "0x%016" PRIx64 ": ", entry); + uint64_t PA = hex_tlb_phys_addr(entry); + uint64_t VA = hex_tlb_virt_addr(entry); + fprintf(f, "V:%" PRId64 " G:%" PRId64 " A1:%" PRId64 " A0:%" PRId64, + GET_TLB_FIELD(entry, PTE_V), GET_TLB_FIELD(entry, PTE_G), + GET_TLB_FIELD(entry, PTE_ATR1), GET_TLB_FIELD(entry, PTE_ATR0)); + fprintf(f, " ASID:0x%02" PRIx64 " VA:0x%08" PRIx64, + GET_TLB_FIELD(entry, PTE_ASID), VA); + fprintf(f, + " X:%" PRId64 " W:%" PRId64 " R:%" PRId64 " U:%" PRId64 + " C:%" PRId64, + GET_TLB_FIELD(entry, PTE_X), GET_TLB_FIELD(entry, PTE_W), + GET_TLB_FIELD(entry, PTE_R), GET_TLB_FIELD(entry, PTE_U), + GET_TLB_FIELD(entry, PTE_C)); + fprintf(f, " PA:0x%09" PRIx64 " SZ:%s (0x%x)", PA, + pgsize_str[hex_tlb_pgsize(entry)], hex_tlb_page_size(entry)); + fprintf(f, "\n"); + return true; + } + + /* Not valid */ + return false; +} + +void dump_mmu(CPUHexagonState *env) +{ + int i; + + HexagonCPU *cpu = env_archcpu(env); + for (i = 0; i < cpu->num_tlbs; i++) { + uint64_t entry = env->hex_tlb->entries[i]; + if (GET_TLB_FIELD(entry, PTE_V)) { + qemu_printf("0x%016" PRIx64 ": ", entry); + uint64_t PA = hex_tlb_phys_addr(entry); + uint64_t VA = hex_tlb_virt_addr(entry); + qemu_printf( + "V:%" PRId64 " G:%" PRId64 " A1:%" PRId64 " A0:%" PRId64, + GET_TLB_FIELD(entry, PTE_V), GET_TLB_FIELD(entry, PTE_G), + GET_TLB_FIELD(entry, PTE_ATR1), GET_TLB_FIELD(entry, PTE_ATR0)); + qemu_printf(" ASID:0x%02" PRIx64 " VA:0x%08" PRIx64, + GET_TLB_FIELD(entry, PTE_ASID), VA); + qemu_printf( + " X:%" PRId64 " W:%" PRId64 " R:%" PRId64 " U:%" PRId64 + " C:%" PRId64, + GET_TLB_FIELD(entry, PTE_X), GET_TLB_FIELD(entry, PTE_W), + GET_TLB_FIELD(entry, PTE_R), GET_TLB_FIELD(entry, PTE_U), + GET_TLB_FIELD(entry, PTE_C)); + qemu_printf(" PA:0x%09" PRIx64 " SZ:%s (0x%x)", PA, + pgsize_str[hex_tlb_pgsize(entry)], + hex_tlb_page_size(entry)); + qemu_printf("\n"); + } + } +} + +static inline void hex_log_tlbw(uint32_t index, uint64_t entry) +{ + if (qemu_loglevel_mask(CPU_LOG_MMU)) { + if (qemu_log_enabled()) { + FILE *logfile = qemu_log_trylock(); + if (logfile) { + fprintf(logfile, "tlbw[%03d]: ", index); + if (!hex_dump_mmu_entry(logfile, entry)) { + fprintf(logfile, "invalid\n"); + } + qemu_log_unlock(logfile); + } + } + } +} + +void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value) +{ + uint32_t myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(index)); + bool old_entry_valid = GET_TLB_FIELD(env->hex_tlb->entries[myidx], PTE_V); + if (old_entry_valid && hexagon_cpu_mmu_enabled(env)) { + /* FIXME - Do we have to invalidate everything here? */ + CPUState *cs = env_cpu(env); + + tlb_flush(cs); + } + env->hex_tlb->entries[myidx] = (value); + hex_log_tlbw(myidx, value); +} + +void hex_mmu_realize(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + if (cs->cpu_index == 0) { + env->hex_tlb = g_malloc0(sizeof(CPUHexagonTLBContext)); + } else { + CPUState *cpu0_s = NULL; + CPUHexagonState *env0 = NULL; + CPU_FOREACH(cpu0_s) { + assert(cpu0_s->cpu_index == 0); + env0 = &(HEXAGON_CPU(cpu0_s)->env); + break; + } + env->hex_tlb = env0->hex_tlb; + } +} + +void hex_mmu_on(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + qemu_log_mask(CPU_LOG_MMU, "Hexagon MMU turned on!\n"); + tlb_flush(cs); + +} + +void hex_mmu_off(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + qemu_log_mask(CPU_LOG_MMU, "Hexagon MMU turned off!\n"); + tlb_flush(cs); +} + +void hex_mmu_mode_change(CPUHexagonState *env) +{ + qemu_log_mask(CPU_LOG_MMU, "Hexagon mode change!\n"); + CPUState *cs = env_cpu(env); + tlb_flush(cs); +} + +static inline bool hex_tlb_entry_match_noperm(uint64_t entry, uint32_t asid, + target_ulong VA) +{ + if (GET_TLB_FIELD(entry, PTE_V)) { + if (GET_TLB_FIELD(entry, PTE_G)) { + /* Global entry - ingnore ASID */ + } else if (asid != NO_ASID) { + uint32_t tlb_asid = GET_TLB_FIELD(entry, PTE_ASID); + if (tlb_asid != asid) { + return false; + } + } + + uint64_t page_size = hex_tlb_page_size(entry); + uint64_t page_start = hex_tlb_virt_addr(entry); + page_start &= ~(page_size - 1); + if (page_start <= VA && VA < page_start + page_size) { + /* FIXME - Anything else we need to check? */ + return true; + } + } + return false; +} + +static inline void hex_tlb_entry_get_perm(CPUHexagonState *env, uint64_t entry, + MMUAccessType access_type, + int mmu_idx, int *prot, + int32_t *excp) +{ + g_assert_not_reached(); +} + +static inline bool hex_tlb_entry_match(CPUHexagonState *env, uint64_t entry, + uint8_t asid, target_ulong VA, + MMUAccessType access_type, hwaddr *PA, + int *prot, int *size, int32_t *excp, + int mmu_idx) +{ + if (hex_tlb_entry_match_noperm(entry, asid, VA)) { + hex_tlb_entry_get_perm(env, entry, access_type, mmu_idx, prot, excp); + *PA = hex_tlb_phys_addr(entry); + *size = hex_tlb_page_size(entry); + return true; + } + return false; +} + +bool hex_tlb_find_match(CPUHexagonState *env, target_ulong VA, + MMUAccessType access_type, hwaddr *PA, int *prot, + int *size, int32_t *excp, int mmu_idx) +{ + *PA = 0; + *prot = 0; + *size = 0; + *excp = 0; + uint32_t ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + uint8_t asid = GET_SSR_FIELD(SSR_ASID, ssr); + int i; + HexagonCPU *cpu = env_archcpu(env); + for (i = 0; i < cpu->num_tlbs; i++) { + uint64_t entry = env->hex_tlb->entries[i]; + if (hex_tlb_entry_match(env, entry, asid, VA, access_type, PA, prot, + size, excp, mmu_idx)) { + return true; + } + } + return false; +} + +static uint32_t hex_tlb_lookup_by_asid(CPUHexagonState *env, uint32_t asid, + uint32_t VA) +{ + g_assert_not_reached(); +} + +/* Called from tlbp instruction */ +uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA) +{ + return hex_tlb_lookup_by_asid(env, GET_SSR_FIELD(SSR_ASID, ssr), VA); +} + +static bool hex_tlb_is_match(CPUHexagonState *env, + uint64_t entry1, uint64_t entry2, + bool consider_gbit) +{ + bool valid1 = GET_TLB_FIELD(entry1, PTE_V); + bool valid2 = GET_TLB_FIELD(entry2, PTE_V); + uint64_t size1 = hex_tlb_page_size(entry1); + uint64_t vaddr1 = hex_tlb_virt_addr(entry1); + vaddr1 &= ~(size1 - 1); + uint64_t size2 = hex_tlb_page_size(entry2); + uint64_t vaddr2 = hex_tlb_virt_addr(entry2); + vaddr2 &= ~(size2 - 1); + int asid1 = GET_TLB_FIELD(entry1, PTE_ASID); + int asid2 = GET_TLB_FIELD(entry2, PTE_ASID); + bool gbit1 = GET_TLB_FIELD(entry1, PTE_G); + bool gbit2 = GET_TLB_FIELD(entry2, PTE_G); + + if (!valid1 || !valid2) { + return false; + } + + if (((vaddr1 <= vaddr2) && (vaddr2 < (vaddr1 + size1))) || + ((vaddr2 <= vaddr1) && (vaddr1 < (vaddr2 + size2)))) { + if (asid1 == asid2) { + return true; + } + if ((consider_gbit && gbit1) || gbit2) { + return true; + } + } + return false; +} + +/* + * Return codes: + * 0 or positive index of match + * -1 multiple matches + * -2 no match + */ +int hex_tlb_check_overlap(CPUHexagonState *env, uint64_t entry, uint64_t index) +{ + int matches = 0; + int last_match = 0; + int i; + + HexagonCPU *cpu = env_archcpu(env); + for (i = 0; i < cpu->num_tlbs; i++) { + if (hex_tlb_is_match(env, entry, env->hex_tlb->entries[i], false)) { + matches++; + last_match = i; + } + } + + if (matches == 1) { + return last_match; + } + if (matches == 0) { + return -2; + } + return -1; +} + +static inline void print_thread(const char *str, CPUState *cs) +{ + g_assert(bql_locked()); + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *thread = &cpu->env; + bool is_stopped = cpu_is_stopped(cs); + int exe_mode = get_exe_mode(thread); + hex_lock_state_t lock_state = thread->tlb_lock_state; + qemu_log_mask(CPU_LOG_MMU, + "%s: threadId = %d: %s, exe_mode = %s, tlb_lock_state = %s\n", + str, + thread->threadId, + is_stopped ? "stopped" : "running", + exe_mode == HEX_EXE_MODE_OFF ? "off" : + exe_mode == HEX_EXE_MODE_RUN ? "run" : + exe_mode == HEX_EXE_MODE_WAIT ? "wait" : + exe_mode == HEX_EXE_MODE_DEBUG ? "debug" : + "unknown", + lock_state == HEX_LOCK_UNLOCKED ? "unlocked" : + lock_state == HEX_LOCK_WAITING ? "waiting" : + lock_state == HEX_LOCK_OWNER ? "owner" : + "unknown"); +} + +static inline void print_thread_states(const char *str) +{ + CPUState *cs; + CPU_FOREACH(cs) { + print_thread(str, cs); + } +} + +/* + * A tlb_lock is taken with either a tlbfault or an explicit + * tlblock insn. The insn tlblock only advances the PC + * after the lock is acquired, similar to k0lock. + */ +void hex_tlb_lock(CPUHexagonState *env) +{ + qemu_log_mask(CPU_LOG_MMU, "hex_tlb_lock: %d\n", env->threadId); + BQL_LOCK_GUARD(); + g_assert((env->tlb_lock_count == 0) || (env->tlb_lock_count == 1)); + + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + uint8_t tlb_lock = GET_SYSCFG_FIELD(SYSCFG_TLBLOCK, syscfg); + if (tlb_lock) { + if (env->tlb_lock_state == HEX_LOCK_QUEUED) { + env->next_PC += 4; + env->tlb_lock_count++; + env->tlb_lock_state = HEX_LOCK_OWNER; + SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1); + return; + } + if (env->tlb_lock_state == HEX_LOCK_OWNER) { + qemu_log_mask(CPU_LOG_MMU | LOG_GUEST_ERROR, + "Double tlblock at PC: 0x%x, thread may hang\n", + env->next_PC); + env->next_PC += 4; + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + return; + } + env->tlb_lock_state = HEX_LOCK_WAITING; + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + } else { + env->next_PC += 4; + env->tlb_lock_count++; + env->tlb_lock_state = HEX_LOCK_OWNER; + SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1); + } + + if (qemu_loglevel_mask(CPU_LOG_MMU)) { + qemu_log_mask(CPU_LOG_MMU, "Threads after hex_tlb_lock:\n"); + print_thread_states("\tThread"); + } +} + +void hex_tlb_unlock(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + g_assert((env->tlb_lock_count == 0) || (env->tlb_lock_count == 1)); + + /* Nothing to do if the TLB isn't locked by this thread */ + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + uint8_t tlb_lock = GET_SYSCFG_FIELD(SYSCFG_TLBLOCK, syscfg); + if ((tlb_lock == 0) || + (env->tlb_lock_state != HEX_LOCK_OWNER)) { + qemu_log_mask(LOG_GUEST_ERROR, + "thread %d attempted to tlbunlock without having the " + "lock, tlb_lock state = %d\n", + env->threadId, env->tlb_lock_state); + g_assert(env->tlb_lock_state != HEX_LOCK_WAITING); + return; + } + + env->tlb_lock_count--; + env->tlb_lock_state = HEX_LOCK_UNLOCKED; + SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 0); + + /* Look for a thread to unlock */ + unsigned int this_threadId = env->threadId; + CPUHexagonState *unlock_thread = NULL; + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *thread = &cpu->env; + + /* + * The hardware implements round-robin fairness, so we look for threads + * starting at env->threadId + 1 and incrementing modulo the number of + * threads. + * + * To implement this, we check if thread is a earlier in the modulo + * sequence than unlock_thread. + * if unlock thread is higher than this thread + * thread must be between this thread and unlock_thread + * else + * thread higher than this thread is ahead of unlock_thread + * thread must be lower then unlock thread + */ + if (thread->tlb_lock_state == HEX_LOCK_WAITING) { + if (!unlock_thread) { + unlock_thread = thread; + } else if (unlock_thread->threadId > this_threadId) { + if (this_threadId < thread->threadId && + thread->threadId < unlock_thread->threadId) { + unlock_thread = thread; + } + } else { + if (thread->threadId > this_threadId) { + unlock_thread = thread; + } + if (thread->threadId < unlock_thread->threadId) { + unlock_thread = thread; + } + } + } + } + if (unlock_thread) { + cs = env_cpu(unlock_thread); + print_thread("\tWaiting thread found", cs); + unlock_thread->tlb_lock_state = HEX_LOCK_QUEUED; + SET_SYSCFG_FIELD(unlock_thread, SYSCFG_TLBLOCK, 1); + cpu_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK); + } + + if (qemu_loglevel_mask(CPU_LOG_MMU)) { + qemu_log_mask(CPU_LOG_MMU, "Threads after hex_tlb_unlock:\n"); + print_thread_states("\tThread"); + } + +} + diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h new file mode 100644 index 000000000000..7c9598281af2 --- /dev/null +++ b/target/hexagon/hex_mmu.h @@ -0,0 +1,30 @@ +/* + * Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HEXAGON_MMU_H +#define HEXAGON_MMU_H + +#include "max.h" + +struct CPUHexagonTLBContext { + uint64_t entries[MAX_TLB_ENTRIES]; +}; + +extern void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value); +extern uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA); +extern void hex_mmu_realize(CPUHexagonState *env); +extern void hex_mmu_on(CPUHexagonState *env); +extern void hex_mmu_off(CPUHexagonState *env); +extern void hex_mmu_mode_change(CPUHexagonState *env); +extern bool hex_tlb_find_match(CPUHexagonState *env, target_ulong VA, + MMUAccessType access_type, hwaddr *PA, int *prot, + int *size, int32_t *excp, int mmu_idx); +extern int hex_tlb_check_overlap(CPUHexagonState *env, uint64_t entry, + uint64_t index); +extern void hex_tlb_lock(CPUHexagonState *env); +extern void hex_tlb_unlock(CPUHexagonState *env); +void dump_mmu(CPUHexagonState *env); +#endif diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index cd768f19ef0c..3458d7994a43 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -40,4 +40,7 @@ void G_NORETURN do_raise_exception(CPUHexagonState *env, target_ulong PC, uintptr_t retaddr); +#define hexagon_cpu_mmu_enabled(env) \ + GET_SYSCFG_FIELD(SYSCFG_MMUEN, ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG)) + #endif diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c index f60e257223da..c576de02f038 100644 --- a/target/hexagon/machine.c +++ b/target/hexagon/machine.c @@ -7,6 +7,33 @@ #include "qemu/osdep.h" #include "migration/cpu.h" #include "cpu.h" +#include "hex_mmu.h" + +static int get_hex_tlb_ptr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + CPUHexagonTLBContext *tlb = pv; + for (int i = 0; i < ARRAY_SIZE(tlb->entries); i++) { + tlb->entries[i] = qemu_get_be64(f); + } + return 0; +} + +static int put_hex_tlb_ptr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, JSONWriter *vmdesc) +{ + CPUHexagonTLBContext *tlb = pv; + for (int i = 0; i < ARRAY_SIZE(tlb->entries); i++) { + qemu_put_be64(f, tlb->entries[i]); + } + return 0; +} + +const VMStateInfo vmstate_info_hex_tlb_ptr = { + .name = "hex_tlb_pointer", + .get = get_hex_tlb_ptr, + .put = put_hex_tlb_ptr, +}; const VMStateDescription vmstate_hexagon_cpu = { @@ -29,6 +56,9 @@ const VMStateDescription vmstate_hexagon_cpu = { VMSTATE_UINTTL(env.threadId, HexagonCPU), VMSTATE_UINTTL(env.cause_code, HexagonCPU), VMSTATE_UINTTL(env.wait_next_pc, HexagonCPU), + VMSTATE_POINTER(env.hex_tlb, HexagonCPU, 0, + vmstate_info_hex_tlb_ptr, CPUHexagonTLBContext *), + VMSTATE_END_OF_LIST() }, }; diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 3ec53010fa02..aa729a3683f1 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -273,7 +273,8 @@ hexagon_ss.add(files( # idef-generated-enabled-instructions # idef_parser_enabled = get_option('hexagon_idef_parser') -if idef_parser_enabled and 'hexagon-linux-user' in target_dirs +if idef_parser_enabled and ('hexagon-linux-user' in target_dirs or + 'hexagon-softmmu' in target_dirs) idef_parser_input_generated = custom_target( 'idef_parser_input.h.inc', output: 'idef_parser_input.h.inc', diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 71c137be308f..9119e42ff77f 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -944,7 +944,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, HexagonCPU *hex_cpu = env_archcpu(cpu_env(cs)); uint32_t hex_flags = dcbase->tb->flags; - ctx->mem_idx = MMU_USER_IDX; + ctx->mem_idx = FIELD_EX32(hex_flags, TB_FLAGS, MMU_INDEX); ctx->num_packets = 0; ctx->num_insns = 0; ctx->num_hvx_insns = 0; From dbf9147b8427849fee3f6513a23d1a2dd81be0b8 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 14:23:29 -0700 Subject: [PATCH 047/109] target/hexagon: Add IRQ events Signed-off-by: Brian Cain --- target/hexagon/cpu_bits.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 5d26815eb9bc..b559a7ba8809 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -26,6 +26,28 @@ enum hex_event { HEX_EVENT_NONE = -1, HEX_EVENT_TRAP0 = 0x008, + HEX_EVENT_FETCH_NO_UPAGE = 0x012, + HEX_EVENT_INVALID_PACKET = 0x015, + HEX_EVENT_INVALID_OPCODE = 0x015, + HEX_EVENT_PC_NOT_ALIGNED = 0x01e, + HEX_EVENT_PRIV_NO_UREAD = 0x024, + HEX_EVENT_PRIV_NO_UWRITE = 0x025, + HEX_EVENT_INT0 = 0x10, + HEX_EVENT_INT1 = 0x11, + HEX_EVENT_INT2 = 0x12, + HEX_EVENT_INT3 = 0x13, + HEX_EVENT_INT4 = 0x14, + HEX_EVENT_INT5 = 0x15, + HEX_EVENT_INT6 = 0x16, + HEX_EVENT_INT7 = 0x17, + HEX_EVENT_INT8 = 0x18, + HEX_EVENT_INT9 = 0x19, + HEX_EVENT_INTA = 0x1a, + HEX_EVENT_INTB = 0x1b, + HEX_EVENT_INTC = 0x1c, + HEX_EVENT_INTD = 0x1d, + HEX_EVENT_INTE = 0x1e, + HEX_EVENT_INTF = 0x1f, }; enum hex_cause { @@ -39,6 +61,18 @@ enum hex_cause { HEX_CAUSE_PRIV_NO_UWRITE = 0x025, HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a, HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b, + HEX_CAUSE_INT0 = 0x0c0, + HEX_CAUSE_INT1 = 0x0c1, + HEX_CAUSE_INT2 = 0x0c2, + HEX_CAUSE_INT3 = 0x0c3, + HEX_CAUSE_INT4 = 0x0c4, + HEX_CAUSE_INT5 = 0x0c5, + HEX_CAUSE_INT6 = 0x0c6, + HEX_CAUSE_INT7 = 0x0c7, + HEX_CAUSE_VIC0 = 0x0c2, + HEX_CAUSE_VIC1 = 0x0c3, + HEX_CAUSE_VIC2 = 0x0c4, + HEX_CAUSE_VIC3 = 0x0c5, }; enum data_cache_state { From 29c5a169cd2372422c8bd1e4f09281847c3afeec Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 14:23:48 -0700 Subject: [PATCH 048/109] target/hexagon: Add clear_wait_mode() definition Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 10 ++++++++++ target/hexagon/cpu_helper.h | 1 + 2 files changed, 11 insertions(+) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 32051dfea394..dde7ec110fe0 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -74,6 +74,16 @@ void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old) g_assert_not_reached(); } +void clear_wait_mode(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl); + thread_wait_mask &= ~(0x1 << env->threadId); + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask); +} + int get_exe_mode(CPUHexagonState *env) { g_assert_not_reached(); diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 7d851f3c5029..c39e995a3dc8 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -16,6 +16,7 @@ void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t); void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old); int get_exe_mode(CPUHexagonState *env); +void clear_wait_mode(CPUHexagonState *env); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) From 9dcba113dad0ab7e07c66ecc7ed079794b390731 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 14:24:13 -0700 Subject: [PATCH 049/109] target/hexagon: Define f{S,G}ET_FIELD macros Signed-off-by: Brian Cain --- target/hexagon/macros.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index b0e9610d98d5..afbbe8e26524 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -649,6 +649,16 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) reg_field_info[FIELD].width, \ reg_field_info[FIELD].offset) +#define fGET_FIELD(VAL, FIELD) \ + fEXTRACTU_BITS(VAL, \ + reg_field_info[FIELD].width, \ + reg_field_info[FIELD].offset) +#define fSET_FIELD(VAL, FIELD, NEWVAL) \ + fINSERT_BITS(VAL, \ + reg_field_info[FIELD].width, \ + reg_field_info[FIELD].offset, \ + (NEWVAL)) + #ifdef QEMU_GENERATE #define fDCZEROA(REG) \ do { \ From edf745f8c13a3dcbaa410fa3ed88fe3b0f2569b4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 14:25:26 -0700 Subject: [PATCH 050/109] target/hexagon: Add hex_interrupts support Co-authored-by: Taylor Simpson Co-authored-by: Sid Manning Co-authored-by: Michael Lambert Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 2 + target/hexagon/cpu.h | 1 + target/hexagon/hex_interrupts.c | 328 ++++++++++++++++++++++++++++++++ target/hexagon/hex_interrupts.h | 15 ++ 4 files changed, 346 insertions(+) create mode 100644 target/hexagon/hex_interrupts.c create mode 100644 target/hexagon/hex_interrupts.h diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 9b785606c626..aace243a0a19 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -59,6 +59,8 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model) static const Property hexagon_cpu_properties[] = { #if !defined(CONFIG_USER_ONLY) DEFINE_PROP_UINT32("num-tlbs", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES), + DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr, + 0xffffffffULL), #endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index d4603b6e0067..20b266cc0a8d 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -179,6 +179,7 @@ struct ArchCPU { bool short_circuit; #ifndef CONFIG_USER_ONLY uint32_t num_tlbs; + uint32_t l2vic_base_addr; #endif }; diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/hex_interrupts.c new file mode 100644 index 000000000000..86ed06c90690 --- /dev/null +++ b/target/hexagon/hex_interrupts.c @@ -0,0 +1,328 @@ +/* + * Copyright(c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "hex_interrupts.h" +#include "macros.h" +#include "sys_macros.h" +#include "system/cpus.h" +#include "cpu_helper.h" + +static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num); + +static bool get_syscfg_gie(CPUHexagonState *env) +{ + target_ulong syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + return GET_SYSCFG_FIELD(SYSCFG_GIE, syscfg); +} + +static bool get_ssr_ex(CPUHexagonState *env) +{ + target_ulong ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + return GET_SSR_FIELD(SSR_EX, ssr); +} + +static bool get_ssr_ie(CPUHexagonState *env) +{ + target_ulong ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + return GET_SSR_FIELD(SSR_IE, ssr); +} + +/* Do these together so we only have to call hexagon_modify_ssr once */ +static void set_ssr_ex_cause(CPUHexagonState *env, int ex, uint32_t cause) +{ + target_ulong old = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, ex); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause); + target_ulong new = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + hexagon_modify_ssr(env, new, old); +} + +static bool get_iad_bit(CPUHexagonState *env, int int_num) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong iad = GET_FIELD(IPENDAD_IAD, ipendad); + return extract32(iad, int_num, 1); +} + +static void set_iad_bit(CPUHexagonState *env, int int_num, int val) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong iad = GET_FIELD(IPENDAD_IAD, ipendad); + iad = deposit32(iad, int_num, 1, val); + fSET_FIELD(ipendad, IPENDAD_IAD, iad); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); +} + +static uint32_t get_ipend(CPUHexagonState *env) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + return GET_FIELD(IPENDAD_IPEND, ipendad); +} + +static inline bool get_ipend_bit(CPUHexagonState *env, int int_num) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad); + return extract32(ipend, int_num, 1); +} + +static void clear_ipend(CPUHexagonState *env, uint32_t mask) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad); + ipend &= ~mask; + fSET_FIELD(ipendad, IPENDAD_IPEND, ipend); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); +} + +static void set_ipend(CPUHexagonState *env, uint32_t mask) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad); + ipend |= mask; + fSET_FIELD(ipendad, IPENDAD_IPEND, ipend); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); +} + +static void set_ipend_bit(CPUHexagonState *env, int int_num, int val) +{ + target_ulong ipendad = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IPENDAD); + target_ulong ipend = GET_FIELD(IPENDAD_IPEND, ipendad); + ipend = deposit32(ipend, int_num, 1, val); + fSET_FIELD(ipendad, IPENDAD_IPEND, ipend); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); +} + +static bool get_imask_bit(CPUHexagonState *env, int int_num) +{ + target_ulong imask = ARCH_GET_SYSTEM_REG(env, HEX_SREG_IMASK); + return extract32(imask, int_num, 1); +} + +static uint32_t get_prio(CPUHexagonState *env) +{ + target_ulong stid = ARCH_GET_SYSTEM_REG(env, HEX_SREG_STID); + return extract32(stid, reg_field_info[STID_PRIO].offset, + reg_field_info[STID_PRIO].width); +} + +static void set_elr(CPUHexagonState *env, target_ulong val) +{ + ARCH_SET_SYSTEM_REG(env, HEX_SREG_ELR, val); +} + +static bool get_schedcfgen(CPUHexagonState *env) +{ + target_ulong schedcfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SCHEDCFG); + return extract32(schedcfg, reg_field_info[SCHEDCFG_EN].offset, + reg_field_info[SCHEDCFG_EN].width); +} + +static bool is_lowest_prio(CPUHexagonState *env, int int_num) +{ + uint32_t my_prio = get_prio(env); + CPUState *cs; + + CPU_FOREACH(cs) { + HexagonCPU *hex_cpu = HEXAGON_CPU(cs); + CPUHexagonState *hex_env = &hex_cpu->env; + if (!hex_is_qualified_for_int(hex_env, int_num)) { + continue; + } + + /* Note that lower values indicate *higher* priority */ + if (my_prio < get_prio(hex_env)) { + return false; + } + } + return true; +} + +static bool hex_is_qualified_for_int(CPUHexagonState *env, int int_num) +{ + bool syscfg_gie = get_syscfg_gie(env); + bool iad = get_iad_bit(env, int_num); + bool ssr_ie = get_ssr_ie(env); + bool ssr_ex = get_ssr_ex(env); + bool imask = get_imask_bit(env, int_num); + + return syscfg_gie && !iad && ssr_ie && !ssr_ex && !imask; +} + +static void clear_pending_locks(CPUHexagonState *env) +{ + g_assert(bql_locked()); + if (env->k0_lock_state == HEX_LOCK_WAITING) { + env->k0_lock_state = HEX_LOCK_UNLOCKED; + } + if (env->tlb_lock_state == HEX_LOCK_WAITING) { + env->tlb_lock_state = HEX_LOCK_UNLOCKED; + } +} + +static bool should_not_exec(CPUHexagonState *env) +{ + return (get_exe_mode(env) == HEX_EXE_MODE_WAIT); +} + +static void restore_state(CPUHexagonState *env, bool int_accepted) +{ + CPUState *cs = env_cpu(env); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI); + if (!int_accepted && should_not_exec(env)) { + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + } +} + +static void hex_accept_int(CPUHexagonState *env, int int_num) +{ + CPUState *cs = env_cpu(env); + target_ulong evb = ARCH_GET_SYSTEM_REG(env, HEX_SREG_EVB); + const int exe_mode = get_exe_mode(env); + const bool in_wait_mode = exe_mode == HEX_EXE_MODE_WAIT; + + set_ipend_bit(env, int_num, 0); + set_iad_bit(env, int_num, 1); + set_ssr_ex_cause(env, 1, HEX_CAUSE_INT0 | int_num); + cs->exception_index = HEX_EVENT_INT0 + int_num; + env->cause_code = HEX_EVENT_INT0 + int_num; + clear_pending_locks(env); + if (in_wait_mode) { + qemu_log_mask(CPU_LOG_INT, + "%s: thread %d resuming, exiting WAIT mode\n", + __func__, env->threadId); + set_elr(env, env->wait_next_pc); + clear_wait_mode(env); + cs->halted = false; + } else if (env->k0_lock_state == HEX_LOCK_WAITING) { + g_assert_not_reached(); + } else { + set_elr(env, env->gpr[HEX_REG_PC]); + } + env->gpr[HEX_REG_PC] = evb | (cs->exception_index << 2); + if (get_ipend(env) == 0) { + restore_state(env, true); + } +} + + +bool hex_check_interrupts(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + bool int_handled = false; + bool ssr_ex = get_ssr_ex(env); + int max_ints; + bool schedcfgen; + + /* Early exit if nothing pending */ + if (get_ipend(env) == 0) { + restore_state(env, false); + return false; + } + + max_ints = reg_field_info[IPENDAD_IPEND].width; + BQL_LOCK_GUARD(); + /* Only check priorities when schedcfgen is set */ + schedcfgen = get_schedcfgen(env); + for (int i = 0; i < max_ints; i++) { + if (!get_iad_bit(env, i) && get_ipend_bit(env, i)) { + qemu_log_mask(CPU_LOG_INT, + "%s: thread[%d] pc = 0x%x found int %d\n", __func__, + env->threadId, env->gpr[HEX_REG_PC], i); + if (hex_is_qualified_for_int(env, i) && + (!schedcfgen || is_lowest_prio(env, i))) { + qemu_log_mask(CPU_LOG_INT, "%s: thread[%d] int %d handled_\n", + __func__, env->threadId, i); + hex_accept_int(env, i); + int_handled = true; + break; + } + bool syscfg_gie = get_syscfg_gie(env); + bool iad = get_iad_bit(env, i); + bool ssr_ie = get_ssr_ie(env); + bool imask = get_imask_bit(env, i); + + qemu_log_mask(CPU_LOG_INT, + "%s: thread[%d] int %d not handled, qualified: %d, " + "schedcfg_en: %d, low prio %d\n", + __func__, env->threadId, i, + hex_is_qualified_for_int(env, i), schedcfgen, + is_lowest_prio(env, i)); + + qemu_log_mask(CPU_LOG_INT, + "%s: thread[%d] int %d not handled, GIE %d, iad %d, " + "SSR:IE %d, SSR:EX: %d, imask bit %d\n", + __func__, env->threadId, i, syscfg_gie, iad, ssr_ie, + ssr_ex, imask); + } + } + + /* + * If we didn't handle the interrupt and it wasn't + * because we were in EX state, then we won't be able + * to execute the interrupt on this CPU unless something + * changes in the CPU state. Clear the interrupt_request bits + * while preserving the IPEND bits, and we can re-assert the + * interrupt_request bit(s) when we execute one of those instructions. + */ + if (!int_handled && !ssr_ex) { + restore_state(env, int_handled); + } else if (int_handled) { + assert(!cs->halted); + } + + return int_handled; +} + +void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type) +{ + if (mask == 0) { + return; + } + + /* + * Notify all CPUs that the interrupt has happened + */ + BQL_LOCK_GUARD(); + clear_ipend(env, mask); + hex_interrupt_update(env); +} + +void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type) +{ + g_assert(bql_locked()); + if (mask == 0) { + return; + } + + /* + * Notify all CPUs that the interrupt has happened + */ + set_ipend(env, mask); + hex_interrupt_update(env); +} + +void hex_interrupt_update(CPUHexagonState *env) +{ + CPUState *cs; + + g_assert(bql_locked()); + if (get_ipend(env) != 0) { + CPU_FOREACH(cs) { + HexagonCPU *hex_cpu = HEXAGON_CPU(cs); + CPUHexagonState *hex_env = &hex_cpu->env; + const int exe_mode = get_exe_mode(hex_env); + if (exe_mode != HEX_EXE_MODE_OFF) { + cs->interrupt_request |= CPU_INTERRUPT_SWI; + cpu_resume(cs); + } + } + } +} diff --git a/target/hexagon/hex_interrupts.h b/target/hexagon/hex_interrupts.h new file mode 100644 index 000000000000..7b4e99dcd30f --- /dev/null +++ b/target/hexagon/hex_interrupts.h @@ -0,0 +1,15 @@ +/* + * Copyright(c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HEX_INTERRUPTS_H +#define HEX_INTERRUPTS_H + +bool hex_check_interrupts(CPUHexagonState *env); +void hex_clear_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type); +void hex_raise_interrupts(CPUHexagonState *env, uint32_t mask, uint32_t type); +void hex_interrupt_update(CPUHexagonState *env); + +#endif From ea7ac92e7b4222e89826f9f70ca1d20250c5920f Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Tue, 7 Nov 2023 19:44:05 -0800 Subject: [PATCH 051/109] hw/intc: Add l2vic interrupt controller Co-authored-by: Matheus Tavares Bernardino Co-authored-by: Damien Hedde Signed-off-by: Brian Cain --- MAINTAINERS | 2 + docs/devel/hexagon-l2vic.rst | 59 +++++ docs/devel/index-internals.rst | 1 + hw/intc/Kconfig | 3 + hw/intc/l2vic.c | 417 +++++++++++++++++++++++++++++++++ hw/intc/l2vic.h | 37 +++ hw/intc/meson.build | 2 + hw/intc/trace-events | 4 + 8 files changed, 525 insertions(+) create mode 100644 docs/devel/hexagon-l2vic.rst create mode 100644 hw/intc/l2vic.c create mode 100644 hw/intc/l2vic.h diff --git a/MAINTAINERS b/MAINTAINERS index 4d1ffb4ba93f..d0a744c8f6c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -229,6 +229,7 @@ Hexagon TCG CPUs M: Brian Cain S: Supported F: target/hexagon/ +F: hw/intc/l2vic.[ch] X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ @@ -240,6 +241,7 @@ F: gdb-xml/hexagon*.xml F: docs/system/target-hexagon.rst F: docs/devel/hexagon-sys.rst F: docs/devel/hexagon-vm.rst +F: docs/devel/hexagon-l2vic.rst T: git https://github.com/quic/qemu.git hex-next Hexagon idef-parser diff --git a/docs/devel/hexagon-l2vic.rst b/docs/devel/hexagon-l2vic.rst new file mode 100644 index 000000000000..088563627445 --- /dev/null +++ b/docs/devel/hexagon-l2vic.rst @@ -0,0 +1,59 @@ +Hexagon L2 Vectored Interrupt Controller +======================================== + + +.. code-block:: none + + +-------+ + | | +----------------+ + | l2vic | | hexagon core | + | | | | + | +-----| | | + ------> |VID0 >------------->irq2 -\ | + ------> | | | | | + ... > | | | | | + ------> | | | | + | +-----| | / | | \ | + | ... | | | | | | | + | +-----| | t0 t1 t2 t3 ...| + ------> |VIDN | | | + ------> | | | | + ------> | | | | + ------> | | | | + | +-----| | | + | | |Global SREG File| + | State | | | + | [ ]|<============|=>[VID ] | + | [ ]|<============|=>[VID1] | + | [ ]| | | + | [ ]| | | + | | | | + +-------+ +----------------+ + +L2VIC/Core Integration +---------------------- + +* hexagon core supports 8 external interrupt sources +* l2vic supports 1024 input interrupts mapped among 4 output interrupts +* l2vic has four output signals: { VID0, VID1, VID2, VID3 } +* l2vic device has a bank of registers per-VID that can be used to query + the status or assert new interrupts. +* Interrupts are 'steered' to threads based on { thread priority, 'EX' state, + thread interrupt mask, thread interrupt enable, global interrupt enable, + etc. }. +* Any hardware thread could conceivably handle any input interrupt, dependent + on state. +* The system register transfer instruction can read the VID0-VID3 values from + the l2vic when reading from hexagon core system registers "VID" and "VID1". +* When l2vic VID0 has multiple active interrupts, it pulses the VID0 output + IRQ and stores the IRQ number for the VID0 register field. Only after this + interrupt is cleared can the l2vic pulse the VID0 output IRQ again and provide + the next interrupt number on the VID0 register. +* The ``ciad`` instruction clears the l2vic input interrupt and un-disables the + core interrupt. If some/an l2vic VID0 interrupt is pending when this occurs, + the next interrupt should fire and any subseqeunt reads of the VID register + should reflect the newly raised interrupt. +* In QEMU, on an external interrupt or an unmasked-pending interrupt, + all vCPUs are triggered (has_work==true) and each will grab the IO lock + while considering the steering logic to determine whether they're the thread + that must handle the interrupt. diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index 01db83c93f11..0f4286688f52 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -14,6 +14,7 @@ Details about QEMU's various subsystems including how to add features to them. ebpf_rss hexagon-sys hexagon-vm + hexagon-l2vic migration/index multi-process reset diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index dd405bdb5d21..471e02df27cf 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -8,6 +8,9 @@ config I8259 config PL190 bool +config L2VIC + bool + config IOAPIC bool select I8259 diff --git a/hw/intc/l2vic.c b/hw/intc/l2vic.c new file mode 100644 index 000000000000..7926ae5d8fa9 --- /dev/null +++ b/hw/intc/l2vic.c @@ -0,0 +1,417 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Arm PrimeCell PL190 Vector Interrupt Controller was used as a reference. + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "l2vic.h" +#include "trace.h" + +#define L2VICA(s, n) (s[(n) >> 2]) + +#define TYPE_L2VIC "l2vic" +#define L2VIC(obj) OBJECT_CHECK(L2VICState, (obj), TYPE_L2VIC) + +#define SLICE_MAX (L2VIC_INTERRUPT_MAX / 32) + +typedef struct L2VICState { + SysBusDevice parent_obj; + + QemuMutex active; + MemoryRegion iomem; + MemoryRegion fast_iomem; + uint32_t level; + /* + * offset 0:vid group 0 etc, 10 bits in each group + * are used: + */ + uint32_t vid_group[4]; + uint32_t vid0; + /* Clear Status of Active Edge interrupt, not used: */ + uint32_t int_clear[SLICE_MAX] QEMU_ALIGNED(16); + /* Enable interrupt source */ + uint32_t int_enable[SLICE_MAX] QEMU_ALIGNED(16); + /* Clear (set to 0) corresponding bit in int_enable */ + uint32_t int_enable_clear; + /* Set (to 1) corresponding bit in int_enable */ + uint32_t int_enable_set; + /* Present for debugging, not used */ + uint32_t int_pending[SLICE_MAX] QEMU_ALIGNED(16); + /* Generate an interrupt */ + uint32_t int_soft; + /* Which enabled interrupt is active */ + uint32_t int_status[SLICE_MAX] QEMU_ALIGNED(16); + /* Edge or Level interrupt */ + uint32_t int_type[SLICE_MAX] QEMU_ALIGNED(16); + /* L2 interrupt group 0-3 0x600-0x7FF */ + uint32_t int_group_n0[SLICE_MAX] QEMU_ALIGNED(16); + uint32_t int_group_n1[SLICE_MAX] QEMU_ALIGNED(16); + uint32_t int_group_n2[SLICE_MAX] QEMU_ALIGNED(16); + uint32_t int_group_n3[SLICE_MAX] QEMU_ALIGNED(16); + qemu_irq irq[8]; +} L2VICState; + + +/* + * Find out if this irq is associated with a group other than + * the default group + */ +static uint32_t *get_int_group(L2VICState *s, int irq) +{ + int n = irq & 0x1f; + if (n < 8) { + return s->int_group_n0; + } + if (n < 16) { + return s->int_group_n1; + } + if (n < 24) { + return s->int_group_n2; + } + return s->int_group_n3; +} + +static int find_slice(int irq) +{ + return irq / 32; +} + +static int get_vid(L2VICState *s, int irq) +{ + uint32_t *group = get_int_group(s, irq); + uint32_t slice = group[find_slice(irq)]; + /* Mask with 0x7 to remove the GRP:EN bit */ + uint32_t val = slice >> ((irq & 0x7) * 4); + if (val & 0x8) { + return val & 0x7; + } else { + return 0; + } +} + +static inline bool vid_active(L2VICState *s) + +{ + /* scan all 1024 bits in int_status arrary */ + const int size = sizeof(s->int_status) * CHAR_BIT; + const int active_irq = find_first_bit((unsigned long *)s->int_status, size); + return ((active_irq != size)) ? true : false; +} + +static bool l2vic_update(L2VICState *s, int irq) +{ + if (vid_active(s)) { + return true; + } + + bool pending = test_bit(irq, (unsigned long *)s->int_pending); + bool enable = test_bit(irq, (unsigned long *)s->int_enable); + if (pending && enable) { + int vid = get_vid(s, irq); + set_bit(irq, (unsigned long *)s->int_status); + clear_bit(irq, (unsigned long *)s->int_pending); + clear_bit(irq, (unsigned long *)s->int_enable); + /* ensure the irq line goes low after going high */ + s->vid0 = irq; + s->vid_group[get_vid(s, irq)] = irq; + + /* already low: now call pulse */ + /* pulse: calls qemu_upper() and then qemu_lower()) */ + qemu_irq_pulse(s->irq[vid + 2]); + trace_l2vic_delivered(irq, vid); + return true; + } + return false; +} + +static void l2vic_update_all(L2VICState *s) +{ + for (int i = 0; i < L2VIC_INTERRUPT_MAX; i++) { + if (l2vic_update(s, i) == true) { + /* once vid is active, no-one else can set it until ciad */ + return; + } + } +} + +static void l2vic_set_irq(void *opaque, int irq, int level) +{ + L2VICState *s = (L2VICState *)opaque; + if (level) { + qemu_mutex_lock(&s->active); + set_bit(irq, (unsigned long *)s->int_pending); + qemu_mutex_unlock(&s->active); + } + l2vic_update(s, irq); +} + +static void l2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + L2VICState *s = (L2VICState *)opaque; + qemu_mutex_lock(&s->active); + trace_l2vic_reg_write((unsigned)offset, (uint32_t)val); + + if (offset == L2VIC_VID_0) { + if ((int)val != L2VIC_CIAD_INSTRUCTION) { + s->vid0 = val; + } else { + /* ciad issued: clear int_status */ + clear_bit(s->vid0, (unsigned long *)s->int_status); + } + } else if (offset >= L2VIC_INT_ENABLEn && + offset < (L2VIC_INT_ENABLE_CLEARn)) { + L2VICA(s->int_enable, offset - L2VIC_INT_ENABLEn) = val; + } else if (offset >= L2VIC_INT_ENABLE_CLEARn && + offset < L2VIC_INT_ENABLE_SETn) { + L2VICA(s->int_enable, offset - L2VIC_INT_ENABLE_CLEARn) &= ~val; + } else if (offset >= L2VIC_INT_ENABLE_SETn && offset < L2VIC_INT_TYPEn) { + L2VICA(s->int_enable, offset - L2VIC_INT_ENABLE_SETn) |= val; + } else if (offset >= L2VIC_INT_TYPEn && offset < L2VIC_INT_TYPEn + 0x80) { + L2VICA(s->int_type, offset - L2VIC_INT_TYPEn) = val; + } else if (offset >= L2VIC_INT_STATUSn && offset < L2VIC_INT_CLEARn) { + L2VICA(s->int_status, offset - L2VIC_INT_STATUSn) = val; + } else if (offset >= L2VIC_INT_CLEARn && offset < L2VIC_SOFT_INTn) { + L2VICA(s->int_clear, offset - L2VIC_INT_CLEARn) = val; + } else if (offset >= L2VIC_INT_PENDINGn && + offset < L2VIC_INT_PENDINGn + 0x80) { + L2VICA(s->int_pending, offset - L2VIC_INT_PENDINGn) = val; + } else if (offset >= L2VIC_SOFT_INTn && offset < L2VIC_INT_PENDINGn) { + L2VICA(s->int_enable, offset - L2VIC_SOFT_INTn) |= val; + /* + * Need to reverse engineer the actual irq number. + */ + int irq = find_first_bit((unsigned long *)&val, + sizeof(s->int_enable[0]) * CHAR_BIT); + hwaddr byteoffset = offset - L2VIC_SOFT_INTn; + g_assert(irq != sizeof(s->int_enable[0]) * CHAR_BIT); + irq += byteoffset * 8; + + /* The soft-int interface only works with edge-triggered interrupts */ + if (test_bit(irq, (unsigned long *)s->int_type)) { + qemu_mutex_unlock(&s->active); + l2vic_set_irq(opaque, irq, 1); + qemu_mutex_lock(&s->active); + } + } else if (offset >= L2VIC_INT_GRPn_0 && offset < L2VIC_INT_GRPn_1) { + L2VICA(s->int_group_n0, offset - L2VIC_INT_GRPn_0) = val; + } else if (offset >= L2VIC_INT_GRPn_1 && offset < L2VIC_INT_GRPn_2) { + L2VICA(s->int_group_n1, offset - L2VIC_INT_GRPn_1) = val; + } else if (offset >= L2VIC_INT_GRPn_2 && offset < L2VIC_INT_GRPn_3) { + L2VICA(s->int_group_n2, offset - L2VIC_INT_GRPn_2) = val; + } else if (offset >= L2VIC_INT_GRPn_3 && offset < L2VIC_INT_GRPn_3 + 0x80) { + L2VICA(s->int_group_n3, offset - L2VIC_INT_GRPn_3) = val; + } else { + qemu_log_mask(LOG_UNIMP, "%s: offset %x unimplemented\n", __func__, + (int)offset); + } + l2vic_update_all(s); + qemu_mutex_unlock(&s->active); + return; +} + +static uint64_t l2vic_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t value; + L2VICState *s = (L2VICState *)opaque; + qemu_mutex_lock(&s->active); + + if (offset == L2VIC_VID_GRP_0) { + value = s->vid_group[0]; + } else if (offset == L2VIC_VID_GRP_1) { + value = s->vid_group[1]; + } else if (offset == L2VIC_VID_GRP_2) { + value = s->vid_group[2]; + } else if (offset == L2VIC_VID_GRP_3) { + value = s->vid_group[3]; + } else if (offset == L2VIC_VID_0) { + value = s->vid0; + } else if (offset >= L2VIC_INT_ENABLEn && + offset < L2VIC_INT_ENABLE_CLEARn) { + value = L2VICA(s->int_enable, offset - L2VIC_INT_ENABLEn); + } else if (offset >= L2VIC_INT_ENABLE_CLEARn && + offset < L2VIC_INT_ENABLE_SETn) { + value = 0; + } else if (offset >= L2VIC_INT_ENABLE_SETn && offset < L2VIC_INT_TYPEn) { + value = 0; + } else if (offset >= L2VIC_INT_TYPEn && offset < L2VIC_INT_TYPEn + 0x80) { + value = L2VICA(s->int_type, offset - L2VIC_INT_TYPEn); + } else if (offset >= L2VIC_INT_STATUSn && offset < L2VIC_INT_CLEARn) { + value = L2VICA(s->int_status, offset - L2VIC_INT_STATUSn); + } else if (offset >= L2VIC_INT_CLEARn && offset < L2VIC_SOFT_INTn) { + value = L2VICA(s->int_clear, offset - L2VIC_INT_CLEARn); + } else if (offset >= L2VIC_SOFT_INTn && offset < L2VIC_INT_PENDINGn) { + value = 0; + } else if (offset >= L2VIC_INT_PENDINGn && + offset < L2VIC_INT_PENDINGn + 0x80) { + value = L2VICA(s->int_pending, offset - L2VIC_INT_PENDINGn); + } else if (offset >= L2VIC_INT_GRPn_0 && offset < L2VIC_INT_GRPn_1) { + value = L2VICA(s->int_group_n0, offset - L2VIC_INT_GRPn_0); + } else if (offset >= L2VIC_INT_GRPn_1 && offset < L2VIC_INT_GRPn_2) { + value = L2VICA(s->int_group_n1, offset - L2VIC_INT_GRPn_1); + } else if (offset >= L2VIC_INT_GRPn_2 && offset < L2VIC_INT_GRPn_3) { + value = L2VICA(s->int_group_n2, offset - L2VIC_INT_GRPn_2); + } else if (offset >= L2VIC_INT_GRPn_3 && offset < L2VIC_INT_GRPn_3 + 0x80) { + value = L2VICA(s->int_group_n3, offset - L2VIC_INT_GRPn_3); + } else { + value = 0; + qemu_log_mask(LOG_GUEST_ERROR, "L2VIC: %s: offset 0x%x\n", __func__, + (int)offset); + } + + trace_l2vic_reg_read((unsigned)offset, value); + qemu_mutex_unlock(&s->active); + + return value; +} + +static const MemoryRegionOps l2vic_ops = { + .read = l2vic_read, + .write = l2vic_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .valid.unaligned = false, +}; + +#define FASTL2VIC_ENABLE 0x0 +#define FASTL2VIC_DISABLE 0x1 +#define FASTL2VIC_INT 0x2 + +static void fastl2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + if (offset == 0) { + uint32_t cmd = (val >> 16) & 0x3; + uint32_t irq = val & 0x3ff; + uint32_t slice = (irq / 32) * 4; + val = 1 << (irq % 32); + + if (cmd == FASTL2VIC_ENABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_SETn + slice, val, size); + } else if (cmd == FASTL2VIC_DISABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_CLEARn + slice, val, size); + } else if (cmd == FASTL2VIC_INT) { + l2vic_write(opaque, L2VIC_SOFT_INTn + slice, val, size); + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write cmd %d\n", __func__, + cmd); + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write offset 0x%08x\n", + __func__, (unsigned int)offset); +} + +static const MemoryRegionOps fastl2vic_ops = { + .write = fastl2vic_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .valid.unaligned = false, +}; + +static void l2vic_reset_hold(Object *obj, ResetType) +{ + L2VICState *s = L2VIC(obj); + memset(s->int_clear, 0, sizeof(s->int_clear)); + memset(s->int_enable, 0, sizeof(s->int_enable)); + memset(s->int_pending, 0, sizeof(s->int_pending)); + memset(s->int_status, 0, sizeof(s->int_status)); + memset(s->int_type, 0, sizeof(s->int_type)); + memset(s->int_group_n0, 0, sizeof(s->int_group_n0)); + memset(s->int_group_n1, 0, sizeof(s->int_group_n1)); + memset(s->int_group_n2, 0, sizeof(s->int_group_n2)); + memset(s->int_group_n3, 0, sizeof(s->int_group_n3)); + s->int_soft = 0; + s->vid0 = 0; + + l2vic_update_all(s); +} + + +static void reset_irq_handler(void *opaque, int irq, int level) +{ + L2VICState *s = (L2VICState *)opaque; + Object *obj = OBJECT(opaque); + if (level) { + l2vic_reset_hold(obj, RESET_TYPE_COLD); + } + l2vic_update_all(s); +} + +static void l2vic_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + L2VICState *s = L2VIC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + memory_region_init_io(&s->iomem, obj, &l2vic_ops, s, "l2vic", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memory_region_init_io(&s->fast_iomem, obj, &fastl2vic_ops, s, "fast", + 0x10000); + sysbus_init_mmio(sbd, &s->fast_iomem); + + qdev_init_gpio_in(dev, l2vic_set_irq, L2VIC_INTERRUPT_MAX); + qdev_init_gpio_in_named(dev, reset_irq_handler, "reset", 1); + for (i = 0; i < 8; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + qemu_mutex_init(&s->active); /* TODO: Remove this is an experiment */ +} + +static const VMStateDescription vmstate_l2vic = { + .name = "l2vic", + .version_id = 1, + .minimum_version_id = 1, + .fields = + (VMStateField[]){ + VMSTATE_UINT32(level, L2VICState), + VMSTATE_UINT32_ARRAY(vid_group, L2VICState, 4), + VMSTATE_UINT32(vid0, L2VICState), + VMSTATE_UINT32_ARRAY(int_enable, L2VICState, SLICE_MAX), + VMSTATE_UINT32(int_enable_clear, L2VICState), + VMSTATE_UINT32(int_enable_set, L2VICState), + VMSTATE_UINT32_ARRAY(int_type, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_status, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_clear, L2VICState, SLICE_MAX), + VMSTATE_UINT32(int_soft, L2VICState), + VMSTATE_UINT32_ARRAY(int_pending, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n0, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n1, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n2, L2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_group_n3, L2VICState, SLICE_MAX), + VMSTATE_END_OF_LIST() } +}; + +static void l2vic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->vmsd = &vmstate_l2vic; + rc->phases.hold = l2vic_reset_hold; +} + +static const TypeInfo l2vic_info = { + .name = TYPE_L2VIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(L2VICState), + .instance_init = l2vic_init, + .class_init = l2vic_class_init, +}; + +static void l2vic_register_types(void) +{ + type_register_static(&l2vic_info); +} + +type_init(l2vic_register_types) diff --git a/hw/intc/l2vic.h b/hw/intc/l2vic.h new file mode 100644 index 000000000000..5a85a539a982 --- /dev/null +++ b/hw/intc/l2vic.h @@ -0,0 +1,37 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#define L2VIC_VID_GRP_0 0x0 /* Read */ +#define L2VIC_VID_GRP_1 0x4 /* Read */ +#define L2VIC_VID_GRP_2 0x8 /* Read */ +#define L2VIC_VID_GRP_3 0xC /* Read */ +#define L2VIC_VID_0 0x10 /* Read SOFTWARE DEFINED */ +#define L2VIC_VID_1 0x14 /* Read SOFTWARE DEFINED NOT YET USED */ +#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */ +#define L2VIC_INT_ENABLE_CLEARn 0x180 /* Write */ +#define L2VIC_INT_ENABLE_SETn 0x200 /* Write */ +#define L2VIC_INT_TYPEn 0x280 /* Read/Write */ +#define L2VIC_INT_STATUSn 0x380 /* Read */ +#define L2VIC_INT_CLEARn 0x400 /* Write */ +#define L2VIC_SOFT_INTn 0x480 /* Write */ +#define L2VIC_INT_PENDINGn 0x500 /* Read */ +#define L2VIC_INT_GRPn_0 0x600 /* Read/Write */ +#define L2VIC_INT_GRPn_1 0x680 /* Read/Write */ +#define L2VIC_INT_GRPn_2 0x700 /* Read/Write */ +#define L2VIC_INT_GRPn_3 0x780 /* Read/Write */ + +#define L2VIC_INTERRUPT_MAX 1024 +#define L2VIC_CIAD_INSTRUCTION -1 +/* + * Note about l2vic groups: + * Each interrupt to L2VIC can be configured to associate with one of + * four groups. + * Group 0 interrupts go to IRQ2 via VID 0 (SSR: 0xC2, the default) + * Group 1 interrupts go to IRQ3 via VID 1 (SSR: 0xC3) + * Group 2 interrupts go to IRQ4 via VID 2 (SSR: 0xC4) + * Group 3 interrupts go to IRQ5 via VID 3 (SSR: 0xC5) + */ diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 510fdfb68865..919abe5eec28 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -67,6 +67,8 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('xics_spapr.c', 'spapr_xi specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) + +specific_ss.add(when: 'CONFIG_L2VIC', if_true: files('l2vic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 3dcf14719833..bc66260fc0cb 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -303,6 +303,10 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u - sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx" sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx" sh_intc_set(int id, int enable) "setting interrupt group %d to %d" +# l2vic.c +l2vic_reg_write(unsigned int addr, uint32_t value) "addr: 0x%03x value: 0x%08"PRIx32 +l2vic_reg_read(unsigned int addr, uint32_t value) "addr: 0x%03x value: 0x%08"PRIx32 +l2vic_delivered(int irq, int vid) "l2vic: delivered %d (vid %d)" # loongson_ipi.c loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 From 1ed40481b2be20bfccaf1c6bc4ebf5f67636b043 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 19:16:02 -0700 Subject: [PATCH 052/109] target/hexagon: Implement ciad helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ciad is the clear interrupt auto disable instruction. This instruction is defined in the Qualcomm Hexagon V71 Programmer's Reference Manual - https://docs.qualcomm.com/bundle/publicresource/80-N2040-51_REV_AB_Hexagon_V71_ProgrammerS_Reference_Manual.pdf See §11.9.2 SYSTEM MONITOR. Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 39 ++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 9205826faa02..5aec9f17f958 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -34,6 +34,11 @@ #include "op_helper.h" #include "cpu_helper.h" #include "translate.h" +#ifndef CONFIG_USER_ONLY +#include "hex_mmu.h" +#include "hw/intc/l2vic.h" +#include "hex_interrupts.h" +#endif #define SF_BIAS 127 #define SF_MANTBITS 23 @@ -1338,9 +1343,36 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) } #ifndef CONFIG_USER_ONLY +static void hexagon_set_vid(CPUHexagonState *env, uint32_t offset, int val) +{ + g_assert((offset == L2VIC_VID_0) || (offset == L2VIC_VID_1)); + CPUState *cs = env_cpu(env); + HexagonCPU *cpu = HEXAGON_CPU(cs); + const hwaddr pend_mem = cpu->l2vic_base_addr + offset; + cpu_physical_memory_write(pend_mem, &val, sizeof(val)); +} + +static void hexagon_clear_last_irq(CPUHexagonState *env, uint32_t offset) +{ + /* + * currently only l2vic is the only attached it uses vid0, remove + * the assert below if anther is added + */ + hexagon_set_vid(env, offset, L2VIC_CIAD_INSTRUCTION); +} + void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + uint32_t ipendad; + uint32_t iad; + + BQL_LOCK_GUARD(); + ipendad = READ_SREG(HEX_SREG_IPENDAD); + iad = fGET_FIELD(ipendad, IPENDAD_IAD); + fSET_FIELD(ipendad, IPENDAD_IAD, iad & ~(mask)); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); + hexagon_clear_last_irq(env, L2VIC_VID_0); + hex_interrupt_update(env); } void HELPER(siad)(CPUHexagonState *env, uint32_t mask) @@ -1416,11 +1448,6 @@ static void modify_syscfg(CPUHexagonState *env, uint32_t val) g_assert_not_reached(); } -static void hexagon_set_vid(CPUHexagonState *env, uint32_t offset, int val) -{ - g_assert_not_reached(); -} - static uint32_t hexagon_find_last_irq(CPUHexagonState *env, uint32_t vid) { g_assert_not_reached(); From 75bd5909bc21aea210ce59a88624e3f8f78a7878 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 19:19:43 -0700 Subject: [PATCH 053/109] target/hexagon: Implement {c,}swi helpers {c,}swi are the "software interrupt"/"Cancel pending interrupts" instructions. Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 5aec9f17f958..764daffb3c88 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1382,12 +1382,14 @@ void HELPER(siad)(CPUHexagonState *env, uint32_t mask) void HELPER(swi)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + hex_raise_interrupts(env, mask, CPU_INTERRUPT_SWI); } void HELPER(cswi)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + hex_clear_interrupts(env, mask, CPU_INTERRUPT_SWI); } void HELPER(iassignw)(CPUHexagonState *env, uint32_t src) From 2af5088b1118e50d1a207816e303b17896088da8 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 19:22:54 -0700 Subject: [PATCH 054/109] target/hexagon: Implement iassign{r,w} helpers iassign{r,w} are the "Interrupt to thread assignment {read,write}" instructions. Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 764daffb3c88..d70b0a8c3623 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1394,12 +1394,55 @@ void HELPER(cswi)(CPUHexagonState *env, uint32_t mask) void HELPER(iassignw)(CPUHexagonState *env, uint32_t src) { - g_assert_not_reached(); + uint32_t modectl; + uint32_t thread_enabled_mask; + CPUState *cpu; + + BQL_LOCK_GUARD(); + modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + + CPU_FOREACH(cpu) { + CPUHexagonState *thread_env = &(HEXAGON_CPU(cpu)->env); + uint32_t thread_id_mask = 0x1 << thread_env->threadId; + if (thread_enabled_mask & thread_id_mask) { + uint32_t imask = ARCH_GET_SYSTEM_REG(thread_env, HEX_SREG_IMASK); + uint32_t intbitpos = (src >> 16) & 0xF; + uint32_t val = (src >> thread_env->threadId) & 0x1; + imask = deposit32(imask, intbitpos, 1, val); + ARCH_SET_SYSTEM_REG(thread_env, HEX_SREG_IMASK, imask); + + qemu_log_mask(CPU_LOG_INT, "%s: thread %d, new imask 0x%x\n", + __func__, thread_env->threadId, imask); + } + } + hex_interrupt_update(env); } uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src) { - g_assert_not_reached(); + uint32_t modectl; + uint32_t thread_enabled_mask; + uint32_t intbitpos; + uint32_t dest_reg; + CPUState *cpu; + + BQL_LOCK_GUARD(); + modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + /* src fields are in same position as modectl, but mean different things */ + intbitpos = GET_FIELD(MODECTL_W, src); + dest_reg = 0; + CPU_FOREACH(cpu) { + CPUHexagonState *thread_env = &(HEXAGON_CPU(cpu)->env); + uint32_t thread_id_mask = 0x1 << thread_env->threadId; + if (thread_enabled_mask & thread_id_mask) { + uint32_t imask = ARCH_GET_SYSTEM_REG(thread_env, HEX_SREG_IMASK); + dest_reg |= ((imask >> intbitpos) & 0x1) << thread_env->threadId; + } + } + + return dest_reg; } void HELPER(start)(CPUHexagonState *env, uint32_t imask) From d905f730f054aa38d538d36998b0105ac5a2e03d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 20:39:01 -0700 Subject: [PATCH 055/109] target/hexagon: Implement start/stop helpers Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 14 +++++- target/hexagon/cpu.h | 3 ++ target/hexagon/cpu_bits.h | 1 + target/hexagon/cpu_helper.c | 97 +++++++++++++++++++++++++++++++++++++ target/hexagon/cpu_helper.h | 3 ++ target/hexagon/op_helper.c | 4 +- 6 files changed, 119 insertions(+), 3 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index aace243a0a19..17e7932d269e 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -32,6 +32,7 @@ #ifndef CONFIG_USER_ONLY #include "sys_macros.h" +#include "qemu/main-loop.h" #endif static void hexagon_v66_cpu_init(Object *obj) { } @@ -61,6 +62,7 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_UINT32("num-tlbs", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES), DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr, 0xffffffffULL), + DEFINE_PROP_UINT32("hvx-contexts", HexagonCPU, hvx_contexts, 0), #endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, @@ -294,8 +296,17 @@ static void mmu_reset(CPUHexagonState *env) memset(env->hex_tlb, 0, sizeof(*env->hex_tlb)); } } -#endif +void hexagon_cpu_soft_reset(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_SSR, 0); + hexagon_ssr_set_cause(env, HEX_CAUSE_RESET); + + target_ulong evb = ARCH_GET_SYSTEM_REG(env, HEX_SREG_EVB); + ARCH_SET_THREAD_REG(env, HEX_REG_PC, evb); +} +#endif static void hexagon_cpu_reset_hold(Object *obj, ResetType type) { @@ -326,6 +337,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) } mmu_reset(env); ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); + hexagon_cpu_soft_reset(env); memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); env->threadId = cs->cpu_index; diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 20b266cc0a8d..f1a9807b50cc 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -41,6 +41,7 @@ typedef struct CPUHexagonTLBContext CPUHexagonTLBContext; #define REG_WRITES_MAX 32 #define PRED_WRITES_MAX 5 /* 4 insns + endloop */ #define VSTORES_MAX 2 +#define VECTOR_UNIT_MAX 8 #ifndef CONFIG_USER_ONLY #define CPU_INTERRUPT_SWI CPU_INTERRUPT_TGT_INT_0 @@ -180,6 +181,7 @@ struct ArchCPU { #ifndef CONFIG_USER_ONLY uint32_t num_tlbs; uint32_t l2vic_base_addr; + uint32_t hvx_contexts; #endif }; @@ -196,6 +198,7 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg); uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg); void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val); +void hexagon_cpu_soft_reset(CPUHexagonState *env); #endif #include "exec/cpu-all.h" diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index b559a7ba8809..610094a759c5 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -52,6 +52,7 @@ enum hex_event { enum hex_cause { HEX_CAUSE_NONE = -1, + HEX_CAUSE_RESET = 0x000, HEX_CAUSE_TRAP0 = 0x172, HEX_CAUSE_FETCH_NO_UPAGE = 0x012, HEX_CAUSE_INVALID_PACKET = 0x015, diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index dde7ec110fe0..44847fcf6bfb 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -84,8 +84,105 @@ void clear_wait_mode(CPUHexagonState *env) SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask); } +void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause) +{ + g_assert(bql_locked()); + + const uint32_t old = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause); + const uint32_t new = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + + hexagon_modify_ssr(env, new, old); +} + + int get_exe_mode(CPUHexagonState *env) { g_assert_not_reached(); } + +static void set_enable_mask(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + thread_enabled_mask |= 0x1 << env->threadId; + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask); +} + +static uint32_t clear_enable_mask(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + thread_enabled_mask &= ~(0x1 << env->threadId); + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask); + return thread_enabled_mask; +} +static void do_start_thread(CPUState *cs, run_on_cpu_data tbd) +{ + BQL_LOCK_GUARD(); + + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + hexagon_cpu_soft_reset(env); + + set_enable_mask(env); + + cs->halted = 0; + cs->exception_index = HEX_EVENT_NONE; + cpu_resume(cs); +} + +void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask) +{ + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + if (!(mask & (0x1 << env->threadId))) { + continue; + } + + if (current_env->threadId != env->threadId) { + async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL); + } + } +} + +/* + * When we have all threads stopped, the return + * value to the shell is register 2 from thread 0. + */ +static target_ulong get_thread0_r2(void) +{ + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *thread = &cpu->env; + if (thread->threadId == 0) { + return thread->gpr[2]; + } + } + g_assert_not_reached(); +} + +void hexagon_stop_thread(CPUHexagonState *env) + +{ + BQL_LOCK_GUARD(); + + uint32_t thread_enabled_mask = clear_enable_mask(env); + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + if (!thread_enabled_mask) { + /* All threads are stopped, exit */ + exit(get_thread0_r2()); + } +} + #endif diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index c39e995a3dc8..6fb354e2785d 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -17,6 +17,9 @@ void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old); int get_exe_mode(CPUHexagonState *env); void clear_wait_mode(CPUHexagonState *env); +void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause); +void hexagon_start_threads(CPUHexagonState *env, uint32_t mask); +void hexagon_stop_thread(CPUHexagonState *env); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index d70b0a8c3623..187468c8030d 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1447,12 +1447,12 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src) void HELPER(start)(CPUHexagonState *env, uint32_t imask) { - g_assert_not_reached(); + hexagon_start_threads(env, imask); } void HELPER(stop)(CPUHexagonState *env) { - g_assert_not_reached(); + hexagon_stop_thread(env); } void HELPER(wait)(CPUHexagonState *env, target_ulong PC) From a7f2da36da7ca3892edc7ab4548e13dfd41a68cb Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:09:08 -0700 Subject: [PATCH 056/109] target/hexagon: Implement modify SSR The per-vCPU System Status Register controls many modal behaviors of the system architecture. When the SSR is updated, we trigger the necessary effects for interrupts, privilege/MMU, and HVX context mapping. Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 101 +++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 44847fcf6bfb..c44e5988dd16 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -14,6 +14,8 @@ #else #include "hw/boards.h" #include "hw/hexagon/hexagon.h" +#include "hex_interrupts.h" +#include "hex_mmu.h" #endif #include "exec/exec-all.h" #include "exec/cpu_ldst.h" @@ -69,9 +71,106 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) g_assert_not_reached(); } +static MMVector VRegs[VECTOR_UNIT_MAX][NUM_VREGS]; +static MMQReg QRegs[VECTOR_UNIT_MAX][NUM_QREGS]; + +/* + * EXT_CONTEXTS + * SSR.XA 2 4 6 8 + * 000 HVX Context 0 HVX Context 0 HVX Context 0 HVX Context 0 + * 001 HVX Context 1 HVX Context 1 HVX Context 1 HVX Context 1 + * 010 HVX Context 0 HVX Context 2 HVX Context 2 HVX Context 2 + * 011 HVX Context 1 HVX Context 3 HVX Context 3 HVX Context 3 + * 100 HVX Context 0 HVX Context 0 HVX Context 4 HVX Context 4 + * 101 HVX Context 1 HVX Context 1 HVX Context 5 HVX Context 5 + * 110 HVX Context 0 HVX Context 2 HVX Context 2 HVX Context 6 + * 111 HVX Context 1 HVX Context 3 HVX Context 3 HVX Context 7 + */ +static int parse_context_idx(CPUHexagonState *env, uint8_t XA) +{ + int ret; + HexagonCPU *cpu = env_archcpu(env); + if (cpu->hvx_contexts == 6 && XA >= 6) { + ret = XA - 6 + 2; + } else { + ret = XA % cpu->hvx_contexts; + } + g_assert(ret >= 0 && ret < VECTOR_UNIT_MAX); + return ret; +} + +static void check_overcommitted_hvx(CPUHexagonState *env, uint32_t ssr) +{ + if (!GET_FIELD(SSR_XE, ssr)) { + return; + } + + uint8_t XA = GET_SSR_FIELD(SSR_XA, ssr); + + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env_ = &cpu->env; + if (env_ == env) { + continue; + } + /* Check if another thread has the XE bit set and same XA */ + uint32_t ssr_ = ARCH_GET_SYSTEM_REG(env_, HEX_SREG_SSR); + if (GET_SSR_FIELD(SSR_XE2, ssr_) && GET_FIELD(SSR_XA, ssr_) == XA) { + qemu_log_mask(LOG_GUEST_ERROR, + "setting SSR.XA '%d' on thread %d but thread" + " %d has same extension active\n", XA, env->threadId, + env_->threadId); + } + } +} + void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old) { - g_assert_not_reached(); + g_assert(bql_locked()); + + bool old_EX = GET_SSR_FIELD(SSR_EX, old); + bool old_UM = GET_SSR_FIELD(SSR_UM, old); + bool old_GM = GET_SSR_FIELD(SSR_GM, old); + bool old_IE = GET_SSR_FIELD(SSR_IE, old); + uint8_t old_XA = GET_SSR_FIELD(SSR_XA, old); + bool new_EX = GET_SSR_FIELD(SSR_EX, new); + bool new_UM = GET_SSR_FIELD(SSR_UM, new); + bool new_GM = GET_SSR_FIELD(SSR_GM, new); + bool new_IE = GET_SSR_FIELD(SSR_IE, new); + uint8_t new_XA = GET_SSR_FIELD(SSR_XA, new); + + if ((old_EX != new_EX) || + (old_UM != new_UM) || + (old_GM != new_GM)) { + hex_mmu_mode_change(env); + } + + uint8_t old_asid = GET_SSR_FIELD(SSR_ASID, old); + uint8_t new_asid = GET_SSR_FIELD(SSR_ASID, new); + if (new_asid != old_asid) { + CPUState *cs = env_cpu(env); + tlb_flush(cs); + } + + if (old_XA != new_XA) { + int old_unit = parse_context_idx(env, old_XA); + int new_unit = parse_context_idx(env, new_XA); + + /* Ownership exchange */ + memcpy(VRegs[old_unit], env->VRegs, sizeof(env->VRegs)); + memcpy(QRegs[old_unit], env->QRegs, sizeof(env->QRegs)); + memcpy(env->VRegs, VRegs[new_unit], sizeof(env->VRegs)); + memcpy(env->QRegs, QRegs[new_unit], sizeof(env->QRegs)); + + check_overcommitted_hvx(env, new); + } + + /* See if the interrupts have been enabled or we have exited EX mode */ + if ((new_IE && !old_IE) || + (!new_EX && old_EX)) { + hex_interrupt_update(env); + } } void clear_wait_mode(CPUHexagonState *env) From f700155b597432340ed17c6542255a95f48f9181 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:20:41 -0700 Subject: [PATCH 057/109] target/hexagon: Implement {g,s}etimask helpers Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 187468c8030d..7a7f1c6ea2fb 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1467,12 +1467,39 @@ void HELPER(resume)(CPUHexagonState *env, uint32_t mask) uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid) { - g_assert_not_reached(); + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *found_cpu = HEXAGON_CPU(cs); + CPUHexagonState *found_env = &found_cpu->env; + if (found_env->threadId == tid) { + target_ulong imask = ARCH_GET_SYSTEM_REG(found_env, HEX_SREG_IMASK); + qemu_log_mask(CPU_LOG_INT, "%s: tid %d imask = 0x%x\n", + __func__, env->threadId, + (unsigned)GET_FIELD(IMASK_MASK, imask)); + return GET_FIELD(IMASK_MASK, imask); + } + } + return 0; } void HELPER(setimask)(CPUHexagonState *env, uint32_t pred, uint32_t imask) { - g_assert_not_reached(); + CPUState *cs; + + BQL_LOCK_GUARD(); + CPU_FOREACH(cs) { + HexagonCPU *found_cpu = HEXAGON_CPU(cs); + CPUHexagonState *found_env = &found_cpu->env; + + if (pred == found_env->threadId) { + SET_SYSTEM_FIELD(found_env, HEX_SREG_IMASK, IMASK_MASK, imask); + qemu_log_mask(CPU_LOG_INT, "%s: tid %d imask 0x%x\n", + __func__, found_env->threadId, imask); + hex_interrupt_update(env); + return; + } + } + hex_interrupt_update(env); } static bool handle_pmu_sreg_write(CPUHexagonState *env, uint32_t reg, From 6a9cc68aaa7e9c984e054d0f3adcd97f4e0dc895 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:25:51 -0700 Subject: [PATCH 058/109] target/hexagon: Implement wait helper Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++ target/hexagon/cpu_helper.h | 1 + target/hexagon/op_helper.c | 6 +++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index c44e5988dd16..ceee61bb1492 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -71,6 +71,46 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) g_assert_not_reached(); } +static void set_wait_mode(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl); + thread_wait_mask |= 0x1 << env->threadId; + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask); +} + +void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC) +{ + g_assert(bql_locked()); + + if (qemu_loglevel_mask(LOG_GUEST_ERROR) && + (env->k0_lock_state != HEX_LOCK_UNLOCKED || + env->tlb_lock_state != HEX_LOCK_UNLOCKED)) { + qemu_log("WARNING: executing wait() with acquired lock" + "may lead to deadlock\n"); + } + g_assert(get_exe_mode(env) != HEX_EXE_MODE_WAIT); + + CPUState *cs = env_cpu(env); + /* + * The addtion of cpu_has_work is borrowed from arm's wfi helper + * and is critical for our stability + */ + if ((cs->exception_index != HEX_EVENT_NONE) || + (cpu_has_work(cs))) { + qemu_log_mask(CPU_LOG_INT, + "%s: thread %d skipping WAIT mode, have some work\n", + __func__, env->threadId); + return; + } + set_wait_mode(env); + env->wait_next_pc = PC + 4; + + cpu_interrupt(cs, CPU_INTERRUPT_HALT); +} + static MMVector VRegs[VECTOR_UNIT_MAX][NUM_VREGS]; static MMQReg QRegs[VECTOR_UNIT_MAX][NUM_QREGS]; diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 6fb354e2785d..fe329a5d5e39 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -20,6 +20,7 @@ void clear_wait_mode(CPUHexagonState *env); void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause); void hexagon_start_threads(CPUHexagonState *env, uint32_t mask); void hexagon_stop_thread(CPUHexagonState *env); +void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 7a7f1c6ea2fb..c2750d479e39 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1457,7 +1457,11 @@ void HELPER(stop)(CPUHexagonState *env) void HELPER(wait)(CPUHexagonState *env, target_ulong PC) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + + if (!fIN_DEBUG_MODE(env->threadId)) { + hexagon_wait_thread(env, PC); + } } void HELPER(resume)(CPUHexagonState *env, uint32_t mask) From b72c595290874bcbbab7bf1aafef3139087445ee Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:35:29 -0700 Subject: [PATCH 059/109] target/hexagon: Implement get_exe_mode() Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 24 ++++++++++++++++++++++++ target/hexagon/reg_fields_def.h.inc | 11 +++++++++++ 2 files changed, 35 insertions(+) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index ceee61bb1492..a23d6b87c63d 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -238,6 +238,30 @@ void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause) int get_exe_mode(CPUHexagonState *env) { + g_assert(bql_locked()); + + target_ulong modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + bool E_bit = thread_enabled_mask & (0x1 << env->threadId); + uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl); + bool W_bit = thread_wait_mask & (0x1 << env->threadId); + target_ulong isdbst = ARCH_GET_SYSTEM_REG(env, HEX_SREG_ISDBST); + uint32_t debugmode = GET_FIELD(ISDBST_DEBUGMODE, isdbst); + bool D_bit = debugmode & (0x1 << env->threadId); + + /* Figure 4-2 */ + if (!D_bit && !W_bit && !E_bit) { + return HEX_EXE_MODE_OFF; + } + if (!D_bit && !W_bit && E_bit) { + return HEX_EXE_MODE_RUN; + } + if (!D_bit && W_bit && E_bit) { + return HEX_EXE_MODE_WAIT; + } + if (D_bit && !W_bit && E_bit) { + return HEX_EXE_MODE_DEBUG; + } g_assert_not_reached(); } diff --git a/target/hexagon/reg_fields_def.h.inc b/target/hexagon/reg_fields_def.h.inc index 156a3514e77d..50b8c26f8bfa 100644 --- a/target/hexagon/reg_fields_def.h.inc +++ b/target/hexagon/reg_fields_def.h.inc @@ -135,3 +135,14 @@ DEF_REG_FIELD(CCR_GRE, 27, 1) DEF_REG_FIELD(CCR_VV1, 29, 1) DEF_REG_FIELD(CCR_VV2, 30, 1) DEF_REG_FIELD(CCR_VV3, 31, 1) + +/* ISDB ST fields */ +DEF_REG_FIELD(ISDBST_WAITRUN, 24, 8) +DEF_REG_FIELD(ISDBST_ONOFF, 16, 8) +DEF_REG_FIELD(ISDBST_DEBUGMODE, 8, 8) +DEF_REG_FIELD(ISDBST_STUFFSTATUS, 5, 1) +DEF_REG_FIELD(ISDBST_CMDSTATUS, 4, 1) +DEF_REG_FIELD(ISDBST_PROCMODE, 3, 1) +DEF_REG_FIELD(ISDBST_MBXINSTATUS, 2, 1) +DEF_REG_FIELD(ISDBST_MBXOUTSTATUS, 1, 1) +DEF_REG_FIELD(ISDBST_READY, 0, 1) From 15e062540155d89c5d56f4498fe76d502e58f704 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:36:56 -0700 Subject: [PATCH 060/109] target/hexagon: Implement arch_get_system_reg() Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index a23d6b87c63d..3c37935abc0a 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -36,7 +36,14 @@ uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index) uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg) { - g_assert_not_reached(); + if (reg == HEX_SREG_PCYCLELO) { + return hexagon_get_sys_pcycle_count_low(env); + } else if (reg == HEX_SREG_PCYCLEHI) { + return hexagon_get_sys_pcycle_count_high(env); + } + + g_assert(reg < NUM_SREGS); + return reg < HEX_SREG_GLB_START ? env->t_sreg[reg] : env->g_sreg[reg]; } uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env) From 9fc10a7051cf80cf2e6375a5619f390ca4743b1d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 27 Aug 2024 21:50:21 -0700 Subject: [PATCH 061/109] target/hexagon: Implement arch_{s,g}et_{thread,system}_reg() Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index fe329a5d5e39..a70df013341d 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -26,20 +26,27 @@ static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) { g_assert(reg < TOTAL_PER_THREAD_REGS); - g_assert_not_reached(); + env->gpr[reg] = val; } static inline uint32_t arch_get_thread_reg(CPUHexagonState *env, uint32_t reg) { g_assert(reg < TOTAL_PER_THREAD_REGS); - g_assert_not_reached(); + return env->gpr[reg]; } +#ifndef CONFIG_USER_ONLY static inline void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) { - g_assert_not_reached(); + g_assert(reg < NUM_SREGS); + if (reg < HEX_SREG_GLB_START) { + env->t_sreg[reg] = val; + } else { + env->g_sreg[reg] = val; + } } +#endif uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg); From 5026cc9741bf2bcb858c2a125435da1635d4a099 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 28 Aug 2024 17:56:18 -0700 Subject: [PATCH 062/109] target/hexagon: Add representation to count cycles The PCYCLE register can be enabled to indicate accumulated clock cycles. Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 3 +++ target/hexagon/cpu.h | 3 ++- target/hexagon/machine.c | 25 ++++++++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 17e7932d269e..0352cc5de858 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -334,6 +334,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) if (cs->cpu_index == 0) { ARCH_SET_SYSTEM_REG(env, HEX_SREG_MODECTL, 0x1); + *(env->g_pcycle_base) = 0; } mmu_reset(env); ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); @@ -395,6 +396,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (cs->cpu_index == 0) { env->g_sreg = g_new0(target_ulong, NUM_SREGS); + env->g_pcycle_base = g_malloc0(sizeof(*env->g_pcycle_base)); } else { CPUState *cpu0_s = NULL; CPUHexagonState *env0 = NULL; @@ -405,6 +407,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) break; } env->g_sreg = env0->g_sreg; + env->g_pcycle_base = env0->g_pcycle_base; } #endif diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index f1a9807b50cc..6b95efc44ee8 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -113,7 +113,8 @@ typedef struct CPUArchState { target_ulong stack_start; uint8_t slot_cancelled; - + uint64_t t_cycle_count; + uint64_t *g_pcycle_base; #ifndef CONFIG_USER_ONLY /* Some system registers are per thread and some are global. */ target_ulong t_sreg[NUM_SREGS]; diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c index c576de02f038..460a0c7f24c3 100644 --- a/target/hexagon/machine.c +++ b/target/hexagon/machine.c @@ -9,6 +9,27 @@ #include "cpu.h" #include "hex_mmu.h" +static int get_u64_ptr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + uint64_t *p = pv; + *p = qemu_get_be64(f); + return 0; +} + +static int put_u64_ptr(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, JSONWriter *vmdesc) +{ + qemu_put_be64(f, *((uint64_t *)pv)); + return 0; +} + +const VMStateInfo vmstate_info_uint64_ptr = { + .name = "uint64_t_pointer", + .get = get_u64_ptr, + .put = put_u64_ptr, +}; + static int get_hex_tlb_ptr(QEMUFile *f, void *pv, size_t size, const VMStateField *field) { @@ -35,7 +56,6 @@ const VMStateInfo vmstate_info_hex_tlb_ptr = { .put = put_hex_tlb_ptr, }; - const VMStateDescription vmstate_hexagon_cpu = { .name = "cpu", .version_id = 0, @@ -58,6 +78,9 @@ const VMStateDescription vmstate_hexagon_cpu = { VMSTATE_UINTTL(env.wait_next_pc, HexagonCPU), VMSTATE_POINTER(env.hex_tlb, HexagonCPU, 0, vmstate_info_hex_tlb_ptr, CPUHexagonTLBContext *), + VMSTATE_UINT64(env.t_cycle_count, HexagonCPU), + VMSTATE_POINTER(env.g_pcycle_base, HexagonCPU, 0, + vmstate_info_uint64_ptr, uint64_t *), VMSTATE_END_OF_LIST() }, From 9c30064ec1b54ad4d0df7c7b6a314e83b65bb69a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 28 Aug 2024 17:58:06 -0700 Subject: [PATCH 063/109] target/hexagon: Add implementation of cycle counters Co-authored-by: Sid Manning Signed-off-by: Brian Cain --- target/hexagon/cpu.h | 25 ++++++++++++++++++++++--- target/hexagon/cpu_helper.c | 13 ++++++++++--- target/hexagon/translate.c | 27 +++++++++++++++++++++++++++ target/hexagon/translate.h | 2 ++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 6b95efc44ee8..9e0cb4203f60 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -27,11 +27,15 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-common.h" #include "hex_regs.h" #include "mmvec/mmvec.h" #include "hw/registerfields.h" +#ifndef CONFIG_USER_ONLY +#include "reg_fields.h" typedef struct CPUHexagonTLBContext CPUHexagonTLBContext; +#endif #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -190,6 +194,7 @@ struct ArchCPU { FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) FIELD(TB_FLAGS, MMU_INDEX, 1, 3) +FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1) G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, @@ -203,6 +208,11 @@ void hexagon_cpu_soft_reset(CPUHexagonState *env); #endif #include "exec/cpu-all.h" + +#ifndef CONFIG_USER_ONLY +#include "cpu_helper.h" +#endif + static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) { @@ -212,16 +222,27 @@ static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, if (*pc == env->gpr[HEX_REG_SA0]) { hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); } - *flags = hex_flags; if (*pc & PCALIGN_MASK) { hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0); } #ifndef CONFIG_USER_ONLY + target_ulong syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + + bool pcycle_enabled = extract32(syscfg, + reg_field_info[SYSCFG_PCYCLEEN].offset, + reg_field_info[SYSCFG_PCYCLEEN].width); + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, cpu_mmu_index(env_cpu(env), false)); + + if (pcycle_enabled) { + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1); + } #else + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, true); hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX); #endif + *flags = hex_flags; } typedef HexagonCPU ArchCPU; @@ -230,6 +251,4 @@ void hexagon_translate_init(void); void hexagon_translate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); -#include "exec/cpu-all.h" - #endif /* HEXAGON_CPU_H */ diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 3c37935abc0a..2f6bbbf5e0f8 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -48,17 +48,24 @@ uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg) uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env) { - g_assert_not_reached(); + uint64_t cycles = 0; + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env_ = &cpu->env; + cycles += env_->t_cycle_count; + } + return *(env->g_pcycle_base) + cycles; } uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env) { - g_assert_not_reached(); + return hexagon_get_sys_pcycle_count(env) >> 32; } uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env) { - g_assert_not_reached(); + return extract64(hexagon_get_sys_pcycle_count(env), 0, 32); } void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 9119e42ff77f..060df6e5eb62 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -57,6 +57,7 @@ TCGv_i64 hex_store_val64[STORES_MAX]; TCGv hex_llsc_addr; TCGv hex_llsc_val; TCGv_i64 hex_llsc_val_i64; +TCGv_i64 hex_cycle_count; TCGv hex_vstore_addr[VSTORES_MAX]; TCGv hex_vstore_size[VSTORES_MAX]; TCGv hex_vstore_pending[VSTORES_MAX]; @@ -125,6 +126,22 @@ static void gen_exception_raw(int excp) gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); } +#ifndef CONFIG_USER_ONLY +static inline void gen_precise_exception(int excp, target_ulong PC) +{ + tcg_gen_movi_tl(hex_cause_code, excp); + gen_exception(HEX_EVENT_PRECISE, PC); +} + +static inline void gen_pcycle_counters(DisasContext *ctx) +{ + if (ctx->pcycle_enabled) { + tcg_gen_addi_i64(hex_cycle_count, hex_cycle_count, ctx->num_cycles); + ctx->num_cycles = 0; + } +} +#endif + static void gen_exec_counters(DisasContext *ctx) { tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT], @@ -133,6 +150,10 @@ static void gen_exec_counters(DisasContext *ctx) hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns); tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_HVX_CNT], hex_gpr[HEX_REG_QEMU_HVX_CNT], ctx->num_hvx_insns); + +#ifndef CONFIG_USER_ONLY + gen_pcycle_counters(ctx); +#endif } static bool use_goto_tb(DisasContext *ctx, target_ulong dest) @@ -785,6 +806,7 @@ static void gen_commit_hvx(DisasContext *ctx) } } +static const int PCYCLES_PER_PACKET = 3; static void update_exec_counters(DisasContext *ctx) { Packet *pkt = ctx->pkt; @@ -804,6 +826,7 @@ static void update_exec_counters(DisasContext *ctx) } ctx->num_packets++; + ctx->num_cycles += PCYCLES_PER_PACKET; ctx->num_insns += num_real_insns; ctx->num_hvx_insns += num_hvx_insns; } @@ -946,11 +969,13 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, ctx->mem_idx = FIELD_EX32(hex_flags, TB_FLAGS, MMU_INDEX); ctx->num_packets = 0; + ctx->num_cycles = 0; ctx->num_insns = 0; ctx->num_hvx_insns = 0; ctx->branch_cond = TCG_COND_NEVER; ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP); ctx->short_circuit = hex_cpu->short_circuit; + ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED); } static void hexagon_tr_tb_start(DisasContextBase *db, CPUState *cpu) @@ -1077,6 +1102,8 @@ void hexagon_translate_init(void) offsetof(CPUHexagonState, llsc_val), "llsc_val"); hex_llsc_val_i64 = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64"); + hex_cycle_count = tcg_global_mem_new_i64(tcg_env, + offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count"); for (i = 0; i < STORES_MAX; i++) { snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i); hex_store_addr[i] = tcg_global_mem_new(tcg_env, diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 0eaa3db03e81..9bc4b3ce8b33 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -83,6 +83,8 @@ typedef struct DisasContext { TCGv new_pred_value[NUM_PREGS]; TCGv branch_taken; TCGv dczero_addr; + bool pcycle_enabled; + uint32_t num_cycles; } DisasContext; bool is_gather_store_insn(DisasContext *ctx); From 209a966c1bc96c368cfe2add3048430faf0f4772 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 28 Aug 2024 17:58:36 -0700 Subject: [PATCH 064/109] target/hexagon: Implement modify_syscfg() Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 52 +++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index c2750d479e39..95e32017e488 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1521,7 +1521,57 @@ static bool handle_pmu_sreg_write(CPUHexagonState *env, uint32_t reg, static void modify_syscfg(CPUHexagonState *env, uint32_t val) { - g_assert_not_reached(); + g_assert(bql_locked()); + + uint32_t old; + uint32_t syscfg_read_only_mask = 0x80001c00; + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + + /* clear read-only bits if they are set in the new value. */ + val &= ~syscfg_read_only_mask; + /* if read-only are currently set in syscfg keep them set. */ + val |= (syscfg & syscfg_read_only_mask); + + uint32_t tmp = val; + old = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_SYSCFG, tmp); + + /* Check for change in MMU enable */ + target_ulong old_mmu_enable = GET_SYSCFG_FIELD(SYSCFG_MMUEN, old); + uint8_t old_en = GET_SYSCFG_FIELD(SYSCFG_PCYCLEEN, old); + uint8_t old_gie = GET_SYSCFG_FIELD(SYSCFG_GIE, old); + target_ulong new_mmu_enable = + GET_SYSCFG_FIELD(SYSCFG_MMUEN, val); + if (new_mmu_enable && !old_mmu_enable) { + hex_mmu_on(env); + } else if (!new_mmu_enable && old_mmu_enable) { + hex_mmu_off(env); + } + + /* Changing pcycle enable from 0 to 1 resets the counters */ + uint8_t new_en = GET_SYSCFG_FIELD(SYSCFG_PCYCLEEN, val); + CPUState *cs; + if (old_en == 0 && new_en == 1) { + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *_env = &cpu->env; + _env->t_cycle_count = 0; + } + } + + /* See if global interrupts are turned on */ + uint8_t new_gie = GET_SYSCFG_FIELD(SYSCFG_GIE, val); + if (!old_gie && new_gie) { + qemu_log_mask(CPU_LOG_INT, "%s: global interrupts enabled\n", __func__); + hex_interrupt_update(env); + } + + if (qemu_loglevel_mask(LOG_UNIMP)) { + int new_v2x = GET_SYSCFG_FIELD(SYSCFG_V2X, val); + if (!new_v2x) { + qemu_log("HVX: 64 byte vector length is unsupported\n"); + } + } } static uint32_t hexagon_find_last_irq(CPUHexagonState *env, uint32_t vid) From 51862108d5becaa31b51bbaf408c748b7471013a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 10:21:50 -0700 Subject: [PATCH 065/109] target/hexagon: Add system event, cause codes Signed-off-by: Brian Cain --- target/hexagon/cpu.h | 10 ++++++- target/hexagon/cpu_bits.h | 55 ++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 9e0cb4203f60..d4f20441a171 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -67,6 +67,15 @@ typedef struct CPUHexagonTLBContext CPUHexagonTLBContext; #define MMU_GUEST_IDX 1 #define MMU_KERNEL_IDX 2 +#define HEXAGON_CPU_IRQ_0 0 +#define HEXAGON_CPU_IRQ_1 1 +#define HEXAGON_CPU_IRQ_2 2 +#define HEXAGON_CPU_IRQ_3 3 +#define HEXAGON_CPU_IRQ_4 4 +#define HEXAGON_CPU_IRQ_5 5 +#define HEXAGON_CPU_IRQ_6 6 +#define HEXAGON_CPU_IRQ_7 7 + typedef enum { HEX_LOCK_UNLOCKED = 0, HEX_LOCK_WAITING = 1, @@ -75,7 +84,6 @@ typedef enum { } hex_lock_state_t; #endif - #define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU typedef struct { diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 610094a759c5..c7cc426ec888 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -24,14 +24,16 @@ #define PCALIGN_MASK (PCALIGN - 1) enum hex_event { - HEX_EVENT_NONE = -1, - HEX_EVENT_TRAP0 = 0x008, - HEX_EVENT_FETCH_NO_UPAGE = 0x012, - HEX_EVENT_INVALID_PACKET = 0x015, - HEX_EVENT_INVALID_OPCODE = 0x015, - HEX_EVENT_PC_NOT_ALIGNED = 0x01e, - HEX_EVENT_PRIV_NO_UREAD = 0x024, - HEX_EVENT_PRIV_NO_UWRITE = 0x025, + HEX_EVENT_NONE = -1, + HEX_EVENT_RESET = 0x0, + HEX_EVENT_IMPRECISE = 0x1, + HEX_EVENT_PRECISE = 0x2, + HEX_EVENT_TLB_MISS_X = 0x4, + HEX_EVENT_TLB_MISS_RW = 0x6, + HEX_EVENT_TRAP0 = 0x8, + HEX_EVENT_TRAP1 = 0x9, + HEX_EVENT_FPTRAP = 0xb, + HEX_EVENT_DEBUG = 0xc, HEX_EVENT_INT0 = 0x10, HEX_EVENT_INT1 = 0x11, HEX_EVENT_INT2 = 0x12, @@ -53,15 +55,38 @@ enum hex_event { enum hex_cause { HEX_CAUSE_NONE = -1, HEX_CAUSE_RESET = 0x000, - HEX_CAUSE_TRAP0 = 0x172, - HEX_CAUSE_FETCH_NO_UPAGE = 0x012, - HEX_CAUSE_INVALID_PACKET = 0x015, - HEX_CAUSE_INVALID_OPCODE = 0x015, - HEX_CAUSE_PC_NOT_ALIGNED = 0x01e, - HEX_CAUSE_PRIV_NO_UREAD = 0x024, - HEX_CAUSE_PRIV_NO_UWRITE = 0x025, + HEX_CAUSE_BIU_PRECISE = 0x001, + HEX_CAUSE_UNSUPORTED_HVX_64B = 0x002, /* QEMU-specific */ + HEX_CAUSE_DOUBLE_EXCEPT = 0x003, + HEX_CAUSE_TRAP0 = 0x008, + HEX_CAUSE_TRAP1 = 0x009, + HEX_CAUSE_FETCH_NO_XPAGE = 0x011, + HEX_CAUSE_FETCH_NO_UPAGE = 0x012, + HEX_CAUSE_INVALID_PACKET = 0x015, + HEX_CAUSE_INVALID_OPCODE = 0x015, + HEX_CAUSE_NO_COPROC_ENABLE = 0x016, + HEX_CAUSE_NO_COPROC2_ENABLE = 0x018, HEX_CAUSE_PRIV_USER_NO_GINSN = 0x01a, HEX_CAUSE_PRIV_USER_NO_SINSN = 0x01b, + HEX_CAUSE_REG_WRITE_CONFLICT = 0x01d, + HEX_CAUSE_PC_NOT_ALIGNED = 0x01e, + HEX_CAUSE_MISALIGNED_LOAD = 0x020, + HEX_CAUSE_MISALIGNED_STORE = 0x021, + HEX_CAUSE_PRIV_NO_READ = 0x022, + HEX_CAUSE_PRIV_NO_WRITE = 0x023, + HEX_CAUSE_PRIV_NO_UREAD = 0x024, + HEX_CAUSE_PRIV_NO_UWRITE = 0x025, + HEX_CAUSE_COPROC_LDST = 0x026, + HEX_CAUSE_STACK_LIMIT = 0x027, + HEX_CAUSE_VWCTRL_WINDOW_MISS = 0x029, + HEX_CAUSE_IMPRECISE_NMI = 0x043, + HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH = 0x044, + HEX_CAUSE_TLBMISSX_CAUSE_NORMAL = 0x060, + HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE = 0x061, + HEX_CAUSE_TLBMISSRW_CAUSE_READ = 0x070, + HEX_CAUSE_TLBMISSRW_CAUSE_WRITE = 0x071, + HEX_CAUSE_DEBUG_SINGLESTEP = 0x80, + HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT = 0x0bf, HEX_CAUSE_INT0 = 0x0c0, HEX_CAUSE_INT1 = 0x0c1, HEX_CAUSE_INT2 = 0x0c2, From 64f749aaec34c966234b14259da4e9af97cb1c26 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 10:22:14 -0700 Subject: [PATCH 066/109] target/hexagon: Implement hex_tlb_entry_get_perm() Signed-off-by: Brian Cain --- target/hexagon/hex_mmu.c | 54 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c index 83ed17892452..ba3172bb1506 100644 --- a/target/hexagon/hex_mmu.c +++ b/target/hexagon/hex_mmu.c @@ -265,7 +265,59 @@ static inline void hex_tlb_entry_get_perm(CPUHexagonState *env, uint64_t entry, int mmu_idx, int *prot, int32_t *excp) { - g_assert_not_reached(); + bool perm_x = GET_TLB_FIELD(entry, PTE_X); + bool perm_w = GET_TLB_FIELD(entry, PTE_W); + bool perm_r = GET_TLB_FIELD(entry, PTE_R); + bool perm_u = GET_TLB_FIELD(entry, PTE_U); + bool user_idx = mmu_idx == MMU_USER_IDX; + + if (mmu_idx == MMU_KERNEL_IDX) { + *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return; + } + + *prot = PAGE_VALID; + switch (access_type) { + case MMU_INST_FETCH: + if (user_idx && !perm_u) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_FETCH_NO_UPAGE; + } else if (!perm_x) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_FETCH_NO_XPAGE; + } + break; + case MMU_DATA_LOAD: + if (user_idx && !perm_u) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_PRIV_NO_UREAD; + } else if (!perm_r) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_PRIV_NO_READ; + } + break; + case MMU_DATA_STORE: + if (user_idx && !perm_u) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_PRIV_NO_UWRITE; + } else if (!perm_w) { + *excp = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_PRIV_NO_WRITE; + } + break; + } + + if (!user_idx || perm_u) { + if (perm_x) { + *prot |= PAGE_EXEC; + } + if (perm_r) { + *prot |= PAGE_READ; + } + if (perm_w) { + *prot |= PAGE_WRITE; + } + } } static inline bool hex_tlb_entry_match(CPUHexagonState *env, uint64_t entry, From 4e99d60cb7b3d7a07b538fb4563afadc603847dd Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 14:33:40 -0700 Subject: [PATCH 067/109] target/hexagon: Implement hex_tlb_lookup_by_asid() Signed-off-by: Brian Cain --- target/hexagon/hex_mmu.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c index ba3172bb1506..348c27d801cf 100644 --- a/target/hexagon/hex_mmu.c +++ b/target/hexagon/hex_mmu.c @@ -360,7 +360,31 @@ bool hex_tlb_find_match(CPUHexagonState *env, target_ulong VA, static uint32_t hex_tlb_lookup_by_asid(CPUHexagonState *env, uint32_t asid, uint32_t VA) { - g_assert_not_reached(); + uint32_t not_found = 0x80000000; + uint32_t idx = not_found; + int i; + + HexagonCPU *cpu = env_archcpu(env); + for (i = 0; i < cpu->num_tlbs; i++) { + uint64_t entry = env->hex_tlb->entries[i]; + if (hex_tlb_entry_match_noperm(entry, asid, VA)) { + if (idx != not_found) { + env->cause_code = HEX_CAUSE_IMPRECISE_MULTI_TLB_MATCH; + break; + } + idx = i; + } + } + + if (idx == not_found) { + qemu_log_mask(CPU_LOG_MMU, "%s: 0x%x, 0x%08x => NOT FOUND\n", + __func__, asid, VA); + } else { + qemu_log_mask(CPU_LOG_MMU, "%s: 0x%x, 0x%08x => %d\n", + __func__, asid, VA, idx); + } + + return idx; } /* Called from tlbp instruction */ From 14e3167f21d1f4672db6db1e0b04e31d5bb98e6d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 14:38:50 -0700 Subject: [PATCH 068/109] target/hexagon: Implement software interrupt Signed-off-by: Brian Cain --- target/hexagon/cpu.h | 5 + target/hexagon/hexswi.c | 258 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 target/hexagon/hexswi.c diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index d4f20441a171..85d1d6cb2f0d 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -258,5 +258,10 @@ typedef HexagonCPU ArchCPU; void hexagon_translate_init(void); void hexagon_translate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); +#ifndef CONFIG_USER_ONLY +void hexagon_cpu_do_interrupt(CPUState *cpu); +void register_trap_exception(CPUHexagonState *env, int type, int imm, + target_ulong PC); +#endif #endif /* HEXAGON_CPU_H */ diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c new file mode 100644 index 000000000000..8bee948af6aa --- /dev/null +++ b/target/hexagon/hexswi.c @@ -0,0 +1,258 @@ +/* + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#ifdef CONFIG_USER_ONLY +#include "exec/helper-proto.h" +#include "qemu.h" +#endif +#include "exec/cpu_ldst.h" +#include "exec/exec-all.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "arch.h" +#include "internal.h" +#include "macros.h" +#include "sys_macros.h" +#include "tcg/tcg-op.h" +#ifndef CONFIG_USER_ONLY +#include "hex_mmu.h" +#endif + +#ifndef CONFIG_USER_ONLY + + +static void set_addresses(CPUHexagonState *env, target_ulong pc_offset, + target_ulong exception_index) + +{ + ARCH_SET_SYSTEM_REG(env, HEX_SREG_ELR, + ARCH_GET_THREAD_REG(env, HEX_REG_PC) + pc_offset); + ARCH_SET_THREAD_REG(env, HEX_REG_PC, + ARCH_GET_SYSTEM_REG(env, HEX_SREG_EVB) | + (exception_index << 2)); +} + +static const char *event_name[] = { + [HEX_EVENT_RESET] = "HEX_EVENT_RESET", + [HEX_EVENT_IMPRECISE] = "HEX_EVENT_IMPRECISE", + [HEX_EVENT_TLB_MISS_X] = "HEX_EVENT_TLB_MISS_X", + [HEX_EVENT_TLB_MISS_RW] = "HEX_EVENT_TLB_MISS_RW", + [HEX_EVENT_TRAP0] = "HEX_EVENT_TRAP0", + [HEX_EVENT_TRAP1] = "HEX_EVENT_TRAP1", + [HEX_EVENT_FPTRAP] = "HEX_EVENT_FPTRAP", + [HEX_EVENT_DEBUG] = "HEX_EVENT_DEBUG", + [HEX_EVENT_INT0] = "HEX_EVENT_INT0", + [HEX_EVENT_INT1] = "HEX_EVENT_INT1", + [HEX_EVENT_INT2] = "HEX_EVENT_INT2", + [HEX_EVENT_INT3] = "HEX_EVENT_INT3", + [HEX_EVENT_INT4] = "HEX_EVENT_INT4", + [HEX_EVENT_INT5] = "HEX_EVENT_INT5", + [HEX_EVENT_INT6] = "HEX_EVENT_INT6", + [HEX_EVENT_INT7] = "HEX_EVENT_INT7", + [HEX_EVENT_INT8] = "HEX_EVENT_INT8", + [HEX_EVENT_INT9] = "HEX_EVENT_INT9", + [HEX_EVENT_INTA] = "HEX_EVENT_INTA", + [HEX_EVENT_INTB] = "HEX_EVENT_INTB", + [HEX_EVENT_INTC] = "HEX_EVENT_INTC", + [HEX_EVENT_INTD] = "HEX_EVENT_INTD", + [HEX_EVENT_INTE] = "HEX_EVENT_INTE", + [HEX_EVENT_INTF] = "HEX_EVENT_INTF" +}; + +void hexagon_cpu_do_interrupt(CPUState *cs) + +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + BQL_LOCK_GUARD(); + + qemu_log_mask(CPU_LOG_INT, "\t%s: event 0x%x:%s, cause 0x%x(%d)\n", + __func__, cs->exception_index, + event_name[cs->exception_index], env->cause_code, + env->cause_code); + + env->llsc_addr = ~0; + + uint32_t ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + if (GET_SSR_FIELD(SSR_EX, ssr) == 1) { + ARCH_SET_SYSTEM_REG(env, HEX_SREG_DIAG, env->cause_code); + env->cause_code = HEX_CAUSE_DOUBLE_EXCEPT; + cs->exception_index = HEX_EVENT_PRECISE; + } + + switch (cs->exception_index) { + case HEX_EVENT_TRAP0: + if (env->cause_code == 0) { + qemu_log_mask(LOG_UNIMP, + "trap0 is unhandled, no semihosting available\n"); + } + + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 4, cs->exception_index); + break; + + case HEX_EVENT_TRAP1: + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 4, cs->exception_index); + break; + + case HEX_EVENT_TLB_MISS_X: + switch (env->cause_code) { + case HEX_CAUSE_TLBMISSX_CAUSE_NORMAL: + case HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE: + qemu_log_mask(CPU_LOG_MMU, + "TLB miss EX exception (0x%x) caught: " + "Cause code (0x%x) " + "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32 + ", BADVA = 0x%" PRIx32 "\n", + cs->exception_index, env->cause_code, env->threadId, + ARCH_GET_THREAD_REG(env, HEX_REG_PC), + ARCH_GET_SYSTEM_REG(env, HEX_SREG_BADVA)); + + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + break; + + default: + cpu_abort(cs, + "1:Hexagon exception %d/0x%x: " + "Unknown cause code %d/0x%x\n", + cs->exception_index, cs->exception_index, env->cause_code, + env->cause_code); + break; + } + break; + + case HEX_EVENT_TLB_MISS_RW: + switch (env->cause_code) { + case HEX_CAUSE_TLBMISSRW_CAUSE_READ: + case HEX_CAUSE_TLBMISSRW_CAUSE_WRITE: + qemu_log_mask(CPU_LOG_MMU, + "TLB miss RW exception (0x%x) caught: " + "Cause code (0x%x) " + "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32 + ", BADVA = 0x%" PRIx32 "\n", + cs->exception_index, env->cause_code, env->threadId, + env->gpr[HEX_REG_PC], + ARCH_GET_SYSTEM_REG(env, HEX_SREG_BADVA)); + + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */ + break; + + default: + cpu_abort(cs, + "2:Hexagon exception %d/0x%x: " + "Unknown cause code %d/0x%x\n", + cs->exception_index, cs->exception_index, env->cause_code, + env->cause_code); + break; + } + break; + + case HEX_EVENT_FPTRAP: + hexagon_ssr_set_cause(env, env->cause_code); + ARCH_SET_THREAD_REG(env, HEX_REG_PC, + ARCH_GET_SYSTEM_REG(env, HEX_SREG_EVB) | + (cs->exception_index << 2)); + break; + + case HEX_EVENT_DEBUG: + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + qemu_log_mask(LOG_UNIMP, "single-step exception is not handled\n"); + break; + + case HEX_EVENT_PRECISE: + switch (env->cause_code) { + case HEX_CAUSE_FETCH_NO_XPAGE: + case HEX_CAUSE_FETCH_NO_UPAGE: + case HEX_CAUSE_PRIV_NO_READ: + case HEX_CAUSE_PRIV_NO_UREAD: + case HEX_CAUSE_PRIV_NO_WRITE: + case HEX_CAUSE_PRIV_NO_UWRITE: + case HEX_CAUSE_MISALIGNED_LOAD: + case HEX_CAUSE_MISALIGNED_STORE: + case HEX_CAUSE_PC_NOT_ALIGNED: + qemu_log_mask(CPU_LOG_MMU, + "MMU permission exception (0x%x) caught: " + "Cause code (0x%x) " + "TID = 0x%" PRIx32 ", PC = 0x%" PRIx32 + ", BADVA = 0x%" PRIx32 "\n", + cs->exception_index, env->cause_code, env->threadId, + env->gpr[HEX_REG_PC], + ARCH_GET_SYSTEM_REG(env, HEX_SREG_BADVA)); + + + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + /* env->sreg[HEX_SREG_BADVA] is set when the exception is raised */ + break; + + case HEX_CAUSE_DOUBLE_EXCEPT: + case HEX_CAUSE_PRIV_USER_NO_SINSN: + case HEX_CAUSE_PRIV_USER_NO_GINSN: + case HEX_CAUSE_INVALID_OPCODE: + case HEX_CAUSE_NO_COPROC_ENABLE: + case HEX_CAUSE_NO_COPROC2_ENABLE: + case HEX_CAUSE_UNSUPORTED_HVX_64B: + case HEX_CAUSE_REG_WRITE_CONFLICT: + case HEX_CAUSE_VWCTRL_WINDOW_MISS: + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + break; + + case HEX_CAUSE_COPROC_LDST: + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + break; + + case HEX_CAUSE_STACK_LIMIT: + hexagon_ssr_set_cause(env, env->cause_code); + set_addresses(env, 0, cs->exception_index); + break; + + default: + cpu_abort(cs, + "3:Hexagon exception %d/0x%x: " + "Unknown cause code %d/0x%x\n", + cs->exception_index, cs->exception_index, env->cause_code, + env->cause_code); + break; + } + break; + + case HEX_EVENT_IMPRECISE: + qemu_log_mask(LOG_UNIMP, + "Imprecise exception: this case is not yet handled"); + break; + + default: + qemu_log_mask(LOG_UNIMP, + "Hexagon Unsupported exception 0x%x/0x%x\n", + cs->exception_index, env->cause_code); + break; + } + + cs->exception_index = HEX_EVENT_NONE; +} + +void register_trap_exception(CPUHexagonState *env, int traptype, int imm, + target_ulong PC) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = (traptype == 0) ? HEX_EVENT_TRAP0 : HEX_EVENT_TRAP1; + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); + + env->cause_code = imm; + env->gpr[HEX_REG_PC] = PC; + cpu_loop_exit(cs); +} +#endif From 189c35b64fc5dd8e951453f67424b63129436f20 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 17:59:42 -0700 Subject: [PATCH 069/109] target/hexagon: Implement exec_interrupt, set_irq Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ target/hexagon/cpu.h | 5 +++ 2 files changed, 80 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 0352cc5de858..5571b82cd51f 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -31,8 +31,10 @@ #include "hex_mmu.h" #ifndef CONFIG_USER_ONLY +#include "macros.h" #include "sys_macros.h" #include "qemu/main-loop.h" +#include "hex_interrupts.h" #endif static void hexagon_v66_cpu_init(Object *obj) { } @@ -275,9 +277,29 @@ static void hexagon_cpu_synchronize_from_tb(CPUState *cs, cpu_env(cs)->gpr[HEX_REG_PC] = tb->pc; } +#ifndef CONFIG_USER_ONLY +bool hexagon_thread_is_enabled(CPUHexagonState *env) +{ + target_ulong modectl = ARCH_GET_SYSTEM_REG(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + bool E_bit = thread_enabled_mask & (0x1 << env->threadId); + + return E_bit; +} +#endif + static bool hexagon_cpu_has_work(CPUState *cs) { +#ifndef CONFIG_USER_ONLY + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + return hexagon_thread_is_enabled(env) && + (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI + | CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK)); +#else return true; +#endif } static void hexagon_restore_state_to_opc(CPUState *cs, @@ -414,19 +436,72 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) mcc->parent_realize(dev, errp); } +#if !defined(CONFIG_USER_ONLY) +static void hexagon_cpu_set_irq(void *opaque, int irq, int level) +{ + HexagonCPU *cpu = opaque; + CPUHexagonState *env = &cpu->env; + + switch (irq) { + case HEXAGON_CPU_IRQ_0 ... HEXAGON_CPU_IRQ_7: + qemu_log_mask(CPU_LOG_INT, "%s: irq %d, level %d\n", + __func__, irq, level); + if (level) { + hex_raise_interrupts(env, 1 << irq, CPU_INTERRUPT_HARD); + } + break; + default: + g_assert_not_reached(); + } +} +#endif + + static void hexagon_cpu_init(Object *obj) { +#if !defined(CONFIG_USER_ONLY) + HexagonCPU *cpu = HEXAGON_CPU(obj); + qdev_init_gpio_in(DEVICE(cpu), hexagon_cpu_set_irq, 8); +#endif } #include "hw/core/tcg-cpu-ops.h" +#ifndef CONFIG_USER_ONLY + +static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + if (interrupt_request & CPU_INTERRUPT_TLB_UNLOCK) { + cs->halted = false; + cpu_reset_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK); + return true; + } + if (interrupt_request & CPU_INTERRUPT_K0_UNLOCK) { + cs->halted = false; + cpu_reset_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK); + return true; + } + if (interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI)) { + return hex_check_interrupts(env); + } + return false; +} + +#endif + static const TCGCPUOps hexagon_tcg_ops = { .initialize = hexagon_translate_init, .translate_code = hexagon_translate_code, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, .restore_state_to_opc = hexagon_restore_state_to_opc, +#if !defined(CONFIG_USER_ONLY) + .cpu_exec_interrupt = hexagon_cpu_exec_interrupt, +#endif /* !CONFIG_USER_ONLY */ }; + static void hexagon_cpu_class_init(ObjectClass *c, void *data) { HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c); diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 85d1d6cb2f0d..38384dbfd6c9 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -209,6 +209,11 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uintptr_t pc); #ifndef CONFIG_USER_ONLY +/* + * @return true if the @a thread_env hardware thread is + * not stopped. + */ +bool hexagon_thread_is_enabled(CPUHexagonState *thread_env); uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg); uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg); void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val); From a1e454dc4156f2fd6f699004a5cad03668a707c4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 18:36:52 -0700 Subject: [PATCH 070/109] FIXME: target/hexagon: Implement hexagon_tlb_fill() FIXME: this commit contains FIXMEs -> "slot" was partially deleted downstream, so... do we need it? Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 138 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 5571b82cd51f..a8731de0811c 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -467,7 +467,142 @@ static void hexagon_cpu_init(Object *obj) #include "hw/core/tcg-cpu-ops.h" -#ifndef CONFIG_USER_ONLY +#if !defined(CONFIG_USER_ONLY) +static bool get_physical_address(CPUHexagonState *env, hwaddr *phys, int *prot, + int *size, int32_t *excp, target_ulong address, + MMUAccessType access_type, int mmu_idx) + +{ + if (hexagon_cpu_mmu_enabled(env)) { + return hex_tlb_find_match(env, address, access_type, phys, prot, size, + excp, mmu_idx); + } else { + *phys = address & 0xFFFFFFFF; + *prot = PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC; + *size = TARGET_PAGE_SIZE; + return true; + } +} + +/* qemu seems to only want to know about TARGET_PAGE_SIZE pages */ +static void find_qemu_subpage(vaddr *addr, hwaddr *phys, int page_size) +{ + vaddr page_start = *addr & ~((vaddr)(page_size - 1)); + vaddr offset = ((*addr - page_start) / TARGET_PAGE_SIZE) * TARGET_PAGE_SIZE; + *addr = page_start + offset; + *phys += offset; +} + + +#define INVALID_BADVA 0xbadabada + +static void set_badva_regs(CPUHexagonState *env, target_ulong VA, int slot, + MMUAccessType access_type) +{ + ARCH_SET_SYSTEM_REG(env, HEX_SREG_BADVA, VA); + + if (access_type == MMU_INST_FETCH || slot == 0) { + ARCH_SET_SYSTEM_REG(env, HEX_SREG_BADVA0, VA); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_BADVA1, INVALID_BADVA); + SET_SSR_FIELD(env, SSR_V0, 1); + SET_SSR_FIELD(env, SSR_V1, 0); + SET_SSR_FIELD(env, SSR_BVS, 0); + } else if (slot == 1) { + ARCH_SET_SYSTEM_REG(env, HEX_SREG_BADVA0, INVALID_BADVA); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_BADVA1, VA); + SET_SSR_FIELD(env, SSR_V0, 0); + SET_SSR_FIELD(env, SSR_V1, 1); + SET_SSR_FIELD(env, SSR_BVS, 1); + } else { + g_assert_not_reached(); + } +} + +static void raise_tlbmiss_exception(CPUState *cs, target_ulong VA, int slot, + MMUAccessType access_type) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + set_badva_regs(env, VA, slot, access_type); + + switch (access_type) { + case MMU_INST_FETCH: + cs->exception_index = HEX_EVENT_TLB_MISS_X; + if ((VA & ~TARGET_PAGE_MASK) == 0) { + env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NEXTPAGE; + } else { + env->cause_code = HEX_CAUSE_TLBMISSX_CAUSE_NORMAL; + } + break; + case MMU_DATA_LOAD: + cs->exception_index = HEX_EVENT_TLB_MISS_RW; + env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_READ; + break; + case MMU_DATA_STORE: + cs->exception_index = HEX_EVENT_TLB_MISS_RW; + env->cause_code = HEX_CAUSE_TLBMISSRW_CAUSE_WRITE; + break; + } +} + +static void raise_perm_exception(CPUState *cs, target_ulong VA, int slot, + MMUAccessType access_type, int32_t excp); +static void raise_perm_exception(CPUState *cs, target_ulong VA, int slot, + MMUAccessType access_type, int32_t excp) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + + set_badva_regs(env, VA, slot, access_type); + cs->exception_index = excp; +} + +static const char *access_type_names[] = { "MMU_DATA_LOAD ", "MMU_DATA_STORE", + "MMU_INST_FETCH" }; + +static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX", + "MMU_KERNEL_IDX" }; + +static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, bool probe, + uintptr_t retaddr) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + int slot = 0 /* This is broken FIXME */; + hwaddr phys; + int prot = 0; + int page_size = 0; + int32_t excp = 0; + bool ret = 0; + + qemu_log_mask( + CPU_LOG_MMU, + "%s: tid = 0x%x, pc = 0x%08" PRIx32 ", vaddr = 0x%08" VADDR_PRIx + ", size = %d, %s,\tprobe = %d, %s\n", + __func__, env->threadId, env->gpr[HEX_REG_PC], address, size, + access_type_names[access_type], probe, mmu_idx_names[mmu_idx]); + ret = get_physical_address(env, &phys, &prot, &page_size, &excp, address, + access_type, mmu_idx); + if (ret) { + if (!excp) { + find_qemu_subpage(&address, &phys, page_size); + tlb_set_page(cs, address, phys, prot, mmu_idx, TARGET_PAGE_SIZE); + return ret; + } else { + raise_perm_exception(cs, address, slot, access_type, excp); + do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC], + retaddr); + } + } + if (probe) { + return false; + } + raise_tlbmiss_exception(cs, address, slot, access_type); + do_raise_exception(env, cs->exception_index, env->gpr[HEX_REG_PC], retaddr); +} + static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { @@ -498,6 +633,7 @@ static const TCGCPUOps hexagon_tcg_ops = { .restore_state_to_opc = hexagon_restore_state_to_opc, #if !defined(CONFIG_USER_ONLY) .cpu_exec_interrupt = hexagon_cpu_exec_interrupt, + .tlb_fill = hexagon_tlb_fill, #endif /* !CONFIG_USER_ONLY */ }; From 5df06afed41bb1816790fa08a213aba7a713be6f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 18:42:58 -0700 Subject: [PATCH 071/109] target/hexagon: Implement siad inst siad is the 'Set interrupt auto disable' instruction. Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 95e32017e488..a473ce2685ed 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1377,7 +1377,15 @@ void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) void HELPER(siad)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + uint32_t ipendad; + uint32_t iad; + + BQL_LOCK_GUARD(); + ipendad = READ_SREG(HEX_SREG_IPENDAD); + iad = fGET_FIELD(ipendad, IPENDAD_IAD); + fSET_FIELD(ipendad, IPENDAD_IAD, iad | mask); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_IPENDAD, ipendad); + hex_interrupt_update(env); } void HELPER(swi)(CPUHexagonState *env, uint32_t mask) From 24f206910fc0f4e2a9d31cf11a2c5bcbb7e3e7e9 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 18:51:44 -0700 Subject: [PATCH 072/109] target/hexagon: Implement hexagon_resume_threads() Signed-off-by: Brian Cain --- target/hexagon/cpu_helper.c | 59 +++++++++++++++++++++++++++++++++++++ target/hexagon/cpu_helper.h | 1 + target/hexagon/op_helper.c | 3 +- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 2f6bbbf5e0f8..884ef203d6d2 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -125,6 +125,65 @@ void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC) cpu_interrupt(cs, CPU_INTERRUPT_HALT); } +static void hexagon_resume_thread(CPUHexagonState *env) +{ + CPUState *cs = env_cpu(env); + clear_wait_mode(env); + /* + * The wait instruction keeps the PC pointing to itself + * so that it has an opportunity to check for interrupts. + * + * When we come out of wait mode, adjust the PC to the + * next executable instruction. + */ + env->gpr[HEX_REG_PC] = env->wait_next_pc; + cs = env_cpu(env); + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); + cs->halted = false; + cs->exception_index = HEX_EVENT_NONE; + qemu_cpu_kick(cs); +} + +void hexagon_resume_threads(CPUHexagonState *current_env, uint32_t mask) +{ + CPUState *cs; + CPUHexagonState *env; + bool found; + + g_assert(bql_locked()); + int nr_cpus = 0; + CPU_FOREACH(cs) { + nr_cpus++; + } + + for (int htid = 0; htid < nr_cpus; ++htid) { + if (!(mask & (0x1 << htid))) { + continue; + } + + found = false; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + env = &cpu->env; + if (env->threadId == htid) { + found = true; + break; + } + } + if (!found) { + cpu_abort(cs, "Error: Hexagon: Illegal resume thread mask 0x%x", + mask); + } + + if (get_exe_mode(env) != HEX_EXE_MODE_WAIT) { + /* this thread not currently in wait mode */ + continue; + } + hexagon_resume_thread(env); + } +} + + static MMVector VRegs[VECTOR_UNIT_MAX][NUM_VREGS]; static MMQReg QRegs[VECTOR_UNIT_MAX][NUM_QREGS]; diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index a70df013341d..c6c783e2f7c7 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -21,6 +21,7 @@ void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause); void hexagon_start_threads(CPUHexagonState *env, uint32_t mask); void hexagon_stop_thread(CPUHexagonState *env); void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC); +void hexagon_resume_threads(CPUHexagonState *env, uint32_t mask); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index a473ce2685ed..1f12724996ab 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1474,7 +1474,8 @@ void HELPER(wait)(CPUHexagonState *env, target_ulong PC) void HELPER(resume)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + hexagon_resume_threads(env, mask); } uint32_t HELPER(getimask)(CPUHexagonState *env, uint32_t tid) From 93a8b32bffc74dc42d7865b1bcb7bcd389fe2d0b Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 18:54:12 -0700 Subject: [PATCH 073/109] target/hexagon: Implement setprio, resched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware-assisted scheduler helps manage tasks on the run queue and interrupt steering. This instruction is defined in the Qualcomm Hexagon V71 Programmer's Reference Manual - https://docs.qualcomm.com/bundle/publicresource/80-N2040-51_REV_AB_Hexagon_V71_ProgrammerS_Reference_Manual.pdf See §11.9.2 SYSTEM MONITOR. Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 1f12724996ab..91deb4329199 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1463,6 +1463,57 @@ void HELPER(stop)(CPUHexagonState *env) hexagon_stop_thread(env); } +static inline QEMU_ALWAYS_INLINE void resched(CPUHexagonState *env) +{ + uint32_t schedcfg; + uint32_t schedcfg_en; + int int_number; + CPUState *cs; + uint32_t lowest_th_prio = 0; /* 0 is highest prio */ + uint32_t bestwait_reg; + uint32_t best_prio; + + BQL_LOCK_GUARD(); + qemu_log_mask(CPU_LOG_INT, "%s: check resched\n", __func__); + schedcfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SCHEDCFG); + schedcfg_en = GET_FIELD(SCHEDCFG_EN, schedcfg); + int_number = GET_FIELD(SCHEDCFG_INTNO, schedcfg); + + if (!schedcfg_en) { + return; + } + + CPU_FOREACH(cs) { + HexagonCPU *thread = HEXAGON_CPU(cs); + CPUHexagonState *thread_env = &(thread->env); + uint32_t th_prio = GET_FIELD( + STID_PRIO, ARCH_GET_SYSTEM_REG(thread_env, HEX_SREG_STID)); + if (!hexagon_thread_is_enabled(thread_env)) { + continue; + } + + lowest_th_prio = (lowest_th_prio > th_prio) + ? lowest_th_prio + : th_prio; + } + + bestwait_reg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_BESTWAIT); + best_prio = GET_FIELD(BESTWAIT_PRIO, bestwait_reg); + + /* + * If the lowest priority thread is lower priority than the + * value in the BESTWAIT register, we must raise the reschedule + * interrupt on the lowest priority thread. + */ + if (lowest_th_prio > best_prio) { + qemu_log_mask(CPU_LOG_INT, + "%s: raising resched int %d, cur PC 0x%08x\n", __func__, + int_number, ARCH_GET_THREAD_REG(env, HEX_REG_PC)); + SET_SYSTEM_FIELD(env, HEX_SREG_BESTWAIT, BESTWAIT_PRIO, 0x1ff); + hex_raise_interrupts(env, 1 << int_number, CPU_INTERRUPT_SWI); + } +} + void HELPER(wait)(CPUHexagonState *env, target_ulong PC) { BQL_LOCK_GUARD(); @@ -1714,6 +1765,20 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg) void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio) { + CPUState *cs; + + BQL_LOCK_GUARD(); + CPU_FOREACH(cs) { + HexagonCPU *found_cpu = HEXAGON_CPU(cs); + CPUHexagonState *found_env = &found_cpu->env; + if (thread == found_env->threadId) { + SET_SYSTEM_FIELD(found_env, HEX_SREG_STID, STID_PRIO, prio); + qemu_log_mask(CPU_LOG_INT, "%s: tid %d prio = 0x%x\n", + __func__, found_env->threadId, prio); + resched(env); + return; + } + } g_assert_not_reached(); } From f0c832196190d37e943c0b16fd8b140d2af9df6e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 20:27:35 -0700 Subject: [PATCH 074/109] target/hexagon: Add sysemu_ops Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index a8731de0811c..3d5164b66926 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -604,6 +604,11 @@ static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size, } +#include "hw/core/sysemu-cpu-ops.h" + +static const struct SysemuCPUOps hexagon_sysemu_ops = { +}; + static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { HexagonCPU *cpu = HEXAGON_CPU(cs); @@ -634,6 +639,8 @@ static const TCGCPUOps hexagon_tcg_ops = { #if !defined(CONFIG_USER_ONLY) .cpu_exec_interrupt = hexagon_cpu_exec_interrupt, .tlb_fill = hexagon_tlb_fill, + .cpu_exec_halt = hexagon_cpu_has_work, + .do_interrupt = hexagon_cpu_do_interrupt, #endif /* !CONFIG_USER_ONLY */ }; @@ -662,7 +669,12 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->gdb_stop_before_watchpoint = true; cc->gdb_core_xml_file = "hexagon-core.xml"; cc->disas_set_info = hexagon_cpu_disas_set_info; +#ifndef CONFIG_USER_ONLY + cc->sysemu_ops = &hexagon_sysemu_ops; +#endif +#ifdef CONFIG_TCG cc->tcg_ops = &hexagon_tcg_ops; +#endif } #ifndef CONFIG_USER_ONLY From ba898c12aadc889f24f4c7c292839d0d8471bb8f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 20:28:34 -0700 Subject: [PATCH 075/109] target/hexagon: Add cpu_get_phys_page_debug() Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 3d5164b66926..5ac24c0f30f8 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -493,6 +493,25 @@ static void find_qemu_subpage(vaddr *addr, hwaddr *phys, int page_size) *phys += offset; } +static hwaddr hexagon_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env = &cpu->env; + hwaddr phys_addr; + int prot; + int page_size = 0; + int32_t excp = 0; + int mmu_idx = MMU_KERNEL_IDX; + + if (get_physical_address(env, &phys_addr, &prot, &page_size, &excp, + addr, 0, mmu_idx)) { + find_qemu_subpage(&addr, &phys_addr, page_size); + return phys_addr; + } + + return -1; +} + #define INVALID_BADVA 0xbadabada @@ -607,6 +626,7 @@ static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size, #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps hexagon_sysemu_ops = { + .get_phys_page_debug = hexagon_cpu_get_phys_page_debug, }; static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request) From 223548b84c99cbbcb4bee11c7bfdf020486109bd Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 20:29:19 -0700 Subject: [PATCH 076/109] target/hexagon: Add vmsd Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 1 + target/hexagon/internal.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 5ac24c0f30f8..c0d9ce1dc2a0 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -691,6 +691,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->disas_set_info = hexagon_cpu_disas_set_info; #ifndef CONFIG_USER_ONLY cc->sysemu_ops = &hexagon_sysemu_ops; + dc->vmsd = &vmstate_hexagon_cpu; #endif #ifdef CONFIG_TCG cc->tcg_ops = &hexagon_tcg_ops; diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 3458d7994a43..34a26350dfb5 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -43,4 +43,9 @@ void G_NORETURN do_raise_exception(CPUHexagonState *env, #define hexagon_cpu_mmu_enabled(env) \ GET_SYSCFG_FIELD(SYSCFG_MMUEN, ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG)) +#ifndef CONFIG_USER_ONLY +extern const VMStateDescription vmstate_hexagon_cpu; +#endif + + #endif From 52621618b64a1ed78e1ce648d862ddee0d6e9f3a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 20:33:40 -0700 Subject: [PATCH 077/109] target/hexagon: Add exec-start-addr prop Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 7 ++----- target/hexagon/cpu.h | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index c0d9ce1dc2a0..9364914dd8df 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -65,6 +65,7 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr, 0xffffffffULL), DEFINE_PROP_UINT32("hvx-contexts", HexagonCPU, hvx_contexts, 0), + DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffffULL), #endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, @@ -361,8 +362,6 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) mmu_reset(env); ARCH_SET_SYSTEM_REG(env, HEX_SREG_HTID, cs->cpu_index); hexagon_cpu_soft_reset(env); - memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); - memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); env->threadId = cs->cpu_index; env->tlb_lock_state = HEX_LOCK_UNLOCKED; env->k0_lock_state = HEX_LOCK_UNLOCKED; @@ -371,6 +370,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) env->next_PC = 0; env->wait_next_pc = 0; env->cause_code = -1; + ARCH_SET_THREAD_REG(env, HEX_REG_PC, cpu->boot_addr); #endif } @@ -413,9 +413,6 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY CPUHexagonState *env = cpu_env(cs); hex_mmu_realize(env); -#endif - cpu_reset(cs); -#ifndef CONFIG_USER_ONLY if (cs->cpu_index == 0) { env->g_sreg = g_new0(target_ulong, NUM_SREGS); env->g_pcycle_base = g_malloc0(sizeof(*env->g_pcycle_base)); diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 38384dbfd6c9..950f1e0ea377 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -195,6 +195,7 @@ struct ArchCPU { uint32_t num_tlbs; uint32_t l2vic_base_addr; uint32_t hvx_contexts; + uint32_t boot_addr; #endif }; From 95a2d24c34d44056108ce57a3c81fc068415e17c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 21:18:54 -0700 Subject: [PATCH 078/109] target/hexagon: Add hexagon_cpu_mmu_index() Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 23 +++++++++++++++++++++ target/hexagon/cpu_helper.c | 41 +++++++++++++++++++++++++++++++++++++ target/hexagon/cpu_helper.h | 1 + 3 files changed, 65 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 9364914dd8df..44913d23bd85 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -661,6 +661,28 @@ static const TCGCPUOps hexagon_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; +static int hexagon_cpu_mmu_index(CPUState *cs, bool ifetch) +{ +#ifndef CONFIG_USER_ONLY + BQL_LOCK_GUARD(); + CPUHexagonState *env = cpu_env(cs); + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + uint8_t mmuen = GET_SYSCFG_FIELD(SYSCFG_MMUEN, syscfg); + if (!mmuen) { + return MMU_KERNEL_IDX; + } + + int cpu_mode = get_cpu_mode(env); + if (cpu_mode == HEX_CPU_MODE_MONITOR) { + return MMU_KERNEL_IDX; + } else if (cpu_mode == HEX_CPU_MODE_GUEST) { + return MMU_GUEST_IDX; + } +#endif + + return MMU_USER_IDX; +} + static void hexagon_cpu_class_init(ObjectClass *c, void *data) { @@ -678,6 +700,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) cc->class_by_name = hexagon_cpu_class_by_name; cc->has_work = hexagon_cpu_has_work; + cc->mmu_index = hexagon_cpu_mmu_index; cc->dump_state = hexagon_dump_state; cc->set_pc = hexagon_cpu_set_pc; cc->get_pc = hexagon_cpu_get_pc; diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 884ef203d6d2..c1f88396df71 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -421,4 +421,45 @@ void hexagon_stop_thread(CPUHexagonState *env) } } +static int sys_in_monitor_mode_ssr(uint32_t ssr) +{ + if ((GET_SSR_FIELD(SSR_EX, ssr) != 0) || + ((GET_SSR_FIELD(SSR_EX, ssr) == 0) && (GET_SSR_FIELD(SSR_UM, ssr) == 0))) + return 1; + return 0; +} + +static int sys_in_guest_mode_ssr(uint32_t ssr) +{ + if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) && + (GET_SSR_FIELD(SSR_UM, ssr) != 0) && + (GET_SSR_FIELD(SSR_GM, ssr) != 0)) + return 1; + return 0; +} + +static int sys_in_user_mode_ssr(uint32_t ssr) +{ + if ((GET_SSR_FIELD(SSR_EX, ssr) == 0) && + (GET_SSR_FIELD(SSR_UM, ssr) != 0) && + (GET_SSR_FIELD(SSR_GM, ssr) == 0)) + return 1; + return 0; +} + +int get_cpu_mode(CPUHexagonState *env) + +{ + uint32_t ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + + if (sys_in_monitor_mode_ssr(ssr)) { + return HEX_CPU_MODE_MONITOR; + } else if (sys_in_guest_mode_ssr(ssr)) { + return HEX_CPU_MODE_GUEST; + } else if (sys_in_user_mode_ssr(ssr)) { + return HEX_CPU_MODE_USER; + } + return HEX_CPU_MODE_MONITOR; +} + #endif diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index c6c783e2f7c7..e49a2a9dc5d1 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -15,6 +15,7 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t); void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t); void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old); +int get_cpu_mode(CPUHexagonState *env); int get_exe_mode(CPUHexagonState *env); void clear_wait_mode(CPUHexagonState *env); void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause); From c9686271b23f25d4169b56dd6c187e6937510862 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 4 Sep 2024 21:22:23 -0700 Subject: [PATCH 079/109] FIXME: why remove this unreachable? Signed-off-by: Brian Cain --- target/hexagon/decode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 23deba2426f8..4e764fca1a00 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -489,7 +489,6 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding) insn->iclass = iclass_bits(encoding); return 1; } - g_assert_not_reached(); } else { uint32_t iclass = get_duplex_iclass(encoding); unsigned int slot0_subinsn = get_slot0_subinsn(encoding); @@ -512,6 +511,11 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding) } g_assert_not_reached(); } + /* + * invalid/unrecognized opcode; return 1 and let gen_insn() raise an + * exception when it sees this empty insn. + */ + return 1; } static void decode_add_endloop_insn(Insn *insn, int loopnum) From 28c8c090ae19b9d1457e48875ea94d548e419b92 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 5 Sep 2024 18:25:32 -0700 Subject: [PATCH 080/109] FIXME: target/hexagon: handle .new values FIXME: What is it about sysemu/supervisor mode that causes this to be required now? Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 20ac3462e256..05232f978db9 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -397,6 +397,12 @@ def helper_arg(self): self.reg_tcg(), f"{self.helper_arg_type()} {self.helper_arg_name()}" ) + def from_subtype(self, subtype): + if subtype == "": + return self + raise Exception( + f"unknown subtype '{subtype}' on generic Register class") + # # Every register is either Single or Pair or Hvx @@ -1269,11 +1275,15 @@ def is_new_reg(tag, regid): f"{regid}N" in semdict[tag] and \ f"{regid}V" not in semdict[tag] -def get_register(tag, regtype, regid): +def get_register(tag, regtype, regid, subtype=""): regid = f"{regtype}{regid}" is_new = is_new_reg(tag, regid) - reg = new_registers[regid] if is_new else registers[regid] - return reg + try: + reg = new_registers[regid] if is_new else registers[regid] + except KeyError: + raise Exception(f"Unknown {'new ' if is_new else ''}register {regid}" +\ + f"from '{tag}' with syntax '{semdict[tag]}'") from None + return reg.from_subtype(subtype) def helper_ret_type(tag, regs): ## If there is a scalar result, it is the return type From 018dcf7723acfbf9becf4e506d28351c61d165ba Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 5 Sep 2024 18:27:04 -0700 Subject: [PATCH 081/109] target/hexagon: Decode trap1, rte as COF Also: handle rte instructions at the end of the packet. Signed-off-by: Brian Cain --- target/hexagon/decode.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 4e764fca1a00..471a3d1dac0a 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -193,6 +193,8 @@ static bool decode_opcode_can_jump(int opcode) if ((GET_ATTRIB(opcode, A_JUMP)) || (GET_ATTRIB(opcode, A_CALL)) || (opcode == J2_trap0) || + (opcode == J2_trap1) || + (opcode == J2_rte) || (opcode == J2_pause)) { /* Exception to A_JUMP attribute */ if (opcode == J4_hintjumpr) { @@ -371,6 +373,18 @@ static void decode_shuffle_for_execution(Packet *packet) break; } } + /* + * And at the very very very end, move any RTE's, since they update + * user/supervisor mode. + */ +#if !defined(CONFIG_USER_ONLY) + for (i = 0; i < last_insn; i++) { + if (packet->insn[i].opcode == J2_rte) { + decode_send_insn_to(packet, i, last_insn); + break; + } + } +#endif } static void From 6ec1673b23b389b1d57868009f811737f6d942d1 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sat, 2 Dec 2023 10:09:53 -0800 Subject: [PATCH 082/109] hw/hexagon: Add machine configs for sysemu Co-authored-by: Sid Manning Signed-off-by: Brian Cain --- MAINTAINERS | 2 + hw/Kconfig | 1 + hw/hexagon/Kconfig | 6 ++ hw/hexagon/hexagon_dsp.c | 171 +++++++++++++++++++++++++++++++ hw/hexagon/machine_configs.h.inc | 69 +++++++++++++ hw/hexagon/meson.build | 5 + hw/meson.build | 1 + include/hw/hexagon/hexagon.h | 151 +++++++++++++++++++++++++++ target/hexagon/machine.c | 1 - 9 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 hw/hexagon/Kconfig create mode 100644 hw/hexagon/hexagon_dsp.c create mode 100644 hw/hexagon/machine_configs.h.inc create mode 100644 hw/hexagon/meson.build create mode 100644 include/hw/hexagon/hexagon.h diff --git a/MAINTAINERS b/MAINTAINERS index d0a744c8f6c8..5b04bccbb166 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -230,6 +230,8 @@ M: Brian Cain S: Supported F: target/hexagon/ F: hw/intc/l2vic.[ch] +F: hw/hexagon/ +F: include/hw/hexagon/ X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/hw/Kconfig b/hw/Kconfig index 1b4e9bb07f7d..b363d4561a50 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -65,6 +65,7 @@ source sparc/Kconfig source sparc64/Kconfig source tricore/Kconfig source xtensa/Kconfig +source hexagon/Kconfig # Symbols used by multiple targets config TEST_DEVICES diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig new file mode 100644 index 000000000000..3fc14756e6df --- /dev/null +++ b/hw/hexagon/Kconfig @@ -0,0 +1,6 @@ +config HEX_DSP + bool + default y + depends on HEXAGON && TCG + imply PTIMER + select L2VIC # Vector PIC diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c new file mode 100644 index 000000000000..8d249884fba8 --- /dev/null +++ b/hw/hexagon/hexagon_dsp.c @@ -0,0 +1,171 @@ +/* + * Hexagon DSP Subsystem emulation. This represents a generic DSP + * subsystem with few peripherals, like the Compute DSP. + * + * Copyright (c) 2020-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "exec/address-spaces.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "hw/hexagon/hexagon.h" +#include "hw/loader.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/log.h" +#include "elf.h" +#include "cpu.h" +#include "include/migration/cpu.h" +#include "include/system/system.h" +#include "target/hexagon/internal.h" +#include "system/reset.h" + +#include "machine_configs.h.inc" + +static void hex_symbol_callback(const char *st_name, int st_info, + uint64_t st_value, uint64_t st_size) +{ +} + +/* Board init. */ +static struct hexagon_board_boot_info hexagon_binfo; + +static void hexagon_load_kernel(HexagonCPU *cpu) +{ + uint64_t pentry; + long kernel_size; + + kernel_size = load_elf_ram_sym(hexagon_binfo.kernel_filename, NULL, NULL, + NULL, &pentry, NULL, NULL, + &hexagon_binfo.kernel_elf_flags, 0, EM_HEXAGON, 0, 0, + &address_space_memory, false, hex_symbol_callback); + + if (kernel_size <= 0) { + error_report("no kernel file '%s'", + hexagon_binfo.kernel_filename); + exit(1); + } + + qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", pentry); +} + +static void hexagon_init_bootstrap(MachineState *machine, HexagonCPU *cpu) +{ + if (machine->kernel_filename) { + hexagon_load_kernel(cpu); + } +} + +static void do_cpu_reset(void *opaque) +{ + HexagonCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + cpu_reset(cs); +} + +static void hexagon_common_init(MachineState *machine, Rev_t rev, + hexagon_machine_config *m_cfg) +{ + memset(&hexagon_binfo, 0, sizeof(hexagon_binfo)); + if (machine->kernel_filename) { + hexagon_binfo.ram_size = machine->ram_size; + hexagon_binfo.kernel_filename = machine->kernel_filename; + } + + machine->enable_graphics = 0; + + MemoryRegion *address_space = get_system_memory(); + + MemoryRegion *sram = g_new(MemoryRegion, 1); + memory_region_init_ram(sram, NULL, "ddr.ram", + machine->ram_size, &error_fatal); + memory_region_add_subregion(address_space, 0x0, sram); + + Error **errp = NULL; + + for (int i = 0; i < machine->smp.cpus; i++) { + HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type)); + qemu_register_reset(do_cpu_reset, cpu); + + /* + * CPU #0 is the only CPU running at boot, others must be + * explicitly enabled via start instruction. + */ + qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); + qdev_prop_set_uint32(DEVICE(cpu), "l2vic-base-addr", m_cfg->l2vic_base); + + if (i == 0) { + hexagon_init_bootstrap(machine, cpu); + DeviceState *l2vic_dev; + l2vic_dev = sysbus_create_varargs("l2vic", m_cfg->l2vic_base, + /* IRQ#, Evnt#,CauseCode */ + qdev_get_gpio_in(DEVICE(cpu), 0), + qdev_get_gpio_in(DEVICE(cpu), 1), + qdev_get_gpio_in(DEVICE(cpu), 2), + qdev_get_gpio_in(DEVICE(cpu), 3), + qdev_get_gpio_in(DEVICE(cpu), 4), + qdev_get_gpio_in(DEVICE(cpu), 5), + qdev_get_gpio_in(DEVICE(cpu), 6), + qdev_get_gpio_in(DEVICE(cpu), 7), + NULL); + sysbus_mmio_map(SYS_BUS_DEVICE(l2vic_dev), 1, + m_cfg->cfgtable.fastl2vic_base << 16); + } + + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + return; + } + + } +} + +static void init_mc(MachineClass *mc) +{ + mc->block_default_type = IF_SD; + mc->default_ram_size = 4 * GiB; + mc->no_parallel = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_serial = 1; + mc->no_sdcard = 1; + mc->is_default = false; + mc->max_cpus = 8; +} + +/* ----------------------------------------------------------------- */ +/* Core-specific configuration settings are defined below this line. */ +/* Config table values defined in machine_configs.h.inc */ +/* ----------------------------------------------------------------- */ + +static void v66g_1024_config_init(MachineState *machine) +{ + hexagon_common_init(machine, v66_rev, &v66g_1024); +} + +static void v66g_1024_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Hexagon V66G_1024"; + mc->init = v66g_1024_config_init; + init_mc(mc); + mc->is_default = true; + mc->default_cpu_type = TYPE_HEXAGON_CPU_V66; + mc->default_cpus = 4; +} + +static const TypeInfo hexagon_machine_types[] = { + { + .name = MACHINE_TYPE_NAME("V66G_1024"), + .parent = TYPE_MACHINE, + .class_init = v66g_1024_init, + }, +}; + +DEFINE_TYPES(hexagon_machine_types) diff --git a/hw/hexagon/machine_configs.h.inc b/hw/hexagon/machine_configs.h.inc new file mode 100644 index 000000000000..fe5ec5f6a09e --- /dev/null +++ b/hw/hexagon/machine_configs.h.inc @@ -0,0 +1,69 @@ +/* + * Hexagon Baseboard System emulation. + * + * Copyright (c) 2020-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +static hexagon_machine_config v66g_1024 = { + .cfgbase = 0xd8180000, + .l2tcm_size = 0x00000000, + .l2vic_base = 0xfc910000, + .l2vic_size = 0x00001000, + .csr_base = 0xfc900000, + .qtmr_rg0 = 0xfc921000, + .qtmr_rg1 = 0xfc922000, + .cfgtable = { + .l2tcm_base = 0x0000d800, + .reserved0 = 0x0000d400, + .subsystem_base = 0x00002000, + .etm_base = 0x0000d805, + .l2cfg_base = 0x0000d81a, + .reserved1 = 0x00000000, + .l1s0_base = 0x0000d820, + .axi2_lowaddr = 0x00003000, + .streamer_base = 0x00000000, + .reserved2 = 0x0000d819, + .fastl2vic_base = 0x0000d81e, + .jtlb_size_entries = 0x00000080, + .coproc_present = 0x00000001, + .ext_contexts = 0x00000004, + .vtcm_base = 0x0000d820, + .vtcm_size_kb = 0x00000100, + .l2tag_size = 0x00000400, + .l2ecomem_size = 0x00000400, + .thread_enable_mask = 0x0000000f, + .eccreg_base = 0x0000d81f, + .l2line_size = 0x00000080, + .tiny_core = 0x00000000, + .l2itcm_size = 0x00000000, + .l2itcm_base = 0x0000d820, + .reserved3 = 0x00000000, + .dtm_present = 0x00000000, + .dma_version = 0x00000000, + .hvx_vec_log_length = 0x00000080, + .core_id = 0x00000000, + .core_count = 0x00000000, + .coproc2_reg0 = 0x00000000, + .coproc2_reg1 = 0x00000000, + .v2x_mode = 0x00000000, + .coproc2_reg2 = 0x00000000, + .coproc2_reg3 = 0x00000000, + .coproc2_reg4 = 0x00000000, + .coproc2_reg5 = 0x00000000, + .coproc2_reg6 = 0x00000000, + .coproc2_reg7 = 0x00000000, + .acd_preset = 0x00000000, + .mnd_preset = 0x00000000, + .l1d_size_kb = 0x00000000, + .l1i_size_kb = 0x00000000, + .l1d_write_policy = 0x00000000, + .vtcm_bank_width = 0x00000000, + .reserved4 = 0x00000000, + .reserved5 = 0x00000000, + .reserved6 = 0x00000000, + .coproc2_cvt_mpy_size = 0x00000000, + .axi3_lowaddr = 0x00000000, + }, +}; + diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build new file mode 100644 index 000000000000..2ef3dbcd3492 --- /dev/null +++ b/hw/hexagon/meson.build @@ -0,0 +1,5 @@ +hexagon_ss = ss.source_set() +hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c',)) + +hw_arch += {'hexagon': hexagon_ss} + diff --git a/hw/meson.build b/hw/meson.build index b827c82c5d7b..91969d6fec18 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -64,3 +64,4 @@ subdir('sparc') subdir('sparc64') subdir('tricore') subdir('xtensa') +subdir('hexagon') diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h new file mode 100644 index 000000000000..0afaac3b1f85 --- /dev/null +++ b/include/hw/hexagon/hexagon.h @@ -0,0 +1,151 @@ +/* + * Hexagon Baseboard System emulation. + * + * Copyright (c) 2020-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef HW_HEXAGON_H +#define HW_HEXAGON_H + +#include "exec/memory.h" + +struct hexagon_board_boot_info { + uint64_t ram_size; + const char *kernel_filename; + uint32_t kernel_elf_flags; +}; + +typedef enum { + unknown_rev = 0, + v66_rev = 0xa666, + v67_rev = 0x2667, + v68_rev = 0x8d68, + v69_rev = 0x8c69, + v71_rev = 0x8c71, + v73_rev = 0x8c73, + v73m_rev = 0xcc73, +} Rev_t; +#define HEXAGON_LATEST_REV v73 +#define HEXAGON_LATEST_REV_UPPER V73 + +/* + * Config table address bases represent bits [35:16]. + */ +#define HEXAGON_CFG_ADDR_BASE(addr) (((addr) >> 16) & 0x0fffff) + +#define HEXAGON_CFGSPACE_ENTRIES (128) + +typedef union { + struct { + /* Base address of L2TCM space */ + uint32_t l2tcm_base; + uint32_t reserved0; + /* Base address of subsystem space */ + uint32_t subsystem_base; + /* Base address of ETM space */ + uint32_t etm_base; + /* Base address of L2 configuration space */ + uint32_t l2cfg_base; + uint32_t reserved1; + /* Base address of L1S */ + uint32_t l1s0_base; + /* Base address of AXI2 */ + uint32_t axi2_lowaddr; + /* Base address of streamer base */ + uint32_t streamer_base; + uint32_t reserved2; + /* Base address of fast L2VIC */ + uint32_t fastl2vic_base; + /* Number of entries in JTLB */ + uint32_t jtlb_size_entries; + /* Coprocessor type */ + uint32_t coproc_present; + /* Number of extension execution contexts available */ + uint32_t ext_contexts; + /* Base address of Hexagon Vector Tightly Coupled Memory (VTCM) */ + uint32_t vtcm_base; + /* Size of VTCM (in KB) */ + uint32_t vtcm_size_kb; + /* L2 tag size */ + uint32_t l2tag_size; + /* Amount of physical L2 memory in released version */ + uint32_t l2ecomem_size; + /* Hardware threads available on the core */ + uint32_t thread_enable_mask; + /* Base address of the ECC registers */ + uint32_t eccreg_base; + /* L2 line size */ + uint32_t l2line_size; + /* Small Core processor (also implies audio extension) */ + uint32_t tiny_core; + /* Size of L2TCM */ + uint32_t l2itcm_size; + /* Base address of L2-ITCM */ + uint32_t l2itcm_base; + uint32_t reserved3; + /* DTM is present */ + uint32_t dtm_present; + /* Version of the DMA */ + uint32_t dma_version; + /* Native HVX vector length in log of bytes */ + uint32_t hvx_vec_log_length; + /* Core ID of the multi-core */ + uint32_t core_id; + /* Number of multi-core cores */ + uint32_t core_count; + uint32_t coproc2_reg0; + uint32_t coproc2_reg1; + /* Supported HVX vector length */ + uint32_t v2x_mode; + uint32_t coproc2_reg2; + uint32_t coproc2_reg3; + uint32_t coproc2_reg4; + uint32_t coproc2_reg5; + uint32_t coproc2_reg6; + uint32_t coproc2_reg7; + /* Voltage droop mitigation technique parameter */ + uint32_t acd_preset; + /* Voltage droop mitigation technique parameter */ + uint32_t mnd_preset; + /* L1 data cache size (in KB) */ + uint32_t l1d_size_kb; + /* L1 instruction cache size in (KB) */ + uint32_t l1i_size_kb; + /* L1 data cache write policy: see HexagonL1WritePolicy */ + uint32_t l1d_write_policy; + /* VTCM bank width */ + uint32_t vtcm_bank_width; + uint32_t reserved4; + uint32_t reserved5; + uint32_t reserved6; + uint32_t coproc2_cvt_mpy_size; + uint32_t consistency_domain; + uint32_t capacity_domain; + uint32_t axi3_lowaddr; + uint32_t coproc2_int8_subcolumns; + uint32_t corecfg_present; + uint32_t coproc2_fp16_acc_exp; + uint32_t AXIM2_secondary_base; + }; + uint32_t raw[HEXAGON_CFGSPACE_ENTRIES]; +} hexagon_config_table; + +typedef struct { + /* Base address of config table */ + uint32_t cfgbase; + /* Size of L2 TCM */ + uint32_t l2tcm_size; + /* Base address of L2VIC */ + uint32_t l2vic_base; + /* Size of L2VIC region */ + uint32_t l2vic_size; + /* QTimer csr base */ + uint32_t csr_base; + uint32_t qtmr_rg0; + uint32_t qtmr_rg1; + hexagon_config_table cfgtable; +} hexagon_machine_config; + +#endif diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c index 460a0c7f24c3..bcad5bb241e5 100644 --- a/target/hexagon/machine.c +++ b/target/hexagon/machine.c @@ -81,7 +81,6 @@ const VMStateDescription vmstate_hexagon_cpu = { VMSTATE_UINT64(env.t_cycle_count, HexagonCPU), VMSTATE_POINTER(env.g_pcycle_base, HexagonCPU, 0, vmstate_info_uint64_ptr, uint64_t *), - VMSTATE_END_OF_LIST() }, }; From 9df8d78dedf4d29cfa2fd9d499780cb5921dd439 Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Wed, 18 Dec 2024 09:23:33 -0800 Subject: [PATCH 083/109] hw/hexagon: Add support for cfgbase Signed-off-by: Sid Manning --- hw/hexagon/hexagon_dsp.c | 16 ++++++++++++++++ target/hexagon/cpu.c | 7 +++++++ target/hexagon/cpu.h | 1 + 3 files changed, 24 insertions(+) diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 8d249884fba8..0ad90bcb056b 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -82,6 +82,12 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, MemoryRegion *address_space = get_system_memory(); + MemoryRegion *config_table_rom = g_new(MemoryRegion, 1); + memory_region_init_rom(config_table_rom, NULL, "config_table.rom", + sizeof(m_cfg->cfgtable), &error_fatal); + memory_region_add_subregion(address_space, m_cfg->cfgbase, + config_table_rom); + MemoryRegion *sram = g_new(MemoryRegion, 1); memory_region_init_ram(sram, NULL, "ddr.ram", machine->ram_size, &error_fatal); @@ -99,6 +105,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, */ qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); qdev_prop_set_uint32(DEVICE(cpu), "l2vic-base-addr", m_cfg->l2vic_base); + qdev_prop_set_uint32(DEVICE(cpu), "config-table-addr", m_cfg->cfgbase); if (i == 0) { hexagon_init_bootstrap(machine, cpu); @@ -123,6 +130,15 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, } } + + hexagon_config_table *config_table = &m_cfg->cfgtable; + + config_table->subsystem_base = HEXAGON_CFG_ADDR_BASE(m_cfg->csr_base); + + rom_add_blob_fixed_as("config_table.rom", config_table, + sizeof(*config_table), m_cfg->cfgbase, + &address_space_memory); + } static void init_mc(MachineClass *mc) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 44913d23bd85..ceef313fd267 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -66,6 +66,8 @@ static const Property hexagon_cpu_properties[] = { 0xffffffffULL), DEFINE_PROP_UINT32("hvx-contexts", HexagonCPU, hvx_contexts, 0), DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffffULL), + DEFINE_PROP_UINT64("config-table-addr", HexagonCPU, config_table_addr, + 0xffffffffULL), #endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, @@ -331,6 +333,8 @@ void hexagon_cpu_soft_reset(CPUHexagonState *env) } #endif + +#define HEXAGON_CFG_ADDR_BASE(addr) (((addr) >> 16) & 0x0fffff) static void hexagon_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -371,6 +375,9 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) env->wait_next_pc = 0; env->cause_code = -1; ARCH_SET_THREAD_REG(env, HEX_REG_PC, cpu->boot_addr); + ARCH_SET_SYSTEM_REG(env, HEX_SREG_CFGBASE, + HEXAGON_CFG_ADDR_BASE(cpu->config_table_addr)); + #endif } diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 950f1e0ea377..0fb629156af3 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -196,6 +196,7 @@ struct ArchCPU { uint32_t l2vic_base_addr; uint32_t hvx_contexts; uint32_t boot_addr; + uint64_t config_table_addr; #endif }; From 206e1cbf9d028eb42495acfb5472bc0e90e676dc Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Oct 2024 13:43:16 -0700 Subject: [PATCH 084/109] qapi: Add hexagon machine to QAPI Signed-off-by: Brian Cain --- qapi/machine.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/machine.json b/qapi/machine.json index a6b8795b09ed..a7070bad4d52 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -33,7 +33,7 @@ # Since: 3.0 ## { 'enum' : 'SysEmuTarget', - 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'hppa', 'i386', + 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'hexagon', 'hppa', 'i386', 'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', From 72126268aba51a89f01c4eee78cebdd2c50ff217 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sat, 2 Dec 2023 10:09:53 -0800 Subject: [PATCH 085/109] target/hexagon: add build config for softmmu Signed-off-by: Brian Cain --- MAINTAINERS | 1 + configs/devices/hexagon-softmmu/default.mak | 7 +++++++ configs/targets/hexagon-softmmu.mak | 5 +++++ target/Kconfig | 1 + target/hexagon/Kconfig | 2 ++ target/hexagon/meson.build | 9 +++++++++ 6 files changed, 25 insertions(+) create mode 100644 configs/devices/hexagon-softmmu/default.mak create mode 100644 configs/targets/hexagon-softmmu.mak create mode 100644 target/hexagon/Kconfig diff --git a/MAINTAINERS b/MAINTAINERS index 5b04bccbb166..6848ceb960fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -238,6 +238,7 @@ F: linux-user/hexagon/ F: tests/tcg/hexagon/ F: disas/hexagon.c F: configs/targets/hexagon-linux-user/default.mak +F: configs/devices/hexagon-softmmu/default.mak F: docker/dockerfiles/debian-hexagon-cross.docker F: gdb-xml/hexagon*.xml F: docs/system/target-hexagon.rst diff --git a/configs/devices/hexagon-softmmu/default.mak b/configs/devices/hexagon-softmmu/default.mak new file mode 100644 index 000000000000..08e709aea72f --- /dev/null +++ b/configs/devices/hexagon-softmmu/default.mak @@ -0,0 +1,7 @@ +# Default configuration for hexagon-softmmu + +# Uncomment the following lines to disable these optional devices: + +# Boards are selected by default, uncomment to keep out of the build. +# CONFIG_HEX_DSP=y +# CONFIG_L2VIC=y diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak new file mode 100644 index 000000000000..8b1fdbf79d55 --- /dev/null +++ b/configs/targets/hexagon-softmmu.mak @@ -0,0 +1,5 @@ +# Default configuration for hexagon-softmmu + +TARGET_ARCH=hexagon +TARGET_SUPPORTS_MTTCG=y +TARGET_XML_FILES=gdb-xml/hexagon-core.xml gdb-xml/hexagon-hvx.xml gdb-xml/hexagon-sys.xml diff --git a/target/Kconfig b/target/Kconfig index d0c7b59d9c71..37781146b9bb 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -16,6 +16,7 @@ source sh4/Kconfig source sparc/Kconfig source tricore/Kconfig source xtensa/Kconfig +source hexagon/Kconfig config TARGET_BIG_ENDIAN bool diff --git a/target/hexagon/Kconfig b/target/hexagon/Kconfig new file mode 100644 index 000000000000..7e556f350633 --- /dev/null +++ b/target/hexagon/Kconfig @@ -0,0 +1,2 @@ +config HEXAGON + bool diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index aa729a3683f1..d2b56b9e65e5 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -245,6 +245,7 @@ decodetree_trans_funcs_generated = custom_target( command: [python, files('gen_trans_funcs.py'), semantics_generated, '@OUTPUT@'], ) hexagon_ss.add(decodetree_trans_funcs_generated) +hexagon_softmmu_ss = ss.source_set() hexagon_ss.add(files( 'cpu.c', @@ -264,6 +265,13 @@ hexagon_ss.add(files( 'mmvec/system_ext_mmvec.c', )) +hexagon_softmmu_ss.add(files( + 'hex_mmu.c', + 'hex_interrupts.c', + 'hexswi.c', + 'machine.c', +)) + # # Step 4.5 # We use flex/bison based idef-parser to generate TCG code for a lot @@ -401,3 +409,4 @@ analyze_funcs_generated = custom_target( hexagon_ss.add(analyze_funcs_generated) target_arch += {'hexagon': hexagon_ss} +target_system_arch += {'hexagon': hexagon_softmmu_ss} From a72e283b6272194d1211ee166e0b86e9cf61790c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 8 Sep 2024 11:56:26 -0700 Subject: [PATCH 086/109] target/hexagon: Implement hexagon_find_last_irq() Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 91deb4329199..9de8f437a682 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1636,7 +1636,13 @@ static void modify_syscfg(CPUHexagonState *env, uint32_t val) static uint32_t hexagon_find_last_irq(CPUHexagonState *env, uint32_t vid) { - g_assert_not_reached(); + int offset = (vid == HEX_SREG_VID) ? L2VIC_VID_0 : L2VIC_VID_1; + CPUState *cs = env_cpu(env); + HexagonCPU *cpu = HEXAGON_CPU(cs); + const hwaddr pend_mem = cpu->l2vic_base_addr + offset; + uint32_t irq; + cpu_physical_memory_read(pend_mem, &irq, sizeof(irq)); + return irq; } static void hexagon_read_timer(CPUHexagonState *env, uint32_t *low, From 2d3237baa709b33fd99196d2c353b998f0b122ed Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 09:34:18 -0700 Subject: [PATCH 087/109] target/hexagon: Implement modify_ssr, resched, pending_interrupt Signed-off-by: Brian Cain --- target/hexagon/helper.h | 3 +++ target/hexagon/op_helper.c | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 730eaf8b9a0f..3df663baeb05 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -129,4 +129,7 @@ DEF_HELPER_1(stop, void, env) DEF_HELPER_2(wait, void, env, i32) DEF_HELPER_2(resume, void, env, i32) DEF_HELPER_2(nmi, void, env, i32) +DEF_HELPER_1(resched, void, env) +DEF_HELPER_3(modify_ssr, void, env, i32, i32) +DEF_HELPER_1(pending_interrupt, void, env) #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 9de8f437a682..62ecf76639d1 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1177,6 +1177,15 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV, return RxxV; } +#ifndef CONFIG_USER_ONLY +void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t new, uint32_t old) +{ + BQL_LOCK_GUARD(); + hexagon_modify_ssr(env, new, old); +} +#endif + + /* Histogram instructions */ void HELPER(vhist)(CPUHexagonState *env) @@ -1514,6 +1523,11 @@ static inline QEMU_ALWAYS_INLINE void resched(CPUHexagonState *env) } } +void HELPER(resched)(CPUHexagonState *env) +{ + resched(env); +} + void HELPER(wait)(CPUHexagonState *env, target_ulong PC) { BQL_LOCK_GUARD(); @@ -1792,6 +1806,12 @@ void HELPER(nmi)(CPUHexagonState *env, uint32_t thread_mask) { g_assert_not_reached(); } + +void HELPER(pending_interrupt)(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + hex_interrupt_update(env); +} #endif From 0c23a77e7b71cd9dc9363b25658fc00c163c479f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 10:07:30 -0700 Subject: [PATCH 088/109] target/hexagon: Add pkt_ends_tb to translation Signed-off-by: Brian Cain --- target/hexagon/translate.c | 99 +++++++++++++++++++++++++++++++++++++- target/hexagon/translate.h | 1 + 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 060df6e5eb62..475726388a3f 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -259,6 +259,18 @@ static bool check_for_attrib(Packet *pkt, int attrib) return false; } +#ifndef CONFIG_USER_ONLY +static bool check_for_opcode(Packet *pkt, uint16_t opcode) +{ + for (int i = 0; i < pkt->num_insns; i++) { + if (pkt->insn[i].opcode == opcode) { + return true; + } + } + return false; +} +#endif + static bool need_slot_cancelled(Packet *pkt) { /* We only need slot_cancelled for conditional store instructions */ @@ -272,6 +284,90 @@ static bool need_slot_cancelled(Packet *pkt) return false; } +#ifndef CONFIG_USER_ONLY +static bool sreg_write_to_global(int reg_num) +{ + return reg_num == HEX_SREG_SSR || + reg_num == HEX_SREG_STID || + reg_num == HEX_SREG_IMASK || + reg_num == HEX_SREG_IPENDAD || + reg_num == HEX_SREG_BESTWAIT || + reg_num == HEX_SREG_SCHEDCFG; +} + +static bool has_sreg_write_to_global(Packet const *pkt) +{ + for (int i = 0; i < pkt->num_insns; i++) { + Insn const *insn = &pkt->insn[i]; + uint16_t opcode = insn->opcode; + if (opcode == Y2_tfrsrcr) { + /* Write to a single sreg */ + int reg_num = insn->regno[0]; + if (sreg_write_to_global(reg_num)) { + return true; + } + } else if (opcode == Y4_tfrspcp) { + /* Write to a sreg pair */ + int reg_num = insn->regno[0]; + if (sreg_write_to_global(reg_num)) { + return true; + } + if (sreg_write_to_global(reg_num + 1)) { + return true; + } + } + } + return false; +} +#endif + +static bool pkt_ends_tb(Packet *pkt) +{ + if (pkt->pkt_has_cof) { + return true; + } +#ifndef CONFIG_USER_ONLY + /* System mode instructions that end TLB */ + if (check_for_opcode(pkt, Y2_swi) || + check_for_opcode(pkt, Y2_cswi) || + check_for_opcode(pkt, Y2_ciad) || + check_for_opcode(pkt, Y4_siad) || + check_for_opcode(pkt, Y2_wait) || + check_for_opcode(pkt, Y2_resume) || + check_for_opcode(pkt, Y2_iassignw) || + check_for_opcode(pkt, Y2_setimask) || + check_for_opcode(pkt, Y4_nmi) || + check_for_opcode(pkt, Y2_setprio) || + check_for_opcode(pkt, Y2_start) || + check_for_opcode(pkt, Y2_stop) || + check_for_opcode(pkt, Y2_k0lock) || + check_for_opcode(pkt, Y2_k0unlock) || + check_for_opcode(pkt, Y2_tlblock) || + check_for_opcode(pkt, Y2_tlbunlock) || + check_for_opcode(pkt, Y2_break) || + check_for_opcode(pkt, Y2_isync) || + check_for_opcode(pkt, Y2_syncht) || + check_for_opcode(pkt, Y2_tlbp) || + check_for_opcode(pkt, Y2_tlbw) || + check_for_opcode(pkt, Y5_ctlbw) || + check_for_opcode(pkt, Y5_tlbasidi)) { + return true; + } + + /* + * Check for sreg writes that would end the TB + */ + if (check_for_attrib(pkt, A_IMPLICIT_WRITES_SSR)) { + return true; + } + if (has_sreg_write_to_global(pkt)) { + return true; + } +#endif + return false; +} + + static bool need_next_PC(DisasContext *ctx) { Packet *pkt = ctx->pkt; @@ -473,6 +569,7 @@ static void gen_start_packet(DisasContext *ctx) tcg_gen_movi_tl(hex_slot_cancelled, 0); } ctx->branch_taken = NULL; + ctx->pkt_ends_tb = pkt_ends_tb(pkt); if (pkt->pkt_has_cof) { ctx->branch_taken = tcg_temp_new(); if (pkt->pkt_has_multi_cof) { @@ -927,7 +1024,7 @@ static void gen_commit_packet(DisasContext *ctx) pkt->vhist_insn->generate(ctx); } - if (pkt->pkt_has_cof) { + if (ctx->pkt_ends_tb || ctx->base.is_jmp == DISAS_NORETURN) { gen_end_tb(ctx); } } diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 9bc4b3ce8b33..c9533fee1f5c 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -84,6 +84,7 @@ typedef struct DisasContext { TCGv branch_taken; TCGv dczero_addr; bool pcycle_enabled; + bool pkt_ends_tb; uint32_t num_cycles; } DisasContext; From d819f503f5760f835a36d97e67cc832942161850 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 09:35:18 -0700 Subject: [PATCH 089/109] FIXME target/hexagon: Add next_PC, {s,g}reg writes FIXME more details about the content and motivation for other changes beyond need next pc Signed-off-by: Brian Cain --- target/hexagon/cpu.h | 2 +- target/hexagon/genptr.c | 7 +- target/hexagon/translate.c | 142 ++++++++++++++++++++++++++++++++----- target/hexagon/translate.h | 2 + 4 files changed, 132 insertions(+), 21 deletions(-) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 0fb629156af3..e48575d375dd 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -143,9 +143,9 @@ typedef struct CPUArchState { hex_lock_state_t k0_lock_state; target_ulong tlb_lock_count; target_ulong k0_lock_count; - target_ulong next_PC; CPUHexagonTLBContext *hex_tlb; #endif + target_ulong next_PC; target_ulong new_value_usr; MemLog mem_log_stores[STORES_MAX]; diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 5554c9515c4d..afc7e5f3a5ab 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -634,14 +634,15 @@ static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr, tcg_gen_brcondi_tl(cond, pred, 0, pred_false); } + TCGv PC_wr = ctx->need_next_pc ? hex_next_PC : hex_gpr[HEX_REG_PC]; if (ctx->pkt->pkt_has_multi_cof) { /* If there are multiple branches in a packet, ignore the second one */ - tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC], + tcg_gen_movcond_tl(TCG_COND_NE, PC_wr, ctx->branch_taken, tcg_constant_tl(0), - hex_gpr[HEX_REG_PC], addr); + PC_wr, addr); tcg_gen_movi_tl(ctx->branch_taken, 1); } else { - tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr); + tcg_gen_mov_tl(PC_wr, addr); } if (cond != TCG_COND_ALWAYS) { diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 475726388a3f..d4b22acb729f 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -49,6 +49,7 @@ static const AnalyzeInsn opcode_analyze[XX_LAST_OPCODE] = { TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; TCGv hex_pred[NUM_PREGS]; TCGv hex_slot_cancelled; +TCGv hex_next_PC; TCGv hex_new_value_usr; TCGv hex_store_addr[STORES_MAX]; TCGv hex_store_width[STORES_MAX]; @@ -61,12 +62,14 @@ TCGv_i64 hex_cycle_count; TCGv hex_vstore_addr[VSTORES_MAX]; TCGv hex_vstore_size[VSTORES_MAX]; TCGv hex_vstore_pending[VSTORES_MAX]; +static bool need_next_PC(DisasContext *ctx); #ifndef CONFIG_USER_ONLY TCGv hex_greg[NUM_GREGS]; TCGv hex_t_sreg[NUM_SREGS]; TCGv_ptr hex_g_sreg_ptr; TCGv hex_g_sreg[NUM_SREGS]; +TCGv hex_cause_code; #endif static const char * const hexagon_prednames[] = { @@ -184,6 +187,9 @@ static void gen_end_tb(DisasContext *ctx) gen_exec_counters(ctx); + if (ctx->need_next_pc) { + tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); + } if (ctx->branch_cond != TCG_COND_NEVER) { if (ctx->branch_cond != TCG_COND_ALWAYS) { TCGLabel *skip = gen_new_label(); @@ -371,18 +377,24 @@ static bool pkt_ends_tb(Packet *pkt) static bool need_next_PC(DisasContext *ctx) { Packet *pkt = ctx->pkt; - - /* Check for conditional control flow or HW loop end */ - for (int i = 0; i < pkt->num_insns; i++) { - uint16_t opcode = pkt->insn[i].opcode; - if (GET_ATTRIB(opcode, A_CONDEXEC) && GET_ATTRIB(opcode, A_COF)) { - return true; - } - if (GET_ATTRIB(opcode, A_HWLOOP0_END) || - GET_ATTRIB(opcode, A_HWLOOP1_END)) { - return true; + if (pkt->pkt_has_cof || ctx->pkt_ends_tb) { + for (int i = 0; i < pkt->num_insns; i++) { + uint16_t opcode = pkt->insn[i].opcode; + if ((GET_ATTRIB(opcode, A_CONDEXEC) && GET_ATTRIB(opcode, A_COF)) || + GET_ATTRIB(opcode, A_HWLOOP0_END) || + GET_ATTRIB(opcode, A_HWLOOP1_END)) { + return true; + } } } + /* + * We end the TB on some instructions that do not change the flow (for + * other reasons). In these cases, we must set pc too, as the insn won't + * do it themselves. + */ + if (ctx->pkt_ends_tb && !check_for_attrib(pkt, A_COF)) { + return true; + } return false; } @@ -523,7 +535,14 @@ static void analyze_packet(DisasContext *ctx) static void gen_start_packet(DisasContext *ctx) { Packet *pkt = ctx->pkt; +#ifndef CONFIG_USER_ONLY + target_ulong next_PC = (check_for_opcode(pkt, Y2_k0lock) || + check_for_opcode(pkt, Y2_tlblock)) ? + ctx->base.pc_next : + ctx->base.pc_next + pkt->encod_pkt_size_in_bytes; +#else target_ulong next_PC = ctx->base.pc_next + pkt->encod_pkt_size_in_bytes; +#endif int i; /* Clear out the disassembly context */ @@ -531,6 +550,10 @@ static void gen_start_packet(DisasContext *ctx) ctx->reg_log_idx = 0; bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS); bitmap_zero(ctx->predicated_regs, TOTAL_PER_THREAD_REGS); +#ifndef CONFIG_USER_ONLY + ctx->greg_log_idx = 0; + ctx->sreg_log_idx = 0; +#endif ctx->preg_log_idx = 0; bitmap_zero(ctx->pregs_written, NUM_PREGS); ctx->future_vregs_idx = 0; @@ -563,21 +586,41 @@ static void gen_start_packet(DisasContext *ctx) * gen phase, so clear it again. */ bitmap_zero(ctx->pregs_written, NUM_PREGS); +#ifndef CONFIG_USER_ONLY + for (i = 0; i < NUM_SREGS; i++) { + ctx->t_sreg_new_value[i] = NULL; + } + for (i = 0; i < ctx->sreg_log_idx; i++) { + int reg_num = ctx->sreg_log[i]; + if (reg_num < HEX_SREG_GLB_START) { + ctx->t_sreg_new_value[reg_num] = tcg_temp_new(); + tcg_gen_mov_tl(ctx->t_sreg_new_value[reg_num], hex_t_sreg[reg_num]); + } + } + for (i = 0; i < NUM_GREGS; i++) { + ctx->greg_new_value[i] = NULL; + } + for (i = 0; i < ctx->greg_log_idx; i++) { + int reg_num = ctx->greg_log[i]; + ctx->greg_new_value[reg_num] = tcg_temp_new(); + } +#endif /* Initialize the runtime state for packet semantics */ if (need_slot_cancelled(pkt)) { tcg_gen_movi_tl(hex_slot_cancelled, 0); } ctx->branch_taken = NULL; - ctx->pkt_ends_tb = pkt_ends_tb(pkt); if (pkt->pkt_has_cof) { ctx->branch_taken = tcg_temp_new(); - if (pkt->pkt_has_multi_cof) { - tcg_gen_movi_tl(ctx->branch_taken, 0); - } - if (need_next_PC(ctx)) { - tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], next_PC); - } + } + if (pkt->pkt_has_multi_cof) { + tcg_gen_movi_tl(ctx->branch_taken, 0); + } + ctx->pkt_ends_tb = pkt_ends_tb(pkt); + ctx->need_next_pc = need_next_PC(ctx); + if (ctx->need_next_pc) { + tcg_gen_movi_tl(hex_next_PC, next_PC); } /* Preload the predicated registers into get_result_gpr(ctx, i) */ @@ -713,6 +756,59 @@ static void gen_reg_writes(DisasContext *ctx) } } +#ifndef CONFIG_USER_ONLY +static void gen_greg_writes(DisasContext *ctx) +{ + int i; + + for (i = 0; i < ctx->greg_log_idx; i++) { + int reg_num = ctx->greg_log[i]; + + tcg_gen_mov_tl(hex_greg[reg_num], ctx->greg_new_value[reg_num]); + } +} + + +static void gen_sreg_writes(DisasContext *ctx) +{ + int i; + + TCGv old_reg = tcg_temp_new(); + for (i = 0; i < ctx->sreg_log_idx; i++) { + int reg_num = ctx->sreg_log[i]; + + if (reg_num == HEX_SREG_SSR) { + tcg_gen_mov_tl(old_reg, hex_t_sreg[reg_num]); + tcg_gen_mov_tl(hex_t_sreg[reg_num], ctx->t_sreg_new_value[reg_num]); + gen_helper_modify_ssr(tcg_env, ctx->t_sreg_new_value[reg_num], + old_reg); + /* This can change processor state, so end the TB */ + ctx->base.is_jmp = DISAS_NORETURN; + } else if ((reg_num == HEX_SREG_STID) || + (reg_num == HEX_SREG_IMASK) || + (reg_num == HEX_SREG_IPENDAD)) { + if (reg_num < HEX_SREG_GLB_START) { + tcg_gen_mov_tl(old_reg, hex_t_sreg[reg_num]); + tcg_gen_mov_tl(hex_t_sreg[reg_num], + ctx->t_sreg_new_value[reg_num]); + } + /* This can change the interrupt state, so end the TB */ + gen_helper_pending_interrupt(tcg_env); + ctx->base.is_jmp = DISAS_NORETURN; + } else if ((reg_num == HEX_SREG_BESTWAIT) || + (reg_num == HEX_SREG_SCHEDCFG)) { + /* This can trigger resched interrupt, so end the TB */ + gen_helper_resched(tcg_env); + ctx->base.is_jmp = DISAS_NORETURN; + } + + if (reg_num < HEX_SREG_GLB_START) { + tcg_gen_mov_tl(hex_t_sreg[reg_num], ctx->t_sreg_new_value[reg_num]); + } + } +} +#endif + static void gen_pred_writes(DisasContext *ctx) { /* Early exit if not needed or the log is empty */ @@ -1012,6 +1108,10 @@ static void gen_commit_packet(DisasContext *ctx) process_store_log(ctx); gen_reg_writes(ctx); +#if !defined(CONFIG_USER_ONLY) + gen_greg_writes(ctx); + gen_sreg_writes(ctx); +#endif gen_pred_writes(ctx); if (pkt->pkt_has_hvx) { gen_commit_hvx(ctx); @@ -1073,6 +1173,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP); ctx->short_circuit = hex_cpu->short_circuit; ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED); + ctx->need_next_pc = false; } static void hexagon_tr_tb_start(DisasContextBase *db, CPUState *cpu) @@ -1201,6 +1302,13 @@ void hexagon_translate_init(void) offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64"); hex_cycle_count = tcg_global_mem_new_i64(tcg_env, offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count"); +#ifndef CONFIG_USER_ONLY + hex_cause_code = tcg_global_mem_new(tcg_env, + offsetof(CPUHexagonState, cause_code), "cause_code"); +#endif + hex_next_PC = tcg_global_mem_new(tcg_env, + offsetof(CPUHexagonState, next_PC), "next_PC"); + for (i = 0; i < STORES_MAX; i++) { snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i); hex_store_addr[i] = tcg_global_mem_new(tcg_env, diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index c9533fee1f5c..ad1a2f404534 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -85,6 +85,7 @@ typedef struct DisasContext { TCGv dczero_addr; bool pcycle_enabled; bool pkt_ends_tb; + bool need_next_pc; uint32_t num_cycles; } DisasContext; @@ -306,6 +307,7 @@ static inline void ctx_log_qreg_read(DisasContext *ctx, } extern TCGv hex_gpr[TOTAL_PER_THREAD_REGS]; +extern TCGv hex_next_PC; extern TCGv hex_pred[NUM_PREGS]; extern TCGv hex_slot_cancelled; extern TCGv hex_new_value_usr; From 4ace7fa6f7fa9ecbf4575b1d2da00300fa7d8a0a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 09:42:54 -0700 Subject: [PATCH 090/109] target/hexagon: s/pkt_has_store/pkt_has_scalar_store To remove any confusion with HVX or other potential store instructions, we'll qualify this context var with "scalar". Signed-off-by: Brian Cain --- target/hexagon/decode.c | 4 ++-- target/hexagon/gen_helper_funcs.py | 2 +- target/hexagon/genptr.c | 3 ++- target/hexagon/idef-parser/README.rst | 2 +- target/hexagon/idef-parser/parser-helpers.c | 4 ++-- target/hexagon/insn.h | 4 ++-- target/hexagon/macros.h | 8 ++++---- target/hexagon/op_helper.c | 4 ++-- target/hexagon/translate.c | 9 +++++---- 9 files changed, 21 insertions(+), 19 deletions(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 471a3d1dac0a..a5073330b849 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -238,9 +238,9 @@ static void decode_set_insn_attr_fields(Packet *pkt) if (GET_ATTRIB(opcode, A_SCALAR_STORE) && !GET_ATTRIB(opcode, A_MEMSIZE_0B)) { if (pkt->insn[i].slot == 0) { - pkt->pkt_has_store_s0 = true; + pkt->pkt_has_scalar_store_s0 = true; } else { - pkt->pkt_has_store_s1 = true; + pkt->pkt_has_scalar_store_s1 = true; } } } diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py index dd8ab6059855..32e3bac74625 100755 --- a/target/hexagon/gen_helper_funcs.py +++ b/target/hexagon/gen_helper_funcs.py @@ -69,7 +69,7 @@ def gen_helper_function(f, tag, tagregs, tagimms): if hex_common.need_slot(tag): if "A_LOAD" in hex_common.attribdict[tag]: f.write(hex_common.code_fmt(f"""\ - bool pkt_has_store_s1 = slotval & 0x1; + bool pkt_has_scalar_store_s1 = slotval & 0x1; """)) f.write(hex_common.code_fmt(f"""\ uint32_t slot = slotval >> 1; diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index afc7e5f3a5ab..f38968271b17 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -558,7 +558,8 @@ static inline void gen_store_conditional8(DisasContext *ctx, #ifndef CONFIG_HEXAGON_IDEF_PARSER static TCGv gen_slotval(DisasContext *ctx) { - int slotval = (ctx->pkt->pkt_has_store_s1 & 1) | (ctx->insn->slot << 1); + int slotval = + (ctx->pkt->pkt_has_scalar_store_s1 & 1) | (ctx->insn->slot << 1); return tcg_constant_tl(slotval); } #endif diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst index 7199177ee33e..235e3debee3c 100644 --- a/target/hexagon/idef-parser/README.rst +++ b/target/hexagon/idef-parser/README.rst @@ -637,7 +637,7 @@ tinycode for the Hexagon ``add`` instruction :: ---- 00021094 - mov_i32 pkt_has_store_s1,$0x0 + mov_i32 pkt_has_scalar_store_s1,$0x0 add_i32 tmp0,r2,r2 mov_i32 loc2,tmp0 mov_i32 new_r1,loc2 diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c index a7dcd85fe43d..3316c230f8a5 100644 --- a/target/hexagon/idef-parser/parser-helpers.c +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -1725,7 +1725,7 @@ void gen_cancel(Context *c, YYLTYPE *locp) void gen_load_cancel(Context *c, YYLTYPE *locp) { - OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_scalar_store_s1) {\n"); OUT(c, locp, "ctx->s1_store_processed = false;\n"); OUT(c, locp, "process_store(ctx, 1);\n"); OUT(c, locp, "}\n"); @@ -1750,7 +1750,7 @@ void gen_load(Context *c, YYLTYPE *locp, HexValue *width, /* Lookup the effective address EA */ find_variable(c, locp, ea, ea); - OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n"); + OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_scalar_store_s1) {\n"); OUT(c, locp, "probe_noshuf_load(", ea, ", ", width, ", ctx->mem_idx);\n"); OUT(c, locp, "process_store(ctx, 1);\n"); OUT(c, locp, "}\n"); diff --git a/target/hexagon/insn.h b/target/hexagon/insn.h index 24dcf7fe9f38..5d59430da9e1 100644 --- a/target/hexagon/insn.h +++ b/target/hexagon/insn.h @@ -66,8 +66,8 @@ struct Packet { bool pkt_has_dczeroa; - bool pkt_has_store_s0; - bool pkt_has_store_s1; + bool pkt_has_scalar_store_s0; + bool pkt_has_scalar_store_s1; bool pkt_has_hvx; Insn *vhist_insn; diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index afbbe8e26524..06c1dd2f407e 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -82,7 +82,7 @@ */ #define CHECK_NOSHUF(VA, SIZE) \ do { \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ probe_noshuf_load(VA, SIZE, ctx->mem_idx); \ process_store(ctx, 1); \ } \ @@ -93,11 +93,11 @@ TCGLabel *noshuf_label = gen_new_label(); \ tcg_gen_brcondi_tl(TCG_COND_EQ, PRED, 0, noshuf_label); \ GET_EA; \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ probe_noshuf_load(EA, SIZE, ctx->mem_idx); \ } \ gen_set_label(noshuf_label); \ - if (insn->slot == 0 && ctx->pkt->pkt_has_store_s1) { \ + if (insn->slot == 0 && ctx->pkt->pkt_has_scalar_store_s1) { \ process_store(ctx, 1); \ } \ } while (0) @@ -524,7 +524,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #define fLOAD(NUM, SIZE, SIGN, EA, DST) \ do { \ - check_noshuf(env, pkt_has_store_s1, slot, EA, SIZE, GETPC()); \ + check_noshuf(env, pkt_has_scalar_store_s1, slot, EA, SIZE, GETPC()); \ DST = (size##SIZE##SIGN##_t)MEM_LOAD##SIZE(env, EA, GETPC()); \ } while (0) #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 62ecf76639d1..fb6bf7724a02 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -491,11 +491,11 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask) * If the load is in slot 0 and there is a store in slot1 (that * wasn't cancelled), we have to do the store first. */ -static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1, +static void check_noshuf(CPUHexagonState *env, bool pkt_has_scalar_store_s1, uint32_t slot, target_ulong vaddr, int size, uintptr_t ra) { - if (slot == 0 && pkt_has_store_s1 && + if (slot == 0 && pkt_has_scalar_store_s1 && ((env->slot_cancelled & (1 << 1)) == 0)) { probe_read(env, vaddr, size, MMU_USER_IDX, ra); commit_store(env, 1, ra); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index d4b22acb729f..0764999178c2 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -913,11 +913,11 @@ static void process_store_log(DisasContext *ctx) * the memory accesses overlap. */ Packet *pkt = ctx->pkt; - if (pkt->pkt_has_store_s1) { + if (pkt->pkt_has_scalar_store_s1) { g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, 1); } - if (pkt->pkt_has_store_s0) { + if (pkt->pkt_has_scalar_store_s0) { g_assert(!pkt->pkt_has_dczeroa); process_store(ctx, 0); } @@ -1044,8 +1044,9 @@ static void gen_commit_packet(DisasContext *ctx) * involved in committing the packet. */ Packet *pkt = ctx->pkt; - bool has_store_s0 = pkt->pkt_has_store_s0; - bool has_store_s1 = (pkt->pkt_has_store_s1 && !ctx->s1_store_processed); + bool has_store_s0 = pkt->pkt_has_scalar_store_s0; + bool has_store_s1 = + (pkt->pkt_has_scalar_store_s1 && !ctx->s1_store_processed); bool has_hvx_store = pkt_has_hvx_store(pkt); if (pkt->pkt_has_dczeroa) { /* From aebf62b918619fc69f1f04d50662f801c0f269f9 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 10:48:04 -0700 Subject: [PATCH 091/109] target/hexagon: Add implicit sysreg writes Signed-off-by: Brian Cain --- target/hexagon/translate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 0764999178c2..ef42a2f8f812 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -426,6 +426,16 @@ static void mark_implicit_reg_write(DisasContext *ctx, int attrib, int rnum) } } +#ifndef CONFIG_USER_ONLY +static void mark_implicit_sreg_write(DisasContext *ctx, int attrib, int snum) +{ + uint16_t opcode = ctx->insn->opcode; + if (GET_ATTRIB(opcode, attrib)) { + ctx_log_sreg_write(ctx, snum); + } +} +#endif + static void mark_implicit_reg_writes(DisasContext *ctx) { mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_FP, HEX_REG_FP); @@ -437,6 +447,12 @@ static void mark_implicit_reg_writes(DisasContext *ctx) mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1); mark_implicit_reg_write(ctx, A_IMPLICIT_WRITES_USR, HEX_REG_USR); mark_implicit_reg_write(ctx, A_FPOP, HEX_REG_USR); + +#ifndef CONFIG_USER_ONLY + mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SGP0, HEX_SREG_SGP0); + mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SGP1, HEX_SREG_SGP1); + mark_implicit_sreg_write(ctx, A_IMPLICIT_WRITES_SSR, HEX_SREG_SSR); +#endif } static void mark_implicit_pred_write(DisasContext *ctx, int attrib, int pnum) From 4433c21de3324c1424e306ed71b823337d229476 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 9 Sep 2024 10:54:48 -0700 Subject: [PATCH 092/109] FIXME target/hexagon: Omit A_SCALAR_STORE from cancelled FIXME: c2b33d0be998bf539953f1dad0aa0d1cc8d9d069 introduced this, so why don't we want/need it anymore? What breaks without this change? Signed-off-by: Brian Cain --- target/hexagon/translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index ef42a2f8f812..f529ac2ff319 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -282,8 +282,7 @@ static bool need_slot_cancelled(Packet *pkt) /* We only need slot_cancelled for conditional store instructions */ for (int i = 0; i < pkt->num_insns; i++) { uint16_t opcode = pkt->insn[i].opcode; - if (GET_ATTRIB(opcode, A_CONDEXEC) && - GET_ATTRIB(opcode, A_SCALAR_STORE)) { + if (GET_ATTRIB(opcode, A_CONDEXEC)) { return true; } } From 515be7f0bf6bbe4288a3e56d759952e8885e577b Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 11 Sep 2024 14:05:59 -0700 Subject: [PATCH 093/109] target/hexagon: Define system, guest reg names Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 29 +++++++++++++++++++++++++++++ target/hexagon/internal.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index ceef313fd267..e23a6d50ccad 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -86,6 +86,35 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { "c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31", }; +#ifndef CONFIG_USER_ONLY +const char * const hexagon_sregnames[] = { + "sgp0", "sgp1", "stid", "elr", "badva0", + "badva1", "ssr", "ccr", "htid", "badva", + "imask", "gevb", "vwctrl", "s13", "s14", + "s15", "evb", "modectl", "syscfg", "segment", + "ipendad", "vid", "vid1", "bestwait", "s24", + "schedcfg", "s26", "cfgbase", "diag", "rev", + "pcyclelo", "pcyclehi", "isdbst", "isdbcfg0", "isdbcfg1", + "livelock", "brkptpc0", "brkptcfg0", "brkptpc1", "brkptcfg1", + "isdbmbxin", "isdbmbxout", "isdben", "isdbgpr", "pmucnt4", + "pmucnt5", "pmucnt6", "pmucnt7", "pmucnt0", "pmucnt1", + "pmucnt2", "pmucnt3", "pmuevtcfg", "pmustid0", "pmuevtcfg1", + "pmustid1", "timerlo", "timerhi", "pmucfg", "rgdr2", + "rgdr", "turkey", "duck", "chicken", +}; + +G_STATIC_ASSERT(NUM_SREGS == ARRAY_SIZE(hexagon_sregnames)); + +const char * const hexagon_gregnames[] = { + "gelr", "gsr", "gosp", "gbadva", "gcommit1t", + "gcommit2t", "gcommit3t", "gcommit4t", "gcommit5t", "gcommit6t", + "gpcycle1t", "gpcycle2t", "gpcycle3t", "gpcycle4t", "gpcycle5t", + "gpcycle6t", "gpmucnt4", "gpmucnt5", "gpmucnt6", "gpmucnt7", + "gcommit7t", "gcommit8t", "gpcycle7t", "gpcycle8t", "gpcyclelo", + "gpcyclehi", "gpmucnt0", "gpmucnt1", "gpmucnt2", "gpmucnt3", + "g30", "g31", +}; +#endif /* * One of the main debugging techniques is to use "-d cpu" and compare against * LLDB output when single stepping. However, the target and qemu put the diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 34a26350dfb5..ecd99e5a4dd0 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -34,6 +34,8 @@ void hexagon_debug_qreg(CPUHexagonState *env, int regnum); void hexagon_debug(CPUHexagonState *env); extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS]; +extern const char * const hexagon_sregnames[]; +extern const char * const hexagon_gregnames[]; void G_NORETURN do_raise_exception(CPUHexagonState *env, uint32_t exception, From ccf017da3b696292eb2fb8145f9d8c26b283d0d0 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 11 Sep 2024 14:06:15 -0700 Subject: [PATCH 094/109] target/hexagon: initialize sys/guest reg TCGvs Signed-off-by: Brian Cain --- target/hexagon/translate.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index f529ac2ff319..9f71c2e20e9d 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -1295,6 +1295,26 @@ void hexagon_translate_init(void) opcode_init(); +#ifndef CONFIG_USER_ONLY + for (i = 0; i < NUM_GREGS; i++) { + hex_greg[i] = tcg_global_mem_new(tcg_env, + offsetof(CPUHexagonState, greg[i]), + hexagon_gregnames[i]); + } + hex_g_sreg_ptr = tcg_global_mem_new_ptr(tcg_env, + offsetof(CPUHexagonState, g_sreg), "hex_g_sreg_ptr"); + for (i = 0; i < NUM_SREGS; i++) { + if (i < HEX_SREG_GLB_START) { + hex_t_sreg[i] = tcg_global_mem_new(tcg_env, + offsetof(CPUHexagonState, t_sreg[i]), + hexagon_sregnames[i]); + } else { + hex_g_sreg[i] = tcg_global_mem_new(hex_g_sreg_ptr, + i * sizeof(target_ulong), + hexagon_sregnames[i]); + } + } +#endif for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { hex_gpr[i] = tcg_global_mem_new(tcg_env, offsetof(CPUHexagonState, gpr[i]), From 2163ff5aff12c59590224931b437b379c8c0ef61 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 12 Sep 2024 07:22:51 -0700 Subject: [PATCH 095/109] target/hexagon: Add TLB, k0 {un,}lock Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 105 ++++++++++++++++++++++++++++++++++++ target/hexagon/sys_macros.h | 8 +-- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index fb6bf7724a02..f5943bd45a94 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1183,6 +1183,111 @@ void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t new, uint32_t old) BQL_LOCK_GUARD(); hexagon_modify_ssr(env, new, old); } + +static void hex_k0_lock(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1)); + + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + if (GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg)) { + if (env->k0_lock_state == HEX_LOCK_QUEUED) { + env->next_PC += 4; + env->k0_lock_count++; + env->k0_lock_state = HEX_LOCK_OWNER; + SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1); + return; + } + if (env->k0_lock_state == HEX_LOCK_OWNER) { + qemu_log_mask(LOG_GUEST_ERROR, + "Double k0lock at PC: 0x%x, thread may hang\n", + env->next_PC); + env->next_PC += 4; + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + return; + } + env->k0_lock_state = HEX_LOCK_WAITING; + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + } else { + env->next_PC += 4; + env->k0_lock_count++; + env->k0_lock_state = HEX_LOCK_OWNER; + SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1); + } + +} + +static void hex_k0_unlock(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1)); + + /* Nothing to do if the k0 isn't locked by this thread */ + uint32_t syscfg = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SYSCFG); + if ((GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg) == 0) || + (env->k0_lock_state != HEX_LOCK_OWNER)) { + qemu_log_mask(LOG_GUEST_ERROR, + "thread %d attempted to unlock k0 without having the " + "lock, k0_lock state = %d, syscfg:k0 = %d\n", + env->threadId, env->k0_lock_state, + GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg)); + g_assert(env->k0_lock_state != HEX_LOCK_WAITING); + return; + } + + env->k0_lock_count--; + env->k0_lock_state = HEX_LOCK_UNLOCKED; + SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 0); + + /* Look for a thread to unlock */ + unsigned int this_threadId = env->threadId; + CPUHexagonState *unlock_thread = NULL; + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *thread = &cpu->env; + + /* + * The hardware implements round-robin fairness, so we look for threads + * starting at env->threadId + 1 and incrementing modulo the number of + * threads. + * + * To implement this, we check if thread is a earlier in the modulo + * sequence than unlock_thread. + * if unlock thread is higher than this thread + * thread must be between this thread and unlock_thread + * else + * thread higher than this thread is ahead of unlock_thread + * thread must be lower then unlock thread + */ + if (thread->k0_lock_state == HEX_LOCK_WAITING) { + if (!unlock_thread) { + unlock_thread = thread; + } else if (unlock_thread->threadId > this_threadId) { + if (this_threadId < thread->threadId && + thread->threadId < unlock_thread->threadId) { + unlock_thread = thread; + } + } else { + if (thread->threadId > this_threadId) { + unlock_thread = thread; + } + if (thread->threadId < unlock_thread->threadId) { + unlock_thread = thread; + } + } + } + } + if (unlock_thread) { + cs = env_cpu(unlock_thread); + unlock_thread->k0_lock_state = HEX_LOCK_QUEUED; + SET_SYSCFG_FIELD(unlock_thread, SYSCFG_K0LOCK, 1); + cpu_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK); + } + +} #endif diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h index 6c9bb0a147ba..186afc9a6fe8 100644 --- a/target/hexagon/sys_macros.h +++ b/target/hexagon/sys_macros.h @@ -143,11 +143,11 @@ #define fDCINVIDX(REG) #define fDCINVA(REG) do { REG = REG; } while (0) /* Nothing to do in qemu */ -#define fSET_TLB_LOCK() g_assert_not_reached() -#define fCLEAR_TLB_LOCK() g_assert_not_reached() +#define fSET_TLB_LOCK() hex_tlb_lock(env); +#define fCLEAR_TLB_LOCK() hex_tlb_unlock(env); -#define fSET_K0_LOCK() g_assert_not_reached() -#define fCLEAR_K0_LOCK() g_assert_not_reached() +#define fSET_K0_LOCK() hex_k0_lock(env); +#define fCLEAR_K0_LOCK() hex_k0_unlock(env); #define fTLB_IDXMASK(INDEX) \ ((INDEX) & (fPOW2_ROUNDUP(fCAST4u(env_archcpu(env)->num_tlbs)) - 1)) From 61f5ce81e958ea24838ea6d7c8696526fa089911 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 12 Sep 2024 14:10:04 -0700 Subject: [PATCH 096/109] FIXME target/hexagon: Define gen_precise_exception() Add PC to raise_exception helper Replace the fGEN_TCG_J2_trap0 macro override with the fTRAP()-generated system helper instead. FIXME: tweak gen_start_packet (move this elsewhere) Signed-off-by: Brian Cain --- target/hexagon/gen_tcg.h | 7 ------- target/hexagon/helper.h | 2 +- target/hexagon/op_helper.c | 10 ++++------ target/hexagon/translate.c | 13 ++++++++----- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 71f8a0e2d084..146aadc73764 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -1370,13 +1370,6 @@ #define fGEN_TCG_S2_storew_rl_st_vi(SHORTCODE) SHORTCODE #define fGEN_TCG_S4_stored_rl_st_vi(SHORTCODE) SHORTCODE -#define fGEN_TCG_J2_trap0(SHORTCODE) \ - do { \ - uiV = uiV; \ - tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->pkt->pc); \ - TCGv excp = tcg_constant_tl(HEX_EVENT_TRAP0); \ - gen_helper_raise_exception(tcg_env, excp); \ - } while (0) #endif #define fGEN_TCG_A2_nop(SHORTCODE) do { } while (0) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 3df663baeb05..5bcb2f48097c 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -18,7 +18,7 @@ #include "internal.h" #include "helper_protos_generated.h.inc" -DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32) +DEF_HELPER_FLAGS_3(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32, i32) DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_3(gather_store, void, env, i32, int) DEF_HELPER_1(commit_hvx_stores, void, env) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index f5943bd45a94..63eea7af5182 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -68,15 +68,13 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, uintptr_t pc) { - CPUState *cs = env_cpu(env); - qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); - cs->exception_index = exception; - cpu_loop_exit_restore(cs, pc); + do_raise_exception(env, exception, pc, 0); } -G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) +G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp, + target_ulong PC) { - hexagon_raise_exception_err(env, excp, 0); + hexagon_raise_exception_err(env, excp, PC); } void log_store32(CPUHexagonState *env, target_ulong addr, diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 9f71c2e20e9d..5ab327e43670 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -124,9 +124,10 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum, return offset; } -static void gen_exception_raw(int excp) +static void gen_exception(int excp, target_ulong PC) { - gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp)); + gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp), + tcg_constant_tl(PC)); } #ifndef CONFIG_USER_ONLY @@ -221,9 +222,11 @@ static void gen_end_tb(DisasContext *ctx) void hex_gen_exception_end_tb(DisasContext *ctx, int excp) { - gen_exec_counters(ctx); - tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC); - gen_exception_raw(excp); +#ifdef CONFIG_USER_ONLY + gen_exception(excp, ctx->pkt->pc); +#else + gen_precise_exception(excp, ctx->pkt->pc); +#endif ctx->base.is_jmp = DISAS_NORETURN; } From 423794424cba62582fbcde46bc5ca422d379736d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 17 Sep 2024 18:15:07 -0700 Subject: [PATCH 097/109] target/hexagon: Add TCG overrides for transfer insts Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_sys.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h index 99323f613531..e98a84818b47 100644 --- a/target/hexagon/gen_tcg_sys.h +++ b/target/hexagon/gen_tcg_sys.h @@ -81,6 +81,31 @@ gen_helper_stop(tcg_env); \ } while (0) +#define fGEN_TCG_Y2_tfrscrr(SHORTCODE) \ + tcg_gen_mov_tl(RdV, SsV) + +#define fGEN_TCG_Y2_tfrsrcr(SHORTCODE) \ + tcg_gen_mov_tl(SdV, RsV) + +#define fGEN_TCG_Y4_tfrscpp(SHORTCODE) \ + tcg_gen_mov_i64(RddV, SssV) + +#define fGEN_TCG_Y4_tfrspcp(SHORTCODE) \ + tcg_gen_mov_i64(SddV, RssV) + +#define fGEN_TCG_G4_tfrgcrr(SHORTCODE) \ + tcg_gen_mov_tl(RdV, GsV) + +#define fGEN_TCG_G4_tfrgrcr(SHORTCODE) \ + tcg_gen_mov_tl(GdV, RsV) + +#define fGEN_TCG_G4_tfrgcpp(SHORTCODE) \ + tcg_gen_mov_i64(RddV, GssV) + +#define fGEN_TCG_G4_tfrgpcp(SHORTCODE) \ + tcg_gen_mov_i64(GddV, RssV) + + /* * rte (return from exception) * Clear the EX bit in SSR From d4d0a5ff991f7955ac8383bd1eba3a5b2910adf7 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 18 Sep 2024 09:33:45 -0700 Subject: [PATCH 098/109] target/hexagon: Add support for loadw_phys Signed-off-by: Brian Cain --- target/hexagon/hex_common.py | 3 +++ target/hexagon/imported/encode_pp.def | 1 + target/hexagon/imported/ldst.idef | 3 +++ 3 files changed, 7 insertions(+) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 05232f978db9..1242786e77ab 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -266,6 +266,9 @@ def need_slot(tag): and "A_CVI_GATHER" not in attribdict[tag] and ("A_STORE" in attribdict[tag] or "A_LOAD" in attribdict[tag]) + and tag != "L4_loadw_phys" + and tag != "L6_memcpy" + and tag != "Y6_dmlink" ): return 1 else: diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 37faf62b1b7e..41e4ab9e3a26 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -388,6 +388,7 @@ DEF_ENC32(L4_return_fnew_pnt, ICLASS_LD" 011 0 000 sssss PP1010vv ---ddddd") /** Load Acquire Store Release Encoding **/ +DEF_ENC32(L4_loadw_phys, ICLASS_LD" 001 0 000 sssss PP1ttttt -00ddddd") DEF_ENC32(L2_loadw_locked, ICLASS_LD" 001 0 000 sssss PP000--- 000ddddd") DEF_ENC32(L4_loadd_locked, ICLASS_LD" 001 0 000 sssss PP010--- 000ddddd") diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index 53198176a994..4e1e5d5326dd 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -203,6 +203,9 @@ Q6INSN(S2_storew_locked,"memw_locked(Rs32,Pd4)=Rt32", ATTRIBS(A_REGWRSIZE_4B,A_M Q6INSN(L4_loadd_locked,"Rdd32=memd_locked(Rs32)", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_LOAD,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK), "Load double with lock", { fEA_REG(RsV); fLOAD_LOCKED(1,8,u,EA,RddV) }) +Q6INSN(L4_loadw_phys,"Rd32=memw_phys(Rs32,Rt32)", ATTRIBS(A_REGWRSIZE_4B,A_PRIV,A_RESTRICT_SLOT0ONLY,A_NOTE_PRIV,A_MEMSIZE_4B,A_LOAD,A_NOTE_NOPACKET,A_RESTRICT_NOPACKET), "Load word from physical address", +{ fLOAD_PHYS(1,4,u,RsV,RtV,RdV); }) + Q6INSN(S4_stored_locked,"memd_locked(Rs32,Pd4)=Rtt32", ATTRIBS(A_REGWRSIZE_8B,A_MEMSIZE_8B,A_STORE,A_RESTRICT_SLOT0ONLY,A_RESTRICT_PACKET_AXOK,A_NOTE_AXOK,A_RESTRICT_LATEPRED,A_NOTE_LATEPRED), "Store word with lock", { fEA_REG(RsV); fSTORE_LOCKED(1,8,EA,RttV,PdV) }) From ea6db7691751ebb980b70991f115c9c8bf455e8a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 15 Oct 2024 18:56:30 -0700 Subject: [PATCH 099/109] hw/hexagon: Add v68, sa8775-cdsp0 defs Signed-off-by: Brian Cain --- hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc | 62 ++++++++++++++++++++++ hw/hexagon/machine_cfg_v68n_1024.h.inc | 63 +++++++++++++++++++++++ hw/hexagon/machine_configs.h.inc | 2 + 3 files changed, 127 insertions(+) create mode 100644 hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc create mode 100644 hw/hexagon/machine_cfg_v68n_1024.h.inc diff --git a/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc new file mode 100644 index 000000000000..83ac4fab3d1b --- /dev/null +++ b/hw/hexagon/machine_cfg_sa8775_cdsp0.h.inc @@ -0,0 +1,62 @@ + +static hexagon_machine_config G_GNUC_UNUSED SA8775P_cdsp0 = { + .cfgbase = 0x24000000 + 0x180000, + .l2tcm_size = 0x00000000, + .l2vic_base = 0x26300000 + 0x90000, + .l2vic_size = 0x00001000, + .csr_base = 0x26300000, + .qtmr_rg0 = 0x26300000 + 0xA1000, + .qtmr_rg1 = 0x26300000 + 0xA2000, + .cfgtable = { + .l2tcm_base = 0x00002400, + .reserved0 = 0x00000000, + .subsystem_base = 0x26380000, + .etm_base = 0x00002419, + .l2cfg_base = 0x0000241a, + .reserved1 = 0x241b0000, + .l1s0_base = 0x00002500, + .axi2_lowaddr = 0x00000000, + .streamer_base = 0x00000000, + .reserved2 = 0x00000000, + .fastl2vic_base = 0x0000241e, + .jtlb_size_entries = 0x00000080, + .coproc_present = 0x00000001, + .ext_contexts = 0x00000004, + .vtcm_base = 0x00002500, + .vtcm_size_kb = 0x00002000, + .l2tag_size = 0x00000400, + .l2ecomem_size = 0x00000000, + .thread_enable_mask = 0x0000003f, + .eccreg_base = 0x0000241f, + .l2line_size = 0x00000080, + .tiny_core = 0x00000000, + .l2itcm_size = 0x00000000, + .l2itcm_base = 0x00002400, + .reserved3 = 0x00000000, + .dtm_present = 0x00000000, + .dma_version = 0x00000003, + .hvx_vec_log_length = 0x00000007, + .core_id = 0x00000000, + .core_count = 0x00000000, + .coproc2_reg0 = 0x00000040, + .coproc2_reg1 = 0x00000020, + .v2x_mode = 0x00000001, + .coproc2_reg2 = 0x00000008, + .coproc2_reg3 = 0x00000020, + .coproc2_reg4 = 0x00000000, + .coproc2_reg5 = 0x00000002, + .coproc2_reg6 = 0x00000016, + .coproc2_reg7 = 0x00000006, + .acd_preset = 0x00000001, + .mnd_preset = 0x00000000, + .l1d_size_kb = 0x00000010, + .l1i_size_kb = 0x00000020, + .l1d_write_policy = 0x00000002, + .vtcm_bank_width = 0x00000080, + .reserved3 = 0x00000001, + .reserved4 = 0x00000000, + .reserved5 = 0x00000003, + .coproc2_cvt_mpy_size = 0x0000000a, + .axi3_lowaddr = 0x000000e0, + }, +}; diff --git a/hw/hexagon/machine_cfg_v68n_1024.h.inc b/hw/hexagon/machine_cfg_v68n_1024.h.inc new file mode 100644 index 000000000000..b501cd8c1c31 --- /dev/null +++ b/hw/hexagon/machine_cfg_v68n_1024.h.inc @@ -0,0 +1,63 @@ + +static hexagon_machine_config G_GNUC_UNUSED v68n_1024 = { + .cfgbase = 0xde000000, + .l2tcm_size = 0x00000000, + .l2vic_base = 0xfc910000, + .l2vic_size = 0x00001000, + .csr_base = 0xfc900000, + .qtmr_rg0 = 0xfc921000, + .qtmr_rg1 = 0xfc922000, + .cfgtable = { + .l2tcm_base = 0x0000d800, + .reserved0 = 0x00000000, + .subsystem_base = 0x00002000, + .etm_base = 0x0000d819, + .l2cfg_base = 0x0000d81a, + .reserved1 = 0x00000000, + .l1s0_base = 0x0000d840, + .axi2_lowaddr = 0x00003000, + .streamer_base = 0xd81c0000, + .reserved2 = 0x0000d81d, + .fastl2vic_base = 0x0000d81e, + .jtlb_size_entries = 0x00000080, + .coproc_present = 0x00000001, + .ext_contexts = 0x00000004, + .vtcm_base = 0x0000d840, + .vtcm_size_kb = 0x00001000, + .l2tag_size = 0x00000400, + .l2ecomem_size = 0x00000400, + .thread_enable_mask = 0x0000003f, + .eccreg_base = 0x0000d81f, + .l2line_size = 0x00000080, + .tiny_core = 0x00000000, + .l2itcm_size = 0x00000000, + .l2itcm_base = 0x0000d820, + .reserved3 = 0x00000000, + .dtm_present = 0x00000000, + .dma_version = 0x00000001, + .hvx_vec_log_length = 0x00000007, + .core_id = 0x00000000, + .core_count = 0x00000000, + .coproc2_reg0 = 0x00000040, + .coproc2_reg1 = 0x00000020, + .v2x_mode = 0x1f1f1f1f, + .coproc2_reg2 = 0x1f1f1f1f, + .coproc2_reg3 = 0x1f1f1f1f, + .coproc2_reg4 = 0x1f1f1f1f, + .coproc2_reg5 = 0x1f1f1f1f, + .coproc2_reg6 = 0x1f1f1f1f, + .coproc2_reg7 = 0x1f1f1f1f, + .acd_preset = 0x1f1f1f1f, + .mnd_preset = 0x1f1f1f1f, + .l1d_size_kb = 0x1f1f1f1f, + .l1i_size_kb = 0x1f1f1f1f, + .l1d_write_policy = 0x1f1f1f1f, + .vtcm_bank_width = 0x1f1f1f1f, + .reserved3 = 0x1f1f1f1f, + .reserved4 = 0x1f1f1f1f, + .reserved5 = 0x1f1f1f1f, + .coproc2_cvt_mpy_size = 0x1f1f1f1f, + .axi3_lowaddr = 0x1f1f1f1f, + }, +}; + diff --git a/hw/hexagon/machine_configs.h.inc b/hw/hexagon/machine_configs.h.inc index fe5ec5f6a09e..0465fb9fa433 100644 --- a/hw/hexagon/machine_configs.h.inc +++ b/hw/hexagon/machine_configs.h.inc @@ -67,3 +67,5 @@ static hexagon_machine_config v66g_1024 = { }, }; +#include "machine_cfg_sa8775_cdsp0.h.inc" +#include "machine_cfg_v68n_1024.h.inc" From 8932b0c1a7542def2c760261ea4c4e6b8a85732e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 22 Oct 2024 13:50:07 -0700 Subject: [PATCH 100/109] hw/hexagon: Modify "Standalone" symbols These symbols are used by Hexagon Standalone OS to indicate whether the program should halt and wait for interrupts at startup. For QEMU, we want these programs to just continue crt0 startup through to the user program's main(). Signed-off-by: Brian Cain --- hw/hexagon/hexagon_dsp.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 0ad90bcb056b..770904d01d3a 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -28,9 +28,17 @@ #include "machine_configs.h.inc" +static hwaddr isdb_secure_flag; +static hwaddr isdb_trusted_flag; static void hex_symbol_callback(const char *st_name, int st_info, uint64_t st_value, uint64_t st_size) { + if (!g_strcmp0("isdb_secure_flag", st_name)) { + isdb_secure_flag = st_value; + } + if (!g_strcmp0("isdb_trusted_flag", st_name)) { + isdb_trusted_flag = st_value; + } } /* Board init. */ @@ -59,6 +67,13 @@ static void hexagon_init_bootstrap(MachineState *machine, HexagonCPU *cpu) { if (machine->kernel_filename) { hexagon_load_kernel(cpu); + uint32_t mem = 1; + if (isdb_secure_flag) { + cpu_physical_memory_write(isdb_secure_flag, &mem, sizeof(mem)); + } + if (isdb_trusted_flag) { + cpu_physical_memory_write(isdb_trusted_flag, &mem, sizeof(mem)); + } } } From ab9a1808625e2067b8f131e0947e7af00899372a Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 28 Jul 2024 22:13:33 -0700 Subject: [PATCH 101/109] hw/hexagon: Define hexagon "virt" machine Signed-off-by: Brian Cain --- configs/devices/hexagon-softmmu/default.mak | 1 + configs/targets/hexagon-softmmu.mak | 2 + hw/hexagon/Kconfig | 8 + hw/hexagon/meson.build | 2 + hw/hexagon/virt.c | 405 ++++++++++++++++++++ include/hw/hexagon/virt.h | 42 ++ 6 files changed, 460 insertions(+) create mode 100644 hw/hexagon/virt.c create mode 100644 include/hw/hexagon/virt.h diff --git a/configs/devices/hexagon-softmmu/default.mak b/configs/devices/hexagon-softmmu/default.mak index 08e709aea72f..37b4f9f3237a 100644 --- a/configs/devices/hexagon-softmmu/default.mak +++ b/configs/devices/hexagon-softmmu/default.mak @@ -3,5 +3,6 @@ # Uncomment the following lines to disable these optional devices: # Boards are selected by default, uncomment to keep out of the build. +# CONFIG_HEX_VIRT=y # CONFIG_HEX_DSP=y # CONFIG_L2VIC=y diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak index 8b1fdbf79d55..3ff448e20ae4 100644 --- a/configs/targets/hexagon-softmmu.mak +++ b/configs/targets/hexagon-softmmu.mak @@ -3,3 +3,5 @@ TARGET_ARCH=hexagon TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES=gdb-xml/hexagon-core.xml gdb-xml/hexagon-hvx.xml gdb-xml/hexagon-sys.xml +TARGET_NEED_FDT=y + diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index 3fc14756e6df..f3f011573105 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -4,3 +4,11 @@ config HEX_DSP depends on HEXAGON && TCG imply PTIMER select L2VIC # Vector PIC + +config HEX_VIRT + bool + default y + depends on HEX_DSP && FDT + select DEVICE_TREE + select VIRTIO_MMIO + select PL011 diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build index 2ef3dbcd3492..649ad6dc02b3 100644 --- a/hw/hexagon/meson.build +++ b/hw/hexagon/meson.build @@ -3,3 +3,5 @@ hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c',)) hw_arch += {'hexagon': hexagon_ss} +hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c',)) + diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c new file mode 100644 index 000000000000..5e4a738599e4 --- /dev/null +++ b/hw/hexagon/virt.c @@ -0,0 +1,405 @@ +/* + * Hexagon virt emulation + * + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "exec/address-spaces.h" +#include "hw/char/pl011.h" +#include "hw/core/sysbus-fdt.h" +#include "hw/hexagon/virt.h" +#include "hw/hexagon/hexagon.h" +#include "hw/loader.h" +#include "hw/qdev-properties.h" +#include "hw/register.h" +#include "qemu/error-report.h" +#include "qemu/guest-random.h" +#include "qemu/units.h" +#include "system/device_tree.h" +#include "system/reset.h" +#include "system/system.h" +#include "elf.h" +#include "machine_cfg_v68n_1024.h.inc" +#include + +static const int VIRTIO_DEV_COUNT = 2; + +static const MemMapEntry base_memmap[] = { + + [VIRT_UART0] = { 0x10000000, 0x00000200 }, + [VIRT_MMIO] = { 0x11000000, 0x00000100 }, + [VIRT_GPT] = { 0xab000000, 0x00001000 }, + [VIRT_FDT] = { 0x99900000, 0x00000200 }, +}; + +static const int irqmap[] = { + [VIRT_MMIO] = 8, /* ...to 8 + VIRTIO_DEV_COUNT - 1 */ + [VIRT_GPT] = 12, + [VIRT_UART0] = 50, +}; + + +static void create_fdt(HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + void *fdt = create_device_tree(&vms->fdt_size); + + if (!fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + ms->fdt = fdt; + + qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,hexagon-virt"); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1); + qemu_fdt_setprop_string(fdt, "/", "model", "linux,hexagon-virt"); + + qemu_fdt_setprop_string(fdt, "/", "model", "hexagon-virt,qemu"); + qemu_fdt_setprop_string(fdt, "/", "compatible", "qcom,sm8150"); + + qemu_fdt_add_subnode(fdt, "/soc"); + qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1); + qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0); + + qemu_fdt_add_subnode(fdt, "/chosen"); + + uint8_t rng_seed[32]; + qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); + qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); +} + +static void fdt_add_hvx(HexagonVirtMachineState *vms, + const hexagon_machine_config *m_cfg, Error **errp) +{ + const MachineState *ms = MACHINE(vms); + uint32_t vtcm_size_bytes = m_cfg->cfgtable.vtcm_size_kb * 1024; + if (vtcm_size_bytes > 0) { + memory_region_init_ram(&vms->vtcm, NULL, "vtcm.ram", vtcm_size_bytes, + errp); + memory_region_add_subregion(vms->sys, m_cfg->cfgtable.vtcm_base, + &vms->vtcm); + + qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm"); + qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible", + "qcom,hexagon_vtcm"); + + assert(sizeof(m_cfg->cfgtable.vtcm_base) == sizeof(uint32_t)); + qemu_fdt_setprop_cells(ms->fdt, "/soc/vtcm", "reg", 0, + m_cfg->cfgtable.vtcm_base, vtcm_size_bytes); + } + + if (m_cfg->cfgtable.ext_contexts > 0) { + qemu_fdt_add_subnode(ms->fdt, "/soc/hvx"); + qemu_fdt_setprop_string(ms->fdt, "/soc/hvx", "compatible", + "qcom,hexagon-hvx"); + qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-max-ctxts", + m_cfg->cfgtable.ext_contexts); + qemu_fdt_setprop_cells(ms->fdt, "/soc/hvx", "qcom,hvx-vlength", + m_cfg->cfgtable.hvx_vec_log_length); + } + +} + +static int32_t irq_hvm_ic_phandle = -1; +static void fdt_add_hvm_pic_node(HexagonVirtMachineState *vms, + const hexagon_machine_config *m_cfg) +{ + MachineState *ms = MACHINE(vms); + irq_hvm_ic_phandle = qemu_fdt_alloc_phandle(ms->fdt); + + qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", + irq_hvm_ic_phandle); + + qemu_fdt_add_subnode(ms->fdt, "/soc/interrupt-controller"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#address-cells", 2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#interrupt-cells", 2); + qemu_fdt_setprop_string(ms->fdt, "/soc/interrupt-controller", "compatible", + "qcom,h2-pic,hvm-pic"); + qemu_fdt_setprop(ms->fdt, "/soc/interrupt-controller", + "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", "phandle", + irq_hvm_ic_phandle); + + sysbus_mmio_map(SYS_BUS_DEVICE(vms->l2vic), 1, + m_cfg->cfgtable.fastl2vic_base); +} + + +static void fdt_add_gpt_node(HexagonVirtMachineState *vms) +{ + g_autofree char *name = NULL; + MachineState *ms = MACHINE(vms); + + name = g_strdup_printf("/soc/gpt@%" PRIx64, + (int64_t) base_memmap[VIRT_GPT].base); + qemu_fdt_add_subnode(ms->fdt, name); + qemu_fdt_setprop_string(ms->fdt, name, "compatible", + "qcom,h2-timer,hvm-timer"); + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqmap[VIRT_GPT], 0); + qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, + base_memmap[VIRT_GPT].base, + base_memmap[VIRT_GPT].size); +} + +static int32_t clock_phandle = -1; +static void fdt_add_clocks(const HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + clock_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_add_subnode(ms->fdt, "/apb-pclk"); + qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "compatible", "fixed-clock"); + qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "#clock-cells", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "clock-frequency", 24000000); + qemu_fdt_setprop_string(ms->fdt, "/apb-pclk", "clock-output-names", + "clk24mhz"); + qemu_fdt_setprop_cell(ms->fdt, "/apb-pclk", "phandle", clock_phandle); +} + +static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart) +{ + char *nodename; + hwaddr base = base_memmap[uart].base; + hwaddr size = base_memmap[uart].size; + assert(uart == 0); + int irq = irqmap[VIRT_UART0 + uart]; + const char compat[] = "arm,pl011\0arm,primecell"; + const char clocknames[] = "uartclk\0apb_pclk"; + MachineState *ms = MACHINE(vms); + + pl011_create(base, qdev_get_gpio_in(vms->l2vic, irq), serial_hd(0)); + + nodename = g_strdup_printf("/pl011@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + + /* Note that we can't use setprop_string because of the embedded NUL */ + qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size); + qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0); + qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clock_phandle, + clock_phandle); + qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames, + sizeof(clocknames)); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", + irq_hvm_ic_phandle); + + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); + qemu_fdt_add_subnode(ms->fdt, "/aliases"); + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", nodename); + + g_free(nodename); +} + +static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + qemu_fdt_add_subnode(ms->fdt, "/cpus"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + + /* cpu nodes */ + for (int num = ms->smp.cpus - 1; num >= 0; num--) { + char *nodename = g_strdup_printf("/cpus/cpu@%d", num); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(ms->fdt)); + g_free(nodename); + } +} + + +static void fdt_add_virtio_devices(const HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + /* VirtIO MMIO devices */ + for (int i = 0; i < VIRTIO_DEV_COUNT; i++) { + char *nodename; + int irq = irqmap[VIRT_MMIO] + i; + size_t size = base_memmap[VIRT_MMIO].size; + hwaddr base = base_memmap[VIRT_MMIO].base + i * size; + + nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "virtio,mmio"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 1, + size); + qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", + irq_hvm_ic_phandle); + + sysbus_create_simple( + "virtio-mmio", base + i * size, + qdev_get_gpio_in(vms->l2vic, irqmap[VIRT_MMIO] + i)); + + g_free(nodename); + } +} + +static void virt_instance_init(Object *obj) +{ + HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(obj); + + create_fdt(vms); +} + +void hexagon_load_fdt(const HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + hwaddr fdt_addr = base_memmap[VIRT_FDT].base; + uint32_t fdtsize = vms->fdt_size; + + /* copy in the device tree */ + qemu_fdt_dumpdtb(ms->fdt, fdtsize); + + rom_add_blob_fixed_as("fdt", ms->fdt, fdtsize, fdt_addr, + &address_space_memory); + qemu_register_reset_nosnapshotload( + qemu_fdt_randomize_seeds, + rom_ptr_for_as(&address_space_memory, fdt_addr, fdtsize)); +} + +static uint64_t load_kernel(const HexagonVirtMachineState *vms) +{ + MachineState *ms = MACHINE(vms); + uint64_t entry = 0; + if (load_elf_ram_sym( + ms->kernel_filename, NULL, NULL, NULL, NULL, &entry, NULL, NULL, 0, + EM_HEXAGON, 0, 0, &address_space_memory, false, NULL) > 0) { + return entry; + } + error_report("error loading '%s'", ms->kernel_filename); + exit(1); +} + +static void do_cpu_reset(void *opaque) +{ + HexagonCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + cpu_reset(cs); +} + +static void virt_init(MachineState *ms) +{ + HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms); + Error **errp = NULL; + const hexagon_machine_config *m_cfg = &v68n_1024; + + qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline); + + vms->sys = get_system_memory(); + + memory_region_init_ram(&vms->ram, NULL, "ddr.ram", ms->ram_size, errp); + memory_region_add_subregion(vms->sys, 0x0, &vms->ram); + + if (m_cfg->l2tcm_size) { + memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size, + errp); + memory_region_add_subregion(vms->sys, m_cfg->cfgtable.l2tcm_base, + &vms->tcm); + } + + memory_region_init_rom(&vms->cfgtable, NULL, "config_table.rom", + sizeof(m_cfg->cfgtable), errp); + memory_region_add_subregion(vms->sys, m_cfg->cfgbase, &vms->cfgtable); + fdt_add_hvx(vms, m_cfg, errp); + const char *cpu_model = ms->cpu_type; + + if (!cpu_model) { + cpu_model = HEXAGON_CPU_TYPE_NAME("v73"); + } + + HexagonCPU *cpu_0 = NULL; + for (int i = 0; i < ms->smp.cpus; i++) { + HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type)); + qemu_register_reset(do_cpu_reset, cpu); + + if (i == 0) { + cpu_0 = cpu; + if (ms->kernel_filename) { + uint64_t entry = load_kernel(vms); + + qdev_prop_set_uint32(DEVICE(cpu_0), "exec-start-addr", entry); + } + } + qdev_prop_set_uint32(DEVICE(cpu), "l2vic-base-addr", m_cfg->l2vic_base); + qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); + qdev_prop_set_uint32(DEVICE(cpu), "hvx-contexts", + m_cfg->cfgtable.ext_contexts); + qdev_prop_set_uint32(DEVICE(cpu), "num-tlbs", + m_cfg->cfgtable.jtlb_size_entries); + + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + return; + } + } + vms->l2vic = sysbus_create_varargs( + "l2vic", m_cfg->l2vic_base, qdev_get_gpio_in(DEVICE(cpu_0), 0), + qdev_get_gpio_in(DEVICE(cpu_0), 1), qdev_get_gpio_in(DEVICE(cpu_0), 2), + qdev_get_gpio_in(DEVICE(cpu_0), 3), qdev_get_gpio_in(DEVICE(cpu_0), 4), + qdev_get_gpio_in(DEVICE(cpu_0), 5), qdev_get_gpio_in(DEVICE(cpu_0), 6), + qdev_get_gpio_in(DEVICE(cpu_0), 7), NULL); + + fdt_add_hvm_pic_node(vms, m_cfg); + fdt_add_virtio_devices(vms); + fdt_add_cpu_nodes(vms); + fdt_add_clocks(vms); + fdt_add_uart(vms, 0); + fdt_add_gpt_node(vms); + + hexagon_config_table *config_table = + (hexagon_config_table *)&m_cfg->cfgtable; + + config_table->l2tcm_base = + HEXAGON_CFG_ADDR_BASE(m_cfg->cfgtable.l2tcm_base); + config_table->subsystem_base = HEXAGON_CFG_ADDR_BASE(m_cfg->csr_base); + config_table->vtcm_base = HEXAGON_CFG_ADDR_BASE(m_cfg->cfgtable.vtcm_base); + config_table->l2cfg_base = + HEXAGON_CFG_ADDR_BASE(m_cfg->cfgtable.l2cfg_base); + config_table->fastl2vic_base = + HEXAGON_CFG_ADDR_BASE(m_cfg->cfgtable.fastl2vic_base); + + rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable, + sizeof(m_cfg->cfgtable), m_cfg->cfgbase, + &address_space_memory); + + + hexagon_load_fdt(vms); +} + + +static void virt_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = virt_init; + mc->default_cpu_type = HEXAGON_CPU_TYPE_NAME("v73"); + mc->default_ram_size = 4 * GiB; + mc->max_cpus = HEXAGON_MAX_CPUS; + mc->default_cpus = 6; + mc->is_default = false; + mc->default_kernel_irqchip_split = false; + mc->block_default_type = IF_VIRTIO; + mc->default_boot_order = NULL; + mc->no_cdrom = 1; + mc->numa_mem_supported = false; + mc->default_nic = "virtio-mmio-bus"; +} + + +static const TypeInfo virt_machine_types[] = { { + .name = TYPE_HEXAGON_VIRT_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(HexagonVirtMachineState), + .class_init = virt_class_init, + .instance_init = virt_instance_init, +} }; + +DEFINE_TYPES(virt_machine_types) diff --git a/include/hw/hexagon/virt.h b/include/hw/hexagon/virt.h new file mode 100644 index 000000000000..1f858d54c08e --- /dev/null +++ b/include/hw/hexagon/virt.h @@ -0,0 +1,42 @@ +/* + * Definitions for hexagon virt board. + * + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_HEXAGONVIRT_H +#define HW_HEXAGONVIRT_H + +#include "target/hexagon/cpu.h" +#include "hw/boards.h" + +#define HEXAGON_MAX_CPUS 8 + +struct HexagonVirtMachineState { + /*< private >*/ + MachineState parent_obj; + + int fdt_size; + MemoryRegion *sys; + MemoryRegion cfgtable; + MemoryRegion ram; + MemoryRegion tcm; + MemoryRegion vtcm; + DeviceState *l2vic; +}; + +void hexagon_load_fdt(const struct HexagonVirtMachineState *vms); + +enum { + VIRT_UART0, + VIRT_GPT, + VIRT_MMIO, + VIRT_FDT, +}; + +#define TYPE_HEXAGON_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +OBJECT_DECLARE_SIMPLE_TYPE(HexagonVirtMachineState, HEXAGON_VIRT_MACHINE) + +#endif /* HW_HEXAGONVIRT_H */ + From 55a84e3e783d4660a572b7ddba79e54c118118c6 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Fri, 6 Dec 2024 10:30:26 -0300 Subject: [PATCH 102/109] target/hexagon: Add guest reg reading functionality Signed-off-by: Matheus Tavares Bernardino --- target/hexagon/cpu.c | 18 +++++++++++++++++- target/hexagon/op_helper.c | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index e23a6d50ccad..e9e624f92aae 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -757,7 +757,23 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data) #ifndef CONFIG_USER_ONLY uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg) { - g_assert_not_reached(); + target_ulong ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + int ssr_ce = GET_SSR_FIELD(SSR_CE, ssr); + + if (reg <= HEX_GREG_G3) { + return env->greg[reg]; + } + switch (reg) { + case HEX_GREG_GPCYCLELO: + return ssr_ce ? hexagon_get_sys_pcycle_count_low(env) : 0; + + case HEX_GREG_GPCYCLEHI: + return ssr_ce ? hexagon_get_sys_pcycle_count_high(env) : 0; + + default: + qemu_log_mask(LOG_UNIMP, "reading greg %d not yet supported.\n", reg); + return 0; + } } #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 63eea7af5182..fc2b43a22685 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1877,13 +1877,28 @@ uint64_t HELPER(sreg_read_pair)(CPUHexagonState *env, uint32_t reg) } uint32_t HELPER(greg_read)(CPUHexagonState *env, uint32_t reg) + { - g_assert_not_reached(); + return hexagon_greg_read(env, reg); } uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg) + { - g_assert_not_reached(); + if (reg == HEX_GREG_G0 || reg == HEX_GREG_G2) { + return (uint64_t)(env->greg[reg]) | + (((uint64_t)(env->greg[reg + 1])) << 32); + } + switch (reg) { + case HEX_GREG_GPCYCLELO: { + target_ulong ssr = ARCH_GET_SYSTEM_REG(env, HEX_SREG_SSR); + int ssr_ce = GET_SSR_FIELD(SSR_CE, ssr); + return ssr_ce ? hexagon_get_sys_pcycle_count(env) : 0; + } + default: + return (uint64_t)hexagon_greg_read(env, reg) | + ((uint64_t)(hexagon_greg_read(env, reg + 1)) << 32); + } } void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio) From cc1b7941d21813b5b1eda23aeb7788ba7448758e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 11 Dec 2024 14:08:53 -0300 Subject: [PATCH 103/109] target/hexagon: Add pcycle setting functionality Signed-off-by: Brian Cain Signed-off-by: Matheus Tavares Bernardino --- target/hexagon/cpu_helper.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index c1f88396df71..d4b7cbfba170 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -71,18 +71,30 @@ uint32_t hexagon_get_sys_pcycle_count_low(CPUHexagonState *env) void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t cycles_hi) { - g_assert_not_reached(); + uint64_t cur_cycles = hexagon_get_sys_pcycle_count(env); + uint64_t cycles = + ((uint64_t)cycles_hi << 32) | extract64(cur_cycles, 0, 32); + hexagon_set_sys_pcycle_count(env, cycles); } void hexagon_set_sys_pcycle_count_low(CPUHexagonState *env, uint32_t cycles_lo) { - g_assert_not_reached(); + uint64_t cur_cycles = hexagon_get_sys_pcycle_count(env); + uint64_t cycles = extract64(cur_cycles, 32, 32) | cycles_lo; + hexagon_set_sys_pcycle_count(env, cycles); } void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) { - g_assert_not_reached(); + *(env->g_pcycle_base) = cycles; + + CPUState *cs; + CPU_FOREACH(cs) { + HexagonCPU *cpu = HEXAGON_CPU(cs); + CPUHexagonState *env_ = &cpu->env; + env_->t_cycle_count = 0; + } } static void set_wait_mode(CPUHexagonState *env) From 1dd8d5df75bf7315ac9e4a66deed00e1baf58b63 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 25 Oct 2024 20:49:14 -0700 Subject: [PATCH 104/109] tests/functional: Add a hexagon minivm test Signed-off-by: Brian Cain --- MAINTAINERS | 1 + tests/functional/meson.build | 8 +++++ tests/functional/test_hexagon_minivm.py | 42 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100755 tests/functional/test_hexagon_minivm.py diff --git a/MAINTAINERS b/MAINTAINERS index 6848ceb960fe..292625bebafd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -245,6 +245,7 @@ F: docs/system/target-hexagon.rst F: docs/devel/hexagon-sys.rst F: docs/devel/hexagon-vm.rst F: docs/devel/hexagon-l2vic.rst +F: tests/functional/test_hexagon_minivm.py T: git https://github.com/quic/qemu.git hex-next Hexagon idef-parser diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 24f7f8f2f1ca..3a62d937668b 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -104,6 +104,14 @@ tests_avr_system_thorough = [ 'avr_mega2560', ] +test_timeouts += { + 'hexagon_minivm': 180, +} + +tests_hexagon_system_quick = [ + 'hexagon_minivm', +] + tests_i386_system_thorough = [ 'i386_tuxrun', ] diff --git a/tests/functional/test_hexagon_minivm.py b/tests/functional/test_hexagon_minivm.py new file mode 100755 index 000000000000..8e09774e092f --- /dev/null +++ b/tests/functional/test_hexagon_minivm.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# +# Copyright(c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +import os +from glob import glob +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern + +class MiniVMTest(QemuSystemTest): + + timeout = 180 + GUEST_ENTRY = 0xc0000000 + + REPO = 'https://artifacts.codelinaro.org/artifactory' + ASSET_TARBALL = \ + Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/' + '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz', + 'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a') + + def test_minivm(self): + self.set_machine('virt') + self.archive_extract(self.ASSET_TARBALL) + rootfs_path = f'{self.workdir}/hexagon-unknown-linux-musl-rootfs' + kernel_path = f'{rootfs_path}/boot/minivm' + + assert(os.path.exists(kernel_path)) + for test_bin_path in glob(f'{rootfs_path}/boot/test_*'): + print(f'# Testing "{os.path.basename(test_bin_path)}"') + + vm = self.get_vm() + vm.add_args('-kernel', kernel_path, + '-device', + f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}') + vm.launch() + vm.wait() + self.assertEqual(vm.exitcode(), 0) + +if __name__ == '__main__': + QemuSystemTest.main() From c425299d1ebe25407d8691b45a7ae9f34572ce8d Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Wed, 18 Dec 2024 09:24:35 -0800 Subject: [PATCH 105/109] FIXME: target/hexagon: Add exit pattern for standalone programs FIXME: we'll omit this commit from upstreaming for now. The SYS_EXIT semihosting call should be included with the rest of the semihosting series, but is useful for testing this series. Signed-off-by: Sid Manning --- target/hexagon/hexswi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c index 8bee948af6aa..d0ffde958914 100644 --- a/target/hexagon/hexswi.c +++ b/target/hexagon/hexswi.c @@ -90,6 +90,15 @@ void hexagon_cpu_do_interrupt(CPUState *cs) if (env->cause_code == 0) { qemu_log_mask(LOG_UNIMP, "trap0 is unhandled, no semihosting available\n"); + + /* + * Detect the code sequence the standalone runtime uses + * to signal the program has finished. + * r0 = #0x18; r2 = #0x0; trap0(#0) + */ + if (env->gpr[HEX_REG_R00] == 0x18) { + exit(env->gpr[HEX_REG_R02]); + } } hexagon_ssr_set_cause(env, env->cause_code); From 3a44861feb501639138ff10154e9825f371a99b7 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 2 Jan 2025 19:47:54 -0800 Subject: [PATCH 106/109] target/hexagon: Add a QTimer address prop This property will be used by a future commit. Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 2 ++ target/hexagon/cpu.h | 1 + 2 files changed, 3 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index e9e624f92aae..dffafe8d8865 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -64,6 +64,8 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_UINT32("num-tlbs", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES), DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr, 0xffffffffULL), + DEFINE_PROP_UINT32("qtimer-base-addr", HexagonCPU, qtimer_base_addr, + 0xffffffffULL), DEFINE_PROP_UINT32("hvx-contexts", HexagonCPU, hvx_contexts, 0), DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffffULL), DEFINE_PROP_UINT64("config-table-addr", HexagonCPU, config_table_addr, diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index e48575d375dd..f462af2a8e77 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -194,6 +194,7 @@ struct ArchCPU { #ifndef CONFIG_USER_ONLY uint32_t num_tlbs; uint32_t l2vic_base_addr; + uint32_t qtimer_base_addr; uint32_t hvx_contexts; uint32_t boot_addr; uint64_t config_table_addr; From 3440997a14f0b483647aadd0f59891714624c2db Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Tue, 7 Nov 2023 17:01:28 -0800 Subject: [PATCH 107/109] hw/timer: Add QTimer device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: QTimer was implemented before ARM SSE Timer was upstreamed, there may be opportunity to use that device instead. Co-authored-by: Damien Hedde Co-authored-by: Tobias Röhmel Signed-off-by: Brian Cain --- MAINTAINERS | 2 + hw/hexagon/hexagon_dsp.c | 2 +- hw/hexagon/virt.c | 23 ++ hw/timer/meson.build | 2 + hw/timer/qct-qtimer.c | 519 ++++++++++++++++++++++++++++++++++ include/hw/timer/qct-qtimer.h | 85 ++++++ 6 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 hw/timer/qct-qtimer.c create mode 100644 include/hw/timer/qct-qtimer.h diff --git a/MAINTAINERS b/MAINTAINERS index 292625bebafd..0a65e76ae1b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -231,7 +231,9 @@ S: Supported F: target/hexagon/ F: hw/intc/l2vic.[ch] F: hw/hexagon/ +F: hw/timer/qct-qtimer.c F: include/hw/hexagon/ +F: include/hw/timer/qct-qtimer.h X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 770904d01d3a..38cee6d56cc1 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -3,7 +3,6 @@ * subsystem with few peripherals, like the Compute DSP. * * Copyright (c) 2020-2024 Qualcomm Innovation Center, Inc. All Rights Reserved. - * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -120,6 +119,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, */ qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); qdev_prop_set_uint32(DEVICE(cpu), "l2vic-base-addr", m_cfg->l2vic_base); + qdev_prop_set_uint32(DEVICE(cpu), "qtimer-base-addr", m_cfg->qtmr_rg0); qdev_prop_set_uint32(DEVICE(cpu), "config-table-addr", m_cfg->cfgbase); if (i == 0) { diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index 5e4a738599e4..1d6ee4876b8c 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -14,6 +14,7 @@ #include "hw/loader.h" #include "hw/qdev-properties.h" #include "hw/register.h" +#include "hw/timer/qct-qtimer.h" #include "qemu/error-report.h" #include "qemu/guest-random.h" #include "qemu/units.h" @@ -243,6 +244,27 @@ static void fdt_add_virtio_devices(const HexagonVirtMachineState *vms) } } +static void create_qtimer(HexagonVirtMachineState *vms, + const hexagon_machine_config *m_cfg) +{ + Error **errp = NULL; + QCTQtimerState *qtimer = QCT_QTIMER(qdev_new(TYPE_QCT_QTIMER)); + + object_property_set_uint(OBJECT(qtimer), "nr_frames", 2, errp); + object_property_set_uint(OBJECT(qtimer), "nr_views", 1, errp); + object_property_set_uint(OBJECT(qtimer), "cnttid", 0x111, errp); + sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), errp); + + + unsigned QTMR0_IRQ = 3; + sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 0, 0xfab20000); + sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_rg0); + sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 0, + qdev_get_gpio_in(vms->l2vic, QTMR0_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), 1, + qdev_get_gpio_in(vms->l2vic, 4)); +} + static void virt_instance_init(Object *obj) { HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(obj); @@ -353,6 +375,7 @@ static void virt_init(MachineState *ms) fdt_add_clocks(vms); fdt_add_uart(vms, 0); fdt_add_gpt_node(vms); + create_qtimer(vms, m_cfg); hexagon_config_table *config_table = (hexagon_config_table *)&m_cfg->cfgtable; diff --git a/hw/timer/meson.build b/hw/timer/meson.build index f5f9eed2d0a9..6c30bf602226 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -34,3 +34,5 @@ specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) system_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) specific_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c')) + +specific_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('qct-qtimer.c')) diff --git a/hw/timer/qct-qtimer.c b/hw/timer/qct-qtimer.c new file mode 100644 index 000000000000..413f7249eef0 --- /dev/null +++ b/hw/timer/qct-qtimer.c @@ -0,0 +1,519 @@ +/* + * Qualcomm QCT QTimer + * + * Copyright(c) 2019-2025 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/timer/qct-qtimer.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" + +/* Common timer implementation. */ + +#define QTIMER_MEM_SIZE_BYTES 0x1000 +#define QTIMER_MEM_REGION_SIZE_BYTES 0x1000 +#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL +#define QTMR_TIMER_INDEX_MASK (0xf000) +#define HIGH_32(val) (0x0ffffffffULL & (val >> 32)) +#define LOW_32(val) (0x0ffffffffULL & val) + +/* + * QTimer version reg: + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Major | Minor | Step | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +static unsigned int TIMER_VERSION = 0x20020000; + +/* + * qct_qtimer_read/write: + * if offset < 0x1000 read restricted registers: + * QCT_QTIMER_AC_CNTFREQ/CNTSR/CNTTID/CNTACR/CNTOFF_(LO/HI)/QCT_QTIMER_VERSION + */ +static uint64_t qct_qtimer_read(void *opaque, hwaddr offset, unsigned size) +{ + QCTQtimerState *s = (QCTQtimerState *)opaque; + uint32_t frame = 0; + + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + return s->freq; + case QCT_QTIMER_AC_CNTSR: + return s->secure; + case QCT_QTIMER_AC_CNTTID: + return s->cnttid; + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame = (offset - 0x40) / 0x4; + if (frame >= s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: QCT_QTIMER_AC_CNT: Bad offset %x\n", __func__, + (int)offset); + return 0x0; + } + return s->timer[frame].cnt_ctrl; + case QCT_QTIMER_VERSION: + return TIMER_VERSION; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: QCT_QTIMER_AC_CNT: Bad offset %x\n", + __func__, (int)offset); + return 0x0; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, + (int)offset); + return 0; +} + +static void qct_qtimer_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + QCTQtimerState *s = (QCTQtimerState *)opaque; + uint32_t frame = 0; + + if (offset < 0x1000) { + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + s->freq = value; + return; + case QCT_QTIMER_AC_CNTSR: + if (value > 0xFF) + qemu_log_mask(LOG_GUEST_ERROR, + "%s: QCT_QTIMER_AC_CNTSR: Bad value %x\n", + __func__, (int)value); + else + s->secure = value; + return; + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame = (offset - QCT_QTIMER_AC_CNTACR_START) / 0x4; + if (frame >= s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: QCT_QTIMER_AC_CNT: Bad offset %x\n", + __func__, (int)offset); + return; + } + s->timer[frame].cnt_ctrl = value; + return; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: QCT_QTIMER_AC_CNT: Bad offset %x\n", __func__, + (int)offset); + return; + } + } else + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", __func__, + (int)offset); +} + +static const MemoryRegionOps qct_qtimer_ops = { + .read = qct_qtimer_read, + .write = qct_qtimer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_qct_qtimer = { + .name = "qct-qtimer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]){ VMSTATE_END_OF_LIST() } +}; + +static void qct_qtimer_init(Object *obj) +{ + QCTQtimerState *s = QCT_QTIMER(obj); + + object_property_add_uint32_ptr(obj, "secure", &s->secure, + OBJ_PROP_FLAG_READ); + object_property_add_uint32_ptr(obj, "frame_id", &s->frame_id, + OBJ_PROP_FLAG_READ); +} + +static void hex_timer_update(QCTHextimerState *s) +{ + /* Update interrupts. */ + int level = s->int_level && (s->control & QCT_QTIMER_CNTP_CTL_ENABLE); + qemu_set_irq(s->irq, level); +} + +static MemTxResult hex_timer_read(void *opaque, hwaddr offset, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + QCTQtimerState *qct_s = (QCTQtimerState *)opaque; + uint32_t slot_nr = (offset & 0xF000) >> 12; + uint32_t reg_offset = offset & 0xFFF; + uint32_t view = slot_nr % qct_s->nr_views; + uint32_t frame = slot_nr / qct_s->nr_views; + + if (frame >= qct_s->nr_frames) { + *data = 0; + return MEMTX_ACCESS_ERROR; + } + QCTHextimerState *s = &qct_s->timer[frame]; + + + /* + * This is the case where we have 2 views, but the second one is not + * implemented. + */ + if (view && !(qct_s->cnttid & (0x4 << (frame * 4)))) { + *data = 0; + return MEMTX_OK; + } + + switch (reg_offset) { + case (QCT_QTIMER_CNT_FREQ): /* Ticks/Second */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RFRQ)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !((s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0PCTEN) || + (s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0VCTEN))) { + return MEMTX_ACCESS_ERROR; + } + + *data = s->freq; + return MEMTX_OK; + case (QCT_QTIMER_CNTP_CVAL_LO): /* TimerLoad */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = LOW_32((s->cntval)); + return MEMTX_OK; + case (QCT_QTIMER_CNTP_CVAL_HI): /* TimerLoad */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = HIGH_32((s->cntval)); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_LO: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RPCT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0PCTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = LOW_32((s->cntpct + (ptimer_get_count(s->timer)))); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_HI: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RPCT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0PCTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = HIGH_32((s->cntpct + (ptimer_get_count(s->timer)))); + return MEMTX_OK; + case (QCT_QTIMER_CNTP_TVAL): /* CVAL - CNTP */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = + (s->cntval - (HIGH_32((s->cntpct + (ptimer_get_count(s->timer)))) + + LOW_32((s->cntpct + (ptimer_get_count(s->timer)))))); + return MEMTX_OK; + case (QCT_QTIMER_CNTP_CTL): /* TimerMIS */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + *data = s->int_level; + return MEMTX_OK; + case QCT_QTIMER_CNTPL0ACR: + if (view) { + *data = 0; + } else { + *data = s->cntpl0acr; + } + return MEMTX_OK; + + case QCT_QTIMER_VERSION: + *data = TIMER_VERSION; + return MEMTX_OK; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", __func__, + (int)offset); + *data = 0; + return MEMTX_ACCESS_ERROR; + } +} + +/* + * Reset the timer limit after settings have changed. + * May only be called from inside a ptimer transaction block. + */ +static void hex_timer_recalibrate(QCTHextimerState *s, int reload) +{ + uint64_t limit; + /* Periodic. */ + limit = s->limit; + ptimer_set_limit(s->timer, limit, reload); +} + +static MemTxResult hex_timer_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + QCTQtimerState *qct_s = (QCTQtimerState *)opaque; + uint32_t slot_nr = (offset & 0xF000) >> 12; + uint32_t reg_offset = offset & 0xFFF; + uint32_t view = slot_nr % qct_s->nr_views; + uint32_t frame = slot_nr / qct_s->nr_views; + + if (frame >= qct_s->nr_frames) { + return MEMTX_ACCESS_ERROR; + } + QCTHextimerState *s = &qct_s->timer[frame]; + + /* + * This is the case where we have 2 views, but the second one is not + * implemented. + */ + if (view && !(qct_s->cnttid & (0x4 << (frame * 4)))) { + return MEMTX_OK; + } + + switch (reg_offset) { + case (QCT_QTIMER_CNTP_CVAL_LO): /* TimerLoad */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + + s->int_level = 0; + s->cntval = value; + ptimer_transaction_begin(s->timer); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + /* + * Pause the timer if it is running. This may cause some + * inaccuracy due to rounding, but avoids other issues. + */ + ptimer_stop(s->timer); + } + hex_timer_recalibrate(s, 1); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + ptimer_run(s->timer, 0); + } + ptimer_transaction_commit(s->timer); + break; + case (QCT_QTIMER_CNTP_CVAL_HI): + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + break; + case (QCT_QTIMER_CNTP_CTL): /* Timer control register */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + ptimer_transaction_begin(s->timer); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + /* + * Pause the timer if it is running. This may cause some + * inaccuracy due to rounding, but avoids other issues. + */ + ptimer_stop(s->timer); + } + s->control = value; + hex_timer_recalibrate(s, s->control & QCT_QTIMER_CNTP_CTL_ENABLE); + ptimer_set_freq(s->timer, s->freq); + ptimer_set_period(s->timer, 1); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + ptimer_run(s->timer, 0); + } + ptimer_transaction_commit(s->timer); + break; + case (QCT_QTIMER_CNTP_TVAL): /* CVAL - CNTP */ + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + + ptimer_transaction_begin(s->timer); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + /* + * Pause the timer if it is running. This may cause some + * inaccuracy due to rounding, but avoids other issues. + */ + ptimer_stop(s->timer); + } + s->cntval = s->cntpct + value; + ptimer_set_freq(s->timer, s->freq); + ptimer_set_period(s->timer, 1); + if (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) { + ptimer_run(s->timer, 0); + } + ptimer_transaction_commit(s->timer); + break; + case QCT_QTIMER_CNTPL0ACR: + if (view) { + break; + } + + s->cntpl0acr = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", __func__, + (int)offset); + return MEMTX_ACCESS_ERROR; + } + hex_timer_update(s); + return MEMTX_OK; +} + +static void hex_timer_tick(void *opaque) +{ + QCTHextimerState *s = (QCTHextimerState *)opaque; + if ((s->cntpct >= s->cntval) && (s->int_level != 1)) { + s->int_level = 1; + hex_timer_update(s); + return; + } + s->cntpct += s->limit; +} + +static const MemoryRegionOps hex_timer_ops = { + .read_with_attrs = hex_timer_read, + .write_with_attrs = hex_timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_hex_timer = { + .name = "hex_timer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]){ VMSTATE_UINT32(control, QCTHextimerState), + VMSTATE_UINT32(cnt_ctrl, QCTHextimerState), + VMSTATE_UINT64(cntpct, QCTHextimerState), + VMSTATE_UINT64(cntval, QCTHextimerState), + VMSTATE_UINT64(limit, QCTHextimerState), + VMSTATE_UINT32(int_level, QCTHextimerState), + VMSTATE_PTIMER(timer, QCTHextimerState), + VMSTATE_END_OF_LIST() } +}; + +static void qct_qtimer_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + QCTQtimerState *s = QCT_QTIMER(dev); + unsigned int i; + + if (s->nr_frames > QCT_QTIMER_TIMER_FRAME_ELTS) { + error_setg(errp, "nr_frames too high"); + return; + } + + if (s->nr_views > QCT_QTIMER_TIMER_VIEW_ELTS) { + error_setg(errp, "nr_views too high"); + return; + } + + memory_region_init_io(&s->iomem, OBJECT(sbd), &qct_qtimer_ops, s, "qutimer", + QTIMER_MEM_SIZE_BYTES); + sysbus_init_mmio(sbd, &s->iomem); + + memory_region_init_io(&s->view_iomem, OBJECT(sbd), &hex_timer_ops, s, + "qutimer_views", + QTIMER_MEM_SIZE_BYTES * s->nr_frames * s->nr_views); + sysbus_init_mmio(sbd, &s->view_iomem); + + for (i = 0; i < s->nr_frames; i++) { + s->timer[i].limit = 1; + s->timer[i].control = QCT_QTIMER_CNTP_CTL_ENABLE; + s->timer[i].cnt_ctrl = + (QCT_QTIMER_AC_CNTACR_RWPT | QCT_QTIMER_AC_CNTACR_RWVT | + QCT_QTIMER_AC_CNTACR_RVOFF | QCT_QTIMER_AC_CNTACR_RFRQ | + QCT_QTIMER_AC_CNTACR_RPVCT | QCT_QTIMER_AC_CNTACR_RPCT); + s->timer[i].qtimer = s; + s->timer[i].freq = QTIMER_DEFAULT_FREQ_HZ; + + s->secure |= (1 << i); + + sysbus_init_irq(sbd, &(s->timer[i].irq)); + + (s->timer[i]).timer = + ptimer_init(hex_timer_tick, &s->timer[i], PTIMER_POLICY_LEGACY); + vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_hex_timer, + &s->timer[i]); + } +} + +static const Property qct_qtimer_properties[] = { + DEFINE_PROP_UINT32("freq", QCTQtimerState, freq, QTIMER_DEFAULT_FREQ_HZ), + DEFINE_PROP_UINT32("nr_frames", QCTQtimerState, nr_frames, 2), + DEFINE_PROP_UINT32("nr_views", QCTQtimerState, nr_views, 1), + DEFINE_PROP_UINT32("cnttid", QCTQtimerState, cnttid, 0x11), +}; + +static void qct_qtimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + + device_class_set_props(k, qct_qtimer_properties); + k->realize = qct_qtimer_realize; + k->vmsd = &vmstate_qct_qtimer; +} + +static const TypeInfo qct_qtimer_info = { + .name = TYPE_QCT_QTIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(QCTQtimerState), + .instance_init = qct_qtimer_init, + .class_init = qct_qtimer_class_init, +}; + +static void qct_qtimer_register_types(void) +{ + type_register_static(&qct_qtimer_info); +} + +type_init(qct_qtimer_register_types) diff --git a/include/hw/timer/qct-qtimer.h b/include/hw/timer/qct-qtimer.h new file mode 100644 index 000000000000..ab02181d0339 --- /dev/null +++ b/include/hw/timer/qct-qtimer.h @@ -0,0 +1,85 @@ +/* + * Qualcomm QCT QTimer + * + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef TIMER_QCT_QTIMER_H +#define TIMER_QCT_QTIMER_H + +#include "hw/ptimer.h" +#include "hw/sysbus.h" + +#define TYPE_QCT_QTIMER "qct-qtimer" +#define TYPE_QCT_HEXTIMER "qct-hextimer" +OBJECT_DECLARE_SIMPLE_TYPE(QCTQtimerState, QCT_QTIMER) +OBJECT_DECLARE_SIMPLE_TYPE(QCTHextimerState, QCT_HEXTIMER) + +struct QCTHextimerState { + QCTQtimerState *qtimer; + ptimer_state *timer; + uint64_t cntval; /* + * Physical timer compare value interrupt when cntpct > + * cntval + */ + uint64_t cntpct; /* Physical counter */ + uint32_t control; + uint32_t cnt_ctrl; + uint32_t cntpl0acr; + uint64_t limit; + uint32_t freq; + uint32_t int_level; + qemu_irq irq; +}; + +#define QCT_QTIMER_TIMER_FRAME_ELTS (8) +#define QCT_QTIMER_TIMER_VIEW_ELTS (2) +struct QCTQtimerState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegion view_iomem; + uint32_t secure; + struct QCTHextimerState timer[QCT_QTIMER_TIMER_FRAME_ELTS]; + uint32_t frame_id; + uint32_t freq; + uint32_t nr_frames; + uint32_t nr_views; + uint32_t cnttid; +}; + +#define QCT_QTIMER_AC_CNTFRQ (0x000) +#define QCT_QTIMER_AC_CNTSR (0x004) +#define QCT_QTIMER_AC_CNTSR_NSN_1 (1 << 0) +#define QCT_QTIMER_AC_CNTSR_NSN_2 (1 << 1) +#define QCT_QTIMER_AC_CNTSR_NSN_3 (1 << 2) +#define QCT_QTIMER_AC_CNTTID (0x08) +#define QCT_QTIMER_AC_CNTACR_0 (0x40) +#define QCT_QTIMER_AC_CNTACR_1 (0x44) +#define QCT_QTIMER_AC_CNTACR_2 (0x48) +#define QCT_QTIMER_AC_CNTACR_RWPT (1 << 5) /* R/W of CNTP_* regs */ +#define QCT_QTIMER_AC_CNTACR_RWVT (1 << 4) /* R/W of CNTV_* regs */ +#define QCT_QTIMER_AC_CNTACR_RVOFF (1 << 3) /* R/W of CNTVOFF register */ +#define QCT_QTIMER_AC_CNTACR_RFRQ (1 << 2) /* R/W of CNTFRQ register */ +#define QCT_QTIMER_AC_CNTACR_RPVCT (1 << 1) /* R/W of CNTVCT register */ +#define QCT_QTIMER_AC_CNTACR_RPCT (1 << 0) /* R/W of CNTPCT register */ +#define QCT_QTIMER_VERSION (0x0fd0) +#define QCT_QTIMER_CNTPCT_LO (0x000) +#define QCT_QTIMER_CNTPCT_HI (0x004) +#define QCT_QTIMER_CNT_FREQ (0x010) +#define QCT_QTIMER_CNTPL0ACR (0x014) +#define QCT_QTIMER_CNTPL0ACR_PL0CTEN (1 << 9) +#define QCT_QTIMER_CNTPL0ACR_PL0TVEN (1 << 8) +#define QCT_QTIMER_CNTPL0ACR_PL0VCTEN (1 << 1) +#define QCT_QTIMER_CNTPL0ACR_PL0PCTEN (1 << 0) +#define QCT_QTIMER_CNTP_CVAL_LO (0x020) +#define QCT_QTIMER_CNTP_CVAL_HI (0x024) +#define QCT_QTIMER_CNTP_TVAL (0x028) +#define QCT_QTIMER_CNTP_CTL (0x02c) +#define QCT_QTIMER_CNTP_CTL_ISTAT (1 << 2) +#define QCT_QTIMER_CNTP_CTL_INTEN (1 << 1) +#define QCT_QTIMER_CNTP_CTL_ENABLE (1 << 0) +#define QCT_QTIMER_AC_CNTACR_START 0x40 +#define QCT_QTIMER_AC_CNTACR_END 0x5C + +#endif /* TIMER_QCT_QTIMER_H */ From 6f08d0256cc013cdbca21c2e805dbea895609eb6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 2 Jan 2025 19:53:06 -0800 Subject: [PATCH 108/109] target/hexagon: Implement hexagon_read_timer() Signed-off-by: Brian Cain --- target/hexagon/op_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index fc2b43a22685..e818a86a8c03 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -37,6 +37,7 @@ #ifndef CONFIG_USER_ONLY #include "hex_mmu.h" #include "hw/intc/l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "hex_interrupts.h" #endif @@ -1765,7 +1766,13 @@ static uint32_t hexagon_find_last_irq(CPUHexagonState *env, uint32_t vid) static void hexagon_read_timer(CPUHexagonState *env, uint32_t *low, uint32_t *high) { - qemu_log_mask(LOG_UNIMP, "reading timer_hi/lo not yet supported\n"); + CPUState *cs = env_cpu(env); + HexagonCPU *cpu = HEXAGON_CPU(cs); + const hwaddr low_addr = cpu->qtimer_base_addr + QCT_QTIMER_CNTPCT_LO; + const hwaddr high_addr = cpu->qtimer_base_addr + QCT_QTIMER_CNTPCT_HI; + + cpu_physical_memory_read(low_addr, low, sizeof(*low)); + cpu_physical_memory_read(high_addr, high, sizeof(*high)); } static inline QEMU_ALWAYS_INLINE void sreg_write(CPUHexagonState *env, From 1298fe7d04f646bde4d9f74acfe492905df9a088 Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Fri, 3 Jan 2025 11:42:41 -0800 Subject: [PATCH 109/109] Update initialization sequence to fix l2vic interrupts Looks like qdev_realize_and_unref must be called first otherwise the associated irqs functions are null. Signed-off-by: Sid Manning --- hw/hexagon/hexagon_dsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 38cee6d56cc1..cd6ca36db791 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -124,6 +124,9 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, if (i == 0) { hexagon_init_bootstrap(machine, cpu); + if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + return; + } DeviceState *l2vic_dev; l2vic_dev = sysbus_create_varargs("l2vic", m_cfg->l2vic_base, /* IRQ#, Evnt#,CauseCode */ @@ -138,9 +141,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, NULL); sysbus_mmio_map(SYS_BUS_DEVICE(l2vic_dev), 1, m_cfg->cfgtable.fastl2vic_base << 16); - } - - if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { + } else if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) { return; }