Initial version of a RiscV64g assembler. There will be some issues and differences between this and the standard RiscV assembler to be detailed later. PiperOrigin-RevId: 715854881 Change-Id: I1a9bca71106fbc30f94a93a3aa0af3dc71888427
diff --git a/riscv/BUILD b/riscv/BUILD index d3e2c14..65faa21 100644 --- a/riscv/BUILD +++ b/riscv/BUILD
@@ -862,6 +862,56 @@ ) cc_library( + name = "riscv64g_encoder", + srcs = [ + "riscv64g_bin_encoder_interface.cc", + "riscv_bin_setters.cc", + ], + hdrs = [ + "riscv64g_bin_encoder_interface.h", + "riscv_bin_setters.h", + ], + deps = [ + ":riscv64g_bin_fmt", + ":riscv64g_isa", + ":riscv_getters", + ":riscv_state", + "@com_google_absl//absl/base:no_destructor", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_mpact-sim//mpact/sim/generic:type_helpers", + "@com_google_mpact-sim//mpact/sim/util/asm", + "@com_googlesource_code_re2//:re2", + ], +) + +cc_binary( + name = "riscv64g_as", + srcs = ["riscv64g_as_main.cc"], + copts = ["-O3"], + deps = [ + ":riscv64g_bin_fmt", + ":riscv64g_encoder", + ":riscv64g_isa", + "@com_github_serge1_elfio//:elfio", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_mpact-sim//mpact/sim/generic:type_helpers", + "@com_google_mpact-sim//mpact/sim/util/asm", + "@com_google_mpact-sim//mpact/sim/util/asm:simple_assembler", + "@com_googlesource_code_re2//:re2", + ], +) + +cc_library( name = "riscv64g_vec_decoder", srcs = [ "riscv64g_vec_decoder.cc",
diff --git a/riscv/riscv64g.isa b/riscv/riscv64g.isa index 7fcbc7f..467e57c 100644 --- a/riscv/riscv64g.isa +++ b/riscv/riscv64g.isa
@@ -43,7 +43,7 @@ slot riscv64g : riscv64i, riscv64c, riscv64m, riscv64_amo_arithmetic, riscv64f, riscv64d, zicsr, zfencei, privileged { default size = 4; default opcode = - disasm: "Illegal instruction at 0x%(@:08x)", + disasm: "Illegal instruction at %(@:08x)", semfunc: "&RiscVIllegalInstruction"; } @@ -57,11 +57,11 @@ resources TwoOp = { next_pc, rs1 : rd[..rd]}; resources ThreeOp = { next_pc, rs1, rs2 : rd[..rd]}; opcodes { - addi{: rs1, I_imm12 : rd}, + addi{: rs1, %reloc(I_imm12) : rd}, resources: TwoOp, disasm: "addi", "%rd, %rs1, %I_imm12", semfunc: "&RV64::RiscVIAdd"; - addiw{: rs1, I_imm12 : rd}, + addiw{: rs1, %reloc(I_imm12) : rd}, resources: TwoOp, disasm: "addiw", "%rd, %rs1, %I_imm12", semfunc: "&RV64::RiscVIAddw"; @@ -87,42 +87,42 @@ semfunc: "&RV64::RiscVIXor"; slli{: rs1, I_uimm6 : rd}, resources: TwoOp, - disasm: "slli", "%rd, %rs1, 0x%(I_uimm6:x)", + disasm: "slli", "%rd, %rs1, %(I_uimm6:x)", semfunc: "&RV64::RiscVISll"; srli{: rs1, I_uimm6 : rd}, resources: TwoOp, - disasm: "srli", "%rd %rs1, 0x%(I_uimm6:x)", + disasm: "srli", "%rd %rs1, %(I_uimm6:x)", semfunc: "&RV64::RiscVISrl"; srai{: rs1, I_uimm6 : rd}, resources: TwoOp, - disasm: "srai", "%rd, %rs1, 0x%(I_uimm6:x)", + disasm: "srai", "%rd, %rs1, %(I_uimm6:x)", semfunc: "&RV64::RiscVISra"; slliw{: rs1, I_uimm5 : rd}, resources: TwoOp, - disasm: "slliw", "%rd, %rs1, 0x%(I_uimm5:x)", + disasm: "slliw", "%rd, %rs1, %(I_uimm5:x)", semfunc: "&RV64::RiscVISllw"; srliw{: rs1, I_uimm5 : rd}, resources: TwoOp, - disasm: "srliw", "%rd %rs1, 0x%(I_uimm5:x)", + disasm: "srliw", "%rd %rs1, %(I_uimm5:x)", semfunc: "&RV64::RiscVISrlw"; sraiw{: rs1, I_uimm5 : rd}, resources: TwoOp, - disasm: "sraiw", "%rd, %rs1, 0x%(I_uimm5:x)", + disasm: "sraiw", "%rd, %rs1, %(I_uimm5:x)", semfunc: "&RV64::RiscVISraw"; - lui{: U_imm20 : rd}, + lui{: %reloc(U_imm20) : rd}, resources: { next_pc : rd[0..]}, - disasm: "lui", "%rd, 0x%(U_imm20:08x)", + disasm: "lui", "%rd, %(U_imm20:08x)", semfunc: "&RV64::RiscVILui"; - auipc{: U_imm20 : rd}, + auipc{: %reloc(U_imm20) : rd}, resources: { next_pc : rd[0..]}, - disasm: "auipc", "%rd, 0x%(U_imm20:08x)", + disasm: "auipc", "%rd, %(U_imm20:08x)", semfunc: "&RV64::RiscVIAuipc"; add{: rs1, rs2 : rd}, resources: ThreeOp, disasm: "add", "%rd, %rs1, %rs2", semfunc: "&RV64::RiscVIAdd"; addw{: rs1, rs2 : rd}, - disasm: "add", "%rd, %rs1, %rs2", + disasm: "addw", "%rd, %rs1, %rs2", semfunc: "&RV64::RiscVIAddw"; slt{: rs1, rs2 : rd}, resources: ThreeOp, @@ -170,7 +170,7 @@ semfunc: "&RV64::RiscVISrlw"; subw{: rs1, rs2 : rd}, resources: ThreeOp, - disasm: "sub", "%rd, %rs1, %rs2", + disasm: "subw", "%rd, %rs1, %rs2", semfunc: "&RV64::RiscVISubw"; sraw{: rs1, rs2 : rd}, resources: ThreeOp, @@ -182,87 +182,87 @@ hint{}, disasm: "hint", semfunc: "&RiscVINop"; - jal{: J_imm20 : next_pc, rd}, + jal{: %reloc(J_imm20) : next_pc, rd}, resources: { next_pc : next_pc[0..], rd[0..]}, disasm: "jal", "%rd, %(@+J_imm20:08x)", semfunc: "&RV64::RiscVIJal"; - jalr{: rs1, J_imm12 : next_pc, rd}, + jalr{: rs1, %reloc(J_imm12) : next_pc, rd}, resources: { next_pc, rs1 : next_pc[0..], rd[0..]}, disasm: "jalr", "%rd, %rs1, %J_imm12", semfunc: "&RV64::RiscVIJalr"; - j{: J_imm20 : next_pc, rd}, + j{: %reloc(J_imm20) : next_pc, rd}, resources: { next_pc : next_pc[0..], rd[0..]}, disasm: "j", "%(@+J_imm20:08x)", semfunc: "&RV64::RiscVIJal"; - jr{: rs1, J_imm12 : next_pc, rd}, + jr{: rs1, %reloc(J_imm12) : next_pc, rd}, resources: { next_pc, rs1 : next_pc[0..], rd[0..]}, - disasm: "jr", "%rs1, %J_imm12", + disasm: "jr", "%rs1, %(J_imm12:08x)", semfunc: "&RV64::RiscVIJalr"; - beq{: rs1, rs2, B_imm12 : next_pc}, + beq{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "beq", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBeq"; - bne{: rs1, rs2, B_imm12 : next_pc}, + bne{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "bne", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBne"; - blt{: rs1, rs2, B_imm12 : next_pc}, + blt{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "blt", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBlt"; - bltu{: rs1, rs2, B_imm12 : next_pc}, + bltu{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "bltu", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBltu"; - bge{: rs1, rs2, B_imm12 : next_pc}, + bge{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "bge", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBge"; - bgeu{: rs1, rs2, B_imm12 : next_pc}, + bgeu{: rs1, rs2, %reloc(B_imm12) : next_pc}, resources: { next_pc, rs1, rs2 : next_pc[0..]}, disasm: "bgeu", "%rs1, %rs2, %(@+B_imm12:08x)", semfunc: "&RV64::RiscVIBgeu"; - ld{(: rs1, I_imm12), (: : rd)}, + ld{(: rs1, %reloc(I_imm12)), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "ld", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILd", "&RV64::RiscVILdChild"; - lw{(: rs1, I_imm12), (: : rd)}, + lw{(: rs1, %reloc(I_imm12)), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lw", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILw", "&RV64::RiscVILwChild"; - lwu{(: rs1, I_imm12), (: : rd)}, + lwu{(: rs1, %reloc(I_imm12)), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lwu", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILw", "&RV64::RiscVILwuChild"; - lh{(: rs1, I_imm12 :), (: : rd)}, + lh{(: rs1, %reloc(I_imm12) :), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lh", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILh", "&RV64::RiscVILhChild"; - lhu{(: rs1, I_imm12 :), (: : rd)}, + lhu{(: rs1, %reloc(I_imm12) :), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lhu", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILhu", "&RV64::RiscVILhuChild"; - lb{(: rs1, I_imm12 :), (: : rd)}, + lb{(: rs1, %reloc(I_imm12) :), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lb", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILb", "&RV64::RiscVILbChild"; - lbu{(: rs1, I_imm12 :), (: : rd)}, + lbu{(: rs1, %reloc(I_imm12) :), (: : rd)}, resources: { next_pc, rs1 : rd[0..]}, disasm: "lbu", "%rd, %I_imm12(%rs1)", semfunc: "&RV64::RiscVILbu", "&RV64::RiscVILbuChild"; - sd{: rs1, S_imm12, rs2 : }, + sd{: rs1, %reloc(S_imm12), rs2 : }, resources: { next_pc, rs1, rs2 : }, disasm: "sd", "%rs2, %S_imm12(%rs1)", semfunc: "&RV64::RiscVISd"; - sw{: rs1, S_imm12, rs2 : }, + sw{: rs1, %reloc(S_imm12), rs2 : }, resources: { next_pc, rs1, rs2 : }, disasm: "sw", "%rs2, %S_imm12(%rs1)", semfunc: "&RV64::RiscVISw"; - sh{: rs1, S_imm12, rs2 : }, + sh{: rs1, %reloc(S_imm12), rs2 : }, resources: { next_pc, rs1, rs2 : }, disasm: "sh", "%rs2, %S_imm12(%rs1)", semfunc: "&RV64::RiscVISh"; - sb{: rs1, S_imm12, rs2 : }, + sb{: rs1, %reloc(S_imm12), rs2 : }, resources: { next_pc, rs1, rs2 : }, disasm: "sb", "%rs2, %S_imm12(%rs1)", semfunc: "&RV64::RiscVISb"; @@ -442,11 +442,11 @@ opcodes { amoswapw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoswap.w", "%rd, rs2, (%rs1)", + disasm: "amoswap.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmoswapw", "&RV64::RiscVILwChild"; amoswapd{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoswap.d", "%rd, rs2, (%rs1)", + disasm: "amoswap.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmoswapd", "&RV64::RiscVILdChild"; } } @@ -460,27 +460,27 @@ opcodes { amoandw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoand.w", "%rd, rs2, (%rs1)", + disasm: "amoand.w%A_aq%A_rl", "%rd, %rs2, (%rs1)", semfunc: "&AAmoandw", "&RV64::RiscVILwChild"; amoandd{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoand.d", "%rd, rs2, (%rs1)", + disasm: "amoand.d%A_aq%A_rl", "%rd, %rs2, (%rs1)", semfunc: "&AAmoandd", "&RV64::RiscVILdChild"; amoorw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoor.w", "%rd, rs2, (%rs1)", + disasm: "amoor.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmoorw", "&RV64::RiscVILwChild"; amoord{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoor.d", "%rd, rs2, (%rs1)", + disasm: "amoor.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmoord", "&RV64::RiscVILdChild"; amoxorw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoxor.w", "%rd, rs2, (%rs1)", + disasm: "amoxor.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmoxorw", "&RV64::RiscVILwChild"; amoxord{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoxor.d", "%rd, rs2, (%rs1)", + disasm: "amoxor.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmoxord", "&RV64::RiscVILdChild"; } } @@ -494,43 +494,43 @@ opcodes { amoaddw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoadd.w", "%rd, rs2, (%rs1)", + disasm: "amoadd.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmoaddw", "&RV64::RiscVILwChild"; amoaddd{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amoadd.d", "%rd, rs2, (%rs1)", + disasm: "amoadd.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmoaddd", "&RV64::RiscVILdChild"; amomaxw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomax.w", "%rd, rs2, (%rs1)", + disasm: "amomax.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmomaxw", "&RV64::RiscVILwChild"; amomaxd{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomax.d", "%rd, rs2, (%rs1)", + disasm: "amomax.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmomaxd", "&RV64::RiscVILdChild"; amomaxuw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomaxu.w", "%rd, rs2, (%rs1)", + disasm: "amomaxu.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmomaxuw", "&RV64::RiscVILwChild"; amomaxud{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomaxu.d", "%rd, rs2, (%rs1)", + disasm: "amomaxu.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmomaxud", "&RV64::RiscVILdChild"; amominw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomin.w", "%rd, rs2, (%rs1)", + disasm: "amomin.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmominw", "&RV64::RiscVILwChild"; amomind{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amomin.d", "%rd, rs2, (%rs1)", + disasm: "amomin.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmomind", "&RV64::RiscVILdChild"; amominuw{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amominu.w", "%rd, rs2, (%rs1)", + disasm: "amominu.w", "%rd, %rs2, (%rs1)", semfunc: "&AAmominuw", "&RV64::RiscVILwChild"; amominud{(: rs1, rs2, A_aq, A_rl), (: : rd)}, resources: ThreeOp, - disasm: "amominu.d", "%rd, rs2, (%rs1)", + disasm: "amominu.d", "%rd, %rs2, (%rs1)", semfunc: "&AAmominud", "&RV64::RiscVILdChild"; } } @@ -621,11 +621,11 @@ resources ThreeOp = { next_pc, frs1, frs2 : frd[0..]}; resources FourOp = { next_pc, frs1, frs2, frs3 : frd[0..]}; opcodes { - flw{(: rs1, I_imm12 : ), (: : frd)}, + flw{(: rs1, %reloc(I_imm12) : ), (: : frd)}, resources: { next_pc, rs1 : frd[0..]}, semfunc: "&RV64::RiscVILw", "&RiscVIFlwChild", disasm: "flw", "%frd, %I_imm12(%rs1)"; - fsw{: rs1, S_imm12, frs2}, + fsw{: rs1, %reloc(S_imm12), frs2}, resources: { next_pc, rs1, frs2}, semfunc: "&RV64::RiscVFSw", disasm: "fsw", "%frs2, %S_imm12(%rs1)"; @@ -752,11 +752,11 @@ default size = 4; default latency = global_latency; opcodes { - fld{(: rs1, I_imm12 : ), (: : drd)}, + fld{(: rs1, %reloc(I_imm12) : ), (: : drd)}, resources: {next_pc, rs1 : drd[0..]}, semfunc: "&RV64::RiscVILd", "&RV64::RiscVILdChild", disasm: "fld", "%drd, %I_imm12(%rs1)"; - fsd{: rs1, S_imm12, drs2}, + fsd{: rs1, %reloc(S_imm12), drs2}, resources: {next_pc, rs1, drs2}, semfunc: "&RV64::RiscVDSd", disasm: "fsd", "%drs2, %S_imm12(%rs1)"; @@ -936,7 +936,7 @@ resources: {next_pc,c3rs1, c3drs2}, disasm: "c.fsd", "%c3drs2, %I_cl_uimm5x8(%c3rs1)", semfunc: "&RV64::RiscVISd"; - cj{: I_cj_imm11, x0 : next_pc, x0}, + cj{: %reloc(I_cj_imm11), x0 : next_pc, x0}, resources: {next_pc,x0 : next_pc[0..], x0[0..]}, disasm: "c.j", "%(@+I_cj_imm11:08x)", semfunc: "&RV64::RiscVIJal"; @@ -948,11 +948,11 @@ resources: {next_pc,crs1, x0 : next_pc[0..], x1[0..]}, disasm: "c.jalr", "%crs1", semfunc: "&RV64::RiscVIJalr"; - cbeqz{: c3rs1, x0, I_cb_imm8 : next_pc}, + cbeqz{: c3rs1, x0, %reloc(I_cb_imm8) : next_pc}, resources: {next_pc,c3rs1, x0 : next_pc[0..]}, disasm: "c.beqz", "%c3rs1, %(@+I_cb_imm8:08x)", semfunc: "&RV64::RiscVIBeq"; - cbnez{: c3rs1, x0, I_cb_imm8 : next_pc}, + cbnez{: c3rs1, x0, %reloc(I_cb_imm8) : next_pc}, resources: {next_pc,c3rs1, x0 : next_pc[0..]}, disasm: "c.bnez", "%c3rs1, %(@+I_cb_imm8:08x)", semfunc: "&RV64::RiscVIBne"; @@ -962,7 +962,7 @@ semfunc: "&RV64::RiscVIAdd"; clui{: I_ci_imm6_12 : rd}, resources: {next_pc : rd[0..]}, - disasm: "c.lui", "%rd, 0x%(I_ci_imm6_12:x)", + disasm: "c.lui", "%rd, %(I_ci_imm6_12:x)", semfunc: "&RV64::RiscVILui"; caddi{: rd, I_ci_imm6 : rd}, resources: {next_pc, rd : rd[0..]}, @@ -982,15 +982,15 @@ semfunc: "&RV64::RiscVIAdd"; cslli{: rd, I_ci_uimm6 : rd}, resources: {next_pc, rd : rd[0..]}, - disasm: "c.slli", "%rd, %rd, 0x%(I_ci_uimm6:x)", + disasm: "c.slli", "%rd, %rd, %(I_ci_uimm6:x)", semfunc: "&RV64::RiscVISll"; csrli{: c3rs1, I_ci_uimm6 : c3rs1}, resources: {next_pc, c3rs1 : c3rs1[0..]}, - disasm: "c.srli", "%c3rs1, %c3rs1, 0x%(I_ci_uimm6:x)", + disasm: "c.srli", "%c3rs1, %c3rs1, %(I_ci_uimm6:x)", semfunc: "&RV64::RiscVISrl"; csrai{: c3rs1, I_ci_uimm6 : c3rs1}, resources: {next_pc, c3rs1 : c3rs1[0..]}, - disasm: "c.srai", "%c3rs1, %c3rs1, 0x%(I_ci_uimm6:x)", + disasm: "c.srai", "%c3rs1, %c3rs1, %(I_ci_uimm6:x)", semfunc: "&RV64::RiscVISra"; candi{: c3rs1, I_ci_imm6 : c3rs1}, resources: {next_pc, c3rs1 : c3rs1[0..]},
diff --git a/riscv/riscv64g_as_main.cc b/riscv/riscv64g_as_main.cc new file mode 100644 index 0000000..fc1ff3e --- /dev/null +++ b/riscv/riscv64g_as_main.cc
@@ -0,0 +1,189 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cstdint> +#include <fstream> +#include <iostream> +#include <optional> +#include <string> +#include <vector> + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "elfio/elf_types.hpp" +#include "elfio/elfio.hpp" +#include "elfio/elfio_dump.hpp" +#include "mpact/sim/generic/type_helpers.h" +#include "mpact/sim/util/asm/opcode_assembler_interface.h" +#include "mpact/sim/util/asm/resolver_interface.h" +#include "mpact/sim/util/asm/simple_assembler.h" +#include "riscv/riscv64g_bin_encoder_interface.h" +#include "riscv/riscv64g_encoder.h" + +using ::mpact::sim::riscv::isa64::RiscV64GBinEncoderInterface; +using ::mpact::sim::riscv::isa64::Riscv64gSlotMatcher; +using ::mpact::sim::util::assembler::SimpleAssembler; + +// This file implements the main function for the generated assembler for +// RiscV64G. + +namespace { + +using ::mpact::sim::generic::operator*; // NOLINT(misc-unused-using-decls) +using ::mpact::sim::util::assembler::OpcodeAssemblerInterface; +using ::mpact::sim::util::assembler::RelocationInfo; +using ::mpact::sim::util::assembler::ResolverInterface; + +// This class implements the byte oriented OpcodeAssemblerInterface, converting +// from the bit interface provided by the SlotMatcher interface. +class RiscV64GAssembler : public OpcodeAssemblerInterface { + public: + RiscV64GAssembler(Riscv64gSlotMatcher* matcher) : matcher_(matcher) {}; + ~RiscV64GAssembler() override = default; + absl::Status Encode(uint64_t address, absl::string_view text, + ResolverInterface* resolver, std::vector<uint8_t>& bytes, + std::vector<RelocationInfo>& relocations) override { + auto res = matcher_->Encode(address, text, 0, resolver, relocations); + if (!res.status().ok()) return res.status(); + auto [value, size] = res.value(); + union { + uint64_t i; + uint8_t b[sizeof(uint64_t)]; + } u; + u.i = value; + for (int i = 0; i < size / 8; ++i) { + bytes.push_back(u.b[i]); + } + return absl::OkStatus(); + } + + private: + Riscv64gSlotMatcher* matcher_; +}; + +} // namespace + +// This flag dumps the info for the generated ELF file. +ABSL_FLAG(bool, dump_elf, false, "Dump the ELF file"); +// Produce a relocatable file as opposed to an executable. +ABSL_FLAG(bool, c, false, "Produce a relocatable file"); +// Specify the output file name. +ABSL_FLAG(std::optional<std::string>, o, std::nullopt, "Output file name"); + +// Supported RiscV ELF flags (TSO memory ordering and compact encodings). +enum class RiscVElfFlags { + kNone = 0, + kRiscvTso = 0x0001, + kRiscvRvc = 0x0010, +}; + +int main(int argc, char* argv[]) { + auto arg_vec = absl::ParseCommandLine(argc, argv); + + if (arg_vec.size() > 2) { + std::cout << "Too many arguments\n"; + return 1; + } + + std::istream* is; + + if (arg_vec.size() == 1) { + is = &std::cin; + } else { + is = new std::fstream(arg_vec[1], std::fstream::in); + } + + RiscV64GBinEncoderInterface bin_encoder_interface; + Riscv64gSlotMatcher matcher(&bin_encoder_interface); + RiscV64GAssembler riscv_64g_assembler(&matcher); + CHECK_OK(matcher.Initialize()); + // Instantiate the assembler. + SimpleAssembler assembler("#", ELFCLASS64, ELFOSABI_LINUX, EM_RISCV, + &riscv_64g_assembler); + // Set the appropriate ELF flags. + assembler.writer().set_flags(*RiscVElfFlags::kRiscvTso | + *RiscVElfFlags::kRiscvRvc); + // Perform the first pass of parsing the assembly code. + auto status = assembler.Parse(*is); + if (!status.ok()) { + std::cout << "Failed to parse assembly: " << status.message() << "\n"; + return 1; + } + // Perform the second pass of parsing the assembly code. This pass will either + // generate an executable or a relocatable file. + std::string output_file_name; + if (absl::GetFlag(FLAGS_c)) { + status = assembler.CreateRelocatable(); + if (arg_vec.size() == 1) { + output_file_name = "stdin.o"; + } else { + std::string input_file_name = arg_vec[1]; + auto dot_pos = input_file_name.find_last_of('.'); + if (dot_pos == std::string::npos) { + output_file_name = absl::StrCat(input_file_name, ".o"); + } else { + output_file_name = + absl::StrCat(input_file_name.substr(0, dot_pos), ".o"); + } + } + } else { + status = assembler.CreateExecutable(0x1000, "main"); + output_file_name = "a.out"; + } + if (!status.ok()) { + std::cout << "Assembly failure: " << status.message() << "\n"; + return 1; + } + // Write out the output file. + if (absl::GetFlag(FLAGS_o).has_value()) { + output_file_name = absl::GetFlag(FLAGS_o).value(); + } + std::ofstream output_file(output_file_name); + if (!output_file.is_open()) { + std::cout << "Failed to open output file: " << output_file_name << "\n"; + return 1; + } + status = assembler.Write(output_file); + if (!status.ok()) { + std::cout << "Failed to write output file: " << status.message() << "\n"; + return 1; + } + output_file.close(); + if (is != &std::cin) delete is; + + // Dump the ELF info if requested. + if (absl::GetFlag(FLAGS_dump_elf)) { + ELFIO::elfio reader; + if (!reader.load(output_file_name)) { + std::cout << "Failed to load output file: " << output_file_name << "\n"; + return 1; + } + + ELFIO::dump::header(std::cout, reader); + ELFIO::dump::section_headers(std::cout, reader); + ELFIO::dump::segment_headers(std::cout, reader); + ELFIO::dump::symbol_tables(std::cout, reader); + ELFIO::dump::notes(std::cout, reader); + ELFIO::dump::modinfo(std::cout, reader); + ELFIO::dump::dynamic_tags(std::cout, reader); + ELFIO::dump::section_datas(std::cout, reader); + ELFIO::dump::segment_datas(std::cout, reader); + } + return 0; +}
diff --git a/riscv/riscv64g_bin_encoder_interface.cc b/riscv/riscv64g_bin_encoder_interface.cc new file mode 100644 index 0000000..7e02c18 --- /dev/null +++ b/riscv/riscv64g_bin_encoder_interface.cc
@@ -0,0 +1,135 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv/riscv64g_bin_encoder_interface.h" + +#include <cstdint> +#include <tuple> +#include <vector> + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "mpact/sim/generic/type_helpers.h" +#include "mpact/sim/util/asm/resolver_interface.h" +#include "riscv/riscv64g_bin_encoder.h" +#include "riscv/riscv64g_encoder.h" +#include "riscv/riscv64g_enums.h" +#include "riscv/riscv_bin_setters.h" + +namespace mpact { +namespace sim { +namespace riscv { +namespace isa64 { + +using ::mpact::sim::generic::operator*; // NOLINT(misc-unused-using-decls) +using ::mpact::sim::util::assembler::ResolverInterface; + +RiscV64GBinEncoderInterface::RiscV64GBinEncoderInterface() { + AddRiscvSourceOpBinSetters<SourceOpEnum, OpMap, encoding64::Encoder>( + source_op_map_); + AddRiscvDestOpBinSetters<DestOpEnum, OpMap, encoding64::Encoder>( + dest_op_map_); + AddRiscvSourceOpRelocationSetters<OpcodeEnum, SourceOpEnum, RelocationMap>( + relocation_source_op_map_); +} + +absl::StatusOr<std::tuple<uint64_t, int>> +RiscV64GBinEncoderInterface::GetOpcodeEncoding(SlotEnum slot, int entry, + OpcodeEnum opcode, + ResolverInterface *resolver) { + return encoding64::kOpcodeEncodings->at(opcode); +} + +absl::StatusOr<uint64_t> RiscV64GBinEncoderInterface::GetSrcOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, SourceOpEnum source_op, int source_num, + ResolverInterface *resolver) { + auto iter = source_op_map_.find(*source_op); + if (iter == source_op_map_.end()) { + return absl::NotFoundError(absl::StrCat( + "Source operand not found for op enum value ", *source_op)); + } + return iter->second(address, text, resolver); +} + +absl::Status RiscV64GBinEncoderInterface::AppendSrcOpRelocation( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, SourceOpEnum source_op, int source_num, + ResolverInterface *resolver, std::vector<RelocationInfo> &relocations) { + auto iter = relocation_source_op_map_.find(std::tie(opcode, source_op)); + if (iter == relocation_source_op_map_.end()) return absl::OkStatus(); + return iter->second(address, text, resolver, relocations); +} + +absl::StatusOr<uint64_t> RiscV64GBinEncoderInterface::GetDestOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, DestOpEnum dest_op, int dest_num, + ResolverInterface *resolver) { + auto iter = dest_op_map_.find(*dest_op); + if (iter == dest_op_map_.end()) { + return absl::NotFoundError( + absl::StrCat("Dest operand not found for op enum value ", *dest_op)); + } + return iter->second(address, text, resolver); +} + +absl::StatusOr<uint64_t> RiscV64GBinEncoderInterface::GetListDestOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, ListDestOpEnum dest_op, int dest_num, + ResolverInterface *resolver) { + auto iter = list_dest_op_map_.find(*dest_op); + if (iter == list_dest_op_map_.end()) { + return absl::NotFoundError(absl::StrCat( + "List dest operand not found for op enum value ", *dest_op)); + } + return iter->second(address, text, resolver); +} + +absl::Status RiscV64GBinEncoderInterface::AppendDestOpRelocation( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, DestOpEnum dest_op, int dest_num, + ResolverInterface *resolver, std::vector<RelocationInfo> &relocations) { + // There are no destination operands that require relocation. + return absl::OkStatus(); +} + +absl::StatusOr<uint64_t> RiscV64GBinEncoderInterface::GetListSrcOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, ListSourceOpEnum source_op, int source_num, + ResolverInterface *resolver) { + auto iter = list_source_op_map_.find(*source_op); + if (iter == list_source_op_map_.end()) { + return absl::NotFoundError(absl::StrCat( + "List source operand not found for op enum value ", *source_op)); + } + return iter->second(address, text, resolver); +} + +absl::StatusOr<uint64_t> RiscV64GBinEncoderInterface::GetPredOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, PredOpEnum pred_op, ResolverInterface *resolver) { + auto iter = pred_op_map_.find(*pred_op); + if (iter == pred_op_map_.end()) { + return absl::NotFoundError(absl::StrCat( + "Predicate operand not found for op enum value ", *pred_op)); + } + return iter->second(address, text, resolver); +} + +} // namespace isa64 +} // namespace riscv +} // namespace sim +} // namespace mpact
diff --git a/riscv/riscv64g_bin_encoder_interface.h b/riscv/riscv64g_bin_encoder_interface.h new file mode 100644 index 0000000..f25fe1d --- /dev/null +++ b/riscv/riscv64g_bin_encoder_interface.h
@@ -0,0 +1,110 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_MPACT_RISCV_RISCV64G_BIN_ENCODER_INTERFACE_H_ +#define THIRD_PARTY_MPACT_RISCV_RISCV64G_BIN_ENCODER_INTERFACE_H_ + +#include <cstdint> +#include <functional> +#include <tuple> +#include <vector> + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "mpact/sim/util/asm/opcode_assembler_interface.h" +#include "mpact/sim/util/asm/resolver_interface.h" +#include "riscv/riscv64g_encoder.h" +#include "riscv/riscv64g_enums.h" + +// This file defines the class that implements the RiscV64GEncoderInterfaceBase. +// This class is used to convert from a text representation to the binary +// encoding of opcodes, source and destination operands. + +namespace mpact { +namespace sim { +namespace riscv { +namespace isa64 { + +using ::mpact::sim::util::assembler::RelocationInfo; +using ::mpact::sim::util::assembler::ResolverInterface; + +class RiscV64GBinEncoderInterface : public RiscV64GEncoderInterfaceBase { + public: + RiscV64GBinEncoderInterface(); + RiscV64GBinEncoderInterface(const RiscV64GBinEncoderInterface &) = delete; + RiscV64GBinEncoderInterface &operator=(const RiscV64GBinEncoderInterface &) = + delete; + ~RiscV64GBinEncoderInterface() override = default; + + absl::StatusOr<std::tuple<uint64_t, int>> GetOpcodeEncoding( + SlotEnum slot, int entry, OpcodeEnum opcode, + ResolverInterface *resolver) override; + absl::StatusOr<uint64_t> GetSrcOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, SourceOpEnum source_op, int source_num, + ResolverInterface *resolver) override; + absl::Status AppendSrcOpRelocation( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, SourceOpEnum source_op, int source_num, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) override; + absl::StatusOr<uint64_t> GetDestOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, DestOpEnum dest_op, int dest_num, + ResolverInterface *resolver) override; + absl::Status AppendDestOpRelocation( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, DestOpEnum dest_op, int dest_num, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) override; + absl::StatusOr<uint64_t> GetListSrcOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, ListSourceOpEnum source_op, int source_num, + ResolverInterface *resolver) override; + absl::StatusOr<uint64_t> GetListDestOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, ListDestOpEnum dest_op, int dest_num, + ResolverInterface *resolver) override; + absl::StatusOr<uint64_t> GetPredOpEncoding( + uint64_t address, absl::string_view text, SlotEnum slot, int entry, + OpcodeEnum opcode, PredOpEnum pred_op, + ResolverInterface *resolver) override; + + private: + using OpMap = absl::flat_hash_map< + int, std::function<absl::StatusOr<uint64_t>(uint64_t, absl::string_view, + ResolverInterface *)>>; + + using RelocationMap = + absl::flat_hash_map<std::tuple<OpcodeEnum, SourceOpEnum>, + std::function<absl::Status( + uint64_t, absl::string_view, ResolverInterface *, + std::vector<RelocationInfo> &)>>; + + OpMap source_op_map_; + RelocationMap relocation_source_op_map_; + OpMap dest_op_map_; + OpMap list_dest_op_map_; + OpMap list_source_op_map_; + OpMap pred_op_map_; +}; + +} // namespace isa64 +} // namespace riscv +} // namespace sim +} // namespace mpact + +#endif // THIRD_PARTY_MPACT_RISCV_RISCV64G_BIN_ENCODER_INTERFACE_H_
diff --git a/riscv/riscv_arm_semihost.cc b/riscv/riscv_arm_semihost.cc index 5a79e1e..b3ba038 100644 --- a/riscv/riscv_arm_semihost.cc +++ b/riscv/riscv_arm_semihost.cc
@@ -238,7 +238,9 @@ LOG(ERROR) << "Program exit not caught in ARM semihosting - no callback"; return absl::NotFoundError("Exit callback not valid in ARM semihosting"); } - LOG(ERROR) << "Exceptions other than ApplicationExit are not implemented"; + LOG(ERROR) << absl::StrCat( + "Exception ", absl::Hex(param_value), " other than ApplicationExit (", + absl::Hex(kAdpStoppedApplicationExit), ") are not implemented"); return absl::UnimplementedError( "Exceptions other than ApplicationExit are not implemented"); }
diff --git a/riscv/riscv_arm_semihost.h b/riscv/riscv_arm_semihost.h index 82ee35a..19d89bd 100644 --- a/riscv/riscv_arm_semihost.h +++ b/riscv/riscv_arm_semihost.h
@@ -15,6 +15,7 @@ #ifndef MPACT_RISCV_RISCV_RISCV_ARM_SEMIHOST_H_ #define MPACT_RISCV_RISCV_RISCV_ARM_SEMIHOST_H_ +#include <cstdint> #include <functional> #include "absl/container/flat_hash_map.h"
diff --git a/riscv/riscv_bin_setters.cc b/riscv/riscv_bin_setters.cc new file mode 100644 index 0000000..6d6684d --- /dev/null +++ b/riscv/riscv_bin_setters.cc
@@ -0,0 +1,145 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv/riscv_bin_setters.h" + +#include <cstdint> +#include <string> +#include <vector> + +#include "absl/base/no_destructor.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "mpact/sim/generic/type_helpers.h" +#include "re2/re2.h" + +namespace mpact { +namespace sim { +namespace riscv { + +namespace internal { + +// Current set of relocation types supported by the assembler. +enum class RelocType { + kNone = 0, + kBranch = 16, + kJal = 17, + kPcrelHi20 = 23, + kPcrelLo12I = 24, + kPcrelLo12S = 25, + kHi20 = 26, + kLo12I = 27, + kLo12S = 28, +}; + +using ::mpact::sim::generic::operator*; // NOLINT(misc-unused-using-decls) + +// This regular expression matches the text for a symbol. The first capture +// group is the relocation type (if present), the second capture group is the +// symbol name. +absl::NoDestructor<RE2> kSymRe( + "^\\s*(%[a-zA-Z0-9_]+)?\\s*\\(?([a-zA-Z_][^)]+)\\)?\\s*$"); + +absl::Status RelocateAddiIImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + if (relo == "%lo") { + relocations.emplace_back(0, sym, *RelocType::kLo12I, 0, 0); + return absl::OkStatus(); + } + if (relo == "%pcrel_lo") { + relocations.emplace_back(0, sym, *RelocType::kPcrelLo12I, 0, 0); + return absl::OkStatus(); + } + if (!relo.empty()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid relocation: '", relo, "'")); + } + return absl::OkStatus(); +} + +absl::Status RelocateJJImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + relocations.emplace_back(0, sym, *RelocType::kJal, 0, 0); + return absl::OkStatus(); +} + +absl::Status RelocateJrJImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + if (relo == "%pcrel_lo") { + relocations.emplace_back(0, sym, *RelocType::kPcrelLo12I, 0, 0); + } + return absl::OkStatus(); +} + +absl::Status RelocateLuiUImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + relocations.emplace_back(0, sym, *RelocType::kHi20, 0, 0); + return absl::OkStatus(); +} + +absl::Status RelocateSdSImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + if (relo == "%lo") { + relocations.emplace_back(0, sym, *RelocType::kLo12S, 0, 0); + return absl::OkStatus(); + } + if (relo == "%pcrel_lo") { + relocations.emplace_back(0, sym, *RelocType::kPcrelLo12S, 0, 0); + return absl::OkStatus(); + } + if (!relo.empty()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid relocation: '", relo, "'")); + } + return absl::OkStatus(); +} + +absl::Status RelocateAuipcUImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations) { + std::string relo; + std::string sym; + if (!RE2::FullMatch(text, *kSymRe, &relo, &sym)) return absl::OkStatus(); + if (relo == "%pcrel_hi") { + relocations.emplace_back(0, sym, *RelocType::kPcrelHi20, 0, 0); + } + return absl::OkStatus(); +} + +} // namespace internal + +} // namespace riscv +} // namespace sim +} // namespace mpact
diff --git a/riscv/riscv_bin_setters.h b/riscv/riscv_bin_setters.h new file mode 100644 index 0000000..4eb312c --- /dev/null +++ b/riscv/riscv_bin_setters.h
@@ -0,0 +1,1040 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_MPACT_RISCV_RISCV_BIN_SETTERS_H_ +#define THIRD_PARTY_MPACT_RISCV_RISCV_BIN_SETTERS_H_ + +#include <cstdint> +#include <initializer_list> +#include <string> +#include <utility> +#include <vector> + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "mpact/sim/util/asm/opcode_assembler_interface.h" +#include "mpact/sim/util/asm/resolver_interface.h" +#include "re2/re2.h" +#include "riscv/riscv_getter_helpers.h" + +// This file contains various setters for the RiscV binary encoder that is used +// by the assembler to map from operand text strings to integer values. + +namespace mpact { +namespace sim { +namespace riscv { + +using ::mpact::sim::util::assembler::RelocationInfo; +using ::mpact::sim::util::assembler::ResolverInterface; + +// Initializer lists for maps for different subsets of registers, mapping from +// the register name to the register number. +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kRegisterList = { + {"x0", 0}, {"x1", 1}, {"x2", 2}, {"x3", 3}, {"x4", 4}, + {"x5", 5}, {"x6", 6}, {"x7", 7}, {"x8", 8}, {"x9", 9}, + {"x10", 10}, {"x11", 11}, {"x12", 12}, {"x13", 13}, {"x14", 14}, + {"x15", 15}, {"x16", 16}, {"x17", 17}, {"x18", 18}, {"x19", 19}, + {"x20", 20}, {"x21", 21}, {"x22", 22}, {"x23", 23}, {"x24", 24}, + {"x25", 25}, {"x26", 26}, {"x27", 27}, {"x28", 28}, {"x29", 29}, + {"x30", 30}, {"x31", 31}, {"zero", 0}, {"ra", 1}, {"sp", 2}, + {"gp", 3}, {"tp", 4}, {"t0", 5}, {"t1", 6}, {"t2", 7}, + {"s0", 8}, {"s1", 9}, {"a0", 10}, {"a1", 11}, {"a2", 12}, + {"a3", 13}, {"a4", 14}, {"a5", 15}, {"a6", 16}, {"a7", 17}, + {"s2", 18}, {"s3", 19}, {"s4", 20}, {"s5", 21}, {"s6", 22}, + {"s7", 23}, {"s8", 24}, {"s9", 25}, {"s10", 26}, {"s11", 27}, + {"t3", 28}, {"t4", 29}, {"t5", 30}, {"t6", 31}}; + +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kCRegisterList = { + {"x8", 8}, {"x9", 9}, {"x10", 10}, {"x11", 11}, + {"x12", 12}, {"x13", 13}, {"x14", 14}, {"x15", 15}, + {"s0", 8}, {"s1", 9}, {"a0", 10}, {"a1", 11}, + {"a2", 12}, {"a3", 13}, {"a4", 14}, {"a5", 15}, +}; + +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kFRegisterList = { + {"f0", 0}, {"f1", 1}, {"f2", 2}, {"f3", 3}, {"f4", 4}, + {"f5", 5}, {"f6", 6}, {"f7", 7}, {"f8", 8}, {"f9", 9}, + {"f10", 10}, {"f11", 11}, {"f12", 12}, {"f13", 13}, {"f14", 14}, + {"f15", 15}, {"f16", 16}, {"f17", 17}, {"f18", 18}, {"f19", 19}, + {"f20", 20}, {"f21", 21}, {"f22", 22}, {"f23", 23}, {"f24", 24}, + {"f25", 25}, {"f26", 26}, {"f27", 27}, {"f28", 28}, {"f29", 29}, + {"f30", 30}, {"f31", 31}, {"ft0", 0}, {"ft1", 1}, {"ft2", 2}, + {"ft3", 3}, {"ft4", 4}, {"ft5", 5}, {"ft6", 6}, {"ft7", 7}, + {"fs0", 8}, {"fs1", 9}, {"fa0", 10}, {"fa1", 11}, {"fa2", 12}, + {"fa3", 13}, {"fa4", 14}, {"fa5", 15}, {"fa6", 16}, {"fa7", 17}, + {"fs2", 18}, {"fs3", 19}, {"fs4", 20}, {"fs5", 21}, {"fs6", 22}, + {"fs7", 23}, {"fs8", 24}, {"fs9", 25}, {"fs10", 26}, {"fs11", 27}, + {"ft8", 28}, {"ft9", 29}, {"ft10", 30}, {"ft11", 31}}; + +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kDRegisterList = { + {"d0", 0}, {"d1", 1}, {"d2", 2}, {"d3", 3}, {"d4", 4}, + {"d5", 5}, {"d6", 6}, {"d7", 7}, {"d8", 8}, {"d9", 9}, + {"d10", 10}, {"d11", 11}, {"d12", 12}, {"d13", 13}, {"d14", 14}, + {"d15", 15}, {"d16", 16}, {"d17", 17}, {"d18", 18}, {"d19", 19}, + {"d20", 20}, {"d21", 21}, {"d22", 22}, {"d23", 23}, {"d24", 24}, + {"d25", 25}, {"d26", 26}, {"d27", 27}, {"d28", 28}, {"d29", 29}, + {"d30", 30}, {"d31", 31}, {"dt0", 0}, {"dt1", 1}, {"dt2", 2}, + {"dt3", 3}, {"dt4", 4}, {"dt5", 5}, {"dt6", 6}, {"dt7", 7}, + {"ds0", 8}, {"ds1", 9}, {"da0", 10}, {"da1", 11}, {"da2", 12}, + {"da3", 13}, {"da4", 14}, {"da5", 15}, {"da6", 16}, {"da7", 17}, + {"ds2", 18}, {"ds3", 19}, {"ds4", 20}, {"ds5", 21}, {"ds6", 22}, + {"ds7", 23}, {"ds8", 24}, {"ds9", 25}, {"ds10", 26}, {"ds11", 27}, + {"dt8", 28}, {"dt9", 29}, {"dt10", 30}, {"dt11", 31}}; + +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kDCRegisterList = { + {"d8", 8}, {"d9", 9}, {"d10", 10}, {"d11", 11}, + {"d12", 12}, {"d13", 13}, {"d14", 14}, {"d15", 15}, + {"ds0", 8}, {"ds1", 9}, {"da0", 10}, {"da1", 11}, + {"da2", 12}, {"da3", 13}, {"da4", 14}, {"da5", 15}, +}; + +// This is the initializer list for the map from CSR register names to register +// numbers. +constexpr std::initializer_list<const std::pair<absl::string_view, uint64_t>> + kCsrRegisterList = { + {"fflags", 0x001}, + {"frm", 0x002}, + {"fcsr", 0x003}, + {"cycle", 0xc00}, + {"time", 0xc01}, + {"instret", 0xc02}, + {"hpmcounter3", 0xc03}, + {"hpmcounter4", 0xc04}, + {"hpmcounter5", 0xc05}, + {"hpmcounter6", 0xc06}, + {"hpmcounter7", 0xc07}, + {"hpmcounter8", 0xc08}, + {"hpmcounter9", 0xc09}, + {"hpmcounter10", 0xc0a}, + {"hpmcounter11", 0xc0b}, + {"hpmcounter12", 0xc0c}, + {"hpmcounter13", 0xc0d}, + {"hpmcounter14", 0xc0e}, + {"hpmcounter15", 0xc0f}, + {"hpmcounter16", 0xc10}, + {"hpmcounter17", 0xc11}, + {"hpmcounter18", 0xc12}, + {"hpmcounter19", 0xc13}, + {"hpmcounter20", 0xc14}, + {"hpmcounter21", 0xc15}, + {"hpmcounter22", 0xc16}, + {"hpmcounter23", 0xc17}, + {"hpmcounter24", 0xc18}, + {"hpmcounter25", 0xc19}, + {"hpmcounter26", 0xc1a}, + {"hpmcounter27", 0xc1b}, + {"hpmcounter28", 0xc1c}, + {"hpmcounter29", 0xc1d}, + {"hpmcounter30", 0xc1e}, + {"hpmcounter31", 0xc1f}, + {"cycleh", 0xc80}, + {"timeh", 0xc81}, + {"instreth", 0xc82}, + {"hpmcounter3h", 0xc83}, + {"hpmcounter4h", 0xc84}, + {"hpmcounter5h", 0xc85}, + {"hpmcounter6h", 0xc86}, + {"hpmcounter7h", 0xc87}, + {"hpmcounter8h", 0xc88}, + {"hpmcounter9h", 0xc89}, + {"hpmcounter10h", 0xc8a}, + {"hpmcounter11h", 0xc8b}, + {"hpmcounter12h", 0xc8c}, + {"hpmcounter13h", 0xc8d}, + {"hpmcounter14h", 0xc8e}, + {"hpmcounter15h", 0xc8f}, + {"hpmcounter16h", 0xc90}, + {"hpmcounter17h", 0xc91}, + {"hpmcounter18h", 0xc92}, + {"hpmcounter19h", 0xc93}, + {"hpmcounter20h", 0xc94}, + {"hpmcounter2h1", 0xc95}, + {"hpmcounter22h", 0xc96}, + {"hpmcounter23h", 0xc97}, + {"hpmcounter24h", 0xc98}, + {"hpmcounter25h", 0xc99}, + {"hpmcounter26h", 0xc9a}, + {"hpmcounter27h", 0xc9b}, + {"hpmcounter28h", 0xc9c}, + {"hpmcounter29h", 0xc9d}, + {"hpmcounter30h", 0xc9e}, + {"hpmcounter3h1", 0xc9f}, + {"sstatus", 0x100}, + {"sie", 0x104}, + {"stvec", 0x105}, + {"stcounteren", 0x106}, + {"senvcfg", 0x10a}, + {"scountinhibit", 0x120}, + {"sscratch", 0x140}, + {"sepc", 0x141}, + {"scause", 0x142}, + {"stval", 0x143}, + {"sip", 0x144}, + {"scountovf", 0xda0}, + {"satp", 0x180}, + {"scontext", 0x5a8}, + {"sstateen0", 0x10c}, + {"sstateen1", 0x10d}, + {"sstateen2", 0x10e}, + {"sstateen3", 0x10f}, + {"hstatus", 0x600}, + {"hedeleg", 0x602}, + {"hideleg", 0x603}, + {"hie", 0x604}, + {"hcounteren", 0x606}, + {"hgeie", 0x607}, + {"hedelegh", 0x612}, + {"htval", 0x643}, + {"hip", 0x644}, + {"hvip", 0x645}, + {"htinst", 0x64a}, + {"hgeip", 0xe12}, + {"henvcfg", 0x60a}, + {"henvcfgh", 0x61a}, + {"hgatp", 0x680}, + {"hcontext", 0x6a8}, + {"htimedelta", 0x605}, + {"htimedeltah", 0x615}, + {"hstateen0", 0x60c}, + {"hstateen1", 0x60d}, + {"hstateen2", 0x60e}, + {"hstateen3", 0x60f}, + {"hstateen0h", 0x61c}, + {"hstateen1h", 0x61d}, + {"hstateen2h", 0x61e}, + {"hstateen3h", 0x61f}, + {"vsstatus", 0x200}, + {"vsie", 0x204}, + {"vstvec", 0x205}, + {"vsscratch", 0x240}, + {"vsepc", 0x241}, + {"vscause", 0x242}, + {"vstval", 0x243}, + {"vsip", 0x244}, + {"vsatp", 0x280}, + {"mvendorid", 0xf11}, + {"marchid", 0xf12}, + {"mimpid", 0xf13}, + {"mhartid", 0xf14}, + {"mconfigptr", 0xf15}, + {"mstatus", 0x300}, + {"misa", 0x301}, + {"medeleg", 0x302}, + {"mideleg", 0x303}, + {"mie", 0x304}, + {"mcounteren", 0x306}, + {"mstatush", 0x310}, + {"medelegh", 0x312}, + {"mscratch", 0x340}, + {"mepc", 0x341}, + {"mcause", 0x342}, + {"mtval", 0x343}, + {"mip", 0x344}, + {"mtinst", 0x34a}, + {"mtval2", 0x34b}, + {"menvcfg", 0x30a}, + {"menvcfgh", 0x31a}, + {"mseccfg", 0x747}, + {"mseccfgh", 0x757}, + {"pmpcfg0", 0x3a0}, + {"pmpcfg1", 0x3a1}, + {"pmpcfg2", 0x3a2}, + {"pmpcfg3", 0x3a3}, + {"pmpcfg4", 0x3a4}, + {"pmpcfg5", 0x3a5}, + {"pmpcfg6", 0x3a6}, + {"pmpcfg7", 0x3a7}, + {"pmpcfg8", 0x3a8}, + {"pmpcfg9", 0x3a9}, + {"pmpcfg10", 0x3aa}, + {"pmpcfg11", 0x3ab}, + {"pmpcfg12", 0x3ac}, + {"pmpcfg13", 0x3ad}, + {"pmpcfg14", 0x3ae}, + {"pmpcfg15", 0x3af}, + {"pmpaddr0", 0x3b0}, + {"pmpaddr1", 0x3b1}, + {"pmpaddr2", 0x3b2}, + {"pmpaddr3", 0x3b3}, + {"pmpaddr4", 0x3b4}, + {"pmpaddr5", 0x3b5}, + {"pmpaddr6", 0x3b6}, + {"pmpaddr7", 0x3b7}, + {"pmpaddr8", 0x3b8}, + {"pmpaddr9", 0x3b9}, + {"pmpaddr10", 0x3ba}, + {"pmpaddr11", 0x3bb}, + {"pmpaddr12", 0x3bc}, + {"pmpaddr13", 0x3bd}, + {"pmpaddr14", 0x3be}, + {"pmpaddr15", 0x3bf}, + {"pmpaddr16", 0x3c0}, + {"pmpaddr17", 0x3c1}, + {"pmpaddr18", 0x3c2}, + {"pmpaddr19", 0x3c3}, + {"pmpaddr20", 0x3c4}, + {"pmpaddr21", 0x3c5}, + {"pmpaddr22", 0x3c6}, + {"pmpaddr23", 0x3c7}, + {"pmpaddr24", 0x3c8}, + {"pmpaddr25", 0x3c9}, + {"pmpaddr26", 0x3ca}, + {"pmpaddr27", 0x3cb}, + {"pmpaddr28", 0x3cc}, + {"pmpaddr29", 0x3cd}, + {"pmpaddr30", 0x3ce}, + {"pmpaddr31", 0x3cf}, + {"pmpaddr32", 0x3d0}, + {"pmpaddr33", 0x3d1}, + {"pmpaddr34", 0x3d2}, + {"pmpaddr35", 0x3d3}, + {"pmpaddr36", 0x3d4}, + {"pmpaddr37", 0x3d5}, + {"pmpaddr38", 0x3d6}, + {"pmpaddr39", 0x3d7}, + {"pmpaddr40", 0x3d8}, + {"pmpaddr41", 0x3d9}, + {"pmpaddr42", 0x3da}, + {"pmpaddr43", 0x3db}, + {"pmpaddr44", 0x3dc}, + {"pmpaddr45", 0x3dd}, + {"pmpaddr46", 0x3de}, + {"pmpaddr47", 0x3df}, + {"pmpaddr48", 0x3e0}, + {"pmpaddr49", 0x3e1}, + {"pmpaddr50", 0x3e2}, + {"pmpaddr51", 0x3e3}, + {"pmpaddr52", 0x3e4}, + {"pmpaddr53", 0x3e5}, + {"pmpaddr54", 0x3e6}, + {"pmpaddr55", 0x3e7}, + {"pmpaddr56", 0x3e8}, + {"pmpaddr57", 0x3e9}, + {"pmpaddr58", 0x3ea}, + {"pmpaddr59", 0x3eb}, + {"pmpaddr60", 0x3ec}, + {"pmpaddr61", 0x3ed}, + {"pmpaddr62", 0x3ee}, + {"pmpaddr63", 0x3ef}, + {"mstateen0", 0x30c}, + {"mstateen1", 0x30d}, + {"mstateen2", 0x30e}, + {"mstateen3", 0x30f}, + {"mstateen0h", 0x31c}, + {"mstateen1h", 0x31d}, + {"mstateen2h", 0x31e}, + {"mstateen3h", 0x31f}, + {"mnscratch", 0x740}, + {"mnepc", 0x741}, + {"mncause", 0x742}, + {"mnstatus", 0x743}, + {"mcycle", 0xb00}, + {"minstret", 0xb02}, + {"mhpmcounter3", 0xb03}, + {"mhpmcounter4", 0xb04}, + {"mhpmcounter5", 0xb05}, + {"mhpmcounter6", 0xb06}, + {"mhpmcounter7", 0xb07}, + {"mhpmcounter8", 0xb08}, + {"mhpmcounter9", 0xb09}, + {"mhpmcounter10", 0xb0a}, + {"mhpmcounter11", 0xb0b}, + {"mhpmcounter12", 0xb0c}, + {"mhpmcounter13", 0xb0d}, + {"mhpmcounter14", 0xb0e}, + {"mhpmcounter15", 0xb0f}, + {"mhpmcounter16", 0xb10}, + {"mhpmcounter17", 0xb11}, + {"mhpmcounter18", 0xb12}, + {"mhpmcounter19", 0xb13}, + {"mhpmcounter20", 0xb14}, + {"mhpmcounter21", 0xb15}, + {"mhpmcounter22", 0xb16}, + {"mhpmcounter23", 0xb17}, + {"mhpmcounter24", 0xb18}, + {"mhpmcounter25", 0xb19}, + {"mhpmcounter26", 0xb1a}, + {"mhpmcounter27", 0xb1b}, + {"mhpmcounter28", 0xb1c}, + {"mhpmcounter29", 0xb1d}, + {"mhpmcounter30", 0xb1e}, + {"mhpmcounter31", 0xb1f}, + {"mcycleh", 0xb80}, + {"minstreth", 0xb82}, + {"mhpmcounter3h", 0xb83}, + {"mhpmcounter4h", 0xb84}, + {"mhpmcounter5h", 0xb85}, + {"mhpmcounter6h", 0xb86}, + {"mhpmcounter7h", 0xb87}, + {"mhpmcounter8h", 0xb88}, + {"mhpmcounter9h", 0xb89}, + {"mhpmcounter10h", 0xb8a}, + {"mhpmcounter11h", 0xb8b}, + {"mhpmcounter12h", 0xb8c}, + {"mhpmcounter13h", 0xb8d}, + {"mhpmcounter14h", 0xb8e}, + {"mhpmcounter15h", 0xb8f}, + {"mhpmcounter16h", 0xb90}, + {"mhpmcounter17h", 0xb91}, + {"mhpmcounter18h", 0xb92}, + {"mhpmcounter19h", 0xb93}, + {"mhpmcounter20h", 0xb94}, + {"mhpmcounter21h", 0xb95}, + {"mhpmcounter22h", 0xb96}, + {"mhpmcounter23h", 0xb97}, + {"mhpmcounter24h", 0xb98}, + {"mhpmcounter25h", 0xb99}, + {"mhpmcounter26h", 0xb9a}, + {"mhpmcounter27h", 0xb9b}, + {"mhpmcounter28h", 0xb9c}, + {"mhpmcounter29h", 0xb9d}, + {"mhpmcounter30h", 0xb9e}, + {"mhpmcounter31h", 0xb9f}, + {"mcountinhibit", 0x320}, + {"mhpmevent3", 0x323}, + {"mhpmevent4", 0x324}, + {"mhpmevent5", 0x325}, + {"mhpmevent6", 0x326}, + {"mhpmevent7", 0x327}, + {"mhpmevent8", 0x328}, + {"mhpmevent9", 0x329}, + {"mhpmevent10", 0x32a}, + {"mhpmevent11", 0x32b}, + {"mhpmevent12", 0x32c}, + {"mhpmevent13", 0x32d}, + {"mhpmevent14", 0x32e}, + {"mhpmevent15", 0x32f}, + {"mhpmevent16", 0x330}, + {"mhpmevent17", 0x331}, + {"mhpmevent18", 0x332}, + {"mhpmevent19", 0x333}, + {"mhpmevent20", 0x334}, + {"mhpmevent21", 0x335}, + {"mhpmevent22", 0x336}, + {"mhpmevent23", 0x337}, + {"mhpmevent24", 0x338}, + {"mhpmevent25", 0x339}, + {"mhpmevent26", 0x33a}, + {"mhpmevent27", 0x33b}, + {"mhpmevent28", 0x33c}, + {"mhpmevent29", 0x33d}, + {"mhpmevent30", 0x33e}, + {"mhpmevent31", 0x33f}, + {"mhpmevent3h", 0x723}, + {"mhpmevent4h", 0x724}, + {"mhpmevent5h", 0x725}, + {"mhpmevent6h", 0x726}, + {"mhpmevent7h", 0x727}, + {"mhpmevent8h", 0x728}, + {"mhpmevent9h", 0x729}, + {"mhpmevent10h", 0x72a}, + {"mhpmevent11h", 0x72b}, + {"mhpmevent12h", 0x72c}, + {"mhpmevent13h", 0x72d}, + {"mhpmevent14h", 0x72e}, + {"mhpmevent15h", 0x72f}, + {"mhpmevent16h", 0x730}, + {"mhpmevent17h", 0x731}, + {"mhpmevent18h", 0x732}, + {"mhpmevent19h", 0x733}, + {"mhpmevent20h", 0x734}, + {"mhpmevent21h", 0x735}, + {"mhpmevent22h", 0x736}, + {"mhpmevent23h", 0x737}, + {"mhpmevent24h", 0x738}, + {"mhpmevent25h", 0x739}, + {"mhpmevent26h", 0x73a}, + {"mhpmevent27h", 0x73b}, + {"mhpmevent28h", 0x73c}, + {"mhpmevent29h", 0x73d}, + {"mhpmevent30h", 0x73e}, + {"mhpmevent31h", 0x73f}, +}; + +// A helper function to convert a text string to an integer. The function takes +// either numeric literals (hexadecimal or decimal), symbol names, or relocation +// functions, e.g., %hi(<symbol name>). +template <typename T> +absl::StatusOr<T> SimpleTextToInt(absl::string_view op_text, + ResolverInterface *resolver) { + T value; + static RE2 hex_re("^\\s*0x([0-9a-fA-F]+)\\s*$"); + static RE2 dec_re("^\\s*(-?[0-9]+)\\s*$"); + static RE2 relo_re("^\\s*\\%[a-zA-Z0-9_]+\\s*\\(([a-zA-Z0-9_]+)\\s*\\)\\s*$"); + static RE2 symbol_re("^\\s*([a-zA-Z0-9_]+)\\s*$"); + std::string str; + std::string text(op_text); + // First see if the operand is a relocation function, and extract the text + // argument. A relocation function is on the form of %name(arg). + if (RE2::FullMatch(op_text, relo_re, &str)) { + text = str; + } + // Extract the hex immediate. + if (RE2::FullMatch(text, hex_re, &str)) { + if (absl::SimpleHexAtoi(str, &value)) return value; + return absl::InvalidArgumentError( + absl::StrCat("Invalid hexadecimal immediate: ", text)); + } + // Extract the decimal immediate. + if (RE2::FullMatch(text, dec_re, &str)) { + if (absl::SimpleAtoi(str, &value)) return value; + return absl::InvalidArgumentError( + absl::StrCat("Invalid decimal immediate: ", text)); + } + // Extract the symbol. + if (RE2::FullMatch(text, symbol_re, &str)) { + if (resolver != nullptr) { + auto res = resolver->Resolve(str); + if (!res.ok()) { + return res.status(); + } + return static_cast<T>(res.value()); + } + } + return absl::InvalidArgumentError(absl::StrCat("Invalid argument: ", text)); +} + +using ValueMap = absl::flat_hash_map<absl::string_view, uint64_t>; + +// This function adds the bin setters for the source operands to the given map. +template <typename Enum, typename Map, typename Encoder> +void AddRiscvSourceOpBinSetters(Map &map) { + Insert(map, *Enum::kAAq, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map = {{"", 0}, {".aq", 1}}; + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::AType::InsertAq(iter->second, 0ULL); + }); + Insert(map, *Enum::kARl, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map = {{"", 0}, {".rl", 1}}; + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::AType::InsertRl(iter->second, 0ULL); + }); + Insert(map, *Enum::kBImm12, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + uint32_t delta = res.value() - address; + return Encoder::BType::InsertBImm(delta, 0ULL); + }); + Insert(map, *Enum::kC3drs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CS::InsertCsRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kC3rs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CL::InsertClRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kC3rs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CS::InsertCsRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kCSRUimm5, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::IType::InsertIUimm5(res.value(), 0ULL); + }); + Insert(map, *Enum::kCdrs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CR::InsertRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kCrs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CR::InsertRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kCrs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::CR::InsertRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kCsr, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCsrRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::IType::InsertUImm12(iter->second, 0ULL); + }); + Insert(map, *Enum::kDrs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kDrs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kDrs3, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::R4Type::InsertRs3(iter->second, 0ULL); + }); + Insert(map, *Enum::kFrs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kFRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kFrs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kFRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kFrs3, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kFRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::R4Type::InsertRs3(iter->second, 0ULL); + }); + Insert(map, *Enum::kICbImm8, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + uint32_t delta = res.value() - address; + return Encoder::CB::InsertBimm(delta, 0ULL); + }); + Insert(map, *Enum::kICiImm6, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertImm6(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiImm612, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertImm18(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiImm6x16, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertCiImm10(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiUimm6, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertUimm6(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiUimm6x4, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertCiImmW(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiUimm6x8, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CI::InsertCiImmD(res.value(), 0ULL); + }); + Insert(map, *Enum::kICiwUimm8x4, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CIW::InsertCiwImm10(res.value(), 0ULL); + }); + Insert(map, *Enum::kICjImm11, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + auto delta = res.value() - address; + return Encoder::CJ::InsertJimm(delta, 0ULL); + }); + Insert(map, *Enum::kIClUimm5x4, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CL::InsertClImmW(res.value(), 0ULL); + }); + Insert(map, *Enum::kIClUimm5x8, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CL::InsertClImmD(res.value(), 0ULL); + }); + Insert(map, *Enum::kICssUimm6x4, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CS::InsertCsImmW(res.value(), 0ULL); + }); + Insert(map, *Enum::kICssUimm6x8, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::CS::InsertCsImmD(res.value(), 0ULL); + }); + Insert(map, *Enum::kIImm12, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::IType::InsertImm12(res.value(), 0ULL); + }); + Insert(map, *Enum::kIUimm5, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::RType::InsertRUimm5(res.value(), 0ULL); + }); + Insert(map, *Enum::kIUimm6, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::RSType::InsertRUimm6(res.value(), 0ULL); + }); + Insert(map, *Enum::kJImm12, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::IType::InsertImm12(res.value(), 0ULL); + }); + Insert(map, *Enum::kJImm20, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<int32_t>(text, resolver); + if (!res.ok()) return res.status(); + uint32_t delta = res.value() - address; + auto value = Encoder::JType::InsertJImm(delta, 0ULL); + return value; + }); + Insert(map, *Enum::kPred, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::Fence::InsertPred(res.value(), 0ULL); + }); + Insert(map, *Enum::kRd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRd(iter->second, 0ULL); + }); + Insert(map, *Enum::kRm, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::R4Type::InsertRs3(iter->second, 0ULL); + }); + Insert(map, *Enum::kRs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kRs2, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::RType::InsertRs2(iter->second, 0ULL); + }); + Insert(map, *Enum::kSImm12, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::SType::InsertSImm(res.value(), 0ULL); + }); + Insert(map, *Enum::kSucc, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::Fence::InsertSucc(res.value(), 0ULL); + }); + Insert(map, *Enum::kUImm20, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + auto res = SimpleTextToInt<uint32_t>(text, resolver); + if (!res.ok()) return res.status(); + return Encoder::UType::InsertUImm(res.value(), 0ULL); + }); +} + +// This function adds the destination operand setters for the RiscV ISA to the +// given map. +template <typename Enum, typename Map, typename Encoder> +void AddRiscvDestOpBinSetters(Map &map) { + Insert(map, *Enum::kC3drd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::CL::InsertClRd(iter->second, 0ULL); + }); + Insert(map, *Enum::kC3rd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::CL::InsertClRd(iter->second, 0ULL); + }); + Insert(map, *Enum::kC3rs1, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::CS::InsertCsRs1(iter->second, 0ULL); + }); + Insert(map, *Enum::kCsr, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kCsrRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid source operand: ", text)); + } + return Encoder::IType::InsertUImm12(iter->second, 0ULL); + }); + Insert(map, *Enum::kDrd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kDRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::RType::InsertRd(iter->second, 0ULL); + }); + Insert(map, *Enum::kFrd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kFRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::RType::InsertRd(iter->second, 0ULL); + }); + Insert(map, *Enum::kRd, + [](uint64_t address, absl::string_view text, + ResolverInterface *resolver) -> absl::StatusOr<uint64_t> { + static ValueMap map(kRegisterList); + auto iter = map.find(text); + if (iter == map.end()) { + return absl::InvalidArgumentError( + absl::StrCat("Invalid destination operand: ", text)); + } + return Encoder::RType::InsertRd(iter->second, 0ULL); + }); +} + +// These functions add the appropriate relocation entry to the relocations +// vector if the operand (in text) requires it. +namespace internal { + +absl::Status RelocateAddiIImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); +absl::Status RelocateJJImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); +absl::Status RelocateJrJImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); +absl::Status RelocateLuiUImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); +absl::Status RelocateSdSImm12(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); +absl::Status RelocateAuipcUImm20(uint64_t address, absl::string_view text, + ResolverInterface *resolver, + std::vector<RelocationInfo> &relocations); + +} // namespace internal + +// This function adds the source operand relocation setters for the RiscV ISA to +// the given map. Notice that the key in the map is the tuple consisting of the +// opcode and the source operand enum values. +template <typename OpcodeEnum, typename SourceOpEnum, typename Map> +void AddRiscvSourceOpRelocationSetters(Map &map) { + Insert(map, OpcodeEnum::kAddi, SourceOpEnum::kIImm12, + internal::RelocateAddiIImm12); + Insert(map, OpcodeEnum::kJal, SourceOpEnum::kJImm20, + internal::RelocateJJImm20); + Insert(map, OpcodeEnum::kJ, SourceOpEnum::kJImm20, internal::RelocateJJImm20); + Insert(map, OpcodeEnum::kJr, SourceOpEnum::kJImm12, + internal::RelocateJrJImm12); + Insert(map, OpcodeEnum::kLui, SourceOpEnum::kUImm20, + internal::RelocateLuiUImm20); + Insert(map, OpcodeEnum::kSd, SourceOpEnum::kSImm12, + internal::RelocateSdSImm12); + Insert(map, OpcodeEnum::kJalr, SourceOpEnum::kJImm12, + internal::RelocateJrJImm12); + Insert(map, OpcodeEnum::kAuipc, SourceOpEnum::kUImm20, + internal::RelocateAuipcUImm20); +} + +} // namespace riscv +} // namespace sim +} // namespace mpact + +#endif // THIRD_PARTY_MPACT_RISCV_RISCV_BIN_SETTERS_H_
diff --git a/riscv/riscv_getter_helpers.h b/riscv/riscv_getter_helpers.h index dc3f91d..408da03 100644 --- a/riscv/riscv_getter_helpers.h +++ b/riscv/riscv_getter_helpers.h
@@ -63,6 +63,16 @@ } } +template <typename M, typename E1, typename E2, typename G> +inline void Insert(M &map, E1 entry1, E2 entry2, G getter) { + auto key = std::tie(entry1, entry2); + if (!map.contains(key)) { + map.insert(std::make_pair(key, getter)); + } else { + map.at(key) = getter; + } +} + // Generic helper functions to create register operands. template <typename RegType> inline DestinationOperandInterface *GetRegisterDestinationOp(RiscVState *state,