aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--LICENCE2
-rw-r--r--Makefile2
-rw-r--r--c_emulator/riscv_platform.c5
-rw-r--r--c_emulator/riscv_platform.h1
-rw-r--r--c_emulator/riscv_platform_impl.c1
-rw-r--r--c_emulator/riscv_platform_impl.h1
-rw-r--r--c_emulator/riscv_sim.c6
-rw-r--r--model/riscv_insts_zcb.sail210
-rw-r--r--model/riscv_sys_regs.sail5
-rw-r--r--ocaml_emulator/platform.ml2
-rw-r--r--ocaml_emulator/riscv_ocaml_sim.ml3
11 files changed, 237 insertions, 1 deletions
diff --git a/LICENCE b/LICENCE
index 9dddf34..432b78d 100644
--- a/LICENCE
+++ b/LICENCE
@@ -16,7 +16,7 @@ Copyright (c) 2017-2024
Brian Campbell
Chris Casinghino
Christopher Pulte
- Codasip, for contributions by Tim Hutt
+ Codasip, for contributions by Tim Hutt, Martin Berger and Ben Fletcher
dylux
eroom1966
Google LLC, for contributions by its employees
diff --git a/Makefile b/Makefile
index deaad55..7068968 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,8 @@ SAIL_DEFAULT_INST += riscv_insts_zbb.sail
SAIL_DEFAULT_INST += riscv_insts_zbc.sail
SAIL_DEFAULT_INST += riscv_insts_zbs.sail
+SAIL_DEFAULT_INST += riscv_insts_zcb.sail
+
SAIL_DEFAULT_INST += riscv_insts_zfh.sail
# Zfa needs to be added after fext, dext and Zfh (as it needs
# definitions from those)
diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.c
index 253da35..6544de6 100644
--- a/c_emulator/riscv_platform.c
+++ b/c_emulator/riscv_platform.c
@@ -32,6 +32,11 @@ bool sys_enable_fdext(unit u)
return rv_enable_fdext;
}
+bool sys_enable_zcb(unit u)
+{
+ return rv_enable_zcb;
+}
+
bool sys_enable_zfinx(unit u)
{
return rv_enable_zfinx;
diff --git a/c_emulator/riscv_platform.h b/c_emulator/riscv_platform.h
index 38fac2f..4a53d12 100644
--- a/c_emulator/riscv_platform.h
+++ b/c_emulator/riscv_platform.h
@@ -4,6 +4,7 @@
bool sys_enable_rvc(unit);
bool sys_enable_next(unit);
bool sys_enable_fdext(unit);
+bool sys_enable_zcb(unit);
bool sys_enable_zfinx(unit);
bool sys_enable_writable_misa(unit);
bool sys_enable_writable_fiom(unit);
diff --git a/c_emulator/riscv_platform_impl.c b/c_emulator/riscv_platform_impl.c
index c2ae256..449bb1d 100644
--- a/c_emulator/riscv_platform_impl.c
+++ b/c_emulator/riscv_platform_impl.c
@@ -6,6 +6,7 @@
uint64_t rv_pmp_count = 0;
uint64_t rv_pmp_grain = 0;
+bool rv_enable_zcb = false;
bool rv_enable_zfinx = false;
bool rv_enable_rvc = true;
bool rv_enable_next = false;
diff --git a/c_emulator/riscv_platform_impl.h b/c_emulator/riscv_platform_impl.h
index e3e4a96..d377c9c 100644
--- a/c_emulator/riscv_platform_impl.h
+++ b/c_emulator/riscv_platform_impl.h
@@ -11,6 +11,7 @@
extern uint64_t rv_pmp_count;
extern uint64_t rv_pmp_grain;
+extern bool rv_enable_zcb;
extern bool rv_enable_zfinx;
extern bool rv_enable_rvc;
extern bool rv_enable_next;
diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c
index 0094e9a..bf68da2 100644
--- a/c_emulator/riscv_sim.c
+++ b/c_emulator/riscv_sim.c
@@ -53,6 +53,7 @@ const char *RV32ISA = "RV32IMAC";
#define OPT_ENABLE_WRITABLE_FIOM 1001
#define OPT_PMP_COUNT 1002
#define OPT_PMP_GRAIN 1003
+#define OPT_ENABLE_ZCB 10014
static bool do_dump_dts = false;
static bool do_show_times = false;
@@ -145,6 +146,7 @@ static struct option options[] = {
{"inst-limit", required_argument, 0, 'l' },
{"enable-zfinx", no_argument, 0, 'x' },
{"enable-writable-fiom", no_argument, 0, OPT_ENABLE_WRITABLE_FIOM},
+ {"enable-zcb", no_argument, 0, OPT_ENABLE_ZCB },
#ifdef SAILCOV
{"sailcov-file", required_argument, 0, 'c' },
#endif
@@ -386,6 +388,10 @@ static int process_args(int argc, char **argv)
case 'l':
insn_limit = atoi(optarg);
break;
+ case OPT_ENABLE_ZCB:
+ fprintf(stderr, "enabling Zcb extension.\n");
+ rv_enable_zcb = true;
+ break;
case 'x':
fprintf(stderr, "enabling Zfinx support.\n");
rv_enable_zfinx = true;
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()
diff --git a/ocaml_emulator/platform.ml b/ocaml_emulator/platform.ml
index a8bde44..2f0aaaf 100644
--- a/ocaml_emulator/platform.ml
+++ b/ocaml_emulator/platform.ml
@@ -10,6 +10,7 @@ let config_enable_writable_misa = ref true
let config_enable_dirty_update = ref false
let config_enable_misaligned_access = ref false
let config_mtval_has_illegal_inst_bits = ref false
+let config_enable_zcb = ref false
let config_enable_writable_fiom = ref true
let config_enable_vext = ref true
let config_pmp_count = ref Big_int.zero
@@ -88,6 +89,7 @@ let enable_vext () = !config_enable_vext
let enable_dirty_update () = !config_enable_dirty_update
let enable_misaligned_access () = !config_enable_misaligned_access
let mtval_has_illegal_inst_bits () = !config_mtval_has_illegal_inst_bits
+let enable_zcb () = !config_enable_zcb
let enable_zfinx () = false
let enable_writable_fiom () = !config_enable_writable_fiom
let pmp_count () = !config_pmp_count
diff --git a/ocaml_emulator/riscv_ocaml_sim.ml b/ocaml_emulator/riscv_ocaml_sim.ml
index 03887b7..8dad8a4 100644
--- a/ocaml_emulator/riscv_ocaml_sim.ml
+++ b/ocaml_emulator/riscv_ocaml_sim.ml
@@ -53,6 +53,9 @@ let options = Arg.align ([("-dump-dts",
("-mtval-has-illegal-inst-bits",
Arg.Set P.config_mtval_has_illegal_inst_bits,
" mtval stores instruction bits on an illegal instruction exception");
+ ("-enable-zcb",
+ Arg.Set P.config_enable_zcb,
+ " enable Zcb (simple code size) extension");
("-enable-writable-fiom",
Arg.Set P.config_enable_writable_fiom,
" enable FIOM (Fence of I/O implies Memory) bit in menvcfg");