diff --git a/arch/ext/Zclsd.yaml b/arch/ext/Zclsd.yaml new file mode 100644 index 000000000..ee17c5647 --- /dev/null +++ b/arch/ext/Zclsd.yaml @@ -0,0 +1,16 @@ +$schema: "ext_schema.json#" +kind: extension +name: Zclsd +conflicts: Zcf +long_name: Compressed Load/Store Pair for RV32 +description: | + This extension adds load and store instructions using register pairs. It does so by reusing existing instruction encodings which are RV64-only. The specification defines 16-bit encodings. + Load and store instructions will use the same definition of even-odd pairs as defined by the Zdinx extension. + The extension improves static code density, by replacing two separate load or store instructions with a single one. In addition, it can provide a performance improvement for implementations that can make use of a wider than XLEN memory interface. +type: unprivileged +versions: + - version: "1.0" + state: ratified + ratification_date: "2025-02" + requires: + allOf: [ Zilsd, Zca ] diff --git a/arch/inst/C/c.ld.yaml b/arch/inst/C/c.ld.yaml index 911001a23..05afd4c01 100644 --- a/arch/inst/C/c.ld.yaml +++ b/arch/inst/C/c.ld.yaml @@ -5,26 +5,39 @@ kind: instruction name: c.ld long_name: Load double description: | - Loads a 64-bit value from memory into register rd. + Loads a 64-bit value from memory into register xd. It computes an effective address by adding the zero-extended offset, scaled by 8, - to the base address in register rs1. - It expands to `ld` `rd, offset(rs1)`. + to the base address in register xs1. + It expands to `ld` `xd, offset(xs1)`. + For RV32, if the Zclsd extension is enabled, this instruction loads a 64-bit value into registers xd and xd+1. It computes an effective address by adding the zero-extended imm, scaled by 8, to the base address in register xs1. definedBy: anyOf: - C - Zca -base: 64 + - Zclsd assembly: xd, imm(xs1) encoding: - match: 011-----------00 - variables: - - name: imm - location: 6-5|12-10 - left_shift: 3 - - name: rd - location: 4-2 - - name: rs1 - location: 9-7 + RV32: + match: 011-----------00 + variables: + - name: imm + location: 6-5|12-10 + left_shift: 3 + - name: xd + location: 4-2 + not: [1, 3, 5, 7] + - name: xs1 + location: 9-7 + RV64: + match: 011-----------00 + variables: + - name: imm + location: 6-5|12-10 + left_shift: 3 + - name: xd + location: 4-2 + - name: xs1 + location: 9-7 access: s: always u: always @@ -35,9 +48,18 @@ operation(): | raise(ExceptionCode::IllegalInstruction, mode(), $encoding); } - XReg virtual_address = X[creg2reg(rs1)] + imm; - - X[creg2reg(rd)] = sext(read_memory<64>(virtual_address, $encoding), 64); + if (xlen() == 32) { + if (implemented?(ExtensionName::Zclsd)) { + Bits<64> val = read_memory<64>(X[creg2reg(xs1)] + imm, $encoding); + X[creg2reg(xd)] = val[31:0]; + X[creg2reg(xd + 1)] = val[63:32]; + } else { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else { + XReg virtual_address = X[creg2reg(xs1)] + imm; + X[creg2reg(xd)] = sext(read_memory<64>(virtual_address, $encoding), 64); + } # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model @@ -45,9 +67,9 @@ operation(): | sail(): | { let offset : xlenbits = sign_extend(imm); - /* Get the address, X(rs1) + offset. + /* Get the address, X(xs1) + offset. Some extensions perform additional checks on address validity. */ - match ext_data_get_addr(rs1, offset, Read(Data), width) { + match ext_data_get_addr(xs1, 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) @@ -57,13 +79,13 @@ sail(): | TR_Address(paddr, _) => match (width) { BYTE => - process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + process_load(xd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), HALF => - process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), - WORD => - process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + process_load(xd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WOxd => + process_load(xd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), DOUBLE if sizeof(xlen) >= 64 => - process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + process_load(xd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), _ => report_invalid_width(__FILE__, __LINE__, width, "load") } } diff --git a/arch/inst/C/c.ldsp.yaml b/arch/inst/C/c.ldsp.yaml index 50786f1d7..3ad003eb4 100644 --- a/arch/inst/C/c.ldsp.yaml +++ b/arch/inst/C/c.ldsp.yaml @@ -9,23 +9,31 @@ description: | into register rd. It computes its effective address by adding the zero-extended offset, scaled by 8, to the stack pointer, x2. - It expands to `ld` `rd, offset(x2)`. - C.LDSP is only valid when rd ≠ x0 the code points with rd=x0 are reserved. + It expands to `ld rd, offset(x2)`. + C.LDSP is only valid when rd ≠ x0; code points with rd=x0 are reserved. definedBy: anyOf: - C - Zca -base: 64 -assembly: xd, imm(sp) +assembly: rd, imm(sp) encoding: - match: 011-----------10 - variables: - - name: imm - location: 4-2|12|6-5 - left_shift: 3 - - name: rd - location: 11-7 - not: 0 + RV32: + match: 011-----------10 + variables: + - name: imm + location: 4-2|12|6-5 + left_shift: 3 + - name: rd + location: 11-7 + not: [0, 1, 3, 5, 7] + RV64: + match: 011-----------10 + variables: + - name: imm + location: 4-2|12|6-5 + left_shift: 3 + - name: rd + location: 11-7 access: s: always u: always @@ -37,5 +45,11 @@ operation(): | } XReg virtual_address = X[2] + imm; + Bits<64> value = read_memory<64>(virtual_address, $encoding); - X[rd] = read_memory<64>(virtual_address, $encoding); + if (MXLEN == 64) { + X[rd] = value; + } else if (MXLEN == 32) { + X[rd] = value[31:0]; + X[rd + 1] = value[63:32]; + } diff --git a/arch/inst/C/c.sd.yaml b/arch/inst/C/c.sd.yaml index e7b55d03b..9d667ad52 100644 --- a/arch/inst/C/c.sd.yaml +++ b/arch/inst/C/c.sd.yaml @@ -5,26 +5,38 @@ kind: instruction name: c.sd long_name: Store double description: | - Stores a 64-bit value in register rs2 to memory. + Stores a 64-bit value in register xs2 to memory. It computes an effective address by adding the zero-extended offset, scaled by 8, - to the base address in register rs1. - It expands to `sd` `rs2, offset(rs1)`. + to the base address in register xs1. + It expands to `sd` `xs2, offset(xs1)`. definedBy: anyOf: - C - Zca -base: 64 + - Zclsd assembly: xs2, imm(xs1) encoding: - match: 111-----------00 - variables: - - name: imm - location: 6-5|12-10 - left_shift: 3 - - name: rs2 - location: 4-2 - - name: rs1 - location: 9-7 + RV32: + match: 111-----------00 + variables: + - name: imm + location: 6-5|12-10 + left_shift: 3 + - name: xs2 + location: 4-2 + not: [1, 3, 5, 7] + - name: xs1 + location: 9-7 + RV64: + match: 111-----------00 + variables: + - name: imm + location: 6-5|12-10 + left_shift: 3 + - name: xs2 + location: 4-2 + - name: xs1 + location: 9-7 access: s: always u: always @@ -35,6 +47,15 @@ operation(): | raise(ExceptionCode::IllegalInstruction, mode(), $encoding); } - XReg virtual_address = X[creg2reg(rs1)] + imm; + XReg virtual_address = X[xs1] + imm; - write_memory<64>(virtual_address, X[creg2reg(rs2)], $encoding); + if (xlen() == 32) { + if (implemented?(ExtensionName::Zclsd)) { + Bits<64> data = {X[creg2reg(xs2) + 1], X[creg2reg(xs2)]}; + write_memory<64>(virtual_address, data, $encoding); + } else { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else { + write_memory<64>(virtual_address, X[xs2], $encoding); + } diff --git a/arch/inst/C/c.sdsp.yaml b/arch/inst/C/c.sdsp.yaml index d5d0d1c46..ffa88a465 100644 --- a/arch/inst/C/c.sdsp.yaml +++ b/arch/inst/C/c.sdsp.yaml @@ -13,16 +13,27 @@ definedBy: anyOf: - C - Zca + - Zclsd base: 64 assembly: xs2, imm(sp) encoding: - match: 111-----------10 - variables: - - name: imm - location: 9-7|12-10 - left_shift: 3 - - name: rs2 - location: 6-2 + RV32: + match: 111-----------10 + variables: + - name: xs2 + location: 6-2 + not: [1, 3, 5, 7] + - name: imm + location: 9-7|12-10 + left_shift: 3 + RV64: + match: 111-----------10 + variables: + - name: xs2 + location: 6-2 + - name: imm + location: 9-7|12-10 + left_shift: 3 access: s: always u: always diff --git a/arch/inst/Zclsd/c.ldsp.yaml b/arch/inst/Zclsd/c.ldsp.yaml new file mode 100644 index 000000000..97ca81b47 --- /dev/null +++ b/arch/inst/Zclsd/c.ldsp.yaml @@ -0,0 +1,45 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.ldsp +long_name: Stack-pointer based load doubleword to even/odd register pair +description: | + Loads a stack-pointer-relative 64-bit value into registers xd and xd+1. It computes its effective + address by adding the zero-extended offset, scaled by 8, to the stack pointer (sp). + It expands to `ld xd, offset(sp)`. + C.LDSP is only valid when xd ≠ x0. In RV32, xd must also be even; odd-numbered xd are reserved. +definedBy: Zclsd +assembly: xd, offset(sp) +encoding: + RV32: + match: 011-----------01 + variables: + - name: xd + location: 11-7 + not: [0, 1, 3, 5, 7] + - name: imm + location: 4-2|12|6-5 + left_shift: 3 + RV64: + match: 011-----------01 + variables: + - name: xd + location: 11-7 + - name: imm + location: 4-2|12|6-5 + left_shift: 3 +access: + s: always + u: always + vs: always + vu: always +operation(): | + Bits base = X[2]; + Bits offset = imm; + Bits eff_addr = base + offset; + + Bits<128> data = read_memory<128>(eff_addr, $encoding); + X[creg2reg(xd)] = data[63:0]; + X[creg2reg(xd)+1] = data[127:64]; +sail(): "" # Not implemented in the Sail model yet diff --git a/arch/inst/Zclsd/c.sd.yaml b/arch/inst/Zclsd/c.sd.yaml new file mode 100644 index 000000000..08b20df5b --- /dev/null +++ b/arch/inst/Zclsd/c.sd.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: c.sd +long_name: Store doubleword from even/odd register pair +description: | + Stores a 64-bit value from registers xs2 and xs2+1. + It computes an effective address by adding the zero-extended offset, scaled by 8, + to the base address in register xs1. + It expands to `sd xs2, offset(xs1)`. + In RV32, xs2 must be an even-numbered register. Combinations with odd-numbered xs2 are reserved. +definedBy: Zclsd +assembly: xs2, offset(xs1) +encoding: + RV32: + match: 111-----------00 + variables: + - name: xs2 + location: 4-2 + - name: xs1 + location: 9-7 + - name: imm + location: 12-10|6-5 + RV64: + match: 111-----------00 + variables: + - name: xs2 + location: 4-2 + - name: xs1 + location: 9-7 + - name: imm + location: 12-10|6-5 +access: + s: always + u: always + vs: always + vu: always +operation(): | + Bits base = X[creg2reg(xs1)]; + Bits offset = imm << 3; + Bits eff_addr = base + offset; + + if (xlen() == 32 && (creg2reg(xs2) % 2 != 0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + Bits<128> data = {X[creg2reg(xs2)+1], X[creg2reg(xs2)]}; + write_memory<64>(eff_addr, data, $encoding); +sail(): "" # Not implemented in the Sail model yet