Skip to content
Merged
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
100 changes: 100 additions & 0 deletions cfgs/qc_iu/arch_overlay/ext/Xqccmp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# yaml-language-server: $schema=../../../../schemas/ext_schema.json

$schema: ext_schema.json#
kind: extension
name: Xqccmp
long_name: 16-bit Push/Pop instructions and double-moves
type: unprivileged
versions:
- version: "0.1.0"
state: development
ratification_date: null
contributors:
- name: Albert Yosher
company: Qualcomm Technologies, Inc.
email: [email protected]
- name: Derek Hower
company: Qualcomm Technologies, Inc.
email: [email protected]
- name: Ana Pazos
company: Qualcomm Technologies, Inc.
email: [email protected]
- name: James Ball
company: Qualcomm Technologies, Inc.
email: [email protected]
requires:
name: Zca
version: ">= 1.0.0"
description: |
The Xqccmp extension is a set of instructions which may be executed as a series of existing 32-bit RISC-V instructions.

This extension reuses some encodings from _c.fsdsp_. Therefore it is _incompatible_ with <<Zcd>>,
which is included when C and D extensions are both present.

NOTE: Xqccmp is primarily targeted at embedded class CPUs due to implementation complexity. Additionally, it is not compatible with architecture class profiles.

The Xqccmp extension depends on the <<Zca>> extension.

The Xqccmp extension using same encodings as Zcmp extension for similar instructions, with 2 major differences:

* Order of load and store of registers is opposite to Zcmp order, but compliant with SW ABI
* Xqccmp on top of Zcmp instructions defines qc.cm.pushfp instruction to manage frame pointer

The PUSH/POP assembly syntax uses several variables, the meaning of which are:

* _reg_list_ is a list containing 1 to 13 registers (ra and 0 to 12 s registers)
** valid values: {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, ..., {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11}
** note that {ra, s0-s10} is _not_ valid, giving 12 lists not 13 for better encoding
* _stack_adj_ is the total size of the stack frame.
** valid values vary with register list length and the specific encoding, see the instruction pages for details.

[%header,cols="^1,^1,4,8"]
|===
|RV32
|RV64
|Mnemonic
|Instruction

|yes
|yes
|qc.cm.push _{reg_list}, -stack_adj_
|<<#insns-qc_cm_push>>

|yes
|yes
|qc.cm.pushfp _{reg_list}, -stack_adj_
|<<#insns-qc_cm_pushfp>>

|yes
|yes
|qc.cm.pop _{reg_list}, stack_adj_
|<<#insns-qc_cm_pop>>

|yes
|yes
|qc.cm.popret _{reg_list}, stack_adj_
|<<#insns-qc_cm_popret>>

|yes
|yes
|qc.cm.popretz _{reg_list}, stack_adj_
|<<#insns-qc_cm_popretz>>

|yes
|yes
|qc.cm.mva01s _rs1', rs2'_
|<<#insns-qc_cm_mva01s>>

|yes
|yes
|qc.cm.mvsa01 _r1s', r2s'_
|<<#insns-qc_cm_mvsa01>>

|===

doc_license:
name: Creative Commons Attribution 4.0 International License
url: https://creativecommons.org/licenses/by/4.0/
company:
name: Qualcomm Technologies, Inc.
url: https://qualcomm.com
38 changes: 38 additions & 0 deletions cfgs/qc_iu/arch_overlay/inst/Xqccmp/qc.cm.mva01s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json

$schema: "inst_schema.json#"
kind: instruction
name: qc.cm.mva01s
long_name: Move two s0-s7 registers into a0-a1
description: |
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.
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.
definedBy:
anyOf:
- Xqccmp
excludedBy:
anyOf:
- allOf: [C, D]
- Zcd
- Zcmp
assembly: r1s, r2s
encoding:
match: 101011---11---10
variables:
- name: r1s
location: 9-7
- name: r2s
location: 4-2
access:
s: always
u: always
vs: always
vu: always
operation(): |
if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]};
XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]};
X[10] = X[xreg1];
X[11] = X[xreg2];
40 changes: 40 additions & 0 deletions cfgs/qc_iu/arch_overlay/inst/Xqccmp/qc.cm.mvsa01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json

$schema: "inst_schema.json#"
kind: instruction
name: qc.cm.mvsa01
long_name: Move a0-a1 into two registers of s0-s7
description: |
This instruction moves a0 into r1s' and a1 into r2s'. r1s' and r2s' must be different.
The execution is atomic, so it is not possible to observe state where only one of r1s' or r2s' has been updated.
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.
definedBy:
anyOf:
- Xqccmp
excludedBy:
anyOf:
- allOf: [C, D]
- Zcd
- Zcmp
assembly: r1s, r2s
encoding:
match: 101011---01---10
variables:
- name: r1s
location: 9-7
- name: r2s
location: 4-2
access:
s: always
u: always
vs: always
vu: always
operation(): |
if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]};
XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]};
X[xreg1] = X[10];
X[xreg2] = X[11];
88 changes: 88 additions & 0 deletions cfgs/qc_iu/arch_overlay/inst/Xqccmp/qc.cm.pop.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json

