diff --git a/Makefile.old b/Makefile.old index 6c538e359..fbcb1222a 100644 --- a/Makefile.old +++ b/Makefile.old @@ -40,6 +40,7 @@ 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_zcmp.sail SAIL_DEFAULT_INST += riscv_insts_zfh.sail # Zfa needs to be added after fext, dext and Zfh (as it needs diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.c index e19008c51..5b5a8f893 100644 --- a/c_emulator/riscv_platform.c +++ b/c_emulator/riscv_platform.c @@ -37,6 +37,16 @@ bool sys_enable_zcb(unit u) return rv_enable_zcb; } +bool sys_enable_zcd(unit u) +{ + return rv_enable_zcd; +} + +bool sys_enable_zcmp(unit u) +{ + return rv_enable_zcmp; +} + 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 8d8d8aaef..cf452c50f 100644 --- a/c_emulator/riscv_platform.h +++ b/c_emulator/riscv_platform.h @@ -5,6 +5,8 @@ bool sys_enable_rvc(unit); bool sys_enable_fdext(unit); bool sys_enable_svinval(unit); bool sys_enable_zcb(unit); +bool sys_enable_zcd(unit); +bool sys_enable_zcmp(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 fd7cbdc2c..2ed103c6c 100644 --- a/c_emulator/riscv_platform_impl.c +++ b/c_emulator/riscv_platform_impl.c @@ -11,6 +11,8 @@ uint64_t rv_vector_elen_exp = 0x6; bool rv_enable_svinval = false; bool rv_enable_zcb = false; +bool rv_enable_zcd = true; +bool rv_enable_zcmp = false; bool rv_enable_zfinx = false; bool rv_enable_rvc = true; bool rv_enable_writable_misa = true; diff --git a/c_emulator/riscv_platform_impl.h b/c_emulator/riscv_platform_impl.h index dc472623a..f52f1d086 100644 --- a/c_emulator/riscv_platform_impl.h +++ b/c_emulator/riscv_platform_impl.h @@ -16,6 +16,8 @@ extern uint64_t rv_vector_elen_exp; extern bool rv_enable_svinval; extern bool rv_enable_zcb; +extern bool rv_enable_zcd; +extern bool rv_enable_zcmp; extern bool rv_enable_zfinx; extern bool rv_enable_rvc; extern bool rv_enable_fdext; diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c index 2d788867a..238afb1c2 100644 --- a/c_emulator/riscv_sim.c +++ b/c_emulator/riscv_sim.c @@ -50,6 +50,8 @@ enum { OPT_PMP_GRAIN, OPT_ENABLE_SVINVAL, OPT_ENABLE_ZCB, + OPT_ENABLE_ZCD, + OPT_ENABLE_ZCMP, OPT_ENABLE_ZICBOM, OPT_ENABLE_ZICBOZ, OPT_ENABLE_SSTC, @@ -148,6 +150,7 @@ static struct option options[] = { {"enable-writable-fiom", no_argument, 0, OPT_ENABLE_WRITABLE_FIOM}, {"enable-svinval", no_argument, 0, OPT_ENABLE_SVINVAL }, {"enable-zcb", no_argument, 0, OPT_ENABLE_ZCB }, + {"enable-zcmp", no_argument, 0, OPT_ENABLE_ZCMP }, {"enable-zicbom", no_argument, 0, OPT_ENABLE_ZICBOM }, {"enable-zicboz", no_argument, 0, OPT_ENABLE_ZICBOZ }, {"cache-block-size", required_argument, 0, OPT_CACHE_BLOCK_SIZE }, @@ -388,6 +391,16 @@ static int process_args(int argc, char **argv) fprintf(stderr, "enabling Zcb extension.\n"); rv_enable_zcb = true; break; + case OPT_ENABLE_ZCD: + fprintf(stderr, "enabling Zcd extension.\n"); + rv_enable_zcd = true; + rv_enable_zcmp = false; + break; + case OPT_ENABLE_ZCMP: + fprintf(stderr, "enabling Zcmp extension.\n"); + rv_enable_zcd = false; + rv_enable_zcmp = true; + break; case OPT_ENABLE_ZICBOM: fprintf(stderr, "enabling Zicbom extension.\n"); rv_enable_zicbom = true; diff --git a/model/CMakeLists.txt b/model/CMakeLists.txt index 15842b420..17f0fe16a 100644 --- a/model/CMakeLists.txt +++ b/model/CMakeLists.txt @@ -66,6 +66,7 @@ foreach (xlen IN ITEMS 32 64) "riscv_insts_zbc.sail" "riscv_insts_zbs.sail" "riscv_insts_zcb.sail" + "riscv_insts_zcmp.sail" "riscv_insts_zfh.sail" # Zfa needs to be added after fext, dext and Zfh (as it needs # definitions from those) diff --git a/model/riscv_extensions.sail b/model/riscv_extensions.sail index 8b5bf2bd8..d9a443fe6 100644 --- a/model/riscv_extensions.sail +++ b/model/riscv_extensions.sail @@ -71,6 +71,8 @@ enum clause extension = Ext_Zcb enum clause extension = Ext_Zcd // Code Size Reduction: compressed single precision floating point loads and stores enum clause extension = Ext_Zcf +// Code Size Reduction: compressed push/pop and double move instructions +enum clause extension = Ext_Zcmp // Bit Manipulation: Address generation enum clause extension = Ext_Zba diff --git a/model/riscv_insts_zcd.sail b/model/riscv_insts_zcd.sail index cbe8f449c..a88fb01f0 100644 --- a/model/riscv_insts_zcd.sail +++ b/model/riscv_insts_zcd.sail @@ -6,7 +6,7 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /*=======================================================================================*/ -function clause extensionEnabled(Ext_Zcd) = extensionEnabled(Ext_Zca) & extensionEnabled(Ext_D) & (xlen == 32 | xlen == 64) +function clause extensionEnabled(Ext_Zcd) = extensionEnabled(Ext_Zca) & extensionEnabled(Ext_D) & sys_enable_zcd() & not(sys_enable_zcmp()) & (xlen == 32 | xlen == 64) union clause ast = C_FLDSP : (bits(6), regidx) diff --git a/model/riscv_insts_zcmp.sail b/model/riscv_insts_zcmp.sail new file mode 100644 index 000000000..03ac49c1f --- /dev/null +++ b/model/riscv_insts_zcmp.sail @@ -0,0 +1,381 @@ +/*=======================================================================================*/ +/* 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 */ +/*=======================================================================================*/ + + +function clause extensionEnabled(Ext_Zcmp) = extensionEnabled(Ext_Zca) & sys_enable_zcmp() & not(sys_enable_zcd()) & (xlen == 32 | xlen == 64) + +function str_dec(str: string) -> int = { + let base : int = 10; + var result : int = 0; + var sign : int = 1; + var num_str : string = str; + + // Handle negative sign + if string_take(num_str, 1) == "-" then { + sign = -1; + num_str = string_drop(num_str, 1); + }; + + // Iterate over each character + foreach (i from 1 to string_length(num_str)) { + let digit : int = match string_take(num_str, 1) { + "0" => 0, + "1" => 1, + "2" => 2, + "3" => 3, + "4" => 4, + "5" => 5, + "6" => 6, + "7" => 7, + "8" => 8, + "9" => 9, + _ => internal_error(__FILE__, __LINE__, "Expected numerical value: " ^ str) + }; + num_str = string_drop(num_str, 1); + result = result * base + digit; + }; + sign * result +} + +mapping zcmp_assembly_rlist : bits(4) <-> string = { + 0x4 <-> "ra", + 0x5 <-> "ra" ^ sep() ^ "s0", + 0x6 <-> "ra" ^ sep() ^ "s0-s1", + 0x7 <-> "ra" ^ sep() ^ "s0-s2", + 0x8 <-> "ra" ^ sep() ^ "s0-s3", + 0x9 <-> "ra" ^ sep() ^ "s0-s4", + 0xa <-> "ra" ^ sep() ^ "s0-s5", + 0xb <-> "ra" ^ sep() ^ "s0-s6", + 0xc <-> "ra" ^ sep() ^ "s0-s7", + 0xd <-> "ra" ^ sep() ^ "s0-s8", + 0xe <-> "ra" ^ sep() ^ "s0-s9", + // To include s10, s11 must also be included. + 0xf <-> "ra" ^ sep() ^ "s0-s11", + + // Using X names instead of ABI names. + 0x4 <-> "x1", + 0x5 <-> "x1" ^ sep() ^ "x8", + 0x6 <-> "x1" ^ sep() ^ "x8-x9", + 0x7 <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18", + 0x8 <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x19", + 0x9 <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x20", + 0xa <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x21", + 0xb <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x22", + 0xc <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x23", + 0xd <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x24", + 0xe <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x25", + 0xf <-> "x1" ^ sep() ^ "x8-x9" ^ sep() ^ "x18-x27", +} + +mapping negative_sign : bool <-> string = { + false <-> "", + true <-> "-", +} + +function get_stack_adj_base(rlist : bits(4)) -> int = { + if(xlen == 32) then + match rlist[3 .. 2] { + 0b01 => 16, + 0b10 => 32, + 0b11 => if rlist == 0b1111 then 64 else 48, + _ => 0 + } + else { + match rlist[3 .. 1] { + 0b010 => 16, + 0b011 => 32, + 0b100 => 48, + 0b101 => 64, + 0b110 => 80, + 0b111 => if rlist == 0b1111 then 112 else 96, + _ => 0 + } + } +} + +mapping zcmp_assembly_mapping : (bits(4), bits(2), bool) <-> string = { + forwards (rlist, spimm54, is_negative) => { + var stack_adj : int = undefined; + let stack_adj_base = get_stack_adj_base(rlist); + stack_adj = stack_adj_base + unsigned(spimm54) * 16; + + if stack_adj_base == 0 then { + "unsupport rlist" ^ sep() ^ negative_sign(is_negative) ^ dec_str(stack_adj) + } else { + "{" ^ zcmp_assembly_rlist(rlist) ^ "}" ^ sep() ^ negative_sign(is_negative) ^ dec_str(stack_adj) + } + }, + backwards str_input => { + var str = str_input; + var rlist : bits(4) = undefined; + var spimm54 : bits(2) = undefined; + var is_negative : bool = false; + + if string_take(str, 7) == "cm.push" then { + is_negative = true; + str = string_drop(str, 9); + } else if string_take(str, 6) == "cm.pop" then { + is_negative = false; + str = string_drop(str, 8); + } else if string_take(str, 9) == "cm.popret" then { + is_negative = false; + str = string_drop(str, 11); + } else { + is_negative = false; + str = string_drop(str, 12); + }; + + if string_take(str, 3) == "ra," then { + if string_take(str, 5) == "ra, s0" then { + rlist = zcmp_assembly_rlist(string_take(str, 5)); + str = string_drop(str, 9); + } else { + if string_take(str, 10) == "ra, s0-s11" then { + rlist = zcmp_assembly_rlist(string_take(str, 10)); + str = string_drop(str, 13); + } else { + rlist = zcmp_assembly_rlist(string_take(str, 9)); + str = string_drop(str, 12); + } + } + } else { + rlist = zcmp_assembly_rlist(string_take(str, 2)); + str = string_drop(str, 5); + }; + + if string_take(str, 1) == "-" then { + str = string_drop(str, 1); + }; + + let stack_adj_offset : int = str_dec(str); + + spimm54 = to_bits(2, (stack_adj_offset - get_stack_adj_base(rlist)) / 16); + + (rlist, spimm54, is_negative) + }, +} + +function zcmp_regmask(rlist : bits(4)) -> bits(32) = { + var mask : bits(32) = zeros(); + + if rlist >=_u 0b0100 then { + mask[1] = bitone + }; + + foreach (i from 5 to unsigned(rlist)) { + assert(i <= 15); + if( (i - 5) < 2 ) then + mask[3 + i] = bitone + else { + mask[11 + i] = bitone + }; + }; + + if(rlist == zero_extend(0xf)) then + mask[27] = bitone; + + mask +} + +/* ****************************************************************** */ +union clause ast = CM_PUSH : (bits(4), bits(2)) + +mapping clause encdec_compressed = CM_PUSH(rlist, spimm) if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b11000 @ rlist : bits(4) @ spimm : bits(2) @ 0b10 if extensionEnabled(Ext_Zcmp) + +function process_cmpush (rlist : bits(4), spimm : bits(2)) -> Retired = { + let addr = X(sp); + let stack_adj = negate_int(get_stack_adj_base(rlist) + unsigned(spimm) * 16); + let new_sp = addr + to_bits(xlen, stack_adj); + let mask = zcmp_regmask(rlist); + + var offset : int = xlen_bytes; + + foreach (i from 31 downto 1) { + if mask[i] == bitone then { + match ext_data_get_addr(sp, to_bits(xlen, negate_int(offset)), Write(Data), xlen_bytes) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, size_bytes(xlen_bytes)) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }, + TR_Address(paddr, _) => { + let eares = mem_write_ea(paddr, xlen_bytes, false, false, false); + match (eares) { + Err(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }, + Ok(_) => { + let reg_val = X(to_bits(5, i)); + match mem_write_value(paddr, xlen_bytes, reg_val, false, false, false) { + Ok(true) => { offset = offset + xlen_bytes }, + Ok(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), + Err(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL } + } + } + } + } + } + } + } + }; + X(sp) = new_sp; + RETIRE_SUCCESS +} + +function clause execute (CM_PUSH(rlist, spimm)) = { + assert(rlist >=_u 0b0100); + + process_cmpush(rlist, spimm) +} + +mapping clause assembly = CM_PUSH(rlist, spimm) if (xlen == 32 | xlen == 64) <-> + "cm.push" ^ spc() ^ zcmp_assembly_mapping(rlist, spimm, false) if (xlen == 32 | xlen == 64) +/* ****************************************************************** */ +union clause ast = CM_POP : (bits(4), bits(2)) + +mapping clause encdec_compressed = CM_POP(rlist, spimm) if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b11010 @ rlist : bits(4) @ spimm : bits(2) @ 0b10 if extensionEnabled(Ext_Zcmp) + +function process_cmpop (rlist : bits(4), spimm : bits(2), write_pc : bool, write_a0 : bool) -> Retired = { + let addr = X(sp); + let stack_adj = get_stack_adj_base(rlist) + unsigned(spimm) * 16; + let new_sp = addr + to_bits(xlen, stack_adj); + let mask = zcmp_regmask(rlist); + + X(sp) = new_sp; + + var offset : int = xlen_bytes; + + foreach (i from 31 downto 1) { + if mask[i] == bitone then { + match ext_data_get_addr(sp, to_bits(xlen, negate_int(offset)), Write(Data), xlen_bytes) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, size_bytes(xlen_bytes)) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }, + TR_Address(paddr, _) => { + match mem_read(Read(Data), paddr, xlen_bytes, false, false, false) { + Ok(v) => { + X(to_bits(5, i)) = extend_value(true, v); + offset = offset + xlen_bytes + }, + Err(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL } + } + } + } + } + } + }; + + // cm.popret or cm.popretz write pc with ra. + if write_pc then { + set_next_pc(X(0b00001)); + }; + + // cm.popretz write a0 with zero. + if write_a0 then { + X(0b01010) = zeros(); + }; + + RETIRE_SUCCESS +} + +function clause execute (CM_POP(rlist, spimm)) = { + assert(rlist >=_u 0b0100); + + process_cmpop(rlist, spimm, false, false) +} + +mapping clause assembly = CM_POP(rlist, spimm) if (xlen == 32 | xlen == 64) <-> + "cm.pop" ^ spc() ^ zcmp_assembly_mapping(rlist, spimm, true) if (xlen == 32 | xlen == 64) + +/* ****************************************************************** */ +union clause ast = CM_POPRET : (bits(4), bits(2)) + +mapping clause encdec_compressed = CM_POPRET(rlist, spimm) if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b11110 @ rlist : bits(4) @ spimm : bits(2) @ 0b10 if extensionEnabled(Ext_Zcmp) + +function clause execute (CM_POPRET(rlist, spimm)) = { + assert(rlist >=_u 0b0100); + + process_cmpop(rlist, spimm, true, false) +} + +mapping clause assembly = CM_POPRET(rlist, spimm) if (xlen == 32 | xlen == 64) <-> + "cm.popret" ^ spc() ^ zcmp_assembly_mapping(rlist, spimm, true) if (xlen == 32 | xlen == 64) +/* ****************************************************************** */ +union clause ast = CM_POPRETZ : (bits(4), bits(2)) + +mapping clause encdec_compressed = CM_POPRETZ(rlist, spimm) if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b11100 @ rlist : bits(4) @ spimm : bits(2) @ 0b10 if extensionEnabled(Ext_Zcmp) + +function clause execute (CM_POPRETZ(rlist, spimm)) = { + assert(rlist >=_u 0b0100); + + process_cmpop(rlist, spimm, true, true) +} + +mapping clause assembly = CM_POPRETZ(rlist, spimm) if (xlen == 32 | xlen == 64) <-> + "cm.popretz" ^ spc() ^ zcmp_assembly_mapping(rlist, spimm, true) if (xlen == 32 | xlen == 64) +/* ****************************************************************** */ +union clause ast = CM_MVA01S : (cregidx, cregidx) + +// Differ from creg_name. +mapping rns_name : cregidx <-> string = { + 0b000 <-> "s0", + 0b001 <-> "s1", + 0b010 <-> "s2", + 0b011 <-> "s3", + 0b100 <-> "s4", + 0b101 <-> "s5", + 0b110 <-> "s6", + 0b111 <-> "s7", +} + +mapping rns_to_regidx : cregidx <-> regidx = { + 0b000 <-> 0b01000, + 0b001 <-> 0b01001, + 0b010 <-> 0b10010, + 0b011 <-> 0b10011, + 0b100 <-> 0b10100, + 0b101 <-> 0b10101, + 0b110 <-> 0b10110, + 0b111 <-> 0b10111, +} + +mapping clause encdec_compressed = CM_MVA01S(r1s', r2s') if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b011 @ r1s' : cregidx @ 0b11 @ r2s' : cregidx @ 0b10 if extensionEnabled(Ext_Zcmp) + +function clause execute (CM_MVA01S(r1s', r2s')) = { + X(10) = X(rns_to_regidx(r1s')); + X(11) = X(rns_to_regidx(r2s')); + + RETIRE_SUCCESS +} + +mapping clause assembly = CM_MVA01S(r1s', r2s') if (xlen == 32 | xlen == 64) <-> + "cm.mva01s" ^ spc() ^ rns_name(r1s') ^ sep() ^ rns_name(r2s') if (xlen == 32 | xlen == 64) +/* ****************************************************************** */ +union clause ast = CM_MVSA01 : (cregidx, cregidx) + +mapping clause encdec_compressed = CM_MVSA01(r1s', r2s') if extensionEnabled(Ext_Zcmp) + <-> 0b101 @ 0b011 @ r1s' : cregidx @ 0b01 @ r2s' : cregidx @ 0b10 if extensionEnabled(Ext_Zcmp) + +function clause execute (CM_MVSA01(r1s', r2s')) = { + assert(r1s' != r2s'); + + X(rns_to_regidx(r1s')) = X(10); + X(rns_to_regidx(r2s')) = X(11); + + RETIRE_SUCCESS +} + +mapping clause assembly = CM_MVSA01(r1s', r2s') if (xlen == 32 | xlen == 64) <-> + "cm.mvsa01" ^ spc() ^ rns_name(r1s') ^ sep() ^ rns_name(r2s') if (xlen == 32 | xlen == 64) diff --git a/model/riscv_sys_regs.sail b/model/riscv_sys_regs.sail index 66289e4d3..ce6b2221e 100644 --- a/model/riscv_sys_regs.sail +++ b/model/riscv_sys_regs.sail @@ -92,6 +92,10 @@ val sys_enable_fdext = pure "sys_enable_fdext" : unit -> bool val sys_enable_svinval = pure "sys_enable_svinval" : unit -> bool /* whether Zcb was enabled at boot */ val sys_enable_zcb = pure "sys_enable_zcb" : unit -> bool +/* whether Zcd was enabled at boot */ +val sys_enable_zcd = pure "sys_enable_zcd" : unit -> bool +/* whether Zcmp was enabled at boot */ +val sys_enable_zcmp = pure "sys_enable_zcmp" : unit -> bool /* whether zfinx was enabled at boot */ val sys_enable_zfinx = pure "sys_enable_zfinx" : unit -> bool /* Whether FIOM bit of menvcfg/senvcfg is enabled. It must be enabled if diff --git a/model/riscv_termination.sail b/model/riscv_termination.sail index 6ea3a0acb..0e3de464f 100644 --- a/model/riscv_termination.sail +++ b/model/riscv_termination.sail @@ -56,6 +56,7 @@ function extensionEnabled_measure(ext : extension) -> int = Ext_Zcb => 2, // Ext_Zca Ext_Zcd => 2, // Ext_Zca, (Ext_D) Ext_Zcf => 2, // Ext_Zca, (Ext_F) + Ext_Zcmp => 2, // Ext_Zca _ => 0 } termination_measure extensionEnabled(ext) = extensionEnabled_measure(ext)