├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── examples ├── .vscode │ ├── c_cpp_properties.json │ └── tasks.json ├── Makefile ├── test_csr.c ├── test_csr.c.rv32imac.disasm ├── test_csr.c.rv64imac.disasm ├── test_csr.cpp ├── test_csr.cpp.rv32imac.disasm ├── test_csr.cpp.rv64imac.disasm ├── test_csr.rv32imac.disasm └── test_csr.rv64imac.disasm ├── include ├── riscv-csr.h └── riscv-csr.hpp ├── requirements.txt ├── rs └── riscv_csr_macros │ ├── .cargo │ └── config │ ├── Cargo.toml │ ├── README.md │ ├── examples │ └── test_csr.rs │ └── src │ └── riscv_csr_macros.rs └── templates ├── riscv-csr.h ├── riscv-csr.hpp ├── riscv_csr_filters.py └── riscv_csr_macros.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | *.elf 34 | 35 | # Python 36 | *.pyc 37 | 38 | # Emacs! 39 | *~ 40 | 41 | # Rust 42 | rs/riscv_csr_macros/target 43 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extern/development-utils"] 2 | path = extern/development-utils 3 | url = https://github.com/nakane1chome/development-utils.git 4 | [submodule "extern/riscv-isa-data"] 5 | path = extern/riscv-isa-data 6 | url = https://github.com/five-embeddev/riscv-isa-data.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GENERATOR_PATH=extern/development-utils/generators/ 2 | ISA_DATA_PATH=extern/riscv-isa-data/ 3 | 4 | all : \ 5 | include/riscv-csr.hpp \ 6 | include/riscv-csr.h \ 7 | rs/riscv_csr_macros/src/riscv_csr_macros.rs 8 | 9 | # Generate generic riscv CSR definitions 10 | include/% : templates/% 11 | ${GENERATOR_PATH}/yaml_jinja.py \ 12 | --filter templates/riscv_csr_filters.py \ 13 | ${ISA_DATA_PATH}/csr.yaml \ 14 | $< \ 15 | $@ 16 | 17 | # Generate generic riscv CSR definitions 18 | rs/riscv_csr_macros/src/riscv_csr_macros.rs : templates/riscv_csr_macros.rs 19 | ${GENERATOR_PATH}/yaml_jinja.py \ 20 | --filter templates/riscv_csr_filters.py \ 21 | ${ISA_DATA_PATH}/csr.yaml \ 22 | $< \ 23 | $@ 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RISC-V CSR Access Routines 2 | 3 | RISC-V System Register Access Routines in various languages. 4 | 5 | For more information see 6 | 7 | The register acccess funtions and classes are generated from templates 8 | based on a yaml definition file. 9 | 10 | Files: 11 | 12 | - `include/riscv-csr.h`: C using macros. 13 | - `include/riscv-csr.hpp`: C++ using an a class interface. 14 | - `rs/riscv_csr_macros/src/riscv_csr_macros.rs`: Rust using macros. 15 | 16 | Generators: 17 | 18 | - `templates/*` : Jinja2 template files used to generate `include/*` 19 | - `templates/riscv_csr_filters.py` : Helper functions for templates. 20 | - `extern/development-utils/generators/yaml_jinja.py` : Program used to generate source code. See . 21 | - `extern/riscv-isa-data/csr.yaml` : CSR definitions. See . 22 | 23 | Examples: 24 | 25 | - `examples/test_csr.c` : Example of using `riscv-csr.h` 26 | - `examples/test_csr.cpp` : Example of using `riscv-csr.hpp` 27 | - `rs/riscv_csr_macros/examples/test_csr.rs` : Example of using `riscv_csr_macros.rs` 28 | -------------------------------------------------------------------------------- /examples/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ARM", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/../include/" 8 | ], 9 | "defines": [ 10 | "_DEBUG", 11 | "__riscv_xlen=32" 12 | ], 13 | "cStandard": "c11", 14 | "cppStandard": "c++17", 15 | "intelliSenseMode": "msvc-x64" 16 | } 17 | ], 18 | "version": 4 19 | } 20 | -------------------------------------------------------------------------------- /examples/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "presentation" : { "reveal": "always" }, 10 | "command": "bash", 11 | "args": ["-c", "make "], 12 | "options": { 13 | "cwd": "${workspaceRoot}" 14 | }, 15 | "group": "build", 16 | "problemMatcher": { 17 | "owner": "cpp", 18 | "fileLocation": ["relative", "${workspaceFolder}"], 19 | "pattern": { 20 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 21 | "file": 1, 22 | "line": 2, 23 | "column": 3, 24 | "severity": 4, 25 | "message": 5 26 | } 27 | } 28 | }, 29 | { 30 | "label": "clean", 31 | "type": "shell", 32 | "presentation" : { "reveal": "always" }, 33 | "command": "bash", 34 | "args": ["-c", "make ", "clean"], 35 | "options": { 36 | "cwd": "${workspaceRoot}" 37 | }, 38 | "group": "build", 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | SRC=test_csr.c 2 | SRC_BASE=test_csr 3 | #CROSS_COMPILE=riscv-none-embed- 4 | CROSS_COMPILE=riscv-none-elf- 5 | GCC=${CROSS_COMPILE}gcc 6 | GXX=${CROSS_COMPILE}g++ 7 | OBJDUMP=${CROSS_COMPILE}objdump 8 | 9 | SPEC_TARGETS=\ 10 | rv32imac_zicsr \ 11 | rv64imac_zicsr 12 | 13 | MABI_rv32imac_zicsr=ilp32 14 | MABI_rv64imac_zicsr=lp64 15 | 16 | ALL=\ 17 | $(SPEC_TARGETS:%=test_csr.c.%.disasm) \ 18 | $(SPEC_TARGETS:%=test_csr.cpp.%.disasm) 19 | 20 | all : ${ALL} 21 | 22 | ${SRC_BASE}.c.%.disasm : ${SRC_BASE}.c 23 | @echo "[TARGET $*]" 24 | ${GCC} \ 25 | -nostartfiles \ 26 | -Werror \ 27 | -Wl,--defsym,_start=0x1000 \ 28 | -I ../include \ 29 | -march=${*} \ 30 | -mabi=${MABI_${*}} \ 31 | -Os \ 32 | -g \ 33 | $< -o $(basename $@).elf 34 | ${OBJDUMP} -S $(basename $@).elf > $@ 35 | 36 | 37 | ${SRC_BASE}.cpp.%.disasm : ${SRC_BASE}.cpp 38 | @echo "[TARGET $*]" 39 | ${GXX} \ 40 | -nostartfiles \ 41 | -Werror \ 42 | -Wl,--defsym,_start=0x1000 \ 43 | -I ../include \ 44 | -march=${*} \ 45 | -mabi=${MABI_${*}} \ 46 | -Os \ 47 | -g \ 48 | -std=c++17 \ 49 | $< -o $(basename $@).elf 50 | ${OBJDUMP} -S $(basename $@).elf > $@ 51 | 52 | test_csr.c.rv32imac.disasm : ../include/riscv-csr.h 53 | 54 | test_csr.c.rv64imac.disasm : ../include/riscv-csr.h 55 | 56 | test_csr.cpp.rv32imac.disasm : ../include/riscv-csr.hpp 57 | 58 | test_csr.cpp.rv64imac.disasm : ../include/riscv-csr.hpp 59 | 60 | clean : 61 | rm -f ${ALL} 62 | -------------------------------------------------------------------------------- /examples/test_csr.c: -------------------------------------------------------------------------------- 1 | /* 2 | Register access functions for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #include "riscv-csr.h" 10 | 11 | static volatile uint_xlen_t saved_mtvec; 12 | 13 | int main(void) { 14 | 15 | uint_xlen_t cause = csr_read_mcause(); 16 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) { 17 | // Interrupt 18 | uint_xlen_t csr_read_mip(); 19 | } else { 20 | // Exception 21 | // Read the source of the exception 22 | uint_xlen_t mepc = csr_read_mepc(); 23 | // Pointless save to mscratch 24 | csr_write_mscratch(mepc); 25 | } 26 | // Enable MIE.MSI 27 | CSR_SET_BITS_IMM_MIE(MIE_MSI_BIT_MASK); 28 | // Enable MIE.MTI 29 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 30 | // Clear mode and read mtvec. 31 | uint_xlen_t old_mtvec = csr_read_clr_bits_mtvec(MTVEC_MODE_ALL_SET_MASK); 32 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) { 33 | // Remove mode bits 34 | old_mtvec &= MTVEC_BASE_ALL_SET_MASK; 35 | } 36 | saved_mtvec = old_mtvec; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /examples/test_csr.c.rv32imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.c.rv32imac.elf: file format elf32-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00010074
: 8 | /******************************************* 9 | * mcause - MRW - Machine Exception Cause 10 | */ 11 | static inline uint_xlen_t csr_read_mcause(void) { 12 | uint_xlen_t value; 13 | __asm__ volatile ("csrr %0, mcause" 14 | 10074: 342027f3 csrr a5,mcause 15 | static volatile uint_xlen_t saved_mtvec; 16 | 17 | int main(void) { 18 | 19 | uint_xlen_t cause = csr_read_mcause(); 20 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) { 21 | 10078: 0007c663 bltz a5,10084 22 | __asm__ volatile ("csrr %0, mepc" 23 | 1007c: 341027f3 csrr a5,mepc 24 | __asm__ volatile ("csrw mscratch, %0" 25 | 10080: 34079073 csrw mscratch,a5 26 | uint_xlen_t mepc = csr_read_mepc(); 27 | // Pointless save to mscratch 28 | csr_write_mscratch(mepc); 29 | } 30 | // Enable MIE.MSI 31 | CSR_SET_BITS_IMM_MIE(MIE_MSI_BIT_MASK); 32 | 10084: 30446073 csrsi mie,8 33 | __asm__ volatile ("csrrs zero, mie, %0" 34 | 10088: 08000793 li a5,128 35 | 1008c: 3047a073 csrs mie,a5 36 | __asm__ volatile ("csrrc %0, mtvec, %1" 37 | 10090: 478d li a5,3 38 | 10092: 3057b7f3 csrrc a5,mtvec,a5 39 | // Enable MIE.MTI 40 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 41 | // Clear mode and read mtvec. 42 | uint_xlen_t old_mtvec = csr_read_clr_bits_mtvec(MTVEC_MODE_ALL_SET_MASK); 43 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) { 44 | 10096: 0037f713 andi a4,a5,3 45 | 1009a: c701 beqz a4,100a2 46 | // Remove mode bits 47 | old_mtvec &= MTVEC_BASE_ALL_SET_MASK; 48 | 1009c: 20000737 lui a4,0x20000 49 | 100a0: 8ff9 and a5,a5,a4 50 | } 51 | saved_mtvec = old_mtvec; 52 | 100a2: 6745 lui a4,0x11 53 | 100a4: 0af72623 sw a5,172(a4) # 110ac <__DATA_BEGIN__> 54 | 55 | } 56 | 100a8: 4501 li a0,0 57 | 100aa: 8082 ret 58 | -------------------------------------------------------------------------------- /examples/test_csr.c.rv64imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.c.rv64imac.elf: file format elf64-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00000000000100b0
: 8 | /******************************************* 9 | * mcause - MRW - Machine Exception Cause 10 | */ 11 | static inline uint_xlen_t csr_read_mcause(void) { 12 | uint_xlen_t value; 13 | __asm__ volatile ("csrr %0, mcause" 14 | 100b0: 342027f3 csrr a5,mcause 15 | static volatile uint_xlen_t saved_mtvec; 16 | 17 | int main(void) { 18 | 19 | uint_xlen_t cause = csr_read_mcause(); 20 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) { 21 | 100b4: 0007c663 bltz a5,100c0 22 | __asm__ volatile ("csrr %0, mepc" 23 | 100b8: 341027f3 csrr a5,mepc 24 | __asm__ volatile ("csrw mscratch, %0" 25 | 100bc: 34079073 csrw mscratch,a5 26 | uint_xlen_t mepc = csr_read_mepc(); 27 | // Pointless save to mscratch 28 | csr_write_mscratch(mepc); 29 | } 30 | // Enable MIE.MSI 31 | CSR_SET_BITS_IMM_MIE(MIE_MSI_BIT_MASK); 32 | 100c0: 30446073 csrsi mie,8 33 | __asm__ volatile ("csrrs zero, mie, %0" 34 | 100c4: 08000793 li a5,128 35 | 100c8: 3047a073 csrs mie,a5 36 | __asm__ volatile ("csrrc %0, mtvec, %1" 37 | 100cc: 478d li a5,3 38 | 100ce: 3057b7f3 csrrc a5,mtvec,a5 39 | // Enable MIE.MTI 40 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 41 | // Clear mode and read mtvec. 42 | uint_xlen_t old_mtvec = csr_read_clr_bits_mtvec(MTVEC_MODE_ALL_SET_MASK); 43 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) { 44 | 100d2: 0037f713 andi a4,a5,3 45 | 100d6: c701 beqz a4,100de 46 | // Remove mode bits 47 | old_mtvec &= MTVEC_BASE_ALL_SET_MASK; 48 | 100d8: 4705 li a4,1 49 | 100da: 1776 slli a4,a4,0x3d 50 | 100dc: 8ff9 and a5,a5,a4 51 | } 52 | saved_mtvec = old_mtvec; 53 | 100de: 6745 lui a4,0x11 54 | 100e0: 0ef73423 sd a5,232(a4) # 110e8 <__DATA_BEGIN__> 55 | 56 | } 57 | 100e4: 4501 li a0,0 58 | 100e6: 8082 ret 59 | -------------------------------------------------------------------------------- /examples/test_csr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Register access functions for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #include "riscv-csr.hpp" 10 | 11 | static volatile riscv::csr::uint_xlen_t saved_mtvec; 12 | 13 | int main(void) { 14 | 15 | riscv::csr::all csrs; 16 | 17 | auto cause = csrs.mcause.read(); 18 | if (cause & riscv::csr::mcause_data::interrupt::BIT_MASK) { 19 | // Interrupt 20 | auto mip = csrs.mip.read(); 21 | } else { 22 | // Exception 23 | // Read the source of the exception 24 | auto mepc = csrs.mepc.read(); 25 | // Pointless save to mscratch 26 | csrs.mscratch.write(mepc); 27 | } 28 | // Enable MIE.MSI 29 | csrs.mie.msi.set(); 30 | // Enable MIE.MTI 31 | csrs.mie.mti.set(); 32 | // Clear mode and read mtvec. 33 | auto old_mtvec = csrs.mtvec.read_clr_bits_const(); 34 | if (old_mtvec & riscv::csr::mtvec_data::mode::ALL_SET_MASK) { 35 | // Remove mode bits 36 | old_mtvec &= riscv::csr::mtvec_data::base::ALL_SET_MASK; 37 | } 38 | saved_mtvec = old_mtvec; 39 | 40 | // ---- 41 | // Try writing const values 42 | 43 | // Write via a register value to the MTVEC 44 | csrs.mtvec.write(0x10); 45 | // Write an immediate value to the MTVEC 46 | csrs.mtvec.write_const<0x10>(); 47 | // Write via a register value to the MTVEC 48 | csrs.mtvec.write_const<0x100000>(); 49 | 50 | // ---- 51 | // Try out the operators 52 | 53 | // Read mcycle via default operator 54 | auto mcycle = csrs.mcycle(); 55 | 56 | #if 0 // TODO - upgrade to gcc that supports these CSRs 57 | // Disable all the counters 58 | csrs.mcountinhibit |= 0xFFFFFFFF; 59 | 60 | // Enable the instruction retired count 61 | csrs.mcountinhibit.ir.clr(); 62 | // Enable the cycle count 63 | csrs.mcountinhibit.cy.write(0); 64 | // Enable the hpm count 65 | csrs.mcountinhibit.hpm.clr(); 66 | #endif 67 | } 68 | -------------------------------------------------------------------------------- /examples/test_csr.cpp.rv32imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.cpp.rv32imac.elf: file format elf32-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00010074
: 8 | static uint_xlen_t read(void) { 9 | uint_xlen_t value; 10 | __asm__ volatile ("csrr %0, mcause" 11 | : "=r" (value) /* output : register */ 12 | : /* input : none */ 13 | : /* clobbers: none */); 14 | 10074: 342027f3 csrr a5,mcause 15 | int main(void) { 16 | 17 | riscv::csr::all csrs; 18 | 19 | auto cause = csrs.mcause.read(); 20 | if (cause & riscv::csr::mcause_data::interrupt::BIT_MASK) { 21 | 10078: 0407d263 bgez a5,100bc 22 | : /* clobbers: none */); 23 | 1007c: 344027f3 csrr a5,mip 24 | : /* clobbers: none */); 25 | 10080: 30446073 csrsi mie,8 26 | : /* clobbers: none */); 27 | 10084: 08000793 li a5,128 28 | 10088: 3047a073 csrs mie,a5 29 | : /* clobbers: none */); 30 | 1008c: 3051f7f3 csrrci a5,mtvec,3 31 | csrs.mie.msi.set(); 32 | // Enable MIE.MTI 33 | csrs.mie.mti.set(); 34 | // Clear mode and read mtvec. 35 | auto old_mtvec = csrs.mtvec.read_clr_bits_const(); 36 | if (old_mtvec & riscv::csr::mtvec_data::mode::ALL_SET_MASK) { 37 | 10090: 0037f713 andi a4,a5,3 38 | 10094: c701 beqz a4,1009c 39 | // Remove mode bits 40 | old_mtvec &= riscv::csr::mtvec_data::base::ALL_SET_MASK; 41 | 10096: 20000737 lui a4,0x20000 42 | 1009a: 8ff9 and a5,a5,a4 43 | } 44 | saved_mtvec = old_mtvec; 45 | 1009c: 6745 lui a4,0x11 46 | 1009e: 0ef72823 sw a5,240(a4) # 110f0 <__DATA_BEGIN__> 47 | : /* clobbers: none */); 48 | 100a2: 47c1 li a5,16 49 | 100a4: 30579073 csrw mtvec,a5 50 | : /* clobbers: none */); 51 | 100a8: 30585073 csrwi mtvec,16 52 | : /* clobbers: none */); 53 | 100ac: 001007b7 lui a5,0x100 54 | 100b0: 30579073 csrw mtvec,a5 55 | : /* clobbers: none */); 56 | 100b4: b00027f3 csrr a5,mcycle 57 | // Enable the cycle count 58 | csrs.mcountinhibit.cy.write(0); 59 | // Enable the hpm count 60 | csrs.mcountinhibit.hpm.clr(); 61 | #endif 62 | } 63 | 100b8: 4501 li a0,0 64 | 100ba: 8082 ret 65 | : /* clobbers: none */); 66 | 100bc: 341027f3 csrr a5,mepc 67 | : /* clobbers: none */); 68 | 100c0: 34079073 csrw mscratch,a5 69 | 100c4: bf75 j 10080 70 | -------------------------------------------------------------------------------- /examples/test_csr.cpp.rv64imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.cpp.rv64imac.elf: file format elf64-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00000000000100b0
: 8 | static uint_xlen_t read(void) { 9 | uint_xlen_t value; 10 | __asm__ volatile ("csrr %0, mcause" 11 | : "=r" (value) /* output : register */ 12 | : /* input : none */ 13 | : /* clobbers: none */); 14 | 100b0: 342027f3 csrr a5,mcause 15 | int main(void) { 16 | 17 | riscv::csr::all csrs; 18 | 19 | auto cause = csrs.mcause.read(); 20 | if (cause & riscv::csr::mcause_data::interrupt::BIT_MASK) { 21 | 100b4: 0407d263 bgez a5,100f8 22 | : /* clobbers: none */); 23 | 100b8: 344027f3 csrr a5,mip 24 | : /* clobbers: none */); 25 | 100bc: 30446073 csrsi mie,8 26 | : /* clobbers: none */); 27 | 100c0: 08000793 li a5,128 28 | 100c4: 3047a073 csrs mie,a5 29 | : /* clobbers: none */); 30 | 100c8: 3051f7f3 csrrci a5,mtvec,3 31 | csrs.mie.msi.set(); 32 | // Enable MIE.MTI 33 | csrs.mie.mti.set(); 34 | // Clear mode and read mtvec. 35 | auto old_mtvec = csrs.mtvec.read_clr_bits_const(); 36 | if (old_mtvec & riscv::csr::mtvec_data::mode::ALL_SET_MASK) { 37 | 100cc: 0037f713 andi a4,a5,3 38 | 100d0: c701 beqz a4,100d8 39 | // Remove mode bits 40 | old_mtvec &= riscv::csr::mtvec_data::base::ALL_SET_MASK; 41 | 100d2: 4705 li a4,1 42 | 100d4: 1776 slli a4,a4,0x3d 43 | 100d6: 8ff9 and a5,a5,a4 44 | } 45 | saved_mtvec = old_mtvec; 46 | 100d8: 6745 lui a4,0x11 47 | 100da: 12f73823 sd a5,304(a4) # 11130 <__DATA_BEGIN__> 48 | : /* clobbers: none */); 49 | 100de: 47c1 li a5,16 50 | 100e0: 30579073 csrw mtvec,a5 51 | : /* clobbers: none */); 52 | 100e4: 30585073 csrwi mtvec,16 53 | : /* clobbers: none */); 54 | 100e8: 001007b7 lui a5,0x100 55 | 100ec: 30579073 csrw mtvec,a5 56 | : /* clobbers: none */); 57 | 100f0: b00027f3 csrr a5,mcycle 58 | // Enable the cycle count 59 | csrs.mcountinhibit.cy.write(0); 60 | // Enable the hpm count 61 | csrs.mcountinhibit.hpm.clr(); 62 | #endif 63 | } 64 | 100f4: 4501 li a0,0 65 | 100f6: 8082 ret 66 | : /* clobbers: none */); 67 | 100f8: 341027f3 csrr a5,mepc 68 | : /* clobbers: none */); 69 | 100fc: 34079073 csrw mscratch,a5 70 | 10100: bf75 j 100bc 71 | -------------------------------------------------------------------------------- /examples/test_csr.rv32imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.rv32imac.elf: file format elf32-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00010074
: 8 | /******************************************* 9 | * mcause - MRW - Machine Exception Cause 10 | */ 11 | static inline uint_xlen_t csr_read_mcause(void) { 12 | uint_xlen_t value; 13 | __asm__ volatile ("csrr %0, mcause" 14 | 10074: 342027f3 csrr a5,mcause 15 | static volatile uint_xlen_t saved_mtvec; 16 | 17 | int main(void) { 18 | 19 | uint_xlen_t cause = csr_read_mcause(); 20 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) { 21 | 10078: 0007c663 bltz a5,10084 22 | __asm__ volatile ("csrr %0, mepc" 23 | 1007c: 341027f3 csrr a5,mepc 24 | __asm__ volatile ("csrw mscratch, %0" 25 | 10080: 34079073 csrw mscratch,a5 26 | uint_xlen_t mepc = csr_read_mepc(); 27 | // Pointless save to mscratch 28 | csr_write_mscratch(mepc); 29 | } 30 | // Enable MIE.MSI 31 | CSR_SET_BITS_IMM_MIE(MIE_MSI_BIT_MASK); 32 | 10084: 30446073 csrsi mie,8 33 | __asm__ volatile ("csrrs zero, mie, %0" 34 | 10088: 08000793 li a5,128 35 | 1008c: 3047a073 csrs mie,a5 36 | __asm__ volatile ("csrrc %0, mtvec, %1" 37 | 10090: 478d li a5,3 38 | 10092: 3057b7f3 csrrc a5,mtvec,a5 39 | // Enable MIE.MTI 40 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 41 | // Clear mode and read mtvec. 42 | uint_xlen_t old_mtvec = csr_read_clr_bits_mtvec(MTVEC_MODE_ALL_SET_MASK); 43 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) { 44 | 10096: 0037f713 andi a4,a5,3 45 | 1009a: c701 beqz a4,100a2 46 | // Remove mode bits 47 | old_mtvec &= MTVEC_BASE_ALL_SET_MASK; 48 | 1009c: 20000737 lui a4,0x20000 49 | 100a0: 8ff9 and a5,a5,a4 50 | } 51 | saved_mtvec = old_mtvec; 52 | 100a2: 6745 lui a4,0x11 53 | 100a4: 0af72623 sw a5,172(a4) # 110ac <__DATA_BEGIN__> 54 | } 55 | 100a8: 4501 li a0,0 56 | 100aa: 8082 ret 57 | -------------------------------------------------------------------------------- /examples/test_csr.rv64imac.disasm: -------------------------------------------------------------------------------- 1 | 2 | test_csr.rv64imac.elf: file format elf64-littleriscv 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 00000000000100b0
: 8 | /******************************************* 9 | * mcause - MRW - Machine Exception Cause 10 | */ 11 | static inline uint_xlen_t csr_read_mcause(void) { 12 | uint_xlen_t value; 13 | __asm__ volatile ("csrr %0, mcause" 14 | 100b0: 342027f3 csrr a5,mcause 15 | static volatile uint_xlen_t saved_mtvec; 16 | 17 | int main(void) { 18 | 19 | uint_xlen_t cause = csr_read_mcause(); 20 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) { 21 | 100b4: 0007c663 bltz a5,100c0 22 | __asm__ volatile ("csrr %0, mepc" 23 | 100b8: 341027f3 csrr a5,mepc 24 | __asm__ volatile ("csrw mscratch, %0" 25 | 100bc: 34079073 csrw mscratch,a5 26 | uint_xlen_t mepc = csr_read_mepc(); 27 | // Pointless save to mscratch 28 | csr_write_mscratch(mepc); 29 | } 30 | // Enable MIE.MSI 31 | CSR_SET_BITS_IMM_MIE(MIE_MSI_BIT_MASK); 32 | 100c0: 30446073 csrsi mie,8 33 | __asm__ volatile ("csrrs zero, mie, %0" 34 | 100c4: 08000793 li a5,128 35 | 100c8: 3047a073 csrs mie,a5 36 | __asm__ volatile ("csrrc %0, mtvec, %1" 37 | 100cc: 478d li a5,3 38 | 100ce: 3057b7f3 csrrc a5,mtvec,a5 39 | // Enable MIE.MTI 40 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 41 | // Clear mode and read mtvec. 42 | uint_xlen_t old_mtvec = csr_read_clr_bits_mtvec(MTVEC_MODE_ALL_SET_MASK); 43 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) { 44 | 100d2: 0037f713 andi a4,a5,3 45 | 100d6: c701 beqz a4,100de 46 | // Remove mode bits 47 | old_mtvec &= MTVEC_BASE_ALL_SET_MASK; 48 | 100d8: 4705 li a4,1 49 | 100da: 1776 slli a4,a4,0x3d 50 | 100dc: 8ff9 and a5,a5,a4 51 | } 52 | saved_mtvec = old_mtvec; 53 | 100de: 6745 lui a4,0x11 54 | 100e0: 0ef73423 sd a5,232(a4) # 110e8 <__DATA_BEGIN__> 55 | } 56 | 100e4: 4501 li a0,0 57 | 100e6: 8082 ret 58 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Python dependencies 2 | # Install via 3 | # pip install -r requirements.txt 4 | jinja2 5 | pyyaml 6 | -------------------------------------------------------------------------------- /rs/riscv_csr_macros/.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "riscv32imac-unknown-none-elf" 3 | -------------------------------------------------------------------------------- /rs/riscv_csr_macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | 11 | [lib] 12 | name="riscv_csr_macros" 13 | path="src/riscv_csr_macros.rs" 14 | 15 | [[example]] 16 | name="test_csr" 17 | path="examples/test_csr.rs" 18 | -------------------------------------------------------------------------------- /rs/riscv_csr_macros/README.md: -------------------------------------------------------------------------------- 1 | # RISC-V CSR Access Routines for Rust, Macro Based 2 | 3 | The `src/riscv_csr_macros.rs` file is generated from `templates/riscv_csr_macros.rs`. 4 | 5 | This implements a macro for each register and each access mode. It is based on the C code. 6 | 7 | ## Building Example 8 | 9 | The `examples/test_csr.rs` file 10 | 11 | Setup Rust and RISC-V target: 12 | ~~~ 13 | curl https://sh.rustup.rs -sSf | sh 14 | 15 | rustup target add riscv32imac-unknown-none-elf 16 | ~~~ 17 | 18 | Build the example: 19 | 20 | ~~~ 21 | cargo build --examples --release 22 | ~~~ 23 | 24 | 25 | -------------------------------------------------------------------------------- /rs/riscv_csr_macros/examples/test_csr.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Register access functions for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | #![no_std] 9 | #![no_main] 10 | 11 | use core::panic::PanicInfo; 12 | 13 | // error: `#[panic_handler]` function required, but not found 14 | #[panic_handler] 15 | fn panic(_info: &PanicInfo) -> ! { 16 | 17 | loop {} 18 | } 19 | 20 | use riscv_csr_macros::csr_read_mcause; 21 | use riscv_csr_macros::csr_read_mip; 22 | use riscv_csr_macros::csr_read_mepc; 23 | use riscv_csr_macros::csr_write_mscratch; 24 | use riscv_csr_macros::csr_read_clr_bits_mtvec; 25 | use riscv_csr_macros::csr_set_bits_mie; 26 | use riscv_csr_macros::csr_set_bits_imm_mie; 27 | use riscv_csr_macros::MCAUSE_INTERRUPT_BIT_MASK; 28 | use riscv_csr_macros::MIE_MTI_BIT_MASK; 29 | use riscv_csr_macros::MTVEC_BASE_ALL_SET_MASK; 30 | use riscv_csr_macros::MTVEC_MODE_ALL_SET_MASK; 31 | use riscv_csr_macros::UintXlen; 32 | 33 | 34 | #[no_mangle] 35 | pub fn test_csr() { 36 | let mut _saved_mtvec: UintXlen = 0; 37 | let cause = csr_read_mcause!(); 38 | if (cause & MCAUSE_INTERRUPT_BIT_MASK) != 0 { 39 | // Interrupt 40 | let _mip = csr_read_mip!(); 41 | } else { 42 | // Exception 43 | // Read the source of the exception 44 | let mepc = csr_read_mepc!(); 45 | // Pointless save to mscratch 46 | csr_write_mscratch!(mepc); 47 | } 48 | // Enable MIE.MSI 49 | csr_set_bits_imm_mie!(MIE_MSI_BIT_MASK); 50 | // Enable MIE.MTI 51 | csr_set_bits_mie!(MIE_MTI_BIT_MASK); 52 | // Clear mode and read mtvec. 53 | let mut old_mtvec = csr_read_clr_bits_mtvec!(MTVEC_MODE_ALL_SET_MASK); 54 | if (old_mtvec & MTVEC_MODE_ALL_SET_MASK) != 0 { 55 | // Remove mode bits 56 | old_mtvec = old_mtvec & MTVEC_BASE_ALL_SET_MASK; 57 | } 58 | _saved_mtvec = old_mtvec; 59 | } 60 | -------------------------------------------------------------------------------- /templates/riscv-csr.h: -------------------------------------------------------------------------------- 1 | /* 2 | Register access functions for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #ifndef RISCV_CSR_H 10 | #define RISCV_CSR_H 11 | 12 | #include 13 | 14 | #if __riscv_xlen==32 15 | typedef uint32_t uint_xlen_t; 16 | typedef uint32_t uint_csr32_t; 17 | typedef uint32_t uint_csr64_t; 18 | #elif __riscv_xlen==64 19 | typedef uint64_t uint_xlen_t; 20 | typedef uint32_t uint_csr32_t; 21 | typedef uint64_t uint_csr64_t; 22 | #else 23 | #error "Unknown XLEN" 24 | #endif 25 | 26 | // Test for Zicsr extension, if relevant 27 | #if defined(__riscv_arch_test) 28 | #if !defined(__riscv_zicsr) 29 | #error "-march must include zicsr to access CSRs" 30 | #endif 31 | #endif 32 | 33 | 34 | {%- for reg_name,reg_data in data.regs.items() %} 35 | {%- if not reg_data.mmio %} 36 | 37 | /******************************************* 38 | * {{reg_name}} - {{reg_data.priv}} - {{reg_data.desc}} 39 | */ 40 | {%- set ctype_reg = reg_data|csr_ctype %} 41 | {%- set ctype_arg = reg_data|arg_ctype %} 42 | {%- if "R" in reg_data.priv %} 43 | static inline {{ctype_arg}} csr_read_{{reg_name}}(void) { 44 | {{ctype_reg}} value; 45 | __asm__ volatile ("csrr %0, {{reg_name}}" 46 | : "=r" (value) /* output : register */ 47 | : /* input : none */ 48 | : /* clobbers: none */); 49 | return value; 50 | } 51 | {%- endif %} 52 | {%- if "W" in reg_data.priv %} 53 | static inline void csr_write_{{reg_name}}({{ctype_reg}} value) { 54 | __asm__ volatile ("csrw {{reg_name}}, %0" 55 | : /* output: none */ 56 | : "r" (value) /* input : from register */ 57 | : /* clobbers: none */); 58 | } 59 | static inline {{ctype_arg}} csr_read_write_{{reg_name}}({{ctype_arg}} new_value) { 60 | {{ctype_reg}} prev_value; 61 | __asm__ volatile ("csrrw %0, {{reg_name}}, %1" 62 | : "=r" (prev_value) /* output: register %0 */ 63 | : "r" (new_value) /* input : register */ 64 | : /* clobbers: none */); 65 | return prev_value; 66 | } 67 | {%- endif%} 68 | {%- if reg_data.fields %} 69 | {%- if "W" in reg_data.priv %} 70 | /* Register CSR bit set and clear instructions */ 71 | static inline void csr_set_bits_{{reg_name}}({{ctype_arg}} mask) { 72 | __asm__ volatile ("csrrs zero, {{reg_name}}, %0" 73 | : /* output: none */ 74 | : "r" (mask) /* input : register */ 75 | : /* clobbers: none */); 76 | } 77 | static inline void csr_clr_bits_{{reg_name}}({{ctype_arg}} mask) { 78 | __asm__ volatile ("csrrc zero, {{reg_name}}, %0" 79 | : /* output: none */ 80 | : "r" (mask) /* input : register */ 81 | : /* clobbers: none */); 82 | } 83 | static inline {{ctype_arg}} csr_read_set_bits_{{reg_name}}({{ctype_arg}} mask) { 84 | {{ctype_reg}} value; 85 | __asm__ volatile ("csrrs %0, {{reg_name}}, %1" 86 | : "=r" (value) /* output: register %0 */ 87 | : "r" (mask) /* input : register */ 88 | : /* clobbers: none */); 89 | return value; 90 | } 91 | static inline {{ctype_arg}} csr_read_clr_bits_{{reg_name}}({{ctype_arg}} mask) { 92 | {{ctype_reg}} value; 93 | __asm__ volatile ("csrrc %0, {{reg_name}}, %1" 94 | : "=r" (value) /* output: register %0 */ 95 | : "r" (mask) /* input : register */ 96 | : /* clobbers: none */); 97 | return value; 98 | } 99 | /* {{reg_name}}, CSR write value via immediate value (only up to 5 bits) */ 100 | #define CSR_WRITE_IMM_{{reg_name|upper}}(VALUE) \ 101 | __asm__ volatile ("csrrwi zero, {{reg_name}}, %0" \ 102 | : /* output: none */ \ 103 | : "i" (VALUE) /* input : immediate */ \ 104 | : /* clobbers: none */) 105 | 106 | /* {{reg_name}}, CSR set bits via immediate value mask (only up to 5 bits) */ 107 | #define CSR_SET_BITS_IMM_{{reg_name|upper}}(MASK) \ 108 | __asm__ volatile ("csrrsi zero, {{reg_name}}, %0" \ 109 | : /* output: none */ \ 110 | : "i" (MASK) /* input : immediate */ \ 111 | : /* clobbers: none */) 112 | 113 | /* {{reg_name}}, CSR clear bits via immediate value mask (only up to 5 bits) */ 114 | #define CSR_CLR_BITS_IMM_{{reg_name|upper}}(MASK) \ 115 | __asm__ volatile ("csrrci zero, {{reg_name}}, %0" \ 116 | : /* output: none */ \ 117 | : "i" (MASK) /* input : immediate */ \ 118 | : /* clobbers: none */) 119 | 120 | {%- endif %} 121 | {%-for field_name,field_data in reg_data.fields.items() %} 122 | {%- set bit_width = field_data|csr_bit_width %} 123 | {%- set bit_offset = field_data|csr_bit_offset %} 124 | #define {{reg_name|upper}}_{{field_name|upper}}_BIT_OFFSET {{bit_offset}} 125 | #define {{reg_name|upper}}_{{field_name|upper}}_BIT_WIDTH {{bit_width}} 126 | #define {{reg_name|upper}}_{{field_name|upper}}_BIT_MASK {{bit_offset|csr_format_mask(bit_width)}} 127 | #define {{reg_name|upper}}_{{field_name|upper}}_ALL_SET_MASK {{0|csr_format_mask(bit_width)}} 128 | {%- endfor%} 129 | {%-endif%} 130 | {%- endif%} 131 | {%- endfor%} 132 | 133 | 134 | #endif // #define RISCV_CSR_H 135 | -------------------------------------------------------------------------------- /templates/riscv-csr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Register access classes for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #ifndef RISCV_CSR_HPP 10 | #define RISCV_CSR_HPP 11 | 12 | #include 13 | 14 | // Test for Zicsr extension, if relevant 15 | #if defined(__riscv_arch_test) 16 | #if !defined(__riscv_zicsr) 17 | #error "-march must include zicsr to access CSRs" 18 | #endif 19 | #endif 20 | 21 | // ------------------------------------------------------------------------ 22 | // Base and common classes 23 | 24 | namespace riscv { 25 | namespace csr { 26 | #if __riscv_xlen==32 27 | using uint_xlen_t = std::uint32_t; 28 | using uint_csr32_t = std::uint32_t; 29 | using uint_csr64_t = std::uint32_t; 30 | #elif __riscv_xlen==64 31 | using uint_xlen_t = std::uint64_t; 32 | using uint_csr32_t = std::uint32_t; 33 | using uint_csr64_t = std::uint64_t; 34 | #else 35 | #error "riscv::csr: unknown __riscv_xlen" 36 | #endif 37 | /** Immediate instructions use a 5 bit immediate field */ 38 | static constexpr uint_xlen_t CSR_IMM_OP_MASK = 0x01F; 39 | 40 | /** CSR: Read only, and read-write base class */ 41 | template class read_only_reg { 42 | public : 43 | using read_datatype_t = typename C::datatype; 44 | 45 | read_only_reg(void) {} 46 | read_only_reg(const read_only_reg&) = delete; 47 | read_only_reg& operator=(const read_only_reg&) = delete; 48 | 49 | /** Read the CSR value */ 50 | static inline read_datatype_t read(void) { 51 | return C::read(); 52 | } 53 | /** Operator alias to read the CSR value */ 54 | inline read_datatype_t operator()(void) { 55 | return C::read(); 56 | } 57 | }; 58 | /** CSR: Write only, and read-write base class */ 59 | template class write_only_reg { 60 | public : 61 | using write_datatype_t = typename C::datatype; 62 | 63 | write_only_reg(void) {} 64 | write_only_reg(const write_only_reg&) = delete; 65 | write_only_reg& operator=(const write_only_reg&) = delete; 66 | 67 | /** Write a constant to the CSR. */ 68 | template void write_const(void) { 69 | if constexpr ((VALUE & CSR_IMM_OP_MASK) == VALUE) { 70 | C::write_imm(VALUE); 71 | } else { 72 | C::write(VALUE); 73 | } 74 | } 75 | /** Write to the CSR. */ 76 | inline void write(const write_datatype_t value) { 77 | C::write(value); 78 | } 79 | /** Set a constant mask of bits in the CSR. */ 80 | template void set_const(void) { 81 | if constexpr ((MASK & CSR_IMM_OP_MASK) == MASK) { 82 | C::set_bits_imm(MASK); 83 | } else { 84 | C::set_bits(MASK); 85 | } 86 | } 87 | /** Set a mask of bits in the CSR. */ 88 | inline void set(write_datatype_t mask) { 89 | C::set_bits(mask); 90 | } 91 | /** Clear a constant mask of bits in the CSR. */ 92 | template void clr_const(void) { 93 | if constexpr ((MASK & CSR_IMM_OP_MASK) == MASK) { 94 | C::clr_bits_imm(MASK); 95 | } else { 96 | C::clr_bits(MASK); 97 | } 98 | } 99 | /** Clear a mask of bits in the CSR. */ 100 | inline void clr(write_datatype_t mask) { 101 | C::clr_bits(mask); 102 | } 103 | /** Operator alias to set mask of bits in the CSR. */ 104 | inline void operator|=(write_datatype_t mask) { 105 | C::set_bits(mask); 106 | } 107 | }; 108 | /** CSR: Read-write base class */ 109 | template class read_write_reg : public read_only_reg, 110 | public write_only_reg { 111 | public: 112 | using datatype_t = typename C::datatype; 113 | 114 | read_write_reg(void) 115 | : read_only_reg() 116 | , write_only_reg() 117 | {} 118 | read_write_reg(const read_write_reg&)=delete; 119 | read_write_reg& operator=(const read_write_reg&)=delete; 120 | 121 | /** Read from, then write a constant value to the CSR. */ 122 | template datatype_t read_write_const(void) { 123 | if constexpr ((VALUE & CSR_IMM_OP_MASK) == VALUE) { 124 | return C::read_write_imm(VALUE); 125 | } else { 126 | return C::read_write(VALUE); 127 | } 128 | } 129 | /** Read from, then write to the CSR. */ 130 | inline datatype_t read_write(const datatype_t value) { 131 | return C::read_write(value); 132 | } 133 | /** Read from, then set a constant bit mask to the CSR. */ 134 | template datatype_t read_set_bits_const(void) { 135 | if constexpr ((MASK & CSR_IMM_OP_MASK) == MASK) { 136 | return C::read_set_bits_imm(MASK); 137 | } else { 138 | return C::read_set_bits(MASK); 139 | } 140 | } 141 | /** Read from, then set a bit mask to the CSR. */ 142 | inline datatype_t read_set_bits(const datatype_t mask) { 143 | return C::read_set_bits(mask); 144 | } 145 | /** Read from, then clear a constant bit mask to the CSR. */ 146 | template datatype_t read_clr_bits_const(void) { 147 | if constexpr ((MASK & CSR_IMM_OP_MASK) == MASK) { 148 | return C::read_clr_bits_imm(MASK); 149 | } else { 150 | return C::read_clr_bits(MASK); 151 | } 152 | } 153 | /** Read from, then clear a bit mask to the CSR. */ 154 | inline datatype_t read_clr_bits(const datatype_t mask) { 155 | return C::read_clr_bits(mask); 156 | } 157 | }; 158 | /** CSR Field: Read only, and read-write base class */ 159 | template class read_only_field { 160 | public: 161 | using read_datatype_t = typename F::datatype; 162 | 163 | read_only_field(void) {} 164 | read_only_field(const read_only_field&)=delete; 165 | read_only_field& operator=(const read_only_field&)=delete; 166 | 167 | /** Read a given field value from a CSR */ 168 | read_datatype_t read(void) { 169 | return (read_datatype_t) ((C::read() & F::BIT_MASK) >> F::BIT_OFFSET); 170 | } 171 | }; 172 | /** CSR Field: Write only, and read-write base class */ 173 | template class write_only_field { 174 | public: 175 | using write_datatype_t = typename F::datatype; 176 | using reg_write_datatype_t = typename C::datatype; 177 | 178 | write_only_field(void) {} 179 | write_only_field(const write_only_field&)=delete; 180 | write_only_field& operator=(const write_only_field&)=delete; 181 | 182 | inline void set(void) { 183 | if constexpr ((F::BIT_MASK & CSR_IMM_OP_MASK) == F::BIT_MASK) { 184 | C::set_bits_imm(F::BIT_MASK); 185 | } else { 186 | C::set_bits(F::BIT_MASK); 187 | } 188 | } 189 | inline void clr(void) { 190 | if constexpr ((F::BIT_MASK & CSR_IMM_OP_MASK) == F::BIT_MASK) { 191 | C::clr_bits_imm(F::BIT_MASK); 192 | } else { 193 | C::clr_bits(F::BIT_MASK); 194 | } 195 | } 196 | }; 197 | /** CSR Field: Read-write base class */ 198 | template class read_write_field 199 | : public read_only_field 200 | , public write_only_field { 201 | public: 202 | using datatype_t = typename F::datatype; 203 | using reg_datatype_t = typename C::datatype; 204 | 205 | read_write_field(void) 206 | : read_only_field() 207 | , write_only_field() 208 | {} 209 | read_write_field(const read_write_field&)=delete; 210 | read_write_field& operator=(const read_write_field&)=delete; 211 | 212 | /* Read-modify-write to write a field. 213 | NOTE - not atomic. 214 | */ 215 | inline void write(const datatype_t value) { 216 | auto org_value = C::read(); 217 | auto new_value = (org_value & ~F::BIT_MASK) | 218 | (((reg_datatype_t)value << F::BIT_OFFSET) & F::BIT_MASK); 219 | C::write(new_value); 220 | } 221 | /* Read-modify-write to set a field, and return original value. 222 | NOTE - not atomic. 223 | */ 224 | inline datatype_t read_write(const datatype_t value) { 225 | auto org_value = C::read(); 226 | auto new_value = (org_value & ~F::BIT_MASK) | 227 | (((reg_datatype_t)value << F::BIT_OFFSET) & F::BIT_MASK); 228 | C::write(new_value); 229 | return (datatype_t) ((org_value & F::BIT_MASK) >> F::BIT_OFFSET); 230 | } 231 | 232 | }; 233 | 234 | /** CSR access context and read/write permission. 235 | */ 236 | typedef enum { 237 | {% for p in data.addr.priv['values'] -%} 238 | {% for rw in data.addr.rw['values'] -%} 239 | {{p.key}}{{rw.key}}, 240 | {% endfor -%} 241 | {% endfor %} 242 | {% for rw in data.addr.rw['values'] -%} 243 | D{{rw.key}}, 244 | {% endfor -%} 245 | } priv_t; 246 | 247 | } /* csr */ 248 | } /* riscv */ 249 | 250 | // ------------------------------------------------------------------------ 251 | // Assembler operations and bit field definitions 252 | 253 | namespace riscv { 254 | namespace csr { 255 | {%- for reg_name,reg_data in data.regs.items() %} 256 | 257 | // ---------------------------------------------------------------- 258 | // {{reg_name}} - {{reg_data.priv}} - {{reg_data.desc}} 259 | // 260 | {%- set ctype_reg = reg_data|csr_ctype %} 261 | {%- set ctype_arg = reg_data|arg_ctype %} 262 | {%- set ctype_imm = "const uint8_t" %} 263 | {%- if not reg_data.mmio %} 264 | /** {{reg_data.desc}} assembler operations */ 265 | struct {{reg_name}}_ops { 266 | using datatype = {{ctype_reg}}; 267 | static constexpr priv_t priv = {{reg_data.priv}}; 268 | {% if "R" in reg_data.priv %} 269 | /** Read {{reg_name}} */ 270 | static {{ctype_arg}} read(void) { 271 | {{ctype_reg}} value; 272 | __asm__ volatile ("csrr %0, {{reg_name}}" 273 | : "=r" (value) /* output : register */ 274 | : /* input : none */ 275 | : /* clobbers: none */); 276 | return value; 277 | } 278 | {%endif%} 279 | {% if "W" in reg_data.priv %} 280 | /** Write {{reg_name}} */ 281 | static void write({{ctype_reg}} value) { 282 | __asm__ volatile ("csrw {{reg_name}}, %0" 283 | : /* output: none */ 284 | : "r" (value) /* input : from register */ 285 | : /* clobbers: none */); 286 | } 287 | /** Write immediate value to {{reg_name}} */ 288 | static void write_imm({{ctype_reg}} value) { 289 | __asm__ volatile ("csrwi {{reg_name}}, %0" 290 | : /* output: none */ 291 | : "i" (value) /* input : from immediate */ 292 | : /* clobbers: none */); 293 | } 294 | /** Read and then write to {{reg_name}} */ 295 | static {{ctype_arg}} read_write({{ctype_reg}} new_value) { 296 | {{ctype_reg}} prev_value; 297 | __asm__ volatile ("csrrw %0, {{reg_name}}, %1" 298 | : "=r" (prev_value) /* output: register %0 */ 299 | : "r" (new_value) /* input : register */ 300 | : /* clobbers: none */); 301 | return prev_value; 302 | } 303 | /** Read and then write immediate value to {{reg_name}} */ 304 | static {{ctype_arg}} read_write_imm({{ctype_imm}} new_value) { 305 | {{ctype_reg}} prev_value; 306 | __asm__ volatile ("csrrwi %0, {{reg_name}}, %1" 307 | : "=r" (prev_value) /* output: register %0 */ 308 | : "i" (new_value) /* input : register */ 309 | : /* clobbers: none */); 310 | return prev_value; 311 | } 312 | 313 | // ------------------------------------------ 314 | // Register CSR bit set and clear instructions 315 | 316 | /** Atomic modify and set bits for {{reg_name}} */ 317 | static void set_bits({{ctype_reg}} mask) { 318 | __asm__ volatile ("csrrs zero, {{reg_name}}, %0" 319 | : /* output: none */ 320 | : "r" (mask) /* input : register */ 321 | : /* clobbers: none */); 322 | } 323 | /** Atomic read and then and set bits for {{reg_name}} */ 324 | static uint32_t read_set_bits({{ctype_reg}} mask) { 325 | {{ctype_reg}} value; 326 | __asm__ volatile ("csrrs %0, {{reg_name}}, %1" 327 | : "=r" (value) /* output: register %0 */ 328 | : "r" (mask) /* input : register */ 329 | : /* clobbers: none */); 330 | return value; 331 | } 332 | /** Atomic modify and clear bits for {{reg_name}} */ 333 | static void clr_bits({{ctype_reg}} mask) { 334 | __asm__ volatile ("csrrc zero, {{reg_name}}, %0" 335 | : /* output: none */ 336 | : "r" (mask) /* input : register */ 337 | : /* clobbers: none */); 338 | } 339 | /** Atomic read and then and clear bits for {{reg_name}} */ 340 | static uint32_t read_clr_bits({{ctype_reg}} mask) { 341 | {{ctype_reg}} value; 342 | __asm__ volatile ("csrrc %0, {{reg_name}}, %1" 343 | : "=r" (value) /* output: register %0 */ 344 | : "r" (mask) /* input : register */ 345 | : /* clobbers: none */); 346 | return value; 347 | } 348 | 349 | // ------------------------------------------ 350 | // Immediate value CSR bit set and clear instructions (only up to 5 bits) 351 | 352 | /** Atomic modify and set bits from immediate for {{reg_name}} */ 353 | static void set_bits_imm({{ctype_imm}} mask) { 354 | __asm__ volatile ("csrrsi zero, {{reg_name}}, %0" 355 | : /* output: none */ 356 | : "i" (mask) /* input : register */ 357 | : /* clobbers: none */); 358 | } 359 | /** Atomic read and then and set bits from immediate for {{reg_name}} */ 360 | static {{ctype_arg}} read_set_bits_imm({{ctype_imm}} mask) { 361 | {{ctype_reg}} value; 362 | __asm__ volatile ("csrrsi %0, {{reg_name}}, %1" 363 | : "=r" (value) /* output: register %0 */ 364 | : "i" (mask) /* input : register */ 365 | : /* clobbers: none */); 366 | return value; 367 | } 368 | /** Atomic modify and clear bits from immediate for {{reg_name}} */ 369 | static void clr_bits_imm({{ctype_imm}} mask) { 370 | __asm__ volatile ("csrrci zero, {{reg_name}}, %0" 371 | : /* output: none */ 372 | : "i" (mask) /* input : register */ 373 | : /* clobbers: none */); 374 | } 375 | /** Atomic read and then and clear bits from immediate for {{reg_name}} */ 376 | static {{ctype_arg}} read_clr_bits_imm({{ctype_imm}} mask) { 377 | {{ctype_reg}} value; 378 | __asm__ volatile ("csrrci %0, {{reg_name}}, %1" 379 | : "=r" (value) /* output: register %0 */ 380 | : "i" (mask) /* input : register */ 381 | : /* clobbers: none */); 382 | return value; 383 | } 384 | {%endif%} 385 | }; /* {{reg_name}}_ops */ 386 | {%- if reg_data.fields %} 387 | /** Parameter data for fields in {{reg_name}} */ 388 | namespace {{reg_name}}_data { 389 | {%-for field_name,field_data in reg_data.fields.items() %} 390 | {%- set bit_width = field_data|csr_bit_width %} 391 | {%- set bit_offset = field_data|csr_bit_offset %} 392 | /** Parameter data for {{field_name}} */ 393 | struct {{field_name}} { 394 | using datatype = {{field_data|csr_ctype}}; 395 | static constexpr {{ctype_reg}} BIT_OFFSET = {{bit_offset}}; 396 | static constexpr {{ctype_reg}} BIT_WIDTH = {{bit_width}}; 397 | static constexpr {{ctype_reg}} BIT_MASK = {{bit_offset|csr_format_mask(bit_width)}}; 398 | static constexpr {{ctype_reg}} ALL_SET_MASK = {{0|csr_format_mask(bit_width)}}; 399 | }; 400 | {%- endfor%} 401 | } /* {{reg_name}}_data */ 402 | {%-endif%} 403 | {%- endif%} 404 | {%- endfor%} 405 | } /* csr */ 406 | } /* riscv */ 407 | 408 | 409 | // ------------------------------------------------------------------------ 410 | // Register and field interface classes. 411 | namespace riscv { 412 | namespace csr { 413 | {%-for reg_name,reg_data in data.regs.items() %} 414 | {%-if not reg_data.mmio %} 415 | {%- set reg_template_class = "riscv::csr::" + reg_name + "_ops" %} 416 | {%-if "WO" in reg_data.priv %} 417 | {%- set priv = "write_only" %} 418 | {%-elif "RW" in reg_data.priv %} 419 | {%- set priv = "read_write" %} 420 | {%-else%} 421 | {%- set priv = "read_only" %} 422 | {%-endif%} 423 | /* {{reg_data.desc}} */ 424 | template class {{reg_name}}_reg : public {{priv}}_reg 425 | { 426 | {%- if reg_data.fields %} 427 | public: 428 | {%-for field_name,field_data in reg_data.fields.items() %} 429 | {%- set field_template_class = "OPS, riscv::csr::" + reg_name + "_data::" + field_name %} 430 | {{priv}}_field<{{field_template_class}}> {{field_name}}; 431 | {%- endfor %} 432 | {%- endif %} 433 | }; 434 | using {{reg_name}} = {{reg_name}}_reg<{{reg_template_class}}>; 435 | {%-endif%} 436 | {%-endfor%} 437 | 438 | /** Encapsulate all CSRs in a single structure. 439 | - No storage is required by this class. 440 | */ 441 | struct all { 442 | {%-for reg_name,reg_data in data.regs.items() %} 443 | {%-if not reg_data.mmio %} 444 | /* {{reg_data.desc}} */ 445 | riscv::csr::{{reg_name}} {{reg_name}}; 446 | {%-endif%} 447 | {%-endfor%} 448 | }; 449 | 450 | } /* csr */ 451 | 452 | static csr::all csrs; 453 | 454 | } /* riscv */ 455 | 456 | #endif // #define RISCV_CSR_HPP 457 | -------------------------------------------------------------------------------- /templates/riscv_csr_filters.py: -------------------------------------------------------------------------------- 1 | # Regiter size conversion used by yaml_jinja.py 2 | # 3 | # Jinja filters for the following register data structure 4 | # 'bits' : (msb, lsb) 5 | 6 | import re 7 | 8 | def _xlen_replace(bit): 9 | return re.sub('[mxsu]xlen','__riscv_xlen', str(bit)) 10 | 11 | def _csr_bit_to_int(bit): 12 | if isinstance(bit, int): 13 | return bit 14 | raise "Compile time defined." 15 | 16 | def csr_bit_width(field_data): 17 | if len(field_data["bits"])==1 : 18 | return 1 19 | else : 20 | try: 21 | msb = _csr_bit_to_int(field_data["bits"][0]) 22 | lsb = _csr_bit_to_int(field_data["bits"][1]) 23 | return (msb - lsb) + 1 24 | except: 25 | return "((" + _xlen_replace(field_data["bits"][0]) + ")-(" + _xlen_replace(field_data["bits"][1]) + ") + 1)" 26 | 27 | def csr_bit_width_rs(field_data): 28 | if len(field_data["bits"])==1 : 29 | return 1 30 | else : 31 | try: 32 | msb = _csr_bit_to_int(field_data["bits"][0]) 33 | lsb = _csr_bit_to_int(field_data["bits"][1]) 34 | return (msb - lsb) + 1 35 | except: 36 | return "(" + _xlen_replace(field_data["bits"][0]) + ")-(" + _xlen_replace(field_data["bits"][1]) + ") + 1" 37 | 38 | def csr_field_imm_valid(field_data): 39 | # Immediate can only store 5 bits 40 | try: 41 | msb = _csr_bit_to_int(field_data["bits"][0]) 42 | if msb < 5: 43 | return True 44 | except: 45 | pass 46 | return False 47 | 48 | 49 | def csr_format_mask(bit_offset, bit_width): 50 | """ Convert a bit offset and width into a mask. 51 | .e.g bit_offset5, bit_width=4 will convert to 0x1C0 52 | """ 53 | if isinstance(bit_offset, int) and isinstance(bit_width, int): 54 | return "0x%x" % (((1< 0: 94 | return "uint_xlen_t" 95 | else: 96 | return "uint" + str(width) + "_t" 97 | return "uint_xlen_t" 98 | 99 | def csr_ctype(field_data): 100 | """ The type passed to, or returned from, the assembler instruction. 101 | """ 102 | if "width" in field_data: 103 | width=str(field_data["width"]) 104 | if width.find("xlen") > 0: 105 | return "uint_xlen_t" 106 | else: 107 | return "uint_csr" + str(width) + "_t" 108 | return "uint_xlen_t" 109 | 110 | def csr_ctype_rs(field_data): 111 | """ The type passed to, or returned from, the assembler instruction. 112 | """ 113 | if "width" in field_data: 114 | width=str(field_data["width"]) 115 | if width.find("xlen") > 0: 116 | return "UintXlen" 117 | else: 118 | return "UintCsr" + str(width) 119 | return "UintXlen" 120 | 121 | 122 | def setup(env): 123 | """ Register the filters in this file to the Jinja environment. 124 | """ 125 | env.filters['csr_bit_width'] = csr_bit_width 126 | env.filters['csr_bit_width_rs'] = csr_bit_width_rs 127 | env.filters['csr_bit_offset'] = csr_bit_offset 128 | env.filters['csr_bit_offset_rs'] = csr_bit_offset_rs 129 | env.filters['csr_format_mask'] = csr_format_mask 130 | env.filters['csr_format_mask_rs'] = csr_format_mask_rs 131 | env.filters['csr_ctype'] = csr_ctype 132 | env.filters['csr_ctype_rs'] = csr_ctype_rs 133 | env.filters['arg_ctype'] = arg_ctype 134 | env.filters['csr_field_imm_valid'] = csr_field_imm_valid 135 | -------------------------------------------------------------------------------- /templates/riscv_csr_macros.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Register access functions for RISC-V system registers. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #![no_std] 10 | 11 | #[cfg(target_pointer_width = "32")] 12 | pub type UintXlen = u32; 13 | #[cfg(target_pointer_width = "32")] 14 | pub type UintCsr64 = u32; 15 | 16 | #[cfg(target_pointer_width = "64")] 17 | pub type UintXlen = u64; 18 | #[cfg(target_pointer_width = "64")] 19 | pub type UintCsr64 = u64; 20 | 21 | pub type UintCsr32 = u32; 22 | 23 | 24 | #[allow(non_upper_case_globals)] 25 | #[cfg(target_pointer_width = "32")] 26 | const __riscv_xlen : isize = 32; 27 | 28 | #[allow(non_upper_case_globals)] 29 | #[cfg(target_pointer_width = "64")] 30 | const __riscv_xlen : isize = 64; 31 | 32 | 33 | {%- for reg_name,reg_data in data.regs.items() %} 34 | {%- if not reg_data.mmio %} 35 | 36 | /******************************************* 37 | * {{reg_name}} - {{reg_data.priv}} - {{reg_data.desc}} 38 | */ 39 | {%- set ctype_reg = reg_data|csr_ctype_rs %} 40 | {%- set ctype_arg = reg_data|arg_ctype %} 41 | /* {{reg_name}}: CSR Whole register access */ 42 | {%- if "R" in reg_data.priv %} 43 | /* {{reg_name}}: CSR read. 44 | e.g. 45 | let _v = csr_read_{{reg_name}}!(); 46 | */ 47 | #[macro_export] 48 | macro_rules! csr_read_{{reg_name}} { 49 | ( ) => ( 50 | { 51 | let tmp_value: {{ctype_reg}}; 52 | unsafe { 53 | use core::arch::asm; 54 | asm!("csrr {0}, {{reg_name}}" , out(reg) tmp_value); 55 | } 56 | tmp_value 57 | } 58 | ); 59 | } 60 | {%- endif %} 61 | {%- if "W" in reg_data.priv %} 62 | /* {{reg_name}}: CSR write 63 | e.g. 64 | csr_write_{{reg_name}}!(0x1234567); 65 | */ 66 | #[macro_export] 67 | macro_rules! csr_write_{{reg_name}} { 68 | ( $x:expr ) => ( 69 | unsafe { 70 | use core::arch::asm; 71 | asm!("csrw {{reg_name}}, {0}" , in(reg) $x); 72 | } 73 | ); 74 | } 75 | /* {{reg_name}}: CSR Read and Write 76 | e.g. 77 | let v_ = csr_read_write_{{reg_name}}!(0x1234567); 78 | */ 79 | #[macro_export] 80 | macro_rules! csr_read_write_{{reg_name}} { 81 | ( $x:expr ) => ( 82 | { 83 | let tmp_value: {{ctype_reg}}; 84 | unsafe { 85 | use core::arch::asm; 86 | asm!("csrrw {0}, {{reg_name}}, {1}" , out(reg) tmp_value, in(reg) $x); 87 | } 88 | tmp_value 89 | } 90 | ); 91 | } 92 | {%- endif%} 93 | 94 | /* {{reg_name}}: CSR Field Modifications - via register */ 95 | 96 | {%- if reg_data.fields %} 97 | {%- if "W" in reg_data.priv %} 98 | /* Register CSR bit set instructions. 99 | e.g. 100 | csr_set_bits_{{reg_name}}!(0x0F0F0F); 101 | */ 102 | #[macro_export] 103 | macro_rules! csr_set_bits_{{reg_name}} { 104 | ( $mask:expr ) => ( 105 | unsafe { 106 | use core::arch::asm; 107 | asm!("csrrs zero, {{reg_name}}, {{'{'}}{{0}}{{'}'}}", in(reg) $mask); 108 | } 109 | ); 110 | } 111 | /* Register CSR bit clear instructions 112 | e.g. 113 | csr_clr_bits_{{reg_name}}!(0x0F0F0F) 114 | */ 115 | #[macro_export] 116 | macro_rules! csr_clr_bits_{{reg_name}} { 117 | ( $mask:expr ) => ( 118 | unsafe { 119 | use core::arch::asm; 120 | asm!("csrrc zero, {{reg_name}}, {{'{'}}{{0}}{{'}'}}", in(reg) $mask); 121 | } 122 | ); 123 | } 124 | /* Register CSR read and then bit set instructions 125 | e.g. 126 | let org_value_ = csr_read_set_bits_{{reg_name}}!(0x0F0F0F) 127 | */ 128 | #[macro_export] 129 | macro_rules! csr_read_set_bits_{{reg_name}} { 130 | ( $mask:expr ) => ( 131 | { 132 | let tmp_value: {{ctype_reg}}; 133 | unsafe { 134 | use core::arch::asm; 135 | asm!("csrrs {{'{'}}{{0}}{{'}'}}, {{reg_name}}, {{'{'}}{{1}}{{'}'}}", out(reg) tmp_value, in(reg) $mask); 136 | } 137 | tmp_value 138 | } 139 | ); 140 | } 141 | /* Register CSR read and then bit clear instructions 142 | e.g. 143 | let org_value_ = csr_read_clr_bits_{{reg_name}}!(0x0F0F0F) 144 | */ 145 | #[macro_export] 146 | macro_rules! csr_read_clr_bits_{{reg_name}} { 147 | ( $mask:expr ) => ( 148 | { 149 | let tmp_value: {{ctype_reg}}; 150 | unsafe { 151 | use core::arch::asm; 152 | asm!("csrrc {{'{'}}{{0}}{{'}'}}, {{reg_name}}, {{'{'}}{{1}}{{'}'}}", out(reg) tmp_value, in(reg) $mask); 153 | } 154 | tmp_value 155 | } 156 | ); 157 | } 158 | /* {{reg_name}}: CSR Field Modifications - via immediate */ 159 | /* {{reg_name}}, CSR write value via immediate value (only up to 5 bits). 160 | e.g. 161 | csr_write_imm_{{reg_name}}!(0x1F); 162 | */ 163 | #[macro_export] 164 | macro_rules! csr_write_imm_{{reg_name}} { 165 | ( $value:ident ) => ( 166 | unsafe { 167 | use core::arch::asm; 168 | asm!(concat!("csrrwi zero, {{reg_name}}, ", stringify!($value))); 169 | } 170 | ); 171 | } 172 | 173 | /* {{reg_name}}, CSR set bits via immediate value mask (only up to 5 bits). 174 | e.g. 175 | csr_set_bits_imm_{{reg_name}}!(0x1F); 176 | */ 177 | #[macro_export] 178 | macro_rules! csr_set_bits_imm_{{reg_name}} { 179 | {%- if reg_data.fields %} 180 | {%-for field_name,field_data in reg_data.fields.items() %} 181 | {%- if field_data|csr_field_imm_valid %} 182 | {%- set bit_width = field_data|csr_bit_width_rs %} 183 | {%- set bit_offset = field_data|csr_bit_offset_rs %} 184 | ( {{reg_name|upper}}_{{field_name|upper}}_BIT_MASK) => { csr_set_bits_imm_{{reg_name}}!({{bit_offset|csr_format_mask_rs(bit_width)}})}; 185 | {%- endif %} 186 | {%- endfor %} 187 | {%- endif %} 188 | ( $value:literal ) => ( 189 | unsafe { 190 | use core::arch::asm; 191 | asm!(concat!("csrrsi zero, {{reg_name}}, ", stringify!($value))); 192 | } 193 | ); 194 | } 195 | /* {{reg_name}}, CSR clear bits via immediate value mask (only up to 5 bits). 196 | e.g. 197 | csr_clr_bits_imm_{{reg_name}}!(0x1F); 198 | */ 199 | #[macro_export] 200 | macro_rules! csr_clr_bits_imm_{{reg_name}} { 201 | {%- if reg_data.fields %} 202 | {%-for field_name,field_data in reg_data.fields.items() %} 203 | {%- if field_data|csr_field_imm_valid %} 204 | {%- set bit_width = field_data|csr_bit_width_rs %} 205 | {%- set bit_offset = field_data|csr_bit_offset_rs %} 206 | ( {{reg_name|upper}}_{{field_name|upper}}_BIT_MASK) => { csr_clr_bits_imm_{{reg_name}}!({{bit_offset|csr_format_mask_rs(bit_width)}})}; 207 | {%- endif %} 208 | {%- endfor %} 209 | {%- endif %} 210 | ( $value:ident ) => ( 211 | unsafe { 212 | use core::arch::asm; 213 | asm!(concat!("csrrci zero, {{reg_name}}, ", stringify!($value))); 214 | } 215 | ); 216 | } 217 | {%- endif %} 218 | {%-endif%} 219 | {%- endif%} 220 | {%- endfor%} 221 | 222 | {%- for reg_name,reg_data in data.regs.items() %} 223 | {%- if not reg_data.mmio %} 224 | {%- if reg_data.fields %} 225 | 226 | /******************************************* 227 | * {{reg_name}} - {{reg_data.priv}} - {{reg_data.desc}} 228 | */ 229 | {%- set ctype_reg = reg_data|csr_ctype %} 230 | {%- set ctype_arg = reg_data|arg_ctype %} 231 | {%-for field_name,field_data in reg_data.fields.items() %} 232 | {%- set bit_width = field_data|csr_bit_width_rs %} 233 | {%- set bit_offset = field_data|csr_bit_offset_rs %} 234 | pub const {{reg_name|upper}}_{{field_name|upper}}_BIT_OFFSET:isize = {{bit_offset}}; 235 | pub const {{reg_name|upper}}_{{field_name|upper}}_BIT_WIDTH:isize = {{bit_width}}; 236 | pub const {{reg_name|upper}}_{{field_name|upper}}_BIT_MASK:UintXlen = {{bit_offset|csr_format_mask_rs(bit_width)}}; 237 | pub const {{reg_name|upper}}_{{field_name|upper}}_ALL_SET_MASK:UintXlen = {{0|csr_format_mask_rs(bit_width)}}; 238 | {%- endfor%} 239 | {%-endif%} 240 | {%-endif%} 241 | {%- endfor%} 242 | 243 | --------------------------------------------------------------------------------