$schema: "inst_schema.json#"
kind: instruction
name: qc.cm.pop
long_name: Destroy function call stack frame
description: |
Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame.
This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj`.

Restrictions on stack_adj:

* it must be enough to store all of the listed registers
* it must be a multiple of 16 (bytes):
** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112
** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160
definedBy:
anyOf:
- Xqccmp
excludedBy:
anyOf:
- allOf: [C, D]
- Zcd
- Zcmp
assembly: reg_list, stack_adj
encoding:
match: 10111010------10
variables:
- name: rlist
location: 7-4
not: [0, 1, 2, 3]
- name: spimm
location: 3-2
access:
s: always
u: always
vs: always
vu: always
operation(): |
if (implemented?(ExtensionName::Xqccmp) && (CSR[misa].C == 1'b0)) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}

XReg size = xlen();
XReg nreg = (rlist == 15) ? 13 : (rlist - 3);
XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF;
XReg virtual_address_sp = X[2];
XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm;
XReg virtual_address_base = virtual_address_new_sp - size;


X[ 1] = read_memory_xlen(virtual_address_base - 0*size, $encoding);
if (nreg > 1) {
X[ 8] = read_memory_xlen(virtual_address_base - 1*size, $encoding);
}
if (nreg > 2) {
X[ 9] = read_memory_xlen(virtual_address_base - 2*size, $encoding);
}
if (nreg > 3) {
X[18] = read_memory_xlen(virtual_address_base - 3*size, $encoding);
}
if (nreg > 4) {
X[19] = read_memory_xlen(virtual_address_base - 4*size, $encoding);
}
if (nreg > 5) {
X[20] = read_memory_xlen(virtual_address_base - 5*size, $encoding);
}
if (nreg > 6) {
X[21] = read_memory_xlen(virtual_address_base - 6*size, $encoding);
}
if (nreg > 7) {
X[22] = read_memory_xlen(virtual_address_base - 7*size, $encoding);
}
if (nreg > 8) {
X[23] = read_memory_xlen(virtual_address_base - 8*size, $encoding);
}
if (nreg > 9) {
X[24] = read_memory_xlen(virtual_address_base - 9*size, $encoding);
}
if (nreg > 10) {
X[25] = read_memory_xlen(virtual_address_base - 10*size, $encoding);
}
if (nreg > 11) {
X[26] = read_memory_xlen(virtual_address_base - 11*size, $encoding);
X[27] = read_memory_xlen(virtual_address_base - 12*size, $encoding);
}

X[2] = virtual_address_new_sp;
89 changes: 89 additions & 0 deletions cfgs/qc_iu/arch_overlay/inst/Xqccmp/qc.cm.popret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# yaml-language-server: $schema=../../../../../schemas/inst_schema.json

$schema: "inst_schema.json#"
kind: instruction
name: qc.cm.popret
long_name: Destroy function call stack frame and return to `ra`.
description: |
Destroy stack frame: load ra and 0 to 12 saved registers from the stack frame, deallocate the stack frame, return to `ra`.
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.

Restrictions on stack_adj:

* it must be enough to store all of the listed registers
* it must be a multiple of 16 (bytes):
** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112
** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160
definedBy:
anyOf:
- Xqccmp
excludedBy:
anyOf:
- allOf: [C, D]
- Zcd
- Zcmp
assembly: reg_list, stack_adj
encoding:
match: 10111110------10
variables:
- name: rlist
location: 7-4
not: [0, 1, 2, 3]
- name: spimm
location: 3-2
access:
s: always
u: always
vs: always
vu: always
operation(): |
if (implemented?(ExtensionName::Xqccmp) && (CSR[misa].C == 1'b0)) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}

XReg size = xlen();
XReg nreg = (rlist == 15) ? 13 : (rlist - 3);
XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF;
XReg virtual_address_sp = X[2];
XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm;
XReg virtual_address_base = virtual_address_new_sp - size;


X[ 1] = read_memory_xlen(virtual_address_base - 0*size, $encoding);
if (nreg > 1) {
X[ 8] = read_memory_xlen(virtual_address_base - 1*size, $encoding);
}
if (nreg > 2) {
X[ 9] = read_memory_xlen(virtual_address_base - 2*size, $encoding);
}
if (nreg > 3) {
X[18] = read_memory_xlen(virtual_address_base - 3*size, $encoding);
}
if (nreg > 4) {
X[19] = read_memory_xlen(virtual_address_base - 4*size, $encoding);
}
if (nreg > 5) {
X[20] = read_memory_xlen(virtual_address_base - 5*size, $encoding);
}
if (nreg > 6) {
X[21] = read_memory_xlen(virtual_address_base - 6*size, $encoding);
}
if (nreg > 7) {
X[22] = read_memory_xlen(virtual_address_base - 7*size, $encoding);
}
if (nreg > 8) {
X[23] = read_memory_xlen(virtual_address_base - 8*size, $encoding);
}
if (nreg > 9) {
X[24] = read_memory_xlen(virtual_address_base - 9*size, $encoding);
}
if (nreg > 10) {
X[25] = read_memory_xlen(virtual_address_base - 10*size, $encoding);
}
if (nreg > 11) {
X[26] = read_memory_xlen(virtual_address_base - 11*size, $encoding);
X[27] = read_memory_xlen(virtual_address_base - 12*size, $encoding);
}

X[2] = virtual_address_new_sp;
jump(X[1]);
Loading
Loading