qpc/ports/risc-v/qv/README.md
MMS e032055963 7.1.3
7.1.3

Replaced QF_EVT_REF_CTR_INC_() with QEvt_refCtr_inc_() in ports
- embOS
- ESP-IDF
- Qt

7.1.3

7.1.3

7.1.3

7.1.3

7.1.3

7.1.3

7.1.2

first commit after fixing history

Revert "7.1.2"

This reverts commit 90cf4e1471b5e9c0853af97af8ec0bc67c7e19c6.

7.1.2

first commit after fixing the history

7.0.1
2023-02-18 09:17:17 -05:00

83 lines
3.7 KiB
Markdown

# QP/C Port to RISC-V
This document describes the QP/C framework port to RISC-V with the cooperative QV kernel. The port is located in the `qpc/ports/risc-v/qv/gnu` directory.
```
qpc/ - QP/C installation directory
+-ports/ - QP/C ports directory
| +-risc-v/ - QP/C port to RISC-V
| | +-qv/ - QP/C port to RISV-V with the QV kernel
| | | +-gnu/ - QP/C port to RISV-V with the QV kernel and GNU compiler
| | | | +-qep_port.h - QEP/C (hierarchical event processor) port
| | | | +-qf_port.h - QF/C (event-driven framework) port
| | | | +-qs_port.h - QS/C (QP/Spy software tracing) port
| | | | +-qv_port.h - QV/C (cooperative QV kernel) port
```
> NOTE:
The `qpc/ports/risc-v/qv/qv/gnu` directory needs to be provided to the compiler's include path.
## Cooperative QV Kernel for RISC-V
The most important aspects of the QP/C port to RISC-V with the cooperative QV kernel are provided as macro definitions in the files `qf_port.h` and `qv_port.h` in the `qpc/ports/risc-v/qv/qv/gnu` directory. The port strives to be generic in that it's designed to support all currently available RISC-V (RV32) chips.
```
file: qf_port.h
~ ~ ~
/* The maximum number of active objects in the application, see NOTE1 */
#define QF_MAX_ACTIVE 32U
/* interrupt disabling policy, see NOTE2 */
#define QF_INT_DISABLE() __asm__ volatile("csrc mstatus,8")
#define QF_INT_ENABLE() __asm__ volatile("csrs mstatus,8")
/* QF critical section entry/exit, see NOTE3 */
#define QF_CRIT_STAT_TYPE unsigned int
#define QF_CRIT_ENTRY(status_) do { \
__asm__ volatile("csrr %0, mstatus" : "=r"(status_)); \
QF_INT_DISABLE(); \
} while (false)
#define QF_CRIT_EXIT(status_) \
__asm__ volatile ("csrw mstatus, %0" :: "rK"(status_))
/* support for fast LOG2, see NOTE4 */
#define QF_LOG2(n_) ((uint_fast8_t)(32U - __builtin_clz((n_))))
/* NOP instruction for RISC-V, NOTE5 */
#define QF_CRIT_EXIT_NOP() __asm__ volatile ("nop")
~ ~ `
```
**[1]** the maximum number of active objects `QF_MAX_ACTIVE` can be increased up to 64, if necessary. Here it is set to a lower level of 32 to slightly improve performance and save some RAM.
**[2]** the port disables interrupts by clearing `mstatus` bit-3 (MIE == Machine Interrupt Enable) and enables interrupts setting `mstatus` bit-3 (MIE).
**[3]** the port uses the "save and restore interrupt status" policy. This policy is appropriate for CPUs that disable interrupts inside ISRs, which is the case with RISC-V. Also, this policy allows *nesting* of critical sections.
**[4]** The port takes advantage of the built-in function `__builtin_clz()` for fast computation of log-base-2, which is used in the QV scheduler.
**[5]** The port uses `NOP` instruction to prevent potential merging of back-to-back critical sections inside the QP/C implementation. This precaution is to reduce interrupt latency.
```
file: qv_port.h
~ ~ ~
/*! macro to put the CPU to sleep inside QV_onIdle() callback */
/* The following QV_CPU_SLEEP() executes the WFI instruction with
* interrupts still DISABLED. Interrupts are enabled only after
* the RISC-V CPU wakes up.
* NOTE: this approach needs to be tested for each specific RISC-V SoC.
*/
#define QV_CPU_SLEEP() do { \
__asm volatile("wfi"); \
QF_INT_ENABLE(); \
} while (false)
~ ~ `
```
**[6]** The QV port can detect the idle condition of the system, which can be utilized to put the system (CPU and peripherals) in a low-power sleep mode. However, the specifics of the QV kernel require the CPU to transition to the sleep mode with interrupts **DISABLED**.
> **NOTE:**
According to the "The RISC-V Instruction Set Manual", the `WFI` instruction can be executed when interrupts are **disabled**.