Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 16077e1

Browse files
Timmmmmartinberger
authored andcommittedApr 15, 2024
Implement Zcb extension
This adds an implementation of the Zcb code size extension. Co-authored-by: Martin Berger <[email protected]>
1 parent f1c043d commit 16077e1

11 files changed

+237
-1
lines changed
 

‎LICENCE

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Copyright (c) 2017-2024
1616
Brian Campbell
1717
Chris Casinghino
1818
Christopher Pulte
19-
Codasip, for contributions by Tim Hutt
19+
Codasip, for contributions by Tim Hutt, Martin Berger and Ben Fletcher
2020
dylux
2121
eroom1966
2222
Google LLC, for contributions by its employees

‎Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ SAIL_DEFAULT_INST += riscv_insts_zbb.sail
3232
SAIL_DEFAULT_INST += riscv_insts_zbc.sail
3333
SAIL_DEFAULT_INST += riscv_insts_zbs.sail
3434

35+
SAIL_DEFAULT_INST += riscv_insts_zcb.sail
36+
3537
SAIL_DEFAULT_INST += riscv_insts_zfh.sail
3638
# Zfa needs to be added after fext, dext and Zfh (as it needs
3739
# definitions from those)

‎c_emulator/riscv_platform.c

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ bool sys_enable_fdext(unit u)
3232
return rv_enable_fdext;
3333
}
3434

