Skip to content

Commit 89b27e7

Browse files
authored
Merge pull request riscv-software-src#438 from riscv-software-src/Xqccmp
Xqccmp extension: initiall add: Similar to Zcmp extension, but with d…
2 parents 520df8c + 93bc8fe commit 89b27e7

File tree

9 files changed

+629
-0
lines changed

9 files changed

+629
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# yaml-language-server: $schema=../../../../schemas/ext_schema.json
2+
3+
$schema: ext_schema.json#
4+
kind: extension
5+
name: Xqccmp
6+
long_name: 16-bit Push/Pop instructions and double-moves
7+
type: unprivileged
8+
versions:
9+
- version: "0.1.0"
10+
state: development
11+
ratification_date: null
12+
contributors:
13+
- name: Albert Yosher
14+
company: Qualcomm Technologies, Inc.
15+
16+
- name: Derek Hower
17+
company: Qualcomm Technologies, Inc.
18+
19+
- name: Ana Pazos
20+
company: Qualcomm Technologies, Inc.
21+
22+
- name: James Ball
23+
company: Qualcomm Technologies, Inc.
24+
25+
requires:
26+
name: Zca
27+
version: ">= 1.0.0"
28+
description: |
29+
The Xqccmp extension is a set of instructions which may be executed as a series of existing 32-bit RISC-V instructions.
30+
31+
This extension reuses some encodings from _c.fsdsp_. Therefore it is _incompatible_ with <<Zcd>>,
32+
which is included when C and D extensions are both present.
33+
34+
NOTE: Xqccmp is primarily targeted at embedded class CPUs due to implementation complexity. Additionally, it is not compatible with architecture class profiles.
35+
36+
The Xqccmp extension depends on the <<Zca>> extension.
37+
38+
The Xqccmp extension using same encodings as Zcmp extension for similar instructions, with 2 major differences:
39+
40+
* Order of load and store of registers is opposite to Zcmp order, but compliant with SW ABI
41+
* Xqccmp on top of Zcmp instructions defines qc.cm.pushfp instruction to manage frame pointer
42+
43+
The PUSH/POP assembly syntax uses several variables, the meaning of which are:
44+
45+
* _reg_list_ is a list containing 1 to 13 registers (ra and 0 to 12 s registers)
46+
** valid values: {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, ..., {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11}
47+
** note that {ra, s0-s10} is _not_ valid, giving 12 lists not 13 for better encoding
48+
* _stack_adj_ is the total size of the stack frame.
49+
** valid values vary with register list length and the specific encoding, see the instruction pages for details.
50+
51+
[%header,cols="^1,^1,4,8"]
52+
|===
53+
|RV32
54+
|RV64
55+
|Mnemonic
56+
|Instruction
57+
58+
|yes
59+
|yes
60+
|qc.cm.push _{reg_list}, -stack_adj_
61+
|<<#insns-qc_cm_push>>
62+
63+
|yes
64+
|yes
65+
|qc.cm.pushfp _{reg_list}, -stack_adj_
66+
|<<#insns-qc_cm_pushfp>>
67+
68+
|yes
69+
|yes
70+
|qc.cm.pop _{reg_list}, stack_adj_
71+
|<<#insns-qc_cm_pop>>
72+
73+
|yes
74+
|yes
75+
|qc.cm.popret _{reg_list}, stack_adj_
76+
|<<#insns-qc_cm_popret>>
77+
78+
|yes
79+
|yes
80+
|qc.cm.popretz _{reg_list}, stack_adj_
81+
|<<#insns-qc_cm_popretz>>
82+
83+
|yes
84+
|yes
85+
|qc.cm.mva01s _rs1', rs2'_
86+
|<<#insns-qc_cm_mva01s>>
87+
88+
|yes
89+
|yes
90+
|qc.cm.mvsa01 _r1s', r2s'_
91+
|<<#insns-qc_cm_mvsa01>>
92+
93+
|===
94+
95+
doc_license:
96+
name: Creative Commons Attribution 4.0 International License
97+
url: https://creativecommons.org/licenses/by/4.0/
98+
company:
99+
name: Qualcomm Technologies, Inc.
100+
url: https://qualcomm.com
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json
2+
3+
$schema: "inst_schema.json#"
4+
kind: instruction
5+
name: qc.cm.mva01s
6+
long_name: Move two s0-s7 registers into a0-a1
7+
description: |
8+
This instruction moves r1s' into a0 and r2s' into a1. The execution is atomic, so it is not possible to observe state where only one of a0 or a1 have been updated.
9+
The encoding uses sreg number specifiers instead of xreg number specifiers to save encoding space. The mapping between them is specified in the pseudo-code below.
10+
definedBy:
11+
anyOf:
12+
- Xqccmp
13+
excludedBy:
14+
anyOf:
15+
- allOf: [C, D]
16+
- Zcd
17+
- Zcmp
18+
assembly: r1s, r2s
19+
encoding:
20+
match: 101011---11---10
21+
variables:
22+
- name: r1s
23+
location: 9-7
24+
- name: r2s
25+
location: 4-2
26+
access:
27+
s: always
28+
u: always
29+
vs: always
30+
vu: always
31+
operation(): |
32+
if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) {
33+
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
34+
}
35+
XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]};
36+
XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]};
37+
X[10] = X[xreg1];
38+
X[11] = X[xreg2];
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json
2+
3+
$schema: "inst_schema.json#"
4+
kind: instruction
5+
name: qc.cm.mvsa01
6+
long_name: Move a0-a1 into two registers of s0-s7
7+
description: |
8+
This instruction moves a0 into r1s' and a1 into r2s'. r1s' and r2s' must be different.
9+
The execution is atomic, so it is not possible to observe state where only one of r1s' or r2s' has been updated.
10+
The encoding uses sreg number specifiers instead of xreg number specifiers to save encoding space.
11+
The mapping between them is specified in the pseudo-code below.
12+
definedBy:
13+
anyOf:
14+
- Xqccmp
15+
excludedBy:
16+
anyOf:
17+
- allOf: [C, D]
18+
- Zcd
19+
- Zcmp
20+
assembly: r1s, r2s
21+
encoding:
22+
match: 101011---01---10
23+
variables:
24+
- name: r1s
25+
location: 9-7
26+
- name: r2s
27+
location: 4-2
28+
access:
29+
s: always
30+
u: always
31+
vs: always
32+
vu: always
33+
operation(): |
34+
if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) {
35+
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
36+
}
37+
XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]};
38+
XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]};
39+
X[xreg1] = X[10];
40+
X[xreg2] = X[11];
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json
2+
3+
$schema: "inst_schema.json#"
4+
kind: instruction
5+
name: qc.cm.pop
6+
long_name: Destroy function call stack frame
7+
description: |
8+
Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame.
9+
This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj`.
10+
11+
Restrictions on stack_adj:
12+
13+
* it must be enough to store all of the listed registers
14+
* it must be a multiple of 16 (bytes):
15+
** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112
16+
** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160
17+
definedBy:
18+
anyOf:
19+
- Xqccmp
20+
excludedBy:
21+
anyOf:
22+
- allOf: [C, D]
23+
- Zcd
24+
- Zcmp
25+
assembly: reg_list, stack_adj
26+
encoding:
27+
match: 10111010------10
28+
variables:
29+
- name: rlist
30+
location: 7-4
31+
not: [0, 1, 2, 3]
32+
- name: spimm
33+
location: 3-2
34+
access:
35+
s: always
36+
u: always
37+
vs: always
38+
vu: always
39+
operation(): |
40+
if (implemented?(ExtensionName::Xqccmp) && (CSR[misa].C == 1'b0)) {
41+
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
42+
}
43+
44+
XReg size = xlen();
45+
XReg nreg = (rlist == 15) ? 13 : (rlist - 3);
46+
XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF;
47+
XReg virtual_address_sp = X[2];
48+
XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm;
49+
XReg virtual_address_base = virtual_address_new_sp - size;
50+
51+
52+
X[ 1] = read_memory_xlen(virtual_address_base - 0*size, $encoding);
53+
if (nreg > 1) {
54+
X[ 8] = read_memory_xlen(virtual_address_base - 1*size, $encoding);
55+
}
56+
if (nreg > 2) {
57+
X[ 9] = read_memory_xlen(virtual_address_base - 2*size, $encoding);
58+
}
59+
if (nreg > 3) {
60+
X[18] = read_memory_xlen(virtual_address_base - 3*size, $encoding);
61+
}
62+
if (nreg > 4) {
63+
X[19] = read_memory_xlen(virtual_address_base - 4*size, $encoding);
64+
}
65+
if (nreg > 5) {
66+
X[20] = read_memory_xlen(virtual_address_base - 5*size, $encoding);
67+
}
68+
if (nreg > 6) {
69+
X[21] = read_memory_xlen(virtual_address_base - 6*size, $encoding);
70+
}
71+
if (nreg > 7) {
72+
X[22] = read_memory_xlen(virtual_address_base - 7*size, $encoding);
73+
}
74+
if (nreg > 8) {
75+
X[23] = read_memory_xlen(virtual_address_base - 8*size, $encoding);
76+
}
77+
if (nreg > 9) {
78+
X[24] = read_memory_xlen(virtual_address_base - 9*size, $encoding);
79+
}
80+
if (nreg > 10) {
81+
X[25] = read_memory_xlen(virtual_address_base - 10*size, $encoding);
82+
}
83+
if (nreg > 11) {
84+
X[26] = read_memory_xlen(virtual_address_base - 11*size, $encoding);
85+
X[27] = read_memory_xlen(virtual_address_base - 12*size, $encoding);
86+
}
87+
88+
X[2] = virtual_address_new_sp;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json
2+
3+
$schema: "inst_schema.json#"
4+
kind: instruction
5+
name: qc.cm.popret
6+
long_name: Destroy function call stack frame and return to `ra`.
7+
description: |
8+
Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame, return to `ra`.
9+
This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj` and then return to ra.
10+
11+
Restrictions on stack_adj:
12+
13+
* it must be enough to store all of the listed registers
14+
* it must be a multiple of 16 (bytes):
15+
** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112
16+
** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160
17+
definedBy:
18+
anyOf:
19+
- Xqccmp
20+
excludedBy:
21+
anyOf:
22+
- allOf: [C, D]
23+
- Zcd
24+
- Zcmp
25+
assembly: reg_list, stack_adj
26+
encoding:
27+
match: 10111110------10
28+
variables:
29+
- name: rlist
30+
location: 7-4
31+
not: [0, 1, 2, 3]
32+
- name: spimm
33+
location: 3-2
34+
access:
35+
s: always
36+
u: always
37+
vs: always
38+
vu: always
39+
operation(): |
40+
if (implemented?(ExtensionName::Xqccmp) && (CSR[misa].C == 1'b0)) {
41+
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
42+
}
43+
44+
XReg size = xlen();
45+
XReg nreg = (rlist == 15) ? 13 : (rlist - 3);
46+
XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF;
47+
XReg virtual_address_sp = X[2];
48+
XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm;
49+
XReg virtual_address_base = virtual_address_new_sp - size;
50+
51+
52+
X[ 1] = read_memory_xlen(virtual_address_base - 0*size, $encoding);
53+
if (nreg > 1) {
54+
X[ 8] = read_memory_xlen(virtual_address_base - 1*size, $encoding);
55+
}
56+
if (nreg > 2) {
57+
X[ 9] = read_memory_xlen(virtual_address_base - 2*size, $encoding);
58+
}
59+
if (nreg > 3) {
60+
X[18] = read_memory_xlen(virtual_address_base - 3*size, $encoding);
61+
}
62+
if (nreg > 4) {
63+
X[19] = read_memory_xlen(virtual_address_base - 4*size, $encoding);
64+
}
65+
if (nreg > 5) {
66+
X[20] = read_memory_xlen(virtual_address_base - 5*size, $encoding);
67+
}
68+
if (nreg > 6) {
69+
X[21] = read_memory_xlen(virtual_address_base - 6*size, $encoding);
70+
}
71+
if (nreg > 7) {
72+
X[22] = read_memory_xlen(virtual_address_base - 7*size, $encoding);
73+
}
74+
if (nreg > 8) {
75+
X[23] = read_memory_xlen(virtual_address_base - 8*size, $encoding);
76+
}
77+
if (nreg > 9) {
78+
X[24] = read_memory_xlen(virtual_address_base - 9*size, $encoding);
79+
}
80+
if (nreg > 10) {
81+
X[25] = read_memory_xlen(virtual_address_base - 10*size, $encoding);
82+
}
83+
if (nreg > 11) {
84+
X[26] = read_memory_xlen(virtual_address_base - 11*size, $encoding);
85+
X[27] = read_memory_xlen(virtual_address_base - 12*size, $encoding);
86+
}
87+
88+
X[2] = virtual_address_new_sp;
89+
jump(X[1]);

0 commit comments

Comments
 (0)