diff --git a/arch/ext/Zclsd.yaml b/arch/ext/Zclsd.yaml new file mode 100644 index 0000000000..ee17c5647b --- /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 911001a23d..9748f0e4b4 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 @@ -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 50786f1d7c..c67a6227ac 100644 --- a/arch/inst/C/c.ldsp.yaml +++ b/arch/inst/C/c.ldsp.yaml @@ -6,26 +6,34 @@ name: c.ldsp long_name: Load doubleword from stack pointer description: | C.LDSP is an RV64C/RV128C-only instruction that loads a 64-bit value from memory - into register rd. + into register xd. 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 xd, offset(x2)`. + C.LDSP is only valid when xd ≠ x0; code points with xd=x0 are reserved. definedBy: anyOf: - C - Zca -base: 64 assembly: xd, 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: xd + 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: xd + 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 (xlen()== 64) { + X[creg2reg(xd)] = value; + } else if (xlen() == 32) { + X[creg2reg(xd)] = value[31:0]; + X[creg2reg(xd) + 1] = value[63:32]; + } diff --git a/arch/inst/C/c.sd.yaml b/arch/inst/C/c.sd.yaml index e7b55d03bb..deff020b68 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. + For RV64, store a 64-bit value in register xs2 to memory. For RV32 with Zclsd extension, store a 64-bit value from the combined values in register pair [xs2, xs2+1] 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[creg2reg(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[creg2reg(xs2)], $encoding); + } diff --git a/arch/inst/C/c.sdsp.yaml b/arch/inst/C/c.sdsp.yaml index d5d0d1c462..fa28298f2a 100644 --- a/arch/inst/C/c.sdsp.yaml +++ b/arch/inst/C/c.sdsp.yaml @@ -13,16 +13,26 @@ definedBy: anyOf: - C - Zca -base: 64 + - Zclsd 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 @@ -35,4 +45,13 @@ operation(): | XReg virtual_address = X[2] + imm; - write_memory<64>(virtual_address, X[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[creg2reg(xs2)], $encoding); + } diff --git a/backends/instructions_appendix/all_instructions.golden.adoc b/backends/instructions_appendix/all_instructions.golden.adoc index 349d8c0731..724b187c87 100644 --- a/backends/instructions_appendix/all_instructions.golden.adoc +++ b/backends/instructions_appendix/all_instructions.golden.adoc @@ -3996,25 +3996,48 @@ Synopsis:: Load double Encoding:: +[NOTE] +This instruction has different encodings in RV32 and RV64 + +RV32:: [wavedrom, ,svg,subs='attributes',width="100%"] .... -{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "rd","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "rs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x3,"type":2}]} +{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "xd != {1,3,5,7}","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "xs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x3,"type":2}]} +.... + +RV64:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "xd","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "xs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x3,"type":2}]} .... 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 xref:insts:ld.adoc#udb:doc:inst:ld[ld] `rd, offset(rs1)`. +to the base address in register xs1. +It expands to xref:insts:ld.adoc#udb:doc:inst:ld[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. Decode Variables:: +*RV32:* + [width="100%", cols="1,2", options="header"] |=== |Variable Name |Location |imm |{$encoding[6:5], $encoding[12:10], 3'd0} -|rd |$encoding[4:2] -|rs1 |$encoding[9:7] +|xd |$encoding[4:2] +|xs1 |$encoding[9:7] +|=== + +*RV64:* + +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|imm |{$encoding[6:5], $encoding[12:10], 3'd0} +|xd |$encoding[4:2] +|xs1 |$encoding[9:7] |=== Included in:: @@ -4026,6 +4049,8 @@ Included in:: | *Zca* | ~> 1.0.0 +| *Zclsd* | ~> 1.0 + |=== @@ -4036,26 +4061,47 @@ Synopsis:: Load doubleword from stack pointer Encoding:: +[NOTE] +This instruction has different encodings in RV32 and RV64 + +RV32:: [wavedrom, ,svg,subs='attributes',width="100%"] .... -{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "imm[4:3|8:6]","type":4},{"bits":5,"name": "rd != 0","type":4},{"bits":1,"name": "imm[5]","type":4},{"bits":3,"name": 0x3,"type":2}]} +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "imm[4:3|8:6]","type":4},{"bits":5,"name": "xd != {0,1,3,5,7}","type":4},{"bits":1,"name": "imm[5]","type":4},{"bits":3,"name": 0x3,"type":2}]} +.... + +RV64:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "imm[4:3|8:6]","type":4},{"bits":5,"name": "xd","type":4},{"bits":1,"name": "imm[5]","type":4},{"bits":3,"name": 0x3,"type":2}]} .... Description:: C.LDSP is an RV64C/RV128C-only instruction that loads a 64-bit value from memory -into register rd. +into register xd. It computes its effective address by adding the zero-extended offset, scaled by 8, to the stack pointer, x2. -It expands to xref:insts:ld.adoc#udb:doc:inst:ld[ld] `rd, offset(x2)`. -C.LDSP is only valid when rd ≠ x0 the code points with rd=x0 are reserved. +It expands to `ld xd, offset(x2)`. +C.LDSP is only valid when xd ≠ x0; code points with xd=x0 are reserved. Decode Variables:: +*RV32:* + [width="100%", cols="1,2", options="header"] |=== |Variable Name |Location |imm |{$encoding[4:2], $encoding[12], $encoding[6:5], 3'd0} -|rd |$encoding[11:7] +|xd |$encoding[11:7] +|=== + +*RV64:* + +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|imm |{$encoding[4:2], $encoding[12], $encoding[6:5], 3'd0} +|xd |$encoding[11:7] |=== Included in:: @@ -4561,25 +4607,47 @@ Synopsis:: Store double Encoding:: +[NOTE] +This instruction has different encodings in RV32 and RV64 + +RV32:: [wavedrom, ,svg,subs='attributes',width="100%"] .... -{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "rs2","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "rs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x7,"type":2}]} +{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "xs2 != {1,3,5,7}","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "xs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x7,"type":2}]} +.... + +RV64:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x0,"type":2},{"bits":3,"name": "xs2","type":4},{"bits":2,"name": "imm[7:6]","type":4},{"bits":3,"name": "xs1","type":4},{"bits":3,"name": "imm[5:3]","type":4},{"bits":3,"name": 0x7,"type":2}]} .... Description:: -Stores a 64-bit value in register rs2 to memory. +For RV64, store a 64-bit value in register xs2 to memory. For RV32 with Zclsd extension, store a 64-bit value from the combined values in register pair [xs2, xs2+1] 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 xref:insts:sd.adoc#udb:doc:inst:sd[sd] `rs2, offset(rs1)`. +to the base address in register xs1. +It expands to xref:insts:sd.adoc#udb:doc:inst:sd[sd] `xs2, offset(xs1)`. Decode Variables:: +*RV32:* + [width="100%", cols="1,2", options="header"] |=== |Variable Name |Location |imm |{$encoding[6:5], $encoding[12:10], 3'd0} -|rs2 |$encoding[4:2] -|rs1 |$encoding[9:7] +|xs2 |$encoding[4:2] +|xs1 |$encoding[9:7] +|=== + +*RV64:* + +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|imm |{$encoding[6:5], $encoding[12:10], 3'd0} +|xs2 |$encoding[4:2] +|xs1 |$encoding[9:7] |=== Included in:: @@ -4591,6 +4659,8 @@ Included in:: | *Zca* | ~> 1.0.0 +| *Zclsd* | ~> 1.0 + |=== @@ -4601,9 +4671,19 @@ Synopsis:: Store doubleword to stack Encoding:: +[NOTE] +This instruction has different encodings in RV32 and RV64 + +RV32:: [wavedrom, ,svg,subs='attributes',width="100%"] .... -{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "rs2","type":4},{"bits":6,"name": "imm[5:3|8:6]","type":4},{"bits":3,"name": 0x7,"type":2}]} +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "xs2 != {1,3,5,7}","type":4},{"bits":6,"name": "imm[5:3|8:6]","type":4},{"bits":3,"name": 0x7,"type":2}]} +.... + +RV64:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "xs2","type":4},{"bits":6,"name": "imm[5:3|8:6]","type":4},{"bits":3,"name": 0x7,"type":2}]} .... Description:: @@ -4614,11 +4694,22 @@ It expands to xref:insts:sd.adoc#udb:doc:inst:sd[sd] `rs2, offset(x2)`. Decode Variables:: +*RV32:* + [width="100%", cols="1,2", options="header"] |=== |Variable Name |Location +|xs2 |$encoding[6:2] +|imm |{$encoding[9:7], $encoding[12:10], 3'd0} +|=== + +*RV64:* + +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|xs2 |$encoding[6:2] |imm |{$encoding[9:7], $encoding[12:10], 3'd0} -|rs2 |$encoding[6:2] |=== Included in:: @@ -4630,6 +4721,8 @@ Included in:: | *Zca* | ~> 1.0.0 +| *Zclsd* | ~> 1.0 + |===