diff --git a/arch/ext/Zcb.yaml b/arch/ext/Zcb.yaml new file mode 100644 index 0000000000..53fb28e66f --- /dev/null +++ b/arch/ext/Zcb.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zcb +long_name: Simple code-size saving instructions +description: | + Zcb has simple code-size saving instructions which are easy to implement on all CPUs. + All proposed encodings are currently reserved for all architectures, and have no conflicts with any existing extensions. + + The Zcb extension depends on the Zca extension. + + As shown on the individual instruction pages, many of the instructions in Zcb depend upon another extension being implemented. + For example, c.mul is only implemented if M or Zmmul is implemented, and c.sext.b is only implemented if Zbb is implemented. + +type: unprivileged +company: + name: RISC-V International + url: https://riscv.org +versions: +- version: "1.0.0" + state: ratified + ratification_date: 2023-04 + repositories: + - url: https://github.com/riscv/riscv-code-size-reduction + branch: main + contributors: + - name: Tariq Kurd + - name: Ibrahim Abu Kharmeh + - name: Torbjørn Viem Ness + - name: Matteo Perotti + - name: Nidal Faour + - name: Bill Traynor + - name: Rafael Sene + - name: Xinlong Wu + - name: sinan + - name: Jeremy Bennett + - name: Heda Chen + - name: Alasdair Armstrong + - name: Graeme Smecher + - name: Nicolas Brunie + - name: Jiawei diff --git a/arch/inst/Zcb/c.lbu.yaml b/arch/inst/Zcb/c.lbu.yaml new file mode 100644 index 0000000000..b521eb8868 --- /dev/null +++ b/arch/inst/Zcb/c.lbu.yaml @@ -0,0 +1,65 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.lbu +long_name: Load unsigned byte, 16-bit encoding +description: | + Loads a 8-bit value from memory into register rd. + It computes an effective address by adding the zero-extended offset, to the base address in register rs1. + It expands to `lbu` `rd, offset(rs1)`. +definedBy: + anyOf: + - Zcb + - Zce +assembly: xd, imm(xs1) +encoding: + match: 100000--------00 + variables: + - name: imm + location: 5|6 + - name: rd + location: 4-2 + - name: rs1 + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg virtual_address = X[rs1+8] + imm; + + X[rd+8] = zext(read_memory<8>(virtual_address, $encoding), 8); + +sail(): | + { + let offset : xlenbits = zero_extend(imm); + /* Get the address, X(rs1c) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1c, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } diff --git a/arch/inst/Zcb/c.lh.yaml b/arch/inst/Zcb/c.lh.yaml new file mode 100644 index 0000000000..938bf6936a --- /dev/null +++ b/arch/inst/Zcb/c.lh.yaml @@ -0,0 +1,66 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.lh +long_name: Load signed halfword, 16-bit encoding +description: | + Loads a 16-bit value from memory into register rd. + It computes an effective address by adding the zero-extended offset, to the base address in register rs1. + It expands to `lh` `rd, offset(rs1)`. +definedBy: + anyOf: + - Zcb + - Zce +assembly: xd, imm(xs1) +encoding: + match: 100001---1----00 + variables: + - name: imm + location: 5 + left_shift: 1 + - name: rd + location: 4-2 + - name: rs1 + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg virtual_address = X[rs1+8] + imm; + + X[rd+8] = sext(read_memory<16>(virtual_address, $encoding), 16); + +sail(): | + { + let offset : xlenbits = zero_extend(imm); + /* Get the address, X(rs1c) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1c, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } diff --git a/arch/inst/Zcb/c.lhu.yaml b/arch/inst/Zcb/c.lhu.yaml new file mode 100644 index 0000000000..e4567e26e5 --- /dev/null +++ b/arch/inst/Zcb/c.lhu.yaml @@ -0,0 +1,66 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.lhu +long_name: Load unsigned halfword, 16-bit encoding +description: | + Loads a 16-bit value from memory into register rd. + It computes an effective address by adding the zero-extended offset, to the base address in register rs1. + It expands to `lhu` `rd, offset(rs1)`. +definedBy: + anyOf: + - Zcb + - Zce +assembly: xd, imm(xs1) +encoding: + match: 100001---0----00 + variables: + - name: imm + location: 5 + left_shift: 1 + - name: rd + location: 4-2 + - name: rs1 + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg virtual_address = X[rs1+8] + imm; + + X[rd+8] = zext(read_memory<16>(virtual_address, $encoding), 16); + +sail(): | + { + let offset : xlenbits = zero_extend(imm); + /* Get the address, X(rs1c) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1c, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rdc, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } diff --git a/arch/inst/Zcb/c.mul.yaml b/arch/inst/Zcb/c.mul.yaml new file mode 100644 index 0000000000..60f22a711b --- /dev/null +++ b/arch/inst/Zcb/c.mul.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.mul +long_name: Multiply, 16-bit encoding +description: | + This instruction multiplies XLEN bits of the source operands from rsd' and rs2' and writes the lowest XLEN bits of the result to rsd'. + +definedBy: + allOf: + - Zcb + - Zmmul +assembly: xd, xs2 +encoding: + match: 100111---10---01 + variables: + - name: rd + location: 9-7 + - name: rs2 + location: 4-2 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::M) && (CSR[misa].M == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = X[rd+8] * X[rs2+8]; + +sail(): | + { + let result_wide = to_bits(2 * sizeof(xlen), signed(X(rsdc)) * signed(X(rs2c))); + X(rsdc) = result_wide[(sizeof(xlen) - 1) .. 0]; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.not.yaml b/arch/inst/Zcb/c.not.yaml new file mode 100644 index 0000000000..2b1ac36514 --- /dev/null +++ b/arch/inst/Zcb/c.not.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.not +long_name: Bitwise not, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. + +definedBy: + anyOf: + - Zcb + - Zce +assembly: xd +encoding: + match: 100111---1110101 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = ~X[rd+8]; + +sail(): | + { + X(rsdc) = X(rsdc) XOR -1; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.sb.yaml b/arch/inst/Zcb/c.sb.yaml new file mode 100644 index 0000000000..95512638b2 --- /dev/null +++ b/arch/inst/Zcb/c.sb.yaml @@ -0,0 +1,37 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.sb +long_name: Store unsigned byte, 16-bit encoding +description: | + Stores a 8-bit value from register rs2 into memory. + It computes an effective address by adding the zero-extended offset, to the base address in register rs1. + It expands to `sb` `rs2, offset(rs1)`. +definedBy: + anyOf: + - Zcb + - Zce +assembly: xs2, imm(xs1) +encoding: + match: 100010--------00 + variables: + - name: imm + location: 5|6 + - name: rs2 + location: 4-2 + - name: rs1 + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg virtual_address = X[rs1+8] + imm; + + write_memory<8>(virtual_address, X[rs2+8][7:0], $encoding); diff --git a/arch/inst/Zcb/c.sext.b.yaml b/arch/inst/Zcb/c.sext.b.yaml new file mode 100644 index 0000000000..f7d368af76 --- /dev/null +++ b/arch/inst/Zcb/c.sext.b.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.sext.b +long_name: Sign-extend byte, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + This instruction sign-extends the least-significant byte of the source to XLEN by copying + the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. + +definedBy: + allOf: + - Zcb + - Zbb +assembly: xd +encoding: + match: 100111---1100101 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = sext(X[rd+8][15:0],8); + +sail(): | + { + let rs1_val = X(rsdc); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTB => zero_extend(rs1_val[7..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]), + RISCV_ZEXTW => zero_extend(rs1_val[31..0]) + }; + X(rsdc) = result; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.sext.h.yaml b/arch/inst/Zcb/c.sext.h.yaml new file mode 100644 index 0000000000..23e181f5f8 --- /dev/null +++ b/arch/inst/Zcb/c.sext.h.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.sext.h +long_name: Sign-extend halfword, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + This instruction sign-extends the least-significant halfword of the source to XLEN by copying + the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. + +definedBy: + allOf: + - Zcb + - Zbb +assembly: xd +encoding: + match: 100111---1101101 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = sext(X[rd+8][15:0],16); + +sail(): | + { + let rs1_val = X(rsdc); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTB => zero_extend(rs1_val[7..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]), + RISCV_ZEXTW => zero_extend(rs1_val[31..0]) + }; + X(rsdc) = result; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.sh.yaml b/arch/inst/Zcb/c.sh.yaml new file mode 100644 index 0000000000..eeb0d9511b --- /dev/null +++ b/arch/inst/Zcb/c.sh.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.sh +long_name: Store unsigned halfword, 16-bit encoding +description: | + Stores a 16-bit value from register rs2 into memory. + It computes an effective address by adding the zero-extended offset, to the base address in register rs1. + It expands to `sh` `rs2, offset(rs1)`. +definedBy: + anyOf: + - Zcb + - Zce +assembly: xs2, imm(xs1) +encoding: + match: 100011---0----00 + variables: + - name: imm + location: 5 + left_shift: 1 + - name: rs2 + location: 4-2 + - name: rs1 + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg virtual_address = X[rs1+8] + imm; + + write_memory<16>(virtual_address, X[rs2+8][15:0], $encoding); diff --git a/arch/inst/Zcb/c.zext.b.yaml b/arch/inst/Zcb/c.zext.b.yaml new file mode 100644 index 0000000000..a59b37ac64 --- /dev/null +++ b/arch/inst/Zcb/c.zext.b.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.zext.b +long_name: Zero-extend byte, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + This instruction zero-extends the least-significant byte of the source to XLEN by inserting + 0's into all of the bits more significant than 7. + +definedBy: + allOf: + - Zcb + - Zbb +assembly: xd +encoding: + match: 100111---1100001 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = X[rd+8][7:0]; + +sail(): | + { + let rs1_val = X(rsdc); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTB => zero_extend(rs1_val[7..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]), + RISCV_ZEXTW => zero_extend(rs1_val[31..0]) + }; + X(rsdc) = result; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.zext.h.yaml b/arch/inst/Zcb/c.zext.h.yaml new file mode 100644 index 0000000000..2be0b9bf34 --- /dev/null +++ b/arch/inst/Zcb/c.zext.h.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.zext.h +long_name: Zero-extend halfword, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + This instruction zero-extends the least-significant halfword of the source to XLEN by inserting + 0's into all of the bits more significant than 15. + +definedBy: + allOf: + - Zcb + - Zbb +assembly: xd +encoding: + match: 100111---1101001 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = X[rd+8][15:0]; + +sail(): | + { + let rs1_val = X(rsdc); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTB => zero_extend(rs1_val[7..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]), + RISCV_ZEXTW => zero_extend(rs1_val[31..0]) + }; + X(rsdc) = result; + RETIRE_SUCCESS + } + + + + diff --git a/arch/inst/Zcb/c.zext.w.yaml b/arch/inst/Zcb/c.zext.w.yaml new file mode 100644 index 0000000000..fc892c6bf2 --- /dev/null +++ b/arch/inst/Zcb/c.zext.w.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.zext.w +long_name: Zero-extend word, 16-bit encoding +description: | + This instruction takes a single source/destination operand. + It zero-extends the least-significant word of the operand to XLEN bits by inserting zeros into all of the bits more significant than 31. + +definedBy: + allOf: + - Zcb + - Zbb +assembly: xd +base: 64 +encoding: + match: 100111---1110001 + variables: + - name: rd + location: 9-7 +access: + s: always + u: always + vs: always + vu: always +operation(): | + + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise (ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + X[rd+8] = X[rd+8][31:0]; + +sail(): | + { + let rs1_val = X(rsdc); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTB => zero_extend(rs1_val[7..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]), + RISCV_ZEXTW => zero_extend(rs1_val[31..0]) + }; + X(rsdc) = result; + RETIRE_SUCCESS + } + + + +