/* * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _HARDWARE_RISCV_ #define _HARDWARE_RISCV_ #include "pico.h" #include "hardware/regs/rvcsr.h" #ifndef __ASSEMBLER__ #ifdef __cplusplus extern "C" { #endif /** \file hardware/riscv.h * \defgroup hardware_riscv hardware_riscv * * \brief Accessors for standard RISC-V hardware (mainly CSRs) * */ #define _riscv_read_csr(csrname) ({ \ uint32_t __csr_tmp_u32; \ asm volatile ("csrr %0, " #csrname : "=r" (__csr_tmp_u32)); \ __csr_tmp_u32; \ }) #define _riscv_write_csr(csrname, data) ({ \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrwi " #csrname ", %0" : : "i" (data)); \ } else { \ asm volatile ("csrw " #csrname ", %0" : : "r" (data)); \ } \ }) #define _riscv_set_csr(csrname, data) ({ \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrsi " #csrname ", %0" : : "i" (data)); \ } else { \ asm volatile ("csrs " #csrname ", %0" : : "r" (data)); \ } \ }) #define _riscv_clear_csr(csrname, data) ({ \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrci " #csrname ", %0" : : "i" (data)); \ } else { \ asm volatile ("csrc " #csrname ", %0" : : "r" (data)); \ } \ }) #define _riscv_read_write_csr(csrname, data) ({ \ uint32_t __csr_tmp_u32; \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrrwi %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \ } else { \ asm volatile ("csrrw %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \ } \ __csr_tmp_u32; \ }) #define _riscv_read_set_csr(csrname, data) ({ \ uint32_t __csr_tmp_u32; \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrrsi %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \ } else { \ asm volatile ("csrrs %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \ } \ __csr_tmp_u32; \ }) #define _riscv_read_clear_csr(csrname, data) ({ \ uint32_t __csr_tmp_u32; \ if (__builtin_constant_p(data) && !((data) & -32u)) { \ asm volatile ("csrrci %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "i" (data)); \ } else { \ asm volatile ("csrrc %0, " #csrname ", %1": "=r" (__csr_tmp_u32) : "r" (data)); \ } \ __csr_tmp_u32; \ }) // Argument macro expansion layer (CSR name may be a macro that expands to a // CSR number, or it may be a bare name that the assembler knows about.) #define riscv_read_csr(csrname) _riscv_read_csr(csrname) #define riscv_write_csr(csrname, data) _riscv_write_csr(csrname, data) #define riscv_set_csr(csrname, data) _riscv_set_csr(csrname, data) #define riscv_clear_csr(csrname, data) _riscv_clear_csr(csrname, data) #define riscv_read_write_csr(csrname, data) _riscv_read_write_csr(csrname, data) #define riscv_read_set_csr(csrname, data) _riscv_read_set_csr(csrname, data) #define riscv_read_clear_csr(csrname, data) _riscv_read_clear_csr(csrname, data) // Helpers for encoding RISC-V immediates // U format, e.g. lui static inline uint32_t riscv_encode_imm_u(uint32_t x) { return (x >> 12) << 12; } // I format, e.g. addi static inline uint32_t riscv_encode_imm_i(uint32_t x) { return (x & 0xfff) << 20; } // The U-format part of a U+I 32-bit immediate: static inline uint32_t riscv_encode_imm_u_hi(uint32_t x) { // We will add a signed 12 bit constant to the "lui" value, // so we need to correct for the carry here. x += (x & 0x800) << 1; return riscv_encode_imm_u(x); } // B format, e.g. bgeu static inline uint32_t riscv_encode_imm_b(uint32_t x) { return (((x >> 12) & 0x01) << 31) | (((x >> 5) & 0x3f) << 25) | (((x >> 1) & 0x0f) << 8) | (((x >> 11) & 0x01) << 7); } // S format, e.g. sw static inline uint32_t riscv_encode_imm_s(uint32_t x) { return (((x >> 5) & 0x7f) << 25) | (((x >> 0) & 0x1f) << 7); } // J format, e.g. jal static inline uint32_t riscv_encode_imm_j(uint32_t x) { return (((x >> 20) & 0x001) << 31) | (((x >> 1) & 0x3ff) << 21) | (((x >> 11) & 0x001) << 20) | (((x >> 12) & 0x0ff) << 12); } // CJ format, e.g. c.jal static inline uint16_t riscv_encode_imm_cj(uint32_t x) { return (uint16_t)( (((x >> 11) & 0x1) << 12) | (((x >> 4) & 0x1) << 11) | (((x >> 8) & 0x3) << 9) | (((x >> 10) & 0x1) << 8) | (((x >> 6) & 0x1) << 7) | (((x >> 7) & 0x1) << 6) | (((x >> 1) & 0x7) << 3) | (((x >> 5) & 0x1) << 2) ); } // CB format, e.g. c.beqz static inline uint16_t riscv_encode_imm_cb(uint32_t x) { return (uint16_t)( (((x >> 8) & 0x1) << 12) | (((x >> 3) & 0x3) << 10) | (((x >> 6) & 0x3) << 5) | (((x >> 1) & 0x3) << 3) | (((x >> 5) & 0x1) << 2) ); } // CI format, e.g. c.addi static inline uint16_t riscv_encode_imm_ci(uint32_t x) { return (uint16_t)( (((x >> 5) & 0x01) << 12) | (((x >> 0) & 0x1f) << 2) ); } #ifdef __cplusplus } #endif #endif #endif