aboutsummaryrefslogtreecommitdiff
path: root/model
diff options
context:
space:
mode:
authorTim Hutt <timothy.hutt@codasip.com>2024-03-05 13:44:32 +0000
committerBill McSpadden <bill@riscv.org>2024-04-15 15:37:18 -0500
commit16077e126b634c006590b02cb758d48a3882528a (patch)
tree8310d601b872a04001d28bb39a95ab9b93b87130 /model
parentf1c043d76b0f5030ced7eaaea34420d3a916fd91 (diff)
downloadsail-riscv-16077e126b634c006590b02cb758d48a3882528a.zip
sail-riscv-16077e126b634c006590b02cb758d48a3882528a.tar.gz
sail-riscv-16077e126b634c006590b02cb758d48a3882528a.tar.bz2
Implement Zcb extension
This adds an implementation of the Zcb code size extension. Co-authored-by: Martin Berger <martinberger@users.noreply.github.com>
Diffstat (limited to 'model')
-rw-r--r--model/riscv_insts_zcb.sail210
-rw-r--r--model/riscv_sys_regs.sail5
2 files changed, 215 insertions, 0 deletions
diff --git a/model/riscv_insts_zcb.sail b/model/riscv_insts_zcb.sail
new file mode 100644
index 0000000..1320736
--- /dev/null
+++ b/model/riscv_insts_zcb.sail
@@ -0,0 +1,210 @@
+/*=======================================================================================*/
+/* This Sail RISC-V architecture model, comprising all files and */
+/* directories except where otherwise noted is subject the BSD */
+/* two-clause license in the LICENSE file. */
+/* */
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*=======================================================================================*/
+
+union clause ast = C_LBU : (bits(2), cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_LBU(uimm1 @ uimm0, rdc, rs1c) if haveZcb()
+ <-> 0b100 @ 0b000 @ rs1c : cregidx @ uimm0 : bits(1) @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
+
+mapping clause assembly = C_LBU(uimm, rdc, rs1c) <->
+ "c.lbu" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
+
+function clause execute C_LBU(uimm, rdc, rs1c) = {
+ let imm : bits(12) = zero_extend(uimm);
+ let rd = creg2reg_idx(rdc);
+ let rs1 = creg2reg_idx(rs1c);
+ execute(LOAD(imm, rs1, rd, true, BYTE, false, false))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_LHU : (bits(2), cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_LHU(uimm1 @ 0b0, rdc, rs1c) if haveZcb()
+ <-> 0b100 @ 0b001 @ rs1c : cregidx @ 0b0 @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
+
+mapping clause assembly = C_LHU(uimm, rdc, rs1c) <->
+ "c.lhu" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
+
+function clause execute C_LHU(uimm, rdc, rs1c) = {
+ let imm : bits(12) = zero_extend(uimm);
+ let rd = creg2reg_idx(rdc);
+ let rs1 = creg2reg_idx(rs1c);
+ execute(LOAD(imm, rs1, rd, true, HALF, false, false))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_LH : (bits(2), cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_LH(uimm1 @ 0b0, rdc, rs1c) if haveZcb()
+ <-> 0b100 @ 0b001 @ rs1c : cregidx @ 0b1 @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
+
+mapping clause assembly = C_LH(uimm, rdc, rs1c) <->
+ "c.lh" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
+
+function clause execute C_LH(uimm, rdc, rs1c) = {
+ let imm : bits(12) = zero_extend(uimm);
+ let rd = creg2reg_idx(rdc);
+ let rs1 = creg2reg_idx(rs1c);
+ execute(LOAD(imm, rs1, rd, false, HALF, false, false))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_SB : (bits(2), cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_SB(uimm1 @ uimm0, rs1c, rs2c) if haveZcb()
+ <-> 0b100 @ 0b010 @ rs1c : cregidx @ uimm0 : bits(1) @ uimm1 : bits(1) @ rs2c @ 0b00 if haveZcb()
+
+mapping clause assembly = C_SB(uimm, rs1c, rs2c) <->
+ "c.sb" ^ spc() ^ creg_name(rs2c) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
+
+function clause execute C_SB(uimm, rs1c, rs2c) = {
+ let imm : bits(12) = zero_extend(uimm);
+ let rs1 = creg2reg_idx(rs1c);
+ let rs2 = creg2reg_idx(rs2c);
+ execute(STORE(imm, rs2, rs1, BYTE, false, false))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_SH : (bits(2), cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_SH(uimm1 @ 0b0, rs1c, rs2c) if haveZcb()
+ <-> 0b100 @ 0b011 @ rs1c : cregidx @ 0b0 @ uimm1 : bits(1) @ rs2c : cregidx @ 0b00 if haveZcb()
+
+mapping clause assembly = C_SH(uimm, rs1c, rs2c) <->
+ "c.sh" ^ spc() ^ creg_name(rs1c) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs2c) ^ opt_spc() ^ ")"
+
+function clause execute C_SH(uimm, rs1c, rs2c) = {
+ let imm : bits(12) = zero_extend(uimm);
+ let rs1 = creg2reg_idx(rs1c);
+ let rs2 = creg2reg_idx(rs2c);
+ execute(STORE(imm, rs2, rs1, HALF, false, false))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_ZEXT_B : (cregidx)
+
+mapping clause encdec_compressed =
+ C_ZEXT_B(rsdc) if haveZcb()
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b000 @ 0b01 if haveZcb()
+
+mapping clause assembly = C_ZEXT_B(rsdc) <->
+ "c.zext.b" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_ZEXT_B(rsdc) = {
+ let rsd = creg2reg_idx(rsdc);
+ X(rsd) = zero_extend(X(rsd)[7..0]);
+ RETIRE_SUCCESS
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_SEXT_B : (cregidx)
+
+mapping clause encdec_compressed =
+ C_SEXT_B(rsdc) if haveZcb() & haveZbb()
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b001 @ 0b01 if haveZcb() & haveZbb()
+
+mapping clause assembly = C_SEXT_B(rsdc) <->
+ "c.sext.b" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_SEXT_B(rsdc) = {
+ let rsd = creg2reg_idx(rsdc);
+ execute(ZBB_EXTOP(rsd, rsd, RISCV_SEXTB))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_ZEXT_H : (cregidx)
+
+mapping clause encdec_compressed =
+ C_ZEXT_H(rsdc) if haveZcb() & haveZbb()
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b010 @ 0b01 if haveZcb() & haveZbb()
+
+mapping clause assembly = C_ZEXT_H(rsdc) <->
+ "c.zext.h" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_ZEXT_H(rsdc) = {
+ let rsd = creg2reg_idx(rsdc);
+ execute(ZBB_EXTOP(rsd, rsd, RISCV_ZEXTH))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_SEXT_H : (cregidx)
+
+mapping clause encdec_compressed =
+ C_SEXT_H(rsdc) if haveZcb() & haveZbb()
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b011 @ 0b01 if haveZcb() & haveZbb()
+
+mapping clause assembly = C_SEXT_H(rsdc) <->
+ "c.sext.h" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_SEXT_H(rsdc) = {
+ let rsd = creg2reg_idx(rsdc);
+ execute(ZBB_EXTOP(rsd, rsd, RISCV_SEXTH))
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_ZEXT_W : (cregidx)
+
+mapping clause encdec_compressed =
+ C_ZEXT_W(rsdc) if haveZcb() & haveZba() & sizeof(xlen) == 64
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b100 @ 0b01 if haveZcb() & haveZba() & sizeof(xlen) == 64
+
+mapping clause assembly = C_ZEXT_W(rsdc) <->
+ "c.zext.w" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_ZEXT_W(rsdc) = {
+ let rsd = creg2reg_idx(rsdc);
+ execute (ZBA_RTYPEUW(0b00000, rsd, rsd, RISCV_ADDUW)) // Note 0b00000 is the regidx of the zero register
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_NOT : (cregidx)
+
+mapping clause encdec_compressed =
+ C_NOT(rsdc) if haveZcb()
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b101 @ 0b01 if haveZcb()
+
+mapping clause assembly = C_NOT(rsdc) <->
+ "c.not" ^ spc() ^ creg_name(rsdc)
+
+function clause execute C_NOT(rsdc) = {
+ let r = creg2reg_idx(rsdc);
+ X(r) = ~(X(r));
+ RETIRE_SUCCESS
+}
+
+/* ****************************************************************** */
+
+union clause ast = C_MUL : (cregidx, cregidx)
+
+mapping clause encdec_compressed =
+ C_MUL(rsdc, rs2c) if haveZcb() & (haveMulDiv() | haveZmmul())
+ <-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b10 @ rs2c : cregidx @ 0b01 if haveZcb() & (haveMulDiv() | haveZmmul())
+
+mapping clause assembly = C_MUL(rsdc, rs2c) <->
+ "c.mul" ^ spc() ^ creg_name(rsdc) ^ sep() ^ creg_name(rs2c)
+
+function clause execute C_MUL(rsdc, rs2c) = {
+ let rd = creg2reg_idx(rsdc);
+ let rs = creg2reg_idx(rs2c);
+ execute(MUL(rs, rd, rd, false, true, true))
+}
diff --git a/model/riscv_sys_regs.sail b/model/riscv_sys_regs.sail
index d8309ec..3e198b4 100644
--- a/model/riscv_sys_regs.sail
+++ b/model/riscv_sys_regs.sail
@@ -84,6 +84,8 @@ val sys_enable_writable_misa = {c: "sys_enable_writable_misa", ocaml: "Platform.
val sys_enable_rvc = {c: "sys_enable_rvc", ocaml: "Platform.enable_rvc", _: "sys_enable_rvc"} : unit -> bool
/* whether misa.{f,d} were enabled at boot */
val sys_enable_fdext = {c: "sys_enable_fdext", ocaml: "Platform.enable_fdext", _: "sys_enable_fdext"} : unit -> bool
+/* whether Zcb was enabled at boot */
+val sys_enable_zcb = {c: "sys_enable_zcb", ocaml: "Platform.enable_zcb", _: "sys_enable_zcb"} : unit -> bool
/* whether zfinx was enabled at boot */
val sys_enable_zfinx = {c: "sys_enable_zfinx", ocaml: "Platform.enable_zfinx", _: "sys_enable_zfinx"} : unit -> bool
/* whether the N extension was enabled at boot */
@@ -309,6 +311,9 @@ function haveZfh() -> bool = (misa[F] == 0b1) & (mstatus[FS] != 0b00)
/* V extension has to enable both via misa.V as well as mstatus.VS */
function haveVExt() -> bool = (misa[V] == 0b1) & (mstatus[VS] != 0b00)
+/* Zcb has simple code-size saving instructions. (The Zcb extension depends on the Zca extension.) */
+function haveZcb() -> bool = sys_enable_zcb()
+
/* Zhinx, Zfinx and Zdinx extensions (TODO: gate FCSR access on [mhs]stateen0 bit 1 when implemented) */
function haveZhinx() -> bool = sys_enable_zfinx()
function haveZfinx() -> bool = sys_enable_zfinx()