3333 #define configENABLE_FPU 0
3434#endif
3535
36+ #ifndef configENABLE_VPU
37+ #define configENABLE_VPU 0
38+ #endif
39+
3640#if __riscv_xlen == 64
3741 #define portWORD_SIZE 8
3842 #define store_x sd
9094 #define portFPU_REG_OFFSET ( regIndex ) ( ( 2 * portWORD_SIZE ) + ( regIndex * portFPU_REG_SIZE ) )
9195 #define portFPU_CONTEXT_SIZE ( portFPU_REG_SIZE * portFPU_REG_COUNT )
9296 #else
93- #error configENABLE_FPU must not be set to 1 if the hardwar does not have FPU
97+ #error configENABLE_FPU must not be set to 1 if the hardware does not have FPU
98+ #endif
99+ #endif
100+
101+ #if ( configENABLE_VPU == 1 )
102+ /* Bit [10:9] in the mstatus encode the status of VPU state which is one of
103+ * the following values:
104+ * 1. Value: 0, Meaning: Off.
105+ * 2. Value: 1, Meaning: Initial.
106+ * 3. Value: 2, Meaning: Clean.
107+ * 4. Value: 3, Meaning: Dirty.
108+ */
109+ #define MSTATUS_VS_MASK 0x600
110+ #define MSTATUS_VS_INITIAL 0x200
111+ #define MSTATUS_VS_CLEAN 0x400
112+ #define MSTATUS_VS_DIRTY 0x600
113+ #define MSTATUS_VS_OFFSET 9
114+
115+ #ifndef __riscv_vector
116+ #error configENABLE_VPU must not be set to 1 if the hardware does not have VPU
94117 #endif
95118#endif
96119/*-----------------------------------------------------------*/
@@ -181,6 +204,72 @@ addi sp, sp, ( portFPU_CONTEXT_SIZE )
181204 .endm
182205/*-----------------------------------------------------------*/
183206
207+ .macro portcontexSAVE_VPU_CONTEXT
208+ /* Un-reserve the space reserved for mstatus and epc. */
209+ add sp , sp , ( 2 * portWORD_SIZE )
210+
211+ csrr t0 , vlenb /* t0 = vlenb. vlenb is the length of each vector register in bytes. */
212+ slli t0 , t0 , 3 /* t0 = vlenb * 8. t0 now contains the space required to store 8 vector registers. */
213+ neg t0 , t0
214+
215+ /* Store the vector registers in group of 8. */
216+ add sp , sp , t0
217+ vs8r .v v0 , (sp ) /* Store v0-v7. */
218+ add sp , sp , t0
219+ vs8r .v v8 , (sp ) /* Store v8-v15. */
220+ add sp , sp , t0
221+ vs8r .v v16 , (sp ) /* Store v16-v23. */
222+ add sp , sp , t0
223+ vs8r .v v24 , (sp ) /* Store v24-v31. */
224+
225+ /* Store the VPU CSRs. */
226+ addi sp , sp , - ( 4 * portWORD_SIZE )
227+ csrr t0 , vstart
228+ store_x t0 , 0 * portWORD_SIZE ( sp )
229+ csrr t0 , vcsr
230+ store_x t0 , 1 * portWORD_SIZE ( sp )
231+ csrr t0 , vl
232+ store_x t0 , 2 * portWORD_SIZE ( sp )
233+ csrr t0 , vtype
234+ store_x t0 , 3 * portWORD_SIZE ( sp )
235+
236+ /* Re-reserve the space for mstatus and epc. */
237+ add sp , sp , - ( 2 * portWORD_SIZE )
238+ .endm
239+ /*-----------------------------------------------------------*/
240+
241+ .macro portcontextRESTORE_VPU_CONTEXT
242+ /* Un-reserve the space reserved for mstatus and epc. */
243+ add sp , sp , ( 2 * portWORD_SIZE )
244+
245+ /* Restore the VPU CSRs. */
246+ load_x t0 , 0 * portWORD_SIZE ( sp )
247+ csrw vstart , t0
248+ load_x t0 , 1 * portWORD_SIZE ( sp )
249+ csrw vcsr , t0
250+ load_x t0 , 2 * portWORD_SIZE ( sp )
251+ load_x t1 , 3 * portWORD_SIZE ( sp )
252+ vsetvl x0 , t0 , t1 /* vlen and vtype can only be updated by using vset*vl* instructions. */
253+ addi sp , sp , ( 4 * portWORD_SIZE )
254+
255+ csrr t0 , vlenb /* t0 = vlenb. vlenb is the length of each vector register in bytes. */
256+ slli t0 , t0 , 3 /* t0 = vlenb * 8. t0 now contains the space required to store 8 vector registers. */
257+
258+ /* Restore the vector registers. */
259+ vl8r .v v24 , (sp )
260+ add sp , sp , t0
261+ vl8r .v v16 , (sp )
262+ add sp , sp , t0
263+ vl8r .v v8 , (sp )
264+ add sp , sp , t0
265+ vl8r .v v0 , (sp )
266+ add sp , sp , t0
267+
268+ /* Re-reserve the space for mstatus and epc. */
269+ add sp , sp , - ( 2 * portWORD_SIZE )
270+ .endm
271+ /*-----------------------------------------------------------*/
272+
184273 .macro portcontextSAVE_CONTEXT_INTERNAL
185274addi sp , sp , - portCONTEXT_SIZE
186275store_x x1 , 2 * portWORD_SIZE ( sp )
@@ -228,6 +317,17 @@ store_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Store the criti
2283171 :
229318#endif
230319
320+ #if ( configENABLE_VPU == 1 )
321+ csrr t0 , mstatus
322+ srl t1 , t0 , MSTATUS_VS_OFFSET
323+ andi t1 , t1 , 3
324+ addi t2 , x0 , 3
325+ bne t1 , t2 , 2f /* If VPU status is not dirty, do not save FPU registers. */
326+
327+ portcontexSAVE_VPU_CONTEXT
328+ 2 :
329+ #endif
330+
231331portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */
232332
233333csrr t0 , mstatus
@@ -238,14 +338,29 @@ store_x t0, 1 * portWORD_SIZE( sp )
238338 srl t1 , t0 , MSTATUS_FS_OFFSET
239339 andi t1 , t1 , 3
240340 addi t2 , x0 , 3
241- bne t1 , t2 , 2f
341+ bne t1 , t2 , 3f
242342
243343 li t1 , ~MSTATUS_FS_MASK
244344 and t0 , t0 , t1
245345 li t1 , MSTATUS_FS_CLEAN
246346 or t0 , t0 , t1
247347 csrw mstatus , t0
248- 2 :
348+ 3 :
349+ #endif
350+
351+ #if ( configENABLE_VPU == 1 )
352+ /* Mark the VPU as clean, if it was dirty and we saved VPU registers. */
353+ srl t1 , t0 , MSTATUS_VS_OFFSET
354+ andi t1 , t1 , 3
355+ addi t2 , x0 , 3
356+ bne t1 , t2 , 4f
357+
358+ li t1 , ~MSTATUS_VS_MASK
359+ and t0 , t0 , t1
360+ li t1 , MSTATUS_VS_CLEAN
361+ or t0 , t0 , t1
362+ csrw mstatus , t0
363+ 4 :
249364#endif
250365
251366load_x t0 , pxCurrentTCB /* Load pxCurrentTCB. */
@@ -288,15 +403,26 @@ csrw mstatus, t0
288403/* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
289404portasmRESTORE_ADDITIONAL_REGISTERS
290405
406+ #if ( configENABLE_VPU == 1 )
407+ csrr t0 , mstatus
408+ srl t1 , t0 , MSTATUS_VS_OFFSET
409+ andi t1 , t1 , 3
410+ addi t2 , x0 , 3
411+ bne t1 , t2 , 5f /* If VPU status is not dirty, do not restore VPU registers. */
412+
413+ portcontextRESTORE_VPU_CONTEXT
414+ 5 :
415+ #endif /* ifdef portasmSTORE_VPU_CONTEXT */
416+
291417#if ( configENABLE_FPU == 1 )
292418 csrr t0 , mstatus
293419 srl t1 , t0 , MSTATUS_FS_OFFSET
294420 andi t1 , t1 , 3
295421 addi t2 , x0 , 3
296- bne t1 , t2 , 3f /* If FPU status is not dirty, do not restore FPU registers. */
422+ bne t1 , t2 , 6f /* If FPU status is not dirty, do not restore FPU registers. */
297423
298424 portcontextRESTORE_FPU_CONTEXT
299- 3 :
425+ 6 :
300426#endif /* ifdef portasmSTORE_FPU_CONTEXT */
301427
302428load_x t0 , portCRITICAL_NESTING_OFFSET * portWORD_SIZE ( sp ) /* Obtain xCriticalNesting value for this task from task's stack. */
0 commit comments