| /* |
| * SPDX-License-Identifier: BSD-2-Clause |
| * |
| * Copyright (c) 2019 Western Digital Corporation or its affiliates. |
| * |
| * Authors: |
| * Anup Patel <anup.patel@wdc.com> |
| */ |
| |
| #ifndef __RISCV_ASM_H__ |
| #define __RISCV_ASM_H__ |
| |
| #ifdef __ASSEMBLY__ |
| #define __ASM_STR(x) x |
| #else |
| #define __ASM_STR(x) #x |
| #endif |
| |
| #if __riscv_xlen == 64 |
| #define __REG_SEL(a, b) __ASM_STR(a) |
| #elif __riscv_xlen == 32 |
| #define __REG_SEL(a, b) __ASM_STR(b) |
| #else |
| #error "Unexpected __riscv_xlen" |
| #endif |
| |
| #define REG_L __REG_SEL(ld, lw) |
| #define REG_S __REG_SEL(sd, sw) |
| #define SZREG __REG_SEL(8, 4) |
| #define LGREG __REG_SEL(3, 2) |
| |
| #if __SIZEOF_POINTER__ == 8 |
| #define BITS_PER_LONG 64 |
| #ifdef __ASSEMBLY__ |
| #define RISCV_PTR .dword |
| #define RISCV_SZPTR 8 |
| #define RISCV_LGPTR 3 |
| #else |
| #define RISCV_PTR ".dword" |
| #define RISCV_SZPTR "8" |
| #define RISCV_LGPTR "3" |
| #endif |
| #elif __SIZEOF_POINTER__ == 4 |
| #define BITS_PER_LONG 32 |
| #ifdef __ASSEMBLY__ |
| #define RISCV_PTR .word |
| #define RISCV_SZPTR 4 |
| #define RISCV_LGPTR 2 |
| #else |
| #define RISCV_PTR ".word" |
| #define RISCV_SZPTR "4" |
| #define RISCV_LGPTR "2" |
| #endif |
| #else |
| #error "Unexpected __SIZEOF_POINTER__" |
| #endif |
| |
| #if (__SIZEOF_INT__ == 4) |
| #define RISCV_INT __ASM_STR(.word) |
| #define RISCV_SZINT __ASM_STR(4) |
| #define RISCV_LGINT __ASM_STR(2) |
| #else |
| #error "Unexpected __SIZEOF_INT__" |
| #endif |
| |
| #if (__SIZEOF_SHORT__ == 2) |
| #define RISCV_SHORT __ASM_STR(.half) |
| #define RISCV_SZSHORT __ASM_STR(2) |
| #define RISCV_LGSHORT __ASM_STR(1) |
| #else |
| #error "Unexpected __SIZEOF_SHORT__" |
| #endif |
| |
| #ifndef __ASSEMBLY__ |
| |
| #define csr_swap(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrrw %0, " __ASM_STR(csr) ", %1"\ |
| : "=r" (__v) : "rK" (__v) \ |
| : "memory"); \ |
| __v; \ |
| }) |
| |
| #define csr_read(csr) \ |
| ({ \ |
| register unsigned long __v; \ |
| __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ |
| : "=r" (__v) : \ |
| : "memory"); \ |
| __v; \ |
| }) |
| |
| #define csr_write(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ |
| : : "rK" (__v) \ |
| : "memory"); \ |
| }) |
| |
| #define csr_read_set(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrrs %0, " __ASM_STR(csr) ", %1"\ |
| : "=r" (__v) : "rK" (__v) \ |
| : "memory"); \ |
| __v; \ |
| }) |
| |
| #define csr_set(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrs " __ASM_STR(csr) ", %0" \ |
| : : "rK" (__v) \ |
| : "memory"); \ |
| }) |
| |
| #define csr_read_clear(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrrc %0, " __ASM_STR(csr) ", %1"\ |
| : "=r" (__v) : "rK" (__v) \ |
| : "memory"); \ |
| __v; \ |
| }) |
| |
| #define csr_clear(csr, val) \ |
| ({ \ |
| unsigned long __v = (unsigned long)(val); \ |
| __asm__ __volatile__ ("csrc " __ASM_STR(csr) ", %0" \ |
| : : "rK" (__v) \ |
| : "memory"); \ |
| }) |
| |
| unsigned long csr_read_num(int csr_num); |
| |
| void csr_write_num(int csr_num, unsigned long val); |
| |
| #define wfi() \ |
| do { \ |
| __asm__ __volatile__ ("wfi" ::: "memory"); \ |
| } while (0) |
| |
| static inline int misa_extension(char ext) |
| { |
| return csr_read(misa) & (1 << (ext - 'A')); |
| } |
| |
| static inline int misa_xlen(void) |
| { |
| return ((long)csr_read(misa) < 0) ? 64 : 32; |
| } |
| |
| static inline void misa_string(char *out, unsigned int out_sz) |
| { |
| unsigned long i, val = csr_read(misa); |
| |
| for (i = 0; i < 26; i++) { |
| if (val & (1 << i)) { |
| *out = 'A' + i; |
| out++; |
| } |
| } |
| *out = '\0'; |
| out++; |
| } |
| |
| int pmp_set(unsigned int n, unsigned long prot, |
| unsigned long addr, unsigned long log2len); |
| |
| int pmp_get(unsigned int n, unsigned long *prot_out, |
| unsigned long *addr_out, unsigned long *log2len_out); |
| |
| #endif /* !__ASSEMBLY__ */ |
| |
| #endif |