blob: 9a9fdf2a4b345a85193b949c911296a4eb000e8c [file] [log] [blame]
// Copyright 2024 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
//
// http://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.
// RiscV 32 bit CHERIoT instruction decoder.
decoder RiscVCheriot {
namespace mpact::sim::cheriot::encoding;
opcode_enum = "isa32::OpcodeEnum";
includes {
#include "cheriot/riscv_cheriot_decoder.h"
}
RiscVCheriotInst32;
RiscVCheriotInst16;
};
format Inst32Format[32] {
fields:
unsigned bits[25];
unsigned opcode[7];
};
// 3 register instruction format.
format RType[32] : Inst32Format {
fields:
unsigned func7[7];
unsigned rs2[5];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
// 2 register instruction format.
format R2Type[32] : Inst32Format {
fields:
unsigned func7[7];
unsigned func5[5];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
overlays:
unsigned r_uimm5[5] = func5;
};
// 4 register instruction format.
format R4Type[32] : Inst32Format {
fields:
unsigned rs3[5];
unsigned func2[2];
unsigned rs2[5];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
// Immediate instruction format.
format IType[32] : Inst32Format {
fields:
signed imm12[12];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
overlays:
unsigned u_imm12[12] = imm12;
};
// 2 immediate instruction format.
format I2Type[32] : Inst32Format {
fields:
signed imm12[12];
unsigned i_uimm5[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
overlays:
unsigned u_imm12[12] = imm12;
};
// 5 bit immediate instruction format.
format I5Type[32] : Inst32Format {
fields:
unsigned func7[7];
unsigned r_uimm5[5];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
// Store instruction format.
format SType[32] : Inst32Format {
fields:
unsigned imm7[7];
unsigned rs2[5];
unsigned rs1[5];
unsigned func3[3];
unsigned imm5[5];
unsigned opcode[7];
overlays:
signed s_imm[12] = imm7, imm5;
};
// Branch instruction format.
format BType[32] : Inst32Format {
fields:
unsigned imm7[7];
unsigned rs2[5];
unsigned rs1[5];
unsigned func3[3];
unsigned imm5[5];
unsigned opcode[7];
overlays:
signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0;
};
// Long immediate instruction format.
format UType[32] : Inst32Format {
fields:
unsigned imm20[20];
unsigned rd[5];
unsigned opcode[7];
overlays:
unsigned u_imm[32] = imm20, 0b0000'0000'0000;
signed s_imm[31] = imm20, 0b000'0000'0000;
};
// Jump instruction format.
format JType[32] : Inst32Format {
fields:
unsigned imm20[20];
unsigned rd[5];
unsigned opcode[7];
overlays:
signed j_imm[21] = imm20[19, 7..0, 8, 18..9], 0b0;
};
// Fence instruction format.
format Fence[32] : Inst32Format {
fields:
unsigned fm[4];
unsigned pred[4];
unsigned succ[4];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
// Atomic instruction format.
format AType[32] : Inst32Format {
fields:
unsigned func5[5];
unsigned aq[1];
unsigned rl[1];
unsigned rs2[5];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
instruction group RiscVCheriotInst32[32] : Inst32Format {
lui : UType : opcode == 0b011'0111;
beq : BType : func3 == 0b000, opcode == 0b110'0011;
bne : BType : func3 == 0b001, opcode == 0b110'0011;
blt : BType : func3 == 0b100, opcode == 0b110'0011;
bge : BType : func3 == 0b101, opcode == 0b110'0011;
bltu : BType : func3 == 0b110, opcode == 0b110'0011;
bgeu : BType : func3 == 0b111, opcode == 0b110'0011;
lb : IType : func3 == 0b000, opcode == 0b000'0011;
lh : IType : func3 == 0b001, opcode == 0b000'0011;
lw : IType : func3 == 0b010, opcode == 0b000'0011;
lbu : IType : func3 == 0b100, opcode == 0b000'0011;
lhu : IType : func3 == 0b101, opcode == 0b000'0011;
sb : SType : func3 == 0b000, opcode == 0b010'0011;
sh : SType : func3 == 0b001, opcode == 0b010'0011;
sw : SType : func3 == 0b010, opcode == 0b010'0011;
addi : IType : func3 == 0b000, opcode == 0b001'0011;
slti : IType : func3 == 0b010, opcode == 0b001'0011;
sltiu : IType : func3 == 0b011, opcode == 0b001'0011;
xori : IType : func3 == 0b100, opcode == 0b001'0011;
ori : IType : func3 == 0b110, opcode == 0b001'0011;
andi : IType : func3 == 0b111, opcode == 0b001'0011;
slli : I5Type : func7 == 0b000'0000, func3==0b001, opcode == 0b001'0011;
srli : I5Type : func7 == 0b000'0000, func3==0b101, opcode == 0b001'0011;
srai : I5Type : func7 == 0b010'0000, func3==0b101, opcode == 0b001'0011;
add : RType : func7 == 0b000'0000, func3==0b000, opcode == 0b011'0011;
sub : RType : func7 == 0b010'0000, func3==0b000, opcode == 0b011'0011;
sll : RType : func7 == 0b000'0000, func3==0b001, opcode == 0b011'0011;
slt : RType : func7 == 0b000'0000, func3==0b010, opcode == 0b011'0011;
sltu : RType : func7 == 0b000'0000, func3==0b011, opcode == 0b011'0011;
xor : RType : func7 == 0b000'0000, func3==0b100, opcode == 0b011'0011;
srl : RType : func7 == 0b000'0000, func3==0b101, opcode == 0b011'0011;
sra : RType : func7 == 0b010'0000, func3==0b101, opcode == 0b011'0011;
or : RType : func7 == 0b000'0000, func3==0b110, opcode == 0b011'0011;
and : RType : func7 == 0b000'0000, func3==0b111, opcode == 0b011'0011;
fence : Fence : func3 == 0b000, opcode == 0b000'1111;
ecall : Inst32Format : bits == 0b0000'0000'0000'00000'000'00000, opcode == 0b111'0011;
ebreak : Inst32Format : bits == 0b0000'0000'0001'00000'000'00000, opcode == 0b111'0011;
// Cheriot instructions.
cheriot_auicgp : UType : opcode == 0x7b;
cheriot_auipcc : UType : opcode == 0x17;
cheriot_andperm : RType : func7 == 0x0d, func3 == 0, opcode == 0x5b;
cheriot_cleartag : R2Type : func7 == 0x7f, func5 == 0x0b, func3 == 0, opcode == 0x5b;
cheriot_getaddr : R2Type : func7 == 0x7f, func5 == 0x0f, func3 == 0, opcode == 0x5b;
cheriot_getbase : R2Type : func7 == 0x7f, func5 == 0x02, func3 == 0, opcode == 0x5b;
cheriot_gethigh : R2Type : func7 == 0x7f, func5 == 0x17, func3 == 0, opcode == 0x5b;
cheriot_getlen : R2Type : func7 == 0x7f, func5 == 0x03, func3 == 0, opcode == 0x5b;
cheriot_getperm : R2Type : func7 == 0x7f, func5 == 0x00, func3 == 0, opcode == 0x5b;
cheriot_gettag : R2Type : func7 == 0x7f, func5 == 0x04, func3 == 0, opcode == 0x5b;
cheriot_gettop : R2Type : func7 == 0x7f, func5 == 0x18, func3 == 0, opcode == 0x5b;
cheriot_gettype : R2Type : func7 == 0x7f, func5 == 0x01, func3 == 0, opcode == 0x5b;
cheriot_incaddr : RType : func7 == 0x11, func3 == 0, opcode == 0x5b;
cheriot_incaddrimm : IType : func3 == 0x1, opcode == 0x5b;
cheriot_jal : JType : rd > 1, opcode == 0x6f;
cheriot_jal_cra : JType : rd == 1, opcode == 0x6f;
cheriot_j : JType : rd == 0, opcode == 0x6f;
// For jalr and jr, need to differentiate when the destination (jalr) or the
// source (jr) designates the cra register.
// Function call (dest != cra) (unsealed or interrupt inheriting forward sentry {0, 1})
cheriot_jalr : IType : func3 == 0x0, rd > 1, opcode == 0x67;
// Function call (dest == cra) (unsealed or forward sentries {0, 1, 2, 3}).
cheriot_jalr_cra : IType : func3 == 0x0, rd == 1, opcode == 0x67;
// Tail call src != cra (unsealed or interrupt inheriting forward sentry {0, 1})
cheriot_jr : IType : func3 == 0x0, rd == 0, rs1 > 1, opcode == 0x67;
// Function return src == cra (return sentries only {4, 5})
cheriot_jr_cra : IType : func3 == 0x0, rd == 0, rs1 == 1, opcode == 0x67;
// Jalr causing exception: both rd and rs1 are 0.
cheriot_jalr_zero: IType : func3 == 0x0, rd == 0, rs1 == 0, opcode == 0x67;
cheriot_lc : IType : func3 == 0x3, opcode == 0x03;
cheriot_move : RType : func7 == 0x7f, rs2 == 0xa, func3 == 0, opcode == 0x5b;
cheriot_representablealignmentmask : R2Type : func7 == 0x7f, func5 == 0x9, func3 == 0, opcode == 0x5b;
cheriot_roundrepresentablelength : R2Type : func7 == 0x7f, func5 == 0x8, func3 == 0, opcode == 0x5b;
cheriot_sc : SType : func3 == 0x3, opcode == 0x23;
cheriot_seal : RType : func7 == 0x0b, func3 == 0, opcode == 0x5b;
cheriot_setaddr : RType : func7 == 0x10, func3 == 0, opcode == 0x5b;
cheriot_setbounds : RType : func7 == 0x08, func3 == 0, opcode == 0x5b;
cheriot_setboundsexact : RType : func7 == 0x09, func3 == 0, opcode == 0x5b;
cheriot_setboundsimm : IType : func3 == 0x02, opcode == 0x5b;
cheriot_setequalexact : RType : func7 == 0x21, func3 == 0, opcode == 0x5b;
cheriot_sethigh : RType : func7 == 0x16, func3 == 0, opcode == 0x5b;
cheriot_specialr : R2Type : func7 == 0x01, func5 >= 28, func5 <= 31, func3 == 0, rs1 == 0, opcode == 0x5b;
cheriot_specialrw : R2Type : func7 == 0x01, func5 >= 28, func5 <= 31, func3 == 0, rs1 != 0, opcode == 0x5b;
cheriot_sub : RType : func7 == 0x14, func3 == 0, opcode == 0x5b;
cheriot_testsubset : RType : func7 == 0x20, func3 == 0, opcode == 0x5b;
cheriot_unseal : RType : func7 == 0x0c, func3 == 0, opcode == 0x5b;
// RiscV32 Instruction fence.
// fencei : IType : func3 == 001, opcode == 0b000'1111;
// RiscV32 multiply divide.
mul : RType : func7 == 0b000'0001, func3 == 0b000, opcode == 0b011'0011;
mulh : RType : func7 == 0b000'0001, func3 == 0b001, opcode == 0b011'0011;
mulhsu : RType : func7 == 0b000'0001, func3 == 0b010, opcode == 0b011'0011;
mulhu : RType : func7 == 0b000'0001, func3 == 0b011, opcode == 0b011'0011;
div : RType : func7 == 0b000'0001, func3 == 0b100, opcode == 0b011'0011;
divu : RType : func7 == 0b000'0001, func3 == 0b101, opcode == 0b011'0011;
rem : RType : func7 == 0b000'0001, func3 == 0b110, opcode == 0b011'0011;
remu : RType : func7 == 0b000'0001, func3 == 0b111, opcode == 0b011'0011;
// RiscV32 atomic instructions.
lrw : AType : func5 == 0b0'0010, rs2 == 0, func3 == 0b010, opcode == 0b010'1111;
scw : AType : func5 == 0b0'0011, func3 == 0b010, opcode == 0b010'1111;
amoswapw : AType : func5 == 0b0'0001, func3 == 0b010, opcode == 0b010'1111;
amoaddw : AType : func5 == 0b0'0000, func3 == 0b010, opcode == 0b010'1111;
amoxorw : AType : func5 == 0b0'0100, func3 == 0b010, opcode == 0b010'1111;
amoandw : AType : func5 == 0b0'1100, func3 == 0b010, opcode == 0b010'1111;
amoorw : AType : func5 == 0b0'1000, func3 == 0b010, opcode == 0b010'1111;
amominw : AType : func5 == 0b1'0000, func3 == 0b010, opcode == 0b010'1111;
amomaxw : AType : func5 == 0b1'0100, func3 == 0b010, opcode == 0b010'1111;
amominuw : AType : func5 == 0b1'1000, func3 == 0b010, opcode == 0b010'1111;
amomaxuw : AType : func5 == 0b1'1100, func3 == 0b010, opcode == 0b010'1111;
// RiscV32 CSR manipulation instructions.
csrrw : IType : func3 == 0b001, rd != 0, opcode == 0b111'0011;
csrrs : IType : func3 == 0b010, rs1 != 0, rd != 0, opcode == 0b111'0011;
csrrc : IType : func3 == 0b011, rs1 != 0, rd != 0, opcode == 0b111'0011;
csrrs_nr : IType : func3 == 0b010, rs1 != 0, rd == 0, opcode == 0b111'0011;
csrrc_nr : IType : func3 == 0b011, rs1 != 0, rd == 0, opcode == 0b111'0011;
csrrw_nr : IType : func3 == 0b001, rd == 0, opcode == 0b111'0011;
csrrs_nw : IType : func3 == 0b010, rs1 == 0, opcode == 0b111'0011;
csrrc_nw : IType : func3 == 0b011, rs1 == 0, opcode == 0b111'0011;
csrrwi : I2Type : func3 == 0b101, rd != 0, opcode == 0b111'0011;
csrrsi : I2Type : func3 == 0b110, i_uimm5 != 0, rd != 0, opcode == 0b111'0011;
csrrci : I2Type : func3 == 0b111, i_uimm5 != 0, rd != 0, opcode == 0b111'0011;
csrrsi_nr: I2Type : func3 == 0b110, i_uimm5 != 0, rd == 0, opcode == 0b111'0011;
csrrci_nr: I2Type : func3 == 0b111, i_uimm5 != 0, rd == 0, opcode == 0b111'0011;
csrrwi_nr: I2Type : func3 == 0b101, rd == 0, opcode == 0b111'0011;
csrrsi_nw: I2Type : func3 == 0b110, i_uimm5 == 0, opcode == 0b111'0011;
csrrci_nw: I2Type : func3 == 0b111, i_uimm5 == 0, opcode == 0b111'0011;
// RiscV32 Privileged instructions.
mret : Inst32Format : bits == 0b001'1000'00010'00000'000'00000, opcode == 0b111'0011;
wfi : Inst32Format : bits == 0b000'1000'00101'00000'000'00000, opcode == 0b111'0011;
// sfence_vma_zz : RType : func7 == 0b000'1001, rs2 == 0, rs1 == 0, func3 == 0, rd == 0, opcode == 0b111'0011;
// sfence_vma_zn : RType : func7 == 0b000'1001, rs2 != 0, rs1 == 0, func3 == 0, rd == 0, opcode == 0b111'0011;
// sfence_vma_nz : RType : func7 == 0b000'1001, rs2 == 0, rs1 != 0, func3 == 0, rd == 0, opcode == 0b111'0011;
// sfence_vma_nn : RType : func7 == 0b000'1001, rs2 != 0, rs1 != 0, func3 == 0, rd == 0, opcode == 0b111'0011;
};
// Compact instruction formats.
format Inst16Format[16] {
fields:
unsigned func3[3];
unsigned bits[11];
unsigned op[2];
};
format CSS[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm6[6];
unsigned rs2[5];
unsigned op[2];
overlays:
unsigned css_imm_w[8] = imm6[1..0], imm6[5..2], 0b00;
unsigned css_imm_d[9] = imm6[2..0], imm6[5..3], 0b000;
};
format CL[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm3[3];
unsigned rs1p[3];
unsigned imm2[2];
unsigned rdp[3];
unsigned op[2];
overlays:
unsigned rs1[5] = 0b01, rs1p;
unsigned rd[5] = 0b01, rdp;
unsigned cl_imm_w[7] = imm2[0], imm3, imm2[1], 0b00;
unsigned cl_imm_d[8] = imm2, imm3, 0b000;
};
format CS[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm3[3];
unsigned rs1p[3];
unsigned imm2[2];
unsigned rs2p[3];
unsigned op[2];
overlays:
unsigned rs1[5] = 0b01, rs1p;
unsigned rs2[5] = 0b01, rs2p;
unsigned cs_imm_w[7] = imm2[0], imm3, imm2[1], 0b00;
unsigned cs_imm_d[8] = imm2, imm3, 0b000;
};
format CJ[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm11[11];
unsigned op[2];
overlays:
signed jimm[12] = imm11[10, 6, 8..7, 4, 5, 0, 9, 3..1], 0b0;
};
format CR[16] : Inst16Format {
fields:
unsigned func4[4];
unsigned rs1[5];
unsigned rs2[5];
unsigned op[2];
overlays:
unsigned rd[5] = rs1;
};
// Compact shift immediate instructions.
format CSH[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm1[1];
unsigned op2[2];
unsigned rs1p[3];
unsigned imm5[5];
unsigned op[2];
overlays:
unsigned uimm6[6] = imm1, imm5;
signed imm6[6] = imm1, imm5;
unsigned imm3[3] = imm1, op2;
unsigned rd[5] = 0b01, rs1p;
unsigned rs1[5] = 0b01, rs1p;
};
// Compact branch instructions.
format CB[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm3[3];
unsigned rs1p[3];
unsigned imm5[5];
unsigned op[2];
overlays:
unsigned rs1[5] = 0b01, rs1p;
signed bimm[9] = imm3[2], imm5[4..3, 0], imm3[1..0], imm5[2..1], 0b0;
};
format CI[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm1[1];
unsigned rs1[5];
unsigned imm5[5];
unsigned op[2];
overlays:
unsigned rd[5] = rs1;
signed imm6[6] = imm1, imm5;
unsigned uimm6[6] = imm1, imm5;
signed imm18[18] = imm1, imm5, 0b0000'0000'0000;
signed ci_imm10[10] = imm1, imm5[2..1, 3, 0, 4], 0b0000;
unsigned ci_imm_w[8] = imm5[1..0], imm1, imm5[4..2], 0b00;
unsigned ci_imm_d[9] = imm5[2..0], imm1, imm5[4..3], 0b000;
};
format CIW[16] : Inst16Format {
fields:
unsigned func3[3];
unsigned imm8[8];
unsigned rdp[3];
unsigned op[2];
overlays:
unsigned rd[5] = 0b01, rdp;
unsigned ciw_imm10[10] = imm8[5..2, 7..6, 0, 1], 0b00;
};
format CA[16] : Inst16Format {
fields:
unsigned func6[6];
unsigned rs1p[3];
unsigned func2[2];
unsigned fs2p[3];
unsigned op[2];
overlays:
unsigned rs1[5] = 0b01, rs1p;
unsigned rs2[5] = 0b01, fs2p;
unsigned rd[5] = 0b01, rs1p;
};
// Compact instruction encodings.
instruction group RiscVCheriotInst16[16] : Inst16Format {
caddi4spn : CIW: func3 == 0b000, op == 0b00, imm8 != 0;
clw : CL : func3 == 0b010, op == 0b00;
clc : CL : func3 == 0b011, op == 0b00;
csw : CS : func3 == 0b110, op == 0b00;
csc : CS : func3 == 0b111, op == 0b00;
cnop : CI : func3 == 0b000, imm1 == 0, rs1 == 0, imm5 == 0, op == 0b01;
chint : CI : func3 == 0b000, imm6 != 0, rs1 == 0, op == 0b01;
caddi : CI : func3 == 0b000, imm6 != 0, rd != 0, op == 0b01;
chint : CI : func3 == 0b000, imm6 == 0, rd != 0, op == 0b01;
cli : CI : func3 == 0b010, rd != 0, op == 0b01;
chint : CI : func3 == 0b010, rd == 0, op == 0b01;
caddi16sp : CI : func3 == 0b011, ci_imm10 != 0, rd == 2, op == 0b01;
clui : CI : func3 == 0b011, rd != 0, rd != 2, imm18 != 0, op == 0b01;
chint : CI : func3 == 0b011, rd == 0, imm18 != 0, op == 0b01;
// TODO(torerik): The following two instructions should have imm1 == 0 and
// imm5 != 0 instead of imm6 != 0 in the constraints, but that has been
// temporarily removed so as to make it easier to verify in TestRIG
csrli : CSH : func3 == 0b100, op2 == 0b00, uimm6 != 0, op == 0b01;
chint : CSH : func3 == 0b100, op2 == 0b00, uimm6 == 0, op == 0b01;
csrai : CSH : func3 == 0b100, op2 == 0b01, uimm6 != 0, op == 0b01;
chint : CSH : func3 == 0b100, op2 == 0b01, uimm6 == 0, op == 0b01;
candi : CSH : func3 == 0b100, op2 == 0b10, op == 0b01;
csub : CA : func6 == 0b100'011, func2 == 0b00, op == 0b01;
cxor : CA : func6 == 0b100'011, func2 == 0b01, op == 0b01;
cor : CA : func6 == 0b100'011, func2 == 0b10, op == 0b01;
cand : CA : func6 == 0b100'011, func2 == 0b11, op == 0b01;
cbeqz : CB : func3 == 0b110, op == 0b01;
cbnez : CB : func3 == 0b111, op == 0b01;
cslli : CI : func3 == 0b000, imm1 == 0, imm5 != 0, rs1 != 0, op == 0b10;
chint : CI : func3 == 0b000, imm1 == 0, rs1 == 0, imm5 != 0, op == 0b10;
chint : CI : func3 == 0b000, imm6 == 0, op == 0b10;
clwsp : CI : func3 == 0b010, rd != 0, op == 0b10;
clcsp : CI : func3 == 0b011, rd != 0, op == 0b10;
cmv : CR : func4 == 0b1000, rs1 != 0, rs2 != 0, op == 0b10;
cebreak : Inst16Format : func3 == 0b100, bits == 0b1'00000'00000, op == 0b10;
cadd : CR : func4 == 0b1001, rs1 != 0, rs2 != 0, op == 0b10;
chint : CR : func4 == 0b1001, rs1 == 0, rs2 != 0, op == 0b10;
cswsp : CSS: func3 == 0b110, op == 0b10;
cscsp : CSS: func3 == 0b111, op == 0b10;
cheriot_cj : CJ : func3 == 0b101, op == 0b01;
cheriot_cjal_cra : CJ : func3 == 0b001, op == 0b01;
cheriot_cjr : CR : func4 == 0b1000, rs1 > 1, rs2 == 0, op == 0b10;
cheriot_cjr_cra : CR : func4 == 0b1000, rs1 == 1, rs2 == 0, op == 0b10;
cheriot_cjalr_cra : CR : func4 == 0b1001, rs1 != 0, rs2 == 0, op == 0b10;
};