Skip to content

Add Zclsd extension YAML #577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions arch/ext/Zclsd.yaml
Original file line number Diff line number Diff line change
@@ -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 ]
70 changes: 45 additions & 25 deletions arch/inst/C/c.ld.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,19 +48,28 @@ 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 <https://github.com/riscv/sail-riscv/blob/master/LICENCE>
# SPDX-License-Identifier: BSD-2-Clause
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)
Expand All @@ -57,17 +79,15 @@ 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")
}
}
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be retained, at the end of the Sail code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "SPDX-SnippetEnd" still needs to be retained.

# SPDX-SnippetEnd
36 changes: 24 additions & 12 deletions arch/inst/C/c.ldsp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,32 @@ 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 &ne; 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the "base: 64", since this instruction is now supportable in RV32.

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
Expand All @@ -36,6 +45,9 @@ operation(): |
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
XReg virtual_address = X[2] + imm;
if (xlen() == 32) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
Comment on lines +48 to +50
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the others, the 32 bit code needs to be merged in here, and this test deleted/modified such that you support both 64 bit mode (as written below), and 32 bit mode (using register pairs).

XReg virtual_address = X[2] + imm;
X[rd] = read_memory<64>(virtual_address, $encoding);
51 changes: 36 additions & 15 deletions arch/inst/C/c.sd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,6 +47,15 @@ operation(): |
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
XReg virtual_address = X[creg2reg(rs1)] + imm;
XReg virtual_address = X[creg2reg(xs1)] + imm;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the creg2reg is only necessary in 32bit mode, where the register field "xs1" is only 3 bits and has to be transformed into the proper register index. This is much like what you've already done for c.ld.

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no creg2reg here, since this is 64 bit mode.

}
24 changes: 17 additions & 7 deletions arch/inst/C/c.sdsp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,26 @@ 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, "xs2" must be even as it is part of a register pair, so add the appropriate not statement (for the 5 bit value).

- 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
Expand Down
45 changes: 45 additions & 0 deletions arch/inst/Zclsd/c.ldsp.yaml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for c.ldsp needs to be merged into arch/inst/C/c.ldsp.yaml, above, then this file removed.

Original file line number Diff line number Diff line change
@@ -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<MXLEN> base = X[2];
Bits<MXLEN> offset = imm;
Bits<MXLEN> 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
50 changes: 50 additions & 0 deletions arch/inst/Zclsd/c.sd.yaml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this content has all been merged into arch/inst/C/c.sd.yaml, this file should be removed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this file

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please explain the reason of removing it ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you're now defining the RV32 version of this instruction in arch/inst/C/c.sd.yaml, so this file is redundant.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood

Original file line number Diff line number Diff line change
@@ -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<MXLEN> base = X[creg2reg(xs1)];
Bits<MXLEN> offset = imm << 3;
Bits<MXLEN> 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
Loading