35+
bool sys_enable_zcb(unit u)
36+
{
37+
return rv_enable_zcb;
38+
}
39+
3540
bool sys_enable_zfinx(unit u)
3641
{
3742
return rv_enable_zfinx;

‎c_emulator/riscv_platform.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
bool sys_enable_rvc(unit);
55
bool sys_enable_next(unit);
66
bool sys_enable_fdext(unit);
7+
bool sys_enable_zcb(unit);
78
bool sys_enable_zfinx(unit);
89
bool sys_enable_writable_misa(unit);
910
bool sys_enable_writable_fiom(unit);

‎c_emulator/riscv_platform_impl.c

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
uint64_t rv_pmp_count = 0;
77
uint64_t rv_pmp_grain = 0;
88

9+
bool rv_enable_zcb = false;
910
bool rv_enable_zfinx = false;
1011
bool rv_enable_rvc = true;
1112
bool rv_enable_next = false;

‎c_emulator/riscv_platform_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
extern uint64_t rv_pmp_count;
1212
extern uint64_t rv_pmp_grain;
1313

14+
extern bool rv_enable_zcb;
1415
extern bool rv_enable_zfinx;
1516
extern bool rv_enable_rvc;
1617
extern bool rv_enable_next;

‎c_emulator/riscv_sim.c

+6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const char *RV32ISA = "RV32IMAC";
5353
#define OPT_ENABLE_WRITABLE_FIOM 1001
5454
#define OPT_PMP_COUNT 1002
5555
#define OPT_PMP_GRAIN 1003
56+
#define OPT_ENABLE_ZCB 10014
5657

5758
static bool do_dump_dts = false;
5859
static bool do_show_times = false;
@@ -145,6 +146,7 @@ static struct option options[] = {
145146
{"inst-limit", required_argument, 0, 'l' },
146147
{"enable-zfinx", no_argument, 0, 'x' },
147148
{"enable-writable-fiom", no_argument, 0, OPT_ENABLE_WRITABLE_FIOM},
149+
{"enable-zcb", no_argument, 0, OPT_ENABLE_ZCB },
148150
#ifdef SAILCOV
149151
{"sailcov-file", required_argument, 0, 'c' },
150152
#endif
@@ -386,6 +388,10 @@ static int process_args(int argc, char **argv)
386388
case 'l':
387389
insn_limit = atoi(optarg);
388390
break;
391+
case OPT_ENABLE_ZCB:
392+
fprintf(stderr, "enabling Zcb extension.\n");
393+
rv_enable_zcb = true;
394+
break;
389395
case 'x':
390396
fprintf(stderr, "enabling Zfinx support.\n");
391397
rv_enable_zfinx = true;

‎model/riscv_insts_zcb.sail

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*=======================================================================================*/
2+
/* This Sail RISC-V architecture model, comprising all files and */
3+
/* directories except where otherwise noted is subject the BSD */
4+
/* two-clause license in the LICENSE file. */
5+
/* */
6+
/* SPDX-License-Identifier: BSD-2-Clause */
7+
/*=======================================================================================*/
8+
9+
union clause ast = C_LBU : (bits(2), cregidx, cregidx)
10+
11+
mapping clause encdec_compressed =
12+
C_LBU(uimm1 @ uimm0, rdc, rs1c) if haveZcb()
13+
<-> 0b100 @ 0b000 @ rs1c : cregidx @ uimm0 : bits(1) @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
14+
15+
mapping clause assembly = C_LBU(uimm, rdc, rs1c) <->
16+
"c.lbu" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
17+
18+
function clause execute C_LBU(uimm, rdc, rs1c) = {
19+
let imm : bits(12) = zero_extend(uimm);
20+
let rd = creg2reg_idx(rdc);
21+
let rs1 = creg2reg_idx(rs1c);
22+
execute(LOAD(imm, rs1, rd, true, BYTE, false, false))
23+
}
24+
25+
/* ****************************************************************** */
26+
27+
union clause ast = C_LHU : (bits(2), cregidx, cregidx)
28+
29+
mapping clause encdec_compressed =
30+
C_LHU(uimm1 @ 0b0, rdc, rs1c) if haveZcb()
31+
<-> 0b100 @ 0b001 @ rs1c : cregidx @ 0b0 @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
32+
33+
mapping clause assembly = C_LHU(uimm, rdc, rs1c) <->
34+
"c.lhu" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
35+
36+
function clause execute C_LHU(uimm, rdc, rs1c) = {
37+
let imm : bits(12) = zero_extend(uimm);
38+
let rd = creg2reg_idx(rdc);
39+
let rs1 = creg2reg_idx(rs1c);
40+
execute(LOAD(imm, rs1, rd, true, HALF, false, false))
41+
}
42+
43+
/* ****************************************************************** */
44+
45+
union clause ast = C_LH : (bits(2), cregidx, cregidx)
46+
47+
mapping clause encdec_compressed =
48+
C_LH(uimm1 @ 0b0, rdc, rs1c) if haveZcb()
49+
<-> 0b100 @ 0b001 @ rs1c : cregidx @ 0b1 @ uimm1 : bits(1) @ rdc : cregidx @ 0b00 if haveZcb()
50+
51+
mapping clause assembly = C_LH(uimm, rdc, rs1c) <->
52+
"c.lh" ^ spc() ^ creg_name(rdc) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
53+
54+
function clause execute C_LH(uimm, rdc, rs1c) = {
55+
let imm : bits(12) = zero_extend(uimm);
56+
let rd = creg2reg_idx(rdc);
57+
let rs1 = creg2reg_idx(rs1c);
58+
execute(LOAD(imm, rs1, rd, false, HALF, false, false))
59+
}
60+
61+
/* ****************************************************************** */
62+
63+
union clause ast = C_SB : (bits(2), cregidx, cregidx)
64+
65+
mapping clause encdec_compressed =
66+
C_SB(uimm1 @ uimm0, rs1c, rs2c) if haveZcb()
67+
<-> 0b100 @ 0b010 @ rs1c : cregidx @ uimm0 : bits(1) @ uimm1 : bits(1) @ rs2c @ 0b00 if haveZcb()
68+
69+
mapping clause assembly = C_SB(uimm, rs1c, rs2c) <->
70+
"c.sb" ^ spc() ^ creg_name(rs2c) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs1c) ^ opt_spc() ^ ")"
71+
72+
function clause execute C_SB(uimm, rs1c, rs2c) = {
73+
let imm : bits(12) = zero_extend(uimm);
74+
let rs1 = creg2reg_idx(rs1c);
75+
let rs2 = creg2reg_idx(rs2c);
76+
execute(STORE(imm, rs2, rs1, BYTE, false, false))
77+
}
78+
79+
/* ****************************************************************** */
80+
81+
union clause ast = C_SH : (bits(2), cregidx, cregidx)
82+
83+
mapping clause encdec_compressed =
84+
C_SH(uimm1 @ 0b0, rs1c, rs2c) if haveZcb()
85+
<-> 0b100 @ 0b011 @ rs1c : cregidx @ 0b0 @ uimm1 : bits(1) @ rs2c : cregidx @ 0b00 if haveZcb()
86+
87+
mapping clause assembly = C_SH(uimm, rs1c, rs2c) <->
88+
"c.sh" ^ spc() ^ creg_name(rs1c) ^ sep() ^ hex_bits_2(uimm) ^ opt_spc() ^ "(" ^ opt_spc() ^ creg_name(rs2c) ^ opt_spc() ^ ")"
89+
90+
function clause execute C_SH(uimm, rs1c, rs2c) = {
91+
let imm : bits(12) = zero_extend(uimm);
92+
let rs1 = creg2reg_idx(rs1c);
93+
let rs2 = creg2reg_idx(rs2c);
94+
execute(STORE(imm, rs2, rs1, HALF, false, false))
95+
}
96+
97+
/* ****************************************************************** */
98+
99+
union clause ast = C_ZEXT_B : (cregidx)
100+
101+
mapping clause encdec_compressed =
102+
C_ZEXT_B(rsdc) if haveZcb()
103+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b000 @ 0b01 if haveZcb()
104+
105+
mapping clause assembly = C_ZEXT_B(rsdc) <->
106+
"c.zext.b" ^ spc() ^ creg_name(rsdc)
107+
108+
function clause execute C_ZEXT_B(rsdc) = {
109+
let rsd = creg2reg_idx(rsdc);
110+
X(rsd) = zero_extend(X(rsd)[7..0]);
111+
RETIRE_SUCCESS
112+
}
113+
114+
/* ****************************************************************** */
115+
116+
union clause ast = C_SEXT_B : (cregidx)
117+
118+
mapping clause encdec_compressed =
119+
C_SEXT_B(rsdc) if haveZcb() & haveZbb()
120+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b001 @ 0b01 if haveZcb() & haveZbb()
121+
122+
mapping clause assembly = C_SEXT_B(rsdc) <->
123+
"c.sext.b" ^ spc() ^ creg_name(rsdc)
124+
125+
function clause execute C_SEXT_B(rsdc) = {
126+
let rsd = creg2reg_idx(rsdc);
127+
execute(ZBB_EXTOP(rsd, rsd, RISCV_SEXTB))
128+
}
129+
130+
/* ****************************************************************** */
131+
132+
union clause ast = C_ZEXT_H : (cregidx)
133+
134+
mapping clause encdec_compressed =
135+
C_ZEXT_H(rsdc) if haveZcb() & haveZbb()
136+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b010 @ 0b01 if haveZcb() & haveZbb()
137+
138+
mapping clause assembly = C_ZEXT_H(rsdc) <->
139+
"c.zext.h" ^ spc() ^ creg_name(rsdc)
140+
141+
function clause execute C_ZEXT_H(rsdc) = {
142+
let rsd = creg2reg_idx(rsdc);
143+
execute(ZBB_EXTOP(rsd, rsd, RISCV_ZEXTH))
144+
}
145+
146+
/* ****************************************************************** */
147+
148+
union clause ast = C_SEXT_H : (cregidx)
149+
150+
mapping clause encdec_compressed =
151+
C_SEXT_H(rsdc) if haveZcb() & haveZbb()
152+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b011 @ 0b01 if haveZcb() & haveZbb()
153+
154+
mapping clause assembly = C_SEXT_H(rsdc) <->
155+
"c.sext.h" ^ spc() ^ creg_name(rsdc)
156+
157+
function clause execute C_SEXT_H(rsdc) = {
158+
let rsd = creg2reg_idx(rsdc);
159+
execute(ZBB_EXTOP(rsd, rsd, RISCV_SEXTH))
160+
}
161+
162+
/* ****************************************************************** */
163+
164+
union clause ast = C_ZEXT_W : (cregidx)
165+
166+
mapping clause encdec_compressed =
167+
C_ZEXT_W(rsdc) if haveZcb() & haveZba() & sizeof(xlen) == 64
168+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b100 @ 0b01 if haveZcb() & haveZba() & sizeof(xlen) == 64
169+
170+
mapping clause assembly = C_ZEXT_W(rsdc) <->
171+
"c.zext.w" ^ spc() ^ creg_name(rsdc)
172+
173+
function clause execute C_ZEXT_W(rsdc) = {
174+
let rsd = creg2reg_idx(rsdc);
175+
execute (ZBA_RTYPEUW(0b00000, rsd, rsd, RISCV_ADDUW)) // Note 0b00000 is the regidx of the zero register
176+
}
177+
178+
/* ****************************************************************** */
179+
180+
union clause ast = C_NOT : (cregidx)
181+
182+
mapping clause encdec_compressed =
183+
C_NOT(rsdc) if haveZcb()
184+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b11 @ 0b101 @ 0b01 if haveZcb()
185+
186+
mapping clause assembly = C_NOT(rsdc) <->
187+
"c.not" ^ spc() ^ creg_name(rsdc)
188+
189+
function clause execute C_NOT(rsdc) = {
190+
let r = creg2reg_idx(rsdc);
191+
X(r) = ~(X(r));
192+
RETIRE_SUCCESS
193+
}
194+
195+
/* ****************************************************************** */
196+
197+
union clause ast = C_MUL : (cregidx, cregidx)
198+
199+
mapping clause encdec_compressed =
200+
C_MUL(rsdc, rs2c) if haveZcb() & (haveMulDiv() | haveZmmul())
201+
<-> 0b100 @ 0b111 @ rsdc : cregidx @ 0b10 @ rs2c : cregidx @ 0b01 if haveZcb() & (haveMulDiv() | haveZmmul())
202+
203+
mapping clause assembly = C_MUL(rsdc, rs2c) <->
204+
"c.mul" ^ spc() ^ creg_name(rsdc) ^ sep() ^ creg_name(rs2c)
205+
206+
function clause execute C_MUL(rsdc, rs2c) = {
207+
let rd = creg2reg_idx(rsdc);
208+
let rs = creg2reg_idx(rs2c);
209+
execute(MUL(rs, rd, rd, false, true, true))
210+
}

‎model/riscv_sys_regs.sail

+5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ val sys_enable_writable_misa = {c: "sys_enable_writable_misa", ocaml: "Platform.
8484
val sys_enable_rvc = {c: "sys_enable_rvc", ocaml: "Platform.enable_rvc", _: "sys_enable_rvc"} : unit -> bool
8585
/* whether misa.{f,d} were enabled at boot */
8686
val sys_enable_fdext = {c: "sys_enable_fdext", ocaml: "Platform.enable_fdext", _: "sys_enable_fdext"} : unit -> bool
87+
/* whether Zcb was enabled at boot */
88+
val sys_enable_zcb = {c: "sys_enable_zcb", ocaml: "Platform.enable_zcb", _: "sys_enable_zcb"} : unit -> bool
8789
/* whether zfinx was enabled at boot */
8890
val sys_enable_zfinx = {c: "sys_enable_zfinx", ocaml: "Platform.enable_zfinx", _: "sys_enable_zfinx"} : unit -> bool
8991
/* whether the N extension was enabled at boot */
@@ -309,6 +311,9 @@ function haveZfh() -> bool = (misa[F] == 0b1) & (mstatus[FS] != 0b00)
309311
/* V extension has to enable both via misa.V as well as mstatus.VS */
310312
function haveVExt() -> bool = (misa[V] == 0b1) & (mstatus[VS] != 0b00)
311313

314+
/* Zcb has simple code-size saving instructions. (The Zcb extension depends on the Zca extension.) */
315+
function haveZcb() -> bool = sys_enable_zcb()
316+
312317
/* Zhinx, Zfinx and Zdinx extensions (TODO: gate FCSR access on [mhs]stateen0 bit 1 when implemented) */
313318
function haveZhinx() -> bool = sys_enable_zfinx()
314319
function haveZfinx() -> bool = sys_enable_zfinx()

‎ocaml_emulator/platform.ml

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let config_enable_writable_misa = ref true
1010
let config_enable_dirty_update = ref false
1111
let config_enable_misaligned_access = ref false
1212
let config_mtval_has_illegal_inst_bits = ref false
13+
let config_enable_zcb = ref false
1314
let config_enable_writable_fiom = ref true
1415
let config_enable_vext = ref true
1516
let config_pmp_count = ref Big_int.zero
@@ -88,6 +89,7 @@ let enable_vext () = !config_enable_vext
8889
let enable_dirty_update () = !config_enable_dirty_update
8990
let enable_misaligned_access () = !config_enable_misaligned_access
9091
let mtval_has_illegal_inst_bits () = !config_mtval_has_illegal_inst_bits
92+
let enable_zcb () = !config_enable_zcb
9193
let enable_zfinx () = false
9294
let enable_writable_fiom () = !config_enable_writable_fiom
9395
let pmp_count () = !config_pmp_count

‎ocaml_emulator/riscv_ocaml_sim.ml

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ let options = Arg.align ([("-dump-dts",
5353
("-mtval-has-illegal-inst-bits",
5454
Arg.Set P.config_mtval_has_illegal_inst_bits,
5555
" mtval stores instruction bits on an illegal instruction exception");
56+
("-enable-zcb",
57+
Arg.Set P.config_enable_zcb,
58+
" enable Zcb (simple code size) extension");
5659
("-enable-writable-fiom",
5760
Arg.Set P.config_enable_writable_fiom,
5861
" enable FIOM (Fence of I/O implies Memory) bit in menvcfg");

0 commit comments

Comments
 (0)
Please sign in to comment.