[PR #270] Suggestion for an Instruction Mapping between QEMU RVI32/64 Translation and Sail Language #356

Closed
opened 2026-01-31 21:30:55 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/qemu/qemu/pull/270

State: closed
Merged: No


Project Proposal: Sail to QEMU Target Downstream Task Issue

The goal of this project is to perhaps create a generated RVI-32/64 translation for QEMU, we hope to utilize Sail as the source for conversion.

The following files are involved:

Below is the following representation/translation in both the files of importance:

Load Upper Immediate instruction

Sail code (model/riscv_insts_base.sail):

function clause execute UTYPE(imm, rd, op) = {
  let off : xlenbits = sign_extend(imm @ 0x000);
  let ret : xlenbits = match op {
    RISCV_LUI   => off,
    RISCV_AUIPC => get_arch_pc() + off
  };
  X(rd) = ret;
  RETIRE_SUCCESS
}

QEMU code (target/riscv/insn_trans/trans_rvi.c.inc):

static bool trans_lui(DisasContext *ctx, arg_lui *a)
{
    gen_set_gpri(ctx, a->rd, a->imm);
    return true;
}
  • static bool: standard template
  • trans_: standard template
  • lui: mnemonic. This could come from parsing the Sail code “mapping clause assembly” directly:
mapping utype_mnemonic : uop <-> string = {
  RISCV_LUI   <-> "lui",
  RISCV_AUIPC <-> "auipc"
}

mapping clause assembly = UTYPE(imm, rd, op)
  <-> utype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_signed_20(imm)

OR, it could come from the JSON, which includes the mnemonic and the Sail function clause execute for the mnemonic.

  • (DisasContext *ctx, arg_: standard template

  • lui: mnemonic

  • *a: standard template

  • gen_set_gpri(ctx, a->[register], a->[immediate]): map from Sail construct X(register) = immediate pattern

Need to understand conventions for names of structure fields, like rd and imm in both the Sail code and the QEMU code.

  • return true: standard template

Standard Template

A standard template would look like:

static bool trans_[mnemonic] (DisasContext *ctx, arg_[mnemonic] *a)
{
    [code]
    return true;
}

And the pattern matching database would include, to start:

Sail Representation QEMU Representation
X(register) = value gen_set_gpri(ctx, a->register, a->immediate)

Translating from the Sail code

Translating from the Sail code involves just working with the code that specifies actions:

let off : xlenbits = sign_extend(imm @ 0x000);
let ret : xlenbits = match op {
  RISCV_LUI   => off,
  RISCV_AUIPC => get_arch_pc() + off
};
X(rd) = ret;

Note that for Load Upper Immediate, only the code associated with RISCV_LUI is executed. This will have to be understood also through parsing the mapping clause assembly and finding that RISCV_LUI is associated exclusively with the lui mnemonic.

  • let off : xlenbits = sign_extend(imm @ 0x000);
    In QEMU, this shift and sign extend is done before trans_lui is called, presumably as a normal part of decoding a “U Format” instruction.
    So, this line can be ignored in translation from Sail to QEMU.

Add Upper Immediate to PC

Looking to another, similar instruction, Add Upper Immediate to PC, Sail code is above (same as Load Upper Immediate).

QEMU code:

static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
{
    TCGv target_pc = dest_gpr(ctx, a->rd);
    gen_pc_plus_diff(target_pc, ctx, a->imm);
    gen_set_gpr(ctx, a->rd, target_pc);
    return true;
}

Initial Patch Example

An initial local patch (Link to commit) was created to demonstrate the mapping of the form:

{
  "lui": {
    "function clause execute UTYPE(imm, rd, op) = {
    let off : xlenbits = sign_extend(imm @ 0x000);
    let ret : xlenbits = match op {
        RISCV_LUI   => off,
        RISCV_AUIPC => get_arch_pc() + off
    };
    X(rd) = ret;
    RETIRE_SUCCESS",
    "static bool trans_lui(DisasContext *ctx, arg_lui *a)
{
        gen_set_gpri(ctx, a->rd, a->imm);
        return true;
}"
  },
  "auipc": {
    "function clause execute UTYPE(imm, rd, op) = {
    let off : xlenbits = sign_extend(imm @ 0x000);
    let ret : xlenbits = match op {
        RISCV_LUI   => off,
        RISCV_AUIPC => get_arch_pc() + off
    };
    X(rd) = ret;
    RETIRE_SUCCESS",
    "static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
{
        TCGv target_pc = dest_gpr(ctx, a->rd);
        gen_pc_plus_diff(target_pc, ctx, a->imm);
        gen_set_gpr(ctx, a->rd, target_pc);
        return true;
}"
}
...

This is another pattern to be added to the translation database:

Sail QEMU
variable = get_arch_pc() + offset target_pc = dest_gpr(ctx, a->rd)
gen_pc_plus_diff(target_pc, ctx, a->imm)

Where the format of the map is:

Map<String, pair<Sail_Instruction_Representation, QEMU_Instruction_Representation>>
The template is consistent, so only the code needs to be translated.

We were hoping to get suggestions and feedback from the community and maintainers based on this task, using the output of the example files used to create a base mapping.

We hope to create a webpage representing the instruction mappings, that the community itself could refer to. We are in the process of constructing a universal page dedicated to these translations across several downstream projects, so it could be referred to and reviewed by those interested in generation/translation of instruction representation across several projects compared against each other.

**Original Pull Request:** https://github.com/qemu/qemu/pull/270 **State:** closed **Merged:** No --- # Project Proposal: Sail to QEMU Target Downstream Task Issue The goal of this project is to perhaps create a generated RVI-32/64 translation for QEMU, we hope to utilize Sail as the source for conversion. ## The following files are involved: - `/model/riscv_insts_base.sail` [Link to file](https://github.com/riscv/sail-riscv/blob/master/model/riscv_insts_base.sail) - `target/riscv/insn_trans/trans_rvi.c.inc` [Link to file](https://github.com/qemu/qemu/blob/master/target/riscv/insn_trans/trans_rvi.c.inc) ## Below is the following representation/translation in both the files of importance: ### Load Upper Immediate instruction **Sail code (`model/riscv_insts_base.sail`):** ```sail function clause execute UTYPE(imm, rd, op) = { let off : xlenbits = sign_extend(imm @ 0x000); let ret : xlenbits = match op { RISCV_LUI => off, RISCV_AUIPC => get_arch_pc() + off }; X(rd) = ret; RETIRE_SUCCESS } ``` QEMU code (target/riscv/insn_trans/trans_rvi.c.inc): ```c static bool trans_lui(DisasContext *ctx, arg_lui *a) { gen_set_gpri(ctx, a->rd, a->imm); return true; } ``` - static bool: standard template - trans_: standard template - lui: mnemonic. This could come from parsing the Sail code “mapping clause assembly” directly: ```sail mapping utype_mnemonic : uop <-> string = { RISCV_LUI <-> "lui", RISCV_AUIPC <-> "auipc" } mapping clause assembly = UTYPE(imm, rd, op) <-> utype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_signed_20(imm) ``` OR, it could come from the JSON, which includes the mnemonic and the Sail function clause execute for the mnemonic. - (DisasContext *ctx, arg_: standard template - lui: mnemonic - *a: standard template - gen_set_gpri(ctx, a->[register], a->[immediate]): map from Sail construct X(register) = immediate pattern Need to understand conventions for names of structure fields, like rd and imm in both the Sail code and the QEMU code. - return true: standard template ## Standard Template A standard template would look like: ```c static bool trans_[mnemonic] (DisasContext *ctx, arg_[mnemonic] *a) { [code] return true; } ``` And the pattern matching database would include, to start: | Sail Representation | QEMU Representation | |----------------------|----------------------------------------------------------| | X(register) = value | gen_set_gpri(ctx, a->register, a->immediate) | ## Translating from the Sail code Translating from the Sail code involves just working with the code that specifies actions: ```sail let off : xlenbits = sign_extend(imm @ 0x000); let ret : xlenbits = match op { RISCV_LUI => off, RISCV_AUIPC => get_arch_pc() + off }; X(rd) = ret; ``` Note that for Load Upper Immediate, only the code associated with RISCV_LUI is executed. This will have to be understood also through parsing the mapping clause assembly and finding that RISCV_LUI is associated exclusively with the lui mnemonic. - let off : xlenbits = sign_extend(imm @ 0x000); In QEMU, this shift and sign extend is done before trans_lui is called, presumably as a normal part of decoding a “U Format” instruction. So, this line can be ignored in translation from Sail to QEMU. ## Add Upper Immediate to PC Looking to another, similar instruction, Add Upper Immediate to PC, Sail code is above (same as Load Upper Immediate). QEMU code: ```c static bool trans_auipc(DisasContext *ctx, arg_auipc *a) { TCGv target_pc = dest_gpr(ctx, a->rd); gen_pc_plus_diff(target_pc, ctx, a->imm); gen_set_gpr(ctx, a->rd, target_pc); return true; } ``` ### Initial Patch Example An initial local patch ([Link to commit](https://github.com/qemu/qemu/commit/aa675e3f44a0b5f7528f5d73f24f865b37735901)) was created to demonstrate the mapping of the form: ``` { "lui": { "function clause execute UTYPE(imm, rd, op) = { let off : xlenbits = sign_extend(imm @ 0x000); let ret : xlenbits = match op { RISCV_LUI => off, RISCV_AUIPC => get_arch_pc() + off }; X(rd) = ret; RETIRE_SUCCESS", "static bool trans_lui(DisasContext *ctx, arg_lui *a) { gen_set_gpri(ctx, a->rd, a->imm); return true; }" }, "auipc": { "function clause execute UTYPE(imm, rd, op) = { let off : xlenbits = sign_extend(imm @ 0x000); let ret : xlenbits = match op { RISCV_LUI => off, RISCV_AUIPC => get_arch_pc() + off }; X(rd) = ret; RETIRE_SUCCESS", "static bool trans_auipc(DisasContext *ctx, arg_auipc *a) { TCGv target_pc = dest_gpr(ctx, a->rd); gen_pc_plus_diff(target_pc, ctx, a->imm); gen_set_gpr(ctx, a->rd, target_pc); return true; }" } ... ``` This is another pattern to be added to the translation database: | Sail | QEMU | |---------------------------------|----------------------------------------------------| | `variable = get_arch_pc() + offset` | `target_pc = dest_gpr(ctx, a->rd)` | | | `gen_pc_plus_diff(target_pc, ctx, a->imm)` | --- Where the format of the map is: Map<String, pair<Sail_Instruction_Representation, QEMU_Instruction_Representation>> The template is consistent, so only the code needs to be translated. We were hoping to get suggestions and feedback from the community and maintainers based on this task, using the output of the example files used to create a base mapping. We hope to create a webpage representing the instruction mappings, that the community itself could refer to. We are in the process of constructing a universal page dedicated to these translations across several downstream projects, so it could be referred to and reviewed by those interested in generation/translation of instruction representation across several projects compared against each other.
claunia added the pull-request label 2026-01-31 21:30:55 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/qemu#356