Skip to content

Commit

Permalink
Implement Zcb extension
Browse files Browse the repository at this point in the history
This adds an implementation of the Zcb code size extension.

Co-authored-by: Martin Berger <martinberger@users.noreply.github.com>
  • Loading branch information
2 people authored and billmcspadden-riscv committed Apr 15, 2024
1 parent f1c043d commit 16077e1
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 1 deletion.
2 changes: 1 addition & 1 deletion LICENCE
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions c_emulator/riscv_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions c_emulator/riscv_sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
210 changes: 210 additions & 0 deletions model/riscv_insts_zcb.sail
Original file line number Diff line number Diff line change
@@ -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))
}
5 changes: 5 additions & 0 deletions model/riscv_sys_regs.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions ocaml_emulator/platform.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ocaml_emulator/riscv_ocaml_sim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down

0 comments on commit 16077e1

Please sign in to comment.