├── .gitignore ├── .cargo └── config.toml ├── xuantie-riscv ├── README.md ├── src │ ├── peripheral │ │ ├── mod.rs │ │ ├── clint.rs │ │ └── plic.rs │ ├── register │ │ ├── mcins.rs │ │ ├── mapbaddr.rs │ │ ├── mrvbr.rs │ │ ├── mrmr.rs │ │ ├── mraddr.rs │ │ ├── mnmipc.rs │ │ ├── meicr.rs │ │ ├── scer2.rs │ │ ├── smel.rs │ │ ├── mcer2.rs │ │ ├── mcpuid.rs │ │ ├── meicr2.rs │ │ ├── smeh.rs │ │ ├── mcor.rs │ │ ├── shcr.rs │ │ ├── mnmicause.rs │ │ ├── scer.rs │ │ ├── mcindex.rs │ │ ├── mhpmcounter.rs │ │ ├── mcer.rs │ │ ├── sxstatus.rs │ │ ├── mcdata.rs │ │ ├── fxcr.rs │ │ ├── mexstatus.rs │ │ ├── mhcr.rs │ │ ├── mhint.rs │ │ ├── mxstatus.rs │ │ └── mccr2.rs │ ├── debug.rs │ ├── asm.rs │ ├── register.rs │ ├── asm │ │ ├── xtheadint.rs │ │ ├── xtheadsync.rs │ │ ├── xtheadcmo.rs │ │ └── dsp0p9.rs │ ├── lib.rs │ ├── paging.rs │ └── macros.rs └── Cargo.toml ├── xuantie-riscv-rt ├── src │ ├── stack.rs │ ├── lib.rs │ ├── arch │ │ ├── mod.rs │ │ ├── riscv_e.rs │ │ ├── riscv_fpu.rs │ │ ├── riscv_i.rs │ │ ├── thead_c906.rs │ │ └── thead_e907.rs │ └── interrupts.rs └── Cargo.toml ├── Cargo.toml ├── .github └── workflows │ └── cargo.yml ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "riscv64imac-unknown-none-elf" 3 | -------------------------------------------------------------------------------- /xuantie-riscv/README.md: -------------------------------------------------------------------------------- 1 | # Xuantie RISC-V 2 | 3 | Low level access to T-Head XuanTie RISC-V processors 4 | -------------------------------------------------------------------------------- /xuantie-riscv/src/peripheral/mod.rs: -------------------------------------------------------------------------------- 1 | //! XuanTie core peripherals. 2 | 3 | pub mod clint; 4 | pub mod plic; 5 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcins.rs: -------------------------------------------------------------------------------- 1 | //! mcins, machine cache instruction register 2 | 3 | set_clear_csr! { 4 | /// Cache read request 5 | , 0x7D2, set_r, clear_r, 1 << 0 6 | } 7 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/stack.rs: -------------------------------------------------------------------------------- 1 | use crate::arch::riscv_i::Stack; 2 | 3 | pub const STACK_SIZE: usize = 8 * 1024; 4 | 5 | #[unsafe(link_section = ".bss.uninit")] 6 | pub static mut STACK: Stack = Stack::new(); 7 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Startup code and minimal runtime for T-Head Xuantie RISC-V CPUs 2 | #![no_std] 3 | 4 | pub mod arch; 5 | pub mod interrupts; 6 | pub mod stack; 7 | 8 | extern "C" { 9 | fn main(); 10 | } 11 | -------------------------------------------------------------------------------- /xuantie-riscv/src/debug.rs: -------------------------------------------------------------------------------- 1 | //! Debug module of XuanTie. 2 | 3 | // pub mod itr; // 0x1F 4 | // pub mod customcs; // 0x70 5 | // pub mod customcmd; // 0x71 6 | // pub mod custombuf; // [0, 7] 0x72..=0x79 7 | // pub mod compid; // 0x7F 8 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/mod.rs: -------------------------------------------------------------------------------- 1 | //! T-Head Xuantie RISC-V core support. 2 | 3 | pub mod thead_c906; 4 | pub mod thead_e907; 5 | 6 | // RISC-V standard extensions. 7 | pub mod riscv_e; 8 | pub mod riscv_fpu; 9 | pub mod riscv_i; 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "xuantie-riscv", 4 | "xuantie-riscv-rt", 5 | ] 6 | resolver = "2" 7 | 8 | [workspace.package] 9 | edition = "2021" 10 | license = "MulanPSL-2.0" 11 | repository = "https://github.com/rustsbi/xuantie" 12 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mapbaddr.rs: -------------------------------------------------------------------------------- 1 | //! mapbaddr, machine APB base address register 2 | use core::arch::asm; 3 | 4 | /// Get APB peripheral base address 5 | #[inline] 6 | pub fn read() -> usize { 7 | let ans: usize; 8 | unsafe { asm!("csrr {}, 0xFC1", out(reg) ans) }; 9 | ans 10 | } 11 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mrvbr.rs: -------------------------------------------------------------------------------- 1 | //! mrvbr, machine reset vector base address register 2 | use core::arch::asm; 3 | 4 | /// Get reset vector base address 5 | #[inline] 6 | pub fn get_rvbr() -> usize { 7 | let ans: usize; 8 | unsafe { asm!("csrr {}, 0x7C7", out(reg) ans) }; 9 | ans 10 | } 11 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mrmr.rs: -------------------------------------------------------------------------------- 1 | //! mrmr, machine reset signal register 2 | use core::arch::asm; 3 | 4 | /// Write to mrmr register to release reset lock for given harts 5 | /// 6 | /// Write `0x1` for hart 0, `0x2` for 1, `0x4` for 2, etc. 7 | #[inline] 8 | pub unsafe fn write(bits: usize) { 9 | asm!("csrs 0x7C6, {}", in(reg) bits); 10 | } 11 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mraddr.rs: -------------------------------------------------------------------------------- 1 | //! mraddr, machine reset address register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie E907, E906 and E902 cores. 6 | use core::arch::asm; 7 | 8 | /// Get machine reset address 9 | #[inline] 10 | pub fn read() -> usize { 11 | let ans: usize; 12 | unsafe { asm!("csrr {}, 0x7E0", out(reg) ans) } 13 | ans 14 | } 15 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/riscv_e.rs: -------------------------------------------------------------------------------- 1 | //! RISC-V RV32E and RV64E structures. 2 | 3 | /// RISC-V program stack. 4 | /// 5 | /// RV32E stacks are 4-byte aligned. 6 | #[repr(align(4))] 7 | pub struct Stack([u8; N]); 8 | 9 | impl Stack { 10 | /// Create an empty stack. 11 | #[inline] 12 | pub const fn new() -> Stack { 13 | Stack([0u8; N]) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mnmipc.rs: -------------------------------------------------------------------------------- 1 | //! mnmipc, machine NMI exception program counter 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie E907, E906 and E902 cores. 6 | use core::arch::asm; 7 | 8 | /// Get NMI exception program counter 9 | #[inline] 10 | pub fn read() -> usize { 11 | let ans: usize; 12 | unsafe { asm!("csrr {}, 0x7E3", out(reg) ans) } 13 | ans 14 | } 15 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/riscv_fpu.rs: -------------------------------------------------------------------------------- 1 | //! RISC-V RVF and RVD specific features. 2 | 3 | /// Initialize RISC-V floating point module. 4 | pub unsafe extern "C" fn init_floating_point() { 5 | unsafe { 6 | core::arch::asm! { 7 | "li t0, 0x4000 8 | li t1, 0x2000 9 | csrc mstatus, t0 10 | csrs mstatus, t1 11 | csrw fcsr, zero", 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/riscv_i.rs: -------------------------------------------------------------------------------- 1 | //! RISC-V RV32I and RV64I structures. 2 | 3 | /// RISC-V program stack. 4 | /// 5 | /// In standard RISC-V ABI specification, the stack grows downward and 6 | /// the stack pointer is always kept 16-byte aligned. 7 | #[repr(align(16))] 8 | pub struct Stack([u8; N]); 9 | 10 | impl Stack { 11 | /// Create an empty stack. 12 | #[inline] 13 | pub const fn new() -> Stack { 14 | Stack([0u8; N]) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /xuantie-riscv/src/asm.rs: -------------------------------------------------------------------------------- 1 | //! Assembly instructions. 2 | //! 3 | //! This module allows you to use XuanTie instructions without using specialized assembler or compiler. 4 | //! 5 | //! Not all these instructions are supported on your XuanTie platform. 6 | //! You may use `mcpuid` register to get your implementation model, or read the manual 7 | //! before using any of following assembly instructions. 8 | 9 | mod xtheadcmo; 10 | pub use xtheadcmo::*; 11 | mod xtheadsync; 12 | pub use xtheadsync::*; 13 | mod xtheadint; 14 | pub use xtheadint::*; 15 | 16 | mod dsp0p9; 17 | pub use dsp0p9::*; 18 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xuantie-riscv-rt" 3 | description = "Minimal runtime / startup for T-Head Xuantie RISC-V CPU's" 4 | version = "0.0.0" 5 | documentation = "https://docs.rs/xuantie" 6 | license.workspace = true 7 | repository.workspace = true 8 | edition.workspace = true 9 | readme = "README.md" 10 | categories = ["embedded", "no-std"] 11 | keywords = ["riscv", "runtime", "startup"] 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | cfg-if = "1.0.0" 17 | 18 | [lib] 19 | name = "xuantie_riscv_rt" 20 | test = false 21 | bench = false 22 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/meicr.rs: -------------------------------------------------------------------------------- 1 | //! meicr, L1-cache hardware fault inject register 2 | use core::arch::asm; 3 | 4 | pub use super::mcer::RAMID; 5 | 6 | set_clear_csr! { 7 | /// L1-cache error control error inject enable 8 | , 0x7D6, set_inj_en, clear_inj_en, 1 << 0 9 | } 10 | set_clear_csr! { 11 | /// Error control error fatal inject enable 12 | , 0x7D6, set_fatal_inj, clear_fatal_inj, 1 << 1 13 | } 14 | 15 | /// Inject hardware fault 16 | /// 17 | /// If `fatal_inj` is `1`, inject a 2-bit error; if `fatal_inj` is `0`, inject a 1-bit error. 18 | /// Set `inj_en` to `1` to start L1-cache error control error injection. 19 | #[inline] 20 | pub unsafe fn write(inj_en: bool, fatal_inj: bool, ramid: RAMID) { 21 | let bits = inj_en as usize | ((fatal_inj as usize) << 1) | ((ramid as usize) << 29); 22 | asm!("csrw 0x7D6, {}", in(reg) bits) 23 | } 24 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/scer2.rs: -------------------------------------------------------------------------------- 1 | //! scer2, supervisor L2-cache error control register 2 | use bit_field::BitField; 3 | 4 | /// scer2 register 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Scer2 { 7 | bits: usize, 8 | } 9 | 10 | impl Scer2 { 11 | /// Error index 12 | #[inline] 13 | pub fn err_index(&self) -> u16 { 14 | self.bits.get_bits(0..=15) as u16 15 | } 16 | /// Error way 17 | #[inline] 18 | pub fn err_way(&self) -> u8 { 19 | self.bits.get_bits(17..=20) as u8 20 | } 21 | /// L2-cache 2 bit or parity error also happened elsewhere other than current position 22 | #[inline] 23 | pub fn oth_err(&self) -> bool { 24 | self.bits.get_bit(30) 25 | } 26 | /// L2-cache 2 bit error correction error or parity check error 27 | #[inline] 28 | pub fn ecc_err(&self) -> bool { 29 | self.bits.get_bit(31) 30 | } 31 | } 32 | 33 | read_csr_as!(Scer2, 0x5C2); 34 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/smel.rs: -------------------------------------------------------------------------------- 1 | //! smel, supervisor memory entry low register. 2 | use crate::paging::Entry; 3 | use core::arch::asm; 4 | 5 | /// Reads the smel register. 6 | /// 7 | /// The `xuantie-riscv`` crate assumes that the `smel` register is available only on 8 | /// 64-bit Xuantie architectures. Attempting to read the smel register on non-64-bit 9 | /// architectures using this function will result in an `unimplemented!` panic. 10 | #[inline] 11 | pub fn read() -> Entry { 12 | match () { 13 | // Only enable smel when 64-bit, as it would contain a page table entry 14 | #[cfg(target_pointer_width = "64")] 15 | () => { 16 | let bits: usize; 17 | unsafe { asm!("csrr {}, 0x9C1", out(reg) bits) } 18 | Entry::from_bits(bits as u64) 19 | } 20 | #[cfg(not(target_pointer_width = "64"))] 21 | () => { 22 | unimplemented!() 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /xuantie-riscv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xuantie-riscv" 3 | description = "Low level access to T-Head XuanTie RISC-V processors" 4 | version = "0.0.0" 5 | documentation = "https://docs.rs/xuantie-riscv" 6 | license.workspace = true 7 | repository.workspace = true 8 | edition.workspace = true 9 | readme = "README.md" 10 | categories = ["embedded", "hardware-support", "no-std"] 11 | keywords = ["riscv", "register", "peripheral"] 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [package.metadata.docs.rs] 16 | default-target = "riscv64imac-unknown-none-elf" 17 | targets = [ 18 | "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", 19 | "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", 20 | ] 21 | 22 | [dependencies] 23 | bit_field = "0.10" 24 | bitflags = "2" 25 | plic = "0.0.2" 26 | volatile-register = "0.2.2" 27 | 28 | [lib] 29 | name = "xuantie_riscv" 30 | test = false 31 | bench = false 32 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcer2.rs: -------------------------------------------------------------------------------- 1 | //! mcer2, machine L2-cache error control register 2 | use bit_field::BitField; 3 | 4 | /// mcer2 register 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Mcer2 { 7 | bits: usize, 8 | } 9 | 10 | impl Mcer2 { 11 | /// Error index 12 | #[inline] 13 | pub fn err_index(&self) -> u16 { 14 | self.bits.get_bits(0..=15) as u16 15 | } 16 | /// Error way 17 | #[inline] 18 | pub fn err_way(&self) -> u8 { 19 | self.bits.get_bits(17..=20) as u8 20 | } 21 | /// L2-cache 2 bit or parity error also happened elsewhere other than current position 22 | #[inline] 23 | pub fn oth_err(&self) -> bool { 24 | self.bits.get_bit(30) 25 | } 26 | /// L2-cache 2 bit error correction error or parity check error 27 | #[inline] 28 | pub fn ecc_err(&self) -> bool { 29 | self.bits.get_bit(31) 30 | } 31 | } 32 | 33 | read_csr_as!(Mcer2, 0x7C4); 34 | 35 | clear_csr! { 36 | /// Clear error correction information valid bit 37 | , 0x7C4, clear_ecc_err, 1 << 31 38 | } 39 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcpuid.rs: -------------------------------------------------------------------------------- 1 | //! mcpuid, processor identification register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie C910, C906, E907, E906 and E902 cores. 6 | //! 7 | //! todo: verify mcpuid read and look it up on C906 manual 8 | use bit_field::BitField; 9 | use core::arch::asm; 10 | 11 | /// Processor information 12 | #[derive(Clone, Copy, Debug)] 13 | pub struct Cpuid { 14 | #[allow(unused)] // todo: remove when all fields implemented 15 | data: [u32; 7], 16 | } 17 | 18 | // todo: all the fields 19 | impl Cpuid { 20 | // pub fn arch(self) -> usize { 21 | 22 | // } 23 | } 24 | 25 | /// Fetch the processor information 26 | #[inline] 27 | pub fn read() -> Cpuid { 28 | let mut data = [0; 7]; 29 | for _ in 0..7 { 30 | let val: u32; 31 | unsafe { asm!("csrr {}, 0xFC0", out(reg) val) }; 32 | match val.get_bits(28..=31) { 33 | idx @ 0..=6 => data[idx as usize] = val, 34 | _ => {} // ignore invalid data indexes 35 | } 36 | } 37 | Cpuid { data } 38 | } 39 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/meicr2.rs: -------------------------------------------------------------------------------- 1 | //! meicr2, L2-cache hardware fault inject register 2 | use core::arch::asm; 3 | 4 | /// L2 error controllable RAM index 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 6 | pub enum L2RAMID { 7 | /// L2-cache tag ram 8 | L2CacheTag = 0, 9 | /// L2-cache data ram 10 | L2CacheData = 1, 11 | /// L2-cache dirty ram 12 | L2CacheDirty = 2, 13 | } 14 | 15 | set_clear_csr! { 16 | /// L2-cache error control error inject enable 17 | , 0x7D7, set_inj_en, clear_inj_en, 1 << 0 18 | } 19 | set_clear_csr! { 20 | /// Error control error fatal inject enable 21 | , 0x7D7, set_fatal_inj, clear_fatal_inj, 1 << 1 22 | } 23 | 24 | /// Inject hardware fault 25 | /// 26 | /// If `fatal_inj` is `1`, inject a 2-bit error; if `fatal_inj` is `0`, inject a 1-bit error. 27 | /// Set `inj_en` to `1` to start L2-cache error control error injection. 28 | #[inline] 29 | pub unsafe fn write(inj_en: bool, fatal_inj: bool, ramid: L2RAMID) { 30 | let bits = inj_en as usize | ((fatal_inj as usize) << 1) | ((ramid as usize) << 29); 31 | asm!("csrw 0x7D7, {}", in(reg) bits) 32 | } 33 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/smeh.rs: -------------------------------------------------------------------------------- 1 | //! smeh, supervisor memory entry high register. 2 | use bit_field::BitField; 3 | 4 | /// smeh register. 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Smeh { 7 | bits: usize, 8 | } 9 | 10 | /// Page size. 11 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 12 | pub enum PageSize { 13 | /// 4-KiB page. 14 | Page4K = 1, 15 | /// 2-MiB page. 16 | Page2M = 2, 17 | /// 1-GiB page. 18 | Page1G = 4, 19 | } 20 | 21 | impl Smeh { 22 | /// Get address space number. 23 | #[inline] 24 | pub fn asid(&self) -> u16 { 25 | self.bits.get_bits(0..=15) as u16 26 | } 27 | /// Get page size. 28 | #[inline] 29 | pub fn page_size(&self) -> PageSize { 30 | match self.bits.get_bits(16..=18) { 31 | 1 => PageSize::Page4K, 32 | 2 => PageSize::Page2M, 33 | 4 => PageSize::Page1G, 34 | _ => unreachable!(), 35 | } 36 | } 37 | /// Get virtual page number. 38 | #[inline] 39 | pub fn vpn(&self) -> usize { 40 | self.bits.get_bits(19..=45) 41 | } 42 | } 43 | 44 | read_csr_as!(Smeh, 0x9C2); 45 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/interrupts.rs: -------------------------------------------------------------------------------- 1 | //! Interrupt handling for Xuantie RISC-V interrupt handling standard. 2 | 3 | unsafe extern "C" { 4 | fn SupervisorSoft(); 5 | fn MachineSoft(); 6 | fn SupervisorTimer(); 7 | fn MachineTimer(); 8 | fn SupervisorExternal(); 9 | fn MachineExternal(); 10 | } 11 | 12 | unsafe extern "C" { 13 | fn THeadPmuOverflow(); 14 | fn THeadEccBusError(); 15 | } 16 | 17 | pub static __CORE_INTERRUPTS: [Option; 18] = [ 18 | None, 19 | Some(SupervisorSoft), 20 | None, 21 | Some(MachineSoft), 22 | None, 23 | Some(SupervisorTimer), 24 | None, 25 | Some(MachineTimer), 26 | None, 27 | Some(SupervisorExternal), 28 | None, 29 | Some(MachineExternal), 30 | None, 31 | Some(THeadPmuOverflow), 32 | None, 33 | None, 34 | Some(THeadEccBusError), 35 | Some(THeadPmuOverflow), 36 | ]; 37 | 38 | // TODO: distinguish different supported core interrupts between c906, c908, etc. cores. 39 | 40 | #[unsafe(no_mangle)] 41 | pub extern "C" fn _dispatch_core_interrupt(code: usize) { 42 | unsafe extern "C" { 43 | fn DefaultHandler(); 44 | } 45 | match __CORE_INTERRUPTS.get(code) { 46 | Some(Some(handler)) => unsafe { handler() }, 47 | _ => unsafe { DefaultHandler() }, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcor.rs: -------------------------------------------------------------------------------- 1 | //! mcor, machine cache operation register 2 | use bit_field::BitField; 3 | use core::arch::asm; 4 | 5 | bitflags::bitflags! { 6 | /// Select cache to operate 7 | pub struct Cache: usize { 8 | /// Select instruction cache 9 | const INSTRUCTION = 1 << 0; 10 | /// Select data cache 11 | const DATA = 1 << 1; 12 | /// Select both instruction and data caches 13 | const BOTH = (1 << 0) | (1 << 1); 14 | } 15 | } 16 | 17 | bitflags::bitflags! { 18 | /// Select operation for caches 19 | pub struct Operation: usize { 20 | /// Invalidate cache 21 | const INVALIDATE = 1 << 4; 22 | /// Clear cache 23 | const CLEAR = 1 << 5; 24 | } 25 | } 26 | 27 | /// Perform cache operation 28 | #[inline] 29 | pub unsafe fn cache(cache: Cache, op: Operation) { 30 | let bits = cache.bits() | op.bits(); 31 | let mut value: usize; 32 | asm!("csrr {}, 0x7C2", out(reg) value); 33 | value.set_bits(0..=5, bits as usize); 34 | asm!("csrw 0x7C2, {}", in(reg) value); 35 | } 36 | 37 | /// Invalidate branch history table 38 | #[inline] 39 | pub unsafe fn bht_inv() { 40 | asm!("csrs 0x7C2, {}", in(reg) 1 << 16); 41 | } 42 | 43 | /// Invalidate branch target buffer table 44 | #[inline] 45 | pub unsafe fn btb_inv() { 46 | asm!("csrs 0x7C2, {}", in(reg) 1 << 17); 47 | } 48 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/shcr.rs: -------------------------------------------------------------------------------- 1 | //! shcr, supervisor hardware configuration register 2 | use bit_field::BitField; 3 | 4 | /// shcr register 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Shcr { 7 | bits: usize, 8 | } 9 | 10 | impl Shcr { 11 | /// I-cache enable 12 | #[inline] 13 | pub fn ie(&self) -> bool { 14 | self.bits.get_bit(0) 15 | } 16 | /// D-cache enable 17 | #[inline] 18 | pub fn de(&self) -> bool { 19 | self.bits.get_bit(1) 20 | } 21 | /// Cache write allocate configuration enable 22 | #[inline] 23 | pub fn wa(&self) -> bool { 24 | self.bits.get_bit(2) 25 | } 26 | /// Write back enable; true for write back, false for write through 27 | #[inline] 28 | pub fn wb(&self) -> bool { 29 | self.bits.get_bit(3) 30 | } 31 | /// Return stack enable 32 | #[inline] 33 | pub fn rs(&self) -> bool { 34 | self.bits.get_bit(4) 35 | } 36 | /// Branch predict enable 37 | #[inline] 38 | pub fn bpe(&self) -> bool { 39 | self.bits.get_bit(5) 40 | } 41 | /// Branch target buffer enable 42 | #[inline] 43 | pub fn btb(&self) -> bool { 44 | self.bits.get_bit(6) 45 | } 46 | /// Write bulk transfer enable 47 | #[inline] 48 | pub fn wbr(&self) -> bool { 49 | self.bits.get_bit(8) 50 | } 51 | } 52 | 53 | read_csr_as!(Shcr, 0x5C1); 54 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mnmicause.rs: -------------------------------------------------------------------------------- 1 | //! mnmicause, machine NMI state register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register as well as all its bits are supported on Xuantie E907, E906 and E902 cores. 6 | use bit_field::BitField; 7 | 8 | /// mnmicause register 9 | #[derive(Clone, Copy, Debug)] 10 | pub struct Mnmicause { 11 | bits: usize, 12 | } 13 | 14 | /// Machine Previous Privilege Mode 15 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 16 | pub enum MPP { 17 | Machine = 3, 18 | Supervisor = 1, 19 | User = 0, 20 | } 21 | 22 | impl Mnmicause { 23 | /// NMI vector exception code in mcause 24 | #[inline] 25 | pub fn nmi_vector(&self) -> usize { 26 | self.bits.get_bits(0..=11) 27 | } 28 | /// NMI mstatus previous interrupt enable 29 | #[inline] 30 | pub fn nmi_mpie(&self) -> bool { 31 | self.bits.get_bit(27) 32 | } 33 | /// NMI mstatus previous privilege mode 34 | #[inline] 35 | pub fn nmi_mpp(&self) -> MPP { 36 | match self.bits.get_bits(28..=29) { 37 | 0b00 => MPP::User, 38 | 0b01 => MPP::Supervisor, 39 | 0b11 => MPP::Machine, 40 | _ => unreachable!(), 41 | } 42 | } 43 | /// NMI INTR (is interrupt) value bit in mcause 44 | #[inline] 45 | pub fn nmi_intr(&self) -> bool { 46 | self.bits.get_bit(31) 47 | } 48 | } 49 | 50 | read_csr_as!(Mnmicause, 0x7E2); 51 | -------------------------------------------------------------------------------- /.github/workflows/cargo.yml: -------------------------------------------------------------------------------- 1 | name: Cargo 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | env: 11 | CARGO_TERM_COLOR: always 12 | 13 | jobs: 14 | format: 15 | name: Format check 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Install Rust toolchain 20 | uses: actions-rs/toolchain@v1 21 | with: 22 | toolchain: nightly-2024-12-11 23 | override: true 24 | components: rustfmt 25 | - name: Run cargo fmt to check formatting 26 | run: cargo fmt --all -- --check 27 | 28 | check: 29 | name: Code check 30 | runs-on: ubuntu-latest 31 | strategy: 32 | matrix: 33 | target: 34 | - riscv32imac-unknown-none-elf 35 | - riscv64imac-unknown-none-elf 36 | - riscv32imc-unknown-none-elf 37 | - riscv64gc-unknown-linux-gnu 38 | 39 | steps: 40 | - uses: actions/checkout@v3 41 | - name: Install Rust toolchain 42 | uses: actions-rs/toolchain@v1 43 | with: 44 | toolchain: nightly-2024-12-11 45 | target: ${{ matrix.target }} 46 | override: true 47 | 48 | - name: Install RISC-V target support 49 | run: | 50 | rustup target add ${{ matrix.target }} 51 | 52 | - name: Run cargo check for xuantie-riscv 53 | run: | 54 | cargo check -p xuantie-riscv --target ${{ matrix.target }} 55 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/scer.rs: -------------------------------------------------------------------------------- 1 | //! scer, supervisor L1-cache error control register 2 | pub use super::mcer::RAMID; 3 | use bit_field::BitField; 4 | 5 | /// scer register 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct Scer { 8 | bits: usize, 9 | } 10 | 11 | impl Scer { 12 | /// Error index 13 | #[inline] 14 | pub fn err_index(&self) -> u16 { 15 | self.bits.get_bits(0..=15) as u16 16 | } 17 | /// Error way 18 | #[inline] 19 | pub fn err_way(&self) -> u8 { 20 | self.bits.get_bits(17..=18) as u8 21 | } 22 | /// RAM that the error correction fatal error taken place 23 | #[inline] 24 | pub fn ramid(&self) -> RAMID { 25 | match self.bits.get_bits(21..=23) { 26 | 0 => RAMID::ICacheTag, 27 | 1 => RAMID::ICacheData, 28 | 2 => RAMID::DCacheTag, 29 | 3 => RAMID::DCacheData, 30 | 4 => RAMID::JTlbTag, 31 | 5 => RAMID::JTlbData, 32 | _ => unreachable!(), 33 | } 34 | } 35 | /// Count of errors that are already fixed 36 | #[inline] 37 | pub fn fix_cnt(&self) -> u8 { 38 | self.bits.get_bits(24..=29) as u8 39 | } 40 | /// Is L1-cache error correction error a fatal error 41 | #[inline] 42 | pub fn err_fatal(&self) -> bool { 43 | self.bits.get_bit(30) 44 | } 45 | /// Error correction information valid 46 | #[inline] 47 | pub fn err_vld(&self) -> bool { 48 | self.bits.get_bit(31) 49 | } 50 | } 51 | 52 | read_csr_as!(Scer, 0x5C3); 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XuanTie 2 | 3 | Low level access to T-Head XuanTie RISC-V processors. 4 | 5 | | Name | Crates | Documents | License | 6 | |:-----|:-------|:--------------|:--------| 7 | | `xuantie-riscv` | [![crates.io](https://img.shields.io/crates/v/xuantie-riscv.svg)](https://crates.io/crates/xuantie-riscv) | [![Documentation](https://docs.rs/xuantie-riscv/badge.svg)](https://docs.rs/xuantie-riscv) | ![License](https://img.shields.io/crates/l/xuantie-riscv.svg) 8 | | `xuantie-riscv-rt` | [![crates.io](https://img.shields.io/crates/v/xuantie-riscv-rt.svg)](https://crates.io/crates/xuantie-riscv-rt) | [![Documentation](https://docs.rs/xuantie-riscv-rt/badge.svg)](https://docs.rs/xuantie-riscv-rt) | ![License](https://img.shields.io/crates/l/xuantie-riscv-rt.svg) 9 | 10 | ## Minimum supported Rust version 11 | 12 | This crate should be built under Rust rustc 1.85.0-nightly (21fe748be 2024-12-11) or later. 13 | 14 | ## Contributing 15 | 16 | We welcome contribution! Please send an issue or pull request if you are ready. 17 | 18 | ## License 19 | 20 | Mulan PSL v2 21 | 22 | ``` 23 | Copyright (c) 2021 RustSBI Team 24 | Rust-XuanTie-Support is licensed under Mulan PSL v2. 25 | You can use this software according to the terms and conditions of the Mulan PSL v2. 26 | You may obtain a copy of Mulan PSL v2 at: 27 | http://license.coscl.org.cn/MulanPSL2 28 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 29 | EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 30 | MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 31 | See the Mulan PSL v2 for more details. 32 | ``` 33 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcindex.rs: -------------------------------------------------------------------------------- 1 | //! mcindex, machine cache visit index register 2 | use bit_field::BitField; 3 | use core::arch::asm; 4 | 5 | /// RAM information 6 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 7 | pub enum RID { 8 | /// Instruction cache tag RAM 9 | ICacheTag = 0, 10 | /// Instruction cache data RAM 11 | ICacheData = 1, 12 | /// Data cache tag RAM 13 | DCacheTag = 2, 14 | /// Data cache data RAM 15 | DCacheData = 3, 16 | } 17 | 18 | /// Set RAM to visit 19 | #[inline] 20 | pub unsafe fn set_rid(rid: RID) { 21 | let mut value: usize; 22 | asm!("csrr {}, 0x7D3", out(reg) value); 23 | value.set_bits(28..=29, rid as usize); 24 | asm!("csrw 0x7D3, {}", in(reg) value); 25 | } 26 | 27 | /// Set way in level 1 28 | #[inline] 29 | pub unsafe fn set_way_l1(way: u8) { 30 | assert!(way <= 0b1111); 31 | let mut value: usize; 32 | asm!("csrr {}, 0x7D3", out(reg) value); 33 | value.set_bits(17..=20, way as usize); 34 | asm!("csrw 0x7D3, {}", in(reg) value); 35 | } 36 | 37 | /// Set way in level 2 38 | #[inline] 39 | pub unsafe fn set_way_l2(way: u8) { 40 | assert!(way <= 0b1111); 41 | let mut value: usize; 42 | asm!("csrr {}, 0x7D3", out(reg) value); 43 | value.set_bits(21..=24, way as usize); 44 | asm!("csrw 0x7D3, {}", in(reg) value); 45 | } 46 | 47 | /// Set cache index 48 | /// 49 | /// Lower 4 for 6 bits may be ignored according to RAM type and actual SoC implementation. 50 | #[inline] 51 | pub unsafe fn set_index(index: u32) { 52 | assert!(index <= 0x1FFFF); 53 | let mut value: usize; 54 | asm!("csrr {}, 0x7D3", out(reg) value); 55 | value.set_bits(0..=16, index as usize); 56 | asm!("csrw 0x7D3, {}", in(reg) value); 57 | } 58 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register.rs: -------------------------------------------------------------------------------- 1 | //! XuanTie extended CSRs. 2 | 3 | // Extended state registers for performance cores 4 | pub mod mxstatus; // 0x7C0 5 | pub mod mhcr; // 0x7C1 6 | pub mod mcor; // 0x7C2 7 | pub mod mccr2; // 0x7C3, mccr2h 0x7CB RV32 8 | pub mod mcer2; // 0x7C4, mcer2h 0x7FF RV32 9 | pub mod mhint; // 0x7C5, mhint2h 0x7CA RV32 10 | pub mod mrmr; // 0x7C6 11 | pub mod mrvbr; // 0x7C7 12 | pub mod mcer; // 0x7C8 13 | // pub mod mcounterwen; // 0x7C9 14 | // pub mod mcounterinten; // 0x7CA 15 | // pub mod mcounterof; // 0x7CB 16 | 17 | // Extended supervisor state registers 18 | pub mod sxstatus; // 0x5C0 19 | pub mod shcr; // 0x5C1 20 | pub mod scer2; // 0x5C2, scer2h 0x5D4 RV32 21 | pub mod scer; // 0x5C3, scerh 0x5D3 RV32 22 | // pub mod scounterinten; // 0x5C4 23 | // pub mod scounterof; // 0x5C5 24 | 25 | // Extended supervisor virtual memory registers 26 | // pub mod smir; // 0x9C0 27 | pub mod smel; // 0x9C1 28 | pub mod smeh; // 0x9C2 29 | // pub mod smcir; // 0x9C3 30 | 31 | // Extended state registers for embedded cores 32 | pub mod mraddr; // 0x7E0 33 | pub mod mexstatus; // 0x7E1 34 | pub mod mnmicause; // 0x7E2 35 | pub mod mnmipc; // 0x7E3 36 | 37 | // Extended float point registers 38 | pub mod fxcr; // 0x800 39 | 40 | // Performance counter 41 | pub mod mhpmcounter; 42 | // pub mod shpmcounter; // 0x5E3..=0x5FF 43 | 44 | // Cache direct access registers 45 | pub mod mcins; // 0x7D2 46 | pub mod mcindex; // 0x7D3, mcindexh 0x7DA RV32 47 | pub mod mcdata; // mcdata0 0x7D4, mcdata1 0x7D5, mcdata0h 0x7DB RV32, mcdata1h 0x7DB? RV32 48 | pub mod meicr; // 0x7D6 49 | pub mod meicr2; // 0x7D7 50 | // pub mod mbeaddr; // 0x7D8 51 | 52 | // Processor identification registers 53 | pub mod mcpuid; // 0xFC0 54 | pub mod mapbaddr; // 0xFC1 55 | // pub mod mapbaddr2; // 0xFC3 56 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mhpmcounter.rs: -------------------------------------------------------------------------------- 1 | //! mhpmcounter, XuanTie performance counter 2 | 3 | /// mhpmcounter3: L1 I-cache access counter 4 | pub fn l1_i_cache_access() -> usize { 5 | unsafe { get_csr_value!(0xB03) } 6 | } 7 | /// mhpmcounter4: L1 I-cache miss counter 8 | pub fn l1_i_cache_miss() -> usize { 9 | unsafe { get_csr_value!(0xB04) } 10 | } 11 | /// mhpmcounter5: I-uTLB miss counter 12 | pub fn i_utlb_miss() -> usize { 13 | unsafe { get_csr_value!(0xB05) } 14 | } 15 | /// mhpmcounter6: D-uTLB miss counter 16 | pub fn d_utlb_miss() -> usize { 17 | unsafe { get_csr_value!(0xB06) } 18 | } 19 | /// mhpmcounter7: jTLB miss counter 20 | pub fn jtlb_miss() -> usize { 21 | unsafe { get_csr_value!(0xB07) } 22 | } 23 | /// mhpmcounter8: Conditional branch mispredict counter 24 | pub fn conditional_branch_mispredict() -> usize { 25 | unsafe { get_csr_value!(0xB08) } 26 | } 27 | /// mhpmcounter9: Conditional branch instruction counter 28 | pub fn conditional_branch_instruction() -> usize { 29 | unsafe { get_csr_value!(0xB09) } 30 | } 31 | /// mhpmcounter13: Store instruction counter 32 | pub fn store_instruction() -> usize { 33 | unsafe { get_csr_value!(0xB0D) } 34 | } 35 | /// mhpmcounter14: L1 D-cache read access counter 36 | pub fn l1_d_cache_read_access() -> usize { 37 | unsafe { get_csr_value!(0xB0E) } 38 | } 39 | /// mhpmcounter15: L1 D-cache read miss counter 40 | pub fn l1_d_cache_read_miss() -> usize { 41 | unsafe { get_csr_value!(0xB0F) } 42 | } 43 | /// mhpmcounter16: L1 D-cache write access counter 44 | pub fn l1_d_cache_write_access() -> usize { 45 | unsafe { get_csr_value!(0xB10) } 46 | } 47 | /// mhpmcounter17: L1 D-cache write miss counter 48 | pub fn l1_d_cache_write_miss() -> usize { 49 | unsafe { get_csr_value!(0xB11) } 50 | } 51 | // 10..=12, 18..=31: undefined 52 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/thead_c906.rs: -------------------------------------------------------------------------------- 1 | use super::riscv_fpu::init_floating_point; 2 | use crate::{ 3 | main, 4 | stack::{STACK, STACK_SIZE}, 5 | }; 6 | 7 | #[unsafe(naked)] 8 | #[unsafe(link_section = ".init")] 9 | pub unsafe extern "C" fn thead_c906_start() -> ! { 10 | core::arch::naked_asm!( 11 | // Disable interrupt 12 | "csrw mie, zero", 13 | // Enable T-Head ISA extension 14 | "li t1, 1 << 22", 15 | "csrs 0x7C0, t1", 16 | // Enable T-Head caches 17 | "li t0, 0x70013 18 | csrw 0x7C2, t0 19 | li t0, 0x11ff 20 | csrw 0x7C1, t0 21 | li t0, 0x638000 22 | csrs 0x7C0, t0 23 | li t0, 0x16e30c 24 | csrw 0x7C5, t0", 25 | // Invalidate instruction and data cache, branch history table 26 | // and branch target buffer table 27 | "li t1, 0x30013", 28 | "csrs 0x7C2, t1", 29 | // Prepare programming language stack 30 | "la sp, {stack} + {stack_size}", 31 | // Clear `.bss` section 32 | "la t1, sbss 33 | la t2, ebss 34 | 3: bgeu t1, t2, 3f 35 | sd zero, 0(t1) 36 | addi t1, t1, 8 37 | j 3b 38 | 3: ", 39 | // Enable floating point unit 40 | "call {init_floating_point}", 41 | // Start Rust main function 42 | "call {main}", 43 | // Platform halt if main function returns 44 | "call {thead_c906_halt}", 45 | stack = sym STACK, 46 | stack_size = const STACK_SIZE, 47 | init_floating_point = sym init_floating_point, 48 | main = sym main, 49 | thead_c906_halt = sym thead_c906_halt, 50 | ) 51 | } 52 | 53 | /// Stop a T-Head C906 core. 54 | #[unsafe(naked)] 55 | pub unsafe extern "C" fn thead_c906_halt() -> ! { 56 | core::arch::naked_asm!( 57 | "li x3, 0x20aaa 58 | csrs mie, x3 59 | csrci mstatus, 0x8 60 | csrci 0x7C5, 0x4 61 | .insn i 0x0B, 0, x0, x0, 0x001 62 | csrci 0x7C1, 0x2 63 | wfi", 64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcer.rs: -------------------------------------------------------------------------------- 1 | //! mcer, machine L1-cache error control register 2 | use bit_field::BitField; 3 | 4 | /// mcer register 5 | #[derive(Clone, Copy, Debug)] 6 | pub struct Mcer { 7 | bits: usize, 8 | } 9 | 10 | /// Error controllable RAM index 11 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 12 | pub enum RAMID { 13 | /// Instruction cache tag ram 14 | ICacheTag = 0, 15 | /// Instruction cache data ram 16 | ICacheData = 1, 17 | /// Data cache tag ram 18 | DCacheTag = 2, 19 | /// Data cache data ram 20 | DCacheData = 3, 21 | /// jTLB tag ram 22 | JTlbTag = 4, 23 | /// jTLB data ram 24 | JTlbData = 5, 25 | } 26 | 27 | impl Mcer { 28 | /// Error index 29 | #[inline] 30 | pub fn err_index(&self) -> u16 { 31 | self.bits.get_bits(0..=15) as u16 32 | } 33 | /// Error way 34 | #[inline] 35 | pub fn err_way(&self) -> u8 { 36 | self.bits.get_bits(17..=18) as u8 37 | } 38 | /// RAM that the error correction fatal error taken place 39 | #[inline] 40 | pub fn ramid(&self) -> RAMID { 41 | match self.bits.get_bits(21..=23) { 42 | 0 => RAMID::ICacheTag, 43 | 1 => RAMID::ICacheData, 44 | 2 => RAMID::DCacheTag, 45 | 3 => RAMID::DCacheData, 46 | 4 => RAMID::JTlbTag, 47 | 5 => RAMID::JTlbData, 48 | _ => unreachable!(), 49 | } 50 | } 51 | /// Count of errors that are already fixed 52 | #[inline] 53 | pub fn fix_cnt(&self) -> u8 { 54 | self.bits.get_bits(24..=29) as u8 55 | } 56 | /// Is L1-cache error correction error a fatal error 57 | #[inline] 58 | pub fn err_fatal(&self) -> bool { 59 | self.bits.get_bit(30) 60 | } 61 | /// Error correction information valid 62 | #[inline] 63 | pub fn err_vld(&self) -> bool { 64 | self.bits.get_bit(31) 65 | } 66 | } 67 | 68 | read_csr_as!(Mcer, 0x7C8); 69 | 70 | clear_csr! { 71 | /// Clear error correction fatal error bit 72 | , 0x7C8, clear_err_fatal, 1 << 30 73 | } 74 | clear_csr! { 75 | /// Clear error correction information valid bit 76 | , 0x7C8, clear_err_vld, 1 << 31 77 | } 78 | -------------------------------------------------------------------------------- /xuantie-riscv-rt/src/arch/thead_e907.rs: -------------------------------------------------------------------------------- 1 | use super::riscv_fpu::init_floating_point; 2 | use crate::{ 3 | main, 4 | stack::{STACK, STACK_SIZE}, 5 | }; 6 | 7 | #[unsafe(naked)] 8 | #[unsafe(link_section = ".init")] 9 | pub unsafe extern "C" fn thead_e907_start() -> ! { 10 | core::arch::naked_asm!( 11 | // 1. Disable interrupt 12 | " csrw mie, zero", 13 | // 2. Hart specific initialization 14 | // Enable T-Head instruction sets (THEADISAEE) and 15 | // misaligned access (MM) in `mxstatus` register. 16 | " li t1, 0x408000 17 | csrs 0x7c0, t1", 18 | // TODO SPUSHEN and SPSWAPEN in `mexstatus` once we have trap handler 19 | // Enable T-Head caches (BTB=1, BPE=1, RS=1, WA=1, WB=1, DE=1, IE=1) 20 | // in `mhcr` register; 21 | // enable T-Head hint operations (PREF_N=3, AMR=1, D_PLD=1) 22 | // in `mhint` register. 23 | " li t0, 0x103f 24 | csrw 0x7c1, t0 25 | li t1, 0x600c 26 | csrw 0x7c5, t1", 27 | // 3. Initialize float point unit 28 | " call {init_floating_point}", 29 | // 4. Clear `.bss` section 30 | " la t0, sbss 31 | la t1, ebss 32 | 2: bgeu t0, t1, 3f 33 | sw zero, 0(t0) 34 | addi t0, t0, 4 35 | j 2b", 36 | "3:", 37 | // 5. Prepare programming language stack 38 | " la sp, {stack} + {stack_size}", 39 | // 6. Start Rust main function 40 | " call {main}", 41 | // 7. Platform halt if main function returns 42 | " call {thead_e907_halt}", 43 | stack = sym STACK, 44 | stack_size = const STACK_SIZE, 45 | init_floating_point = sym init_floating_point, 46 | main = sym main, 47 | thead_e907_halt = sym thead_e907_halt, 48 | ) 49 | } 50 | 51 | /// Stop a T-Head E907 core. 52 | #[unsafe(naked)] 53 | pub unsafe extern "C" fn thead_e907_halt() -> ! { 54 | core::arch::naked_asm!( 55 | "li t0, 0x1c 56 | csrc 0x7e1, t0 57 | csrci mstatus, 0x8 58 | 2: wfi 59 | j 2b", 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/sxstatus.rs: -------------------------------------------------------------------------------- 1 | //! sxstatus, supervisor extended state register 2 | pub use super::mxstatus::PM; 3 | use bit_field::BitField; 4 | 5 | /// sxstatus register 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct Sxstatus { 8 | bits: usize, 9 | } 10 | 11 | impl Sxstatus { 12 | /// User mode performance monitor enable 13 | #[inline] 14 | pub fn pmdu(&self) -> bool { 15 | self.bits.get_bit(10) 16 | } 17 | /// Supervisor mode performance monitor enable 18 | #[inline] 19 | pub fn pmds(&self) -> bool { 20 | self.bits.get_bit(11) 21 | } 22 | /// Machine mode performance monitor enable 23 | #[inline] 24 | pub fn pmdm(&self) -> bool { 25 | self.bits.get_bit(12) 26 | } 27 | /// Is PMP minimum stride 4K bytes 28 | #[inline] 29 | pub fn pmp4k(&self) -> bool { 30 | self.bits.get_bit(14) 31 | } 32 | /// Unaligned access enable 33 | #[inline] 34 | pub fn mm(&self) -> bool { 35 | self.bits.get_bit(15) 36 | } 37 | /// User mode allow extended cache instruction 38 | #[inline] 39 | pub fn ucme(&self) -> bool { 40 | self.bits.get_bit(16) 41 | } 42 | /// CLINT supervisor extension enable 43 | #[inline] 44 | pub fn clintee(&self) -> bool { 45 | self.bits.get_bit(17) 46 | } 47 | /// Hardware refill when TLB item absent enable 48 | #[inline] 49 | pub fn mhrd(&self) -> bool { 50 | self.bits.get_bit(18) 51 | } 52 | /// Extend MMU page table entry address attributes enable 53 | #[inline] 54 | pub fn maee(&self) -> bool { 55 | self.bits.get_bit(21) 56 | } 57 | /// T-Head extended instruction set architecture enable 58 | #[inline] 59 | pub fn theadisaee(&self) -> bool { 60 | self.bits.get_bit(22) 61 | } 62 | /// Current privileged mode 63 | #[inline] 64 | pub fn pm(&self) -> PM { 65 | match self.bits.get_bits(30..=31) { 66 | 0b00 => PM::User, 67 | 0b01 => PM::Supervisor, 68 | 0b11 => PM::Machine, 69 | _ => unreachable!(), 70 | } 71 | } 72 | } 73 | 74 | read_csr_as!(Sxstatus, 0x5C0); 75 | 76 | set_clear_csr! { 77 | /// Unaligned access enable 78 | , 0x5C0, set_mm, clear_mm, 1 << 15 79 | } 80 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mcdata.rs: -------------------------------------------------------------------------------- 1 | //! mcdata{0,1}, machine cache data registers 2 | use bit_field::BitField; 3 | use core::arch::asm; 4 | 5 | /// I-cache tag RAM visit result 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct ICacheTag { 8 | pub tag: u32, 9 | pub valid: bool, 10 | } 11 | 12 | /// Get I-cache tag visit result 13 | #[inline] 14 | pub fn get_icache_tag() -> ICacheTag { 15 | let mcdata0 = read_mcdata0(); 16 | ICacheTag { 17 | tag: mcdata0.get_bits(12..=39) as u32, 18 | valid: mcdata0.get_bit(0), 19 | } 20 | } 21 | 22 | /// I-cache data RAM visit result 23 | #[derive(Clone, Copy, Debug)] 24 | pub struct ICacheData { 25 | pub data: u128, 26 | } 27 | 28 | /// Get I-cache data visit result 29 | #[inline] 30 | pub fn get_icache_data() -> ICacheData { 31 | let (mcdata0, mcdata1) = read_mcdata(); 32 | ICacheData { 33 | data: (mcdata0 as u128) | ((mcdata1 as u128) << 64), 34 | } 35 | } 36 | 37 | /// D-cache tag RAM visit result 38 | #[derive(Clone, Copy, Debug)] 39 | pub struct DCacheTag { 40 | pub tag: u32, 41 | pub dirty: bool, 42 | pub valid: bool, 43 | } 44 | 45 | /// Get D-cache tag visit result 46 | #[inline] 47 | pub fn get_dcache_tag() -> DCacheTag { 48 | let mcdata0 = read_mcdata0(); 49 | DCacheTag { 50 | tag: mcdata0.get_bits(12..=39) as u32, 51 | dirty: mcdata0.get_bit(2), 52 | valid: mcdata0.get_bit(0), 53 | } 54 | } 55 | 56 | /// D-cache data RAM visit result 57 | #[derive(Clone, Copy, Debug)] 58 | pub struct DCacheData { 59 | pub data: u128, 60 | } 61 | 62 | /// Get D-cache data visit result 63 | #[inline] 64 | pub fn get_dcache_data() -> DCacheData { 65 | let (mcdata0, mcdata1) = read_mcdata(); 66 | DCacheData { 67 | data: (mcdata0 as u128) | ((mcdata1 as u128) << 64), 68 | } 69 | } 70 | 71 | #[inline] 72 | fn read_mcdata() -> (usize, usize) { 73 | let (mcdata0, mcdata1); 74 | unsafe { 75 | asm!( 76 | "csrr {0}, 0x7D4", 77 | "csrr {1}, 0x7D5", 78 | out(reg) mcdata0, 79 | out(reg) mcdata1, 80 | ); 81 | } 82 | (mcdata0, mcdata1) 83 | } 84 | 85 | #[inline] 86 | fn read_mcdata0() -> usize { 87 | let mcdata0; 88 | unsafe { 89 | asm!("csrr {}, 0x7D4", out(reg) mcdata0); 90 | } 91 | mcdata0 92 | } 93 | -------------------------------------------------------------------------------- /xuantie-riscv/src/asm/xtheadint.rs: -------------------------------------------------------------------------------- 1 | use core::arch::asm; 2 | 3 | // T-Head extended instructions are mostly encoded under custom-0 opcode space (opcode 0x0B). 4 | 5 | /// Fast interrupt stack push instruction. 6 | /// 7 | /// Push interrupt switch registers into current stack. 8 | /// It pushes `mcause`, `mepc`, `x1`, `x5` to `x7`, `x10` to `x17` and `x28` to `x31` into stack. 9 | /// Another word, the pushed `xi` integer registers are `ra`, `t0` to `t6`, and `a0` to `a7` (not in order) 10 | /// other than CSR registers `mcause` and `mepc`. 11 | /// 12 | /// In pseudocode, it performs like: 13 | /// 14 | /// ```no_run 15 | /// # let mut sp: *mut u8 = core::ptr::null_mut(); 16 | /// # let (mcause, mepc, ra, t6) = (0, 0, 0, 0); 17 | /// # unsafe { 18 | /// *sp.sub(1) = mcause; 19 | /// *sp.sub(2) = mepc; 20 | /// *sp.sub(3) = ra; 21 | /// /* ... Mem[sp - 4] ..= Mem[sp - 72] ← mcause, mepc, {xi} */ 22 | /// *sp.sub(18) = t6; 23 | /// sp = sp.sub(18); 24 | /// # } 25 | /// ``` 26 | /// 27 | /// # Permissions 28 | /// 29 | /// Must run on M mode. 30 | /// 31 | /// # Exceptions 32 | /// 33 | /// Raises store unaligned exception, store access exception, or illegal instruction exception. 34 | #[inline] 35 | pub unsafe fn ipush() { 36 | // ipush 37 | asm!(".insn i 0x0B, 0, x0, x0, 0x004") 38 | } 39 | 40 | /// Fast interrupt stack pop instruction. 41 | /// 42 | /// Pop interrupt switch registers from current stack, and return from interrupt environment. 43 | /// It pops `mcause`, `mepc`, `x1`, `x5` to `x7`, `x10` to `x17` and `x28` to `x31` from stack. 44 | /// Another word, the popped `xi` integer registers are `ra`, `t0` to `t6`, and `a0` to `a7` (not in order) 45 | /// other than CSR registers `mcause` and `mepc`. 46 | /// 47 | /// In pseudocode, it performs like: 48 | /// 49 | /// ```no_run 50 | /// # mod riscv { pub mod asm { pub fn mret() {} }} 51 | /// # let sp: *mut u8 = core::ptr::null_mut(); 52 | /// # unsafe { 53 | /// let mcause = *sp.add(17); 54 | /// let mepc = *sp.add(16); 55 | /// let ra = *sp.add(15); 56 | /// /* ... mcause, mepc, {xi} ← Mem[sp + 68] ..= Mem[sp] */ 57 | /// let t6 = *sp.add(0); 58 | /// let sp = sp.add(18); 59 | /// riscv::asm::mret(); 60 | /// # } 61 | /// ``` 62 | /// 63 | /// # Permissions 64 | /// 65 | /// Must run on M mode. 66 | /// 67 | /// # Exceptions 68 | /// 69 | /// Raises store unaligned exception, store access exception, or illegal instruction exception. 70 | #[inline] 71 | pub unsafe fn ipop() { 72 | // ipop 73 | asm!(".insn i 0x0B, 0, x0, x0, 0x005") 74 | } 75 | -------------------------------------------------------------------------------- /xuantie-riscv/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Low level access to T-Head XuanTie RISC-V processors. 2 | //! 3 | //! # Examples 4 | //! 5 | //! Here's a list of example code of how to using this library under different scenarios. 6 | //! 7 | //! ## Enable and invalidate caches 8 | //! 9 | //! C906 will invalid both I-cache and D-cache automatically when reset. 10 | //! Use the following operation, we can enable I-cache and D-cache. 11 | //! 12 | //! ```no_run 13 | //! use xuantie_riscv::register::mhcr; 14 | //! // enable D-cache 15 | //! unsafe { mhcr::set_de() }; 16 | //! // enable I-cache 17 | //! unsafe { mhcr::set_ie() }; 18 | //! ``` 19 | //! 20 | //! Additionally, we can invalidate I-cache or D-cache manually if necessary. 21 | //! 22 | //! ```no_run 23 | //! // If we don't have `mxstatus.theadisaee` enabled 24 | //! use xuantie_riscv::register::mcor::{self, Cache, Operation}; 25 | //! // invalidate caches. Use `Cache::DATA` or `Cache::INSTRUCION` 26 | //! // to invalid a specific cache. 27 | //! unsafe { mcor::cache(Cache::BOTH, Operation::INVALIDATE); } 28 | //! ``` 29 | //! ```no_run 30 | //! // If we have `mxstatus.theadisaee` enabled 31 | //! use xuantie_riscv::asm::{icache_iall, dcache_iall, sync_is}; 32 | //! // invalidate I-cache 33 | //! unsafe { icache_iall(); sync_is(); } 34 | //! // invalidate D-cache 35 | //! unsafe { dcache_iall(); sync_is(); } 36 | //! ``` 37 | //! 38 | //! ## CPU power down 39 | //! 40 | //! The following code would power down a Xuantie C906 core. 41 | //! This procedure is useful when developing SBI implementations. 42 | //! 43 | //! Make sure the hart is at M mode when executing the following code. 44 | //! 45 | //! ```no_run 46 | //! # mod riscv { pub mod register { pub mod mstatus { pub fn clear_mie() {} }} pub mod asm { pub fn wfi() {}}} 47 | //! use riscv::{asm::wfi, register::mstatus}; 48 | //! use xuantie_riscv::{asm::dcache_call, register::{mhint, mhcr}}; 49 | //! // power down the current processor hart 50 | //! unsafe fn shutdown() -> ! { 51 | //! // disable interrupt 52 | //! mstatus::clear_mie(); 53 | //! // disable data prefetch 54 | //! mhint::clear_dpld(); 55 | //! // clear D-cache 56 | //! dcache_call(); 57 | //! // disable D-cache 58 | //! mhcr::clear_de(); 59 | //! // execute wait-for-interrupt instruction 60 | //! wfi(); 61 | //! // no instruction would be able to wake this WFI 62 | //! unreachable!() 63 | //! } 64 | //! ``` 65 | #![no_std] 66 | 67 | #[macro_use] 68 | mod macros; 69 | pub mod asm; 70 | pub mod debug; 71 | pub mod paging; 72 | pub mod peripheral; 73 | 74 | #[rustfmt::skip] 75 | pub mod register; 76 | -------------------------------------------------------------------------------- /xuantie-riscv/src/paging.rs: -------------------------------------------------------------------------------- 1 | //! Paging support. 2 | 3 | use bit_field::BitField; 4 | 5 | /// XuanTie extended 64-bit page table entry. 6 | #[derive(Clone, Copy, Debug)] 7 | #[repr(transparent)] 8 | pub struct Entry { 9 | bits: u64, 10 | } 11 | 12 | impl Entry { 13 | /// Convert bit representation into page entry, keeping all the bits. 14 | #[inline] 15 | pub const fn from_bits(bits: u64) -> Entry { 16 | Entry { bits } 17 | } 18 | /// Returns the raw value of the entry. 19 | #[inline] 20 | pub const fn bits(&self) -> u64 { 21 | self.bits 22 | } 23 | /// Set physical page number. 24 | #[inline] 25 | pub fn set_ppn(&mut self, ppn: u64) { 26 | assert!(ppn <= (1 << (28 + 1))); 27 | self.bits |= ppn << 10; 28 | } 29 | /// Get physical page number. 30 | #[inline] 31 | pub fn ppn(&self) -> u64 { 32 | self.bits.get_bits(10..38) 33 | } 34 | /// Insert entry flags, setting corresponding bits to one. 35 | #[inline] 36 | pub fn insert_flags(&mut self, other: Flags) { 37 | self.bits |= other.bits() 38 | } 39 | /// Remove entry flags, setting corresponding bits to zero. 40 | #[inline] 41 | pub fn remove_flags(&mut self, other: Flags) { 42 | self.bits &= !other.bits() 43 | } 44 | /// Inserts or removes entry flags depending on the passed value. 45 | #[inline] 46 | pub fn set_flags(&mut self, other: Flags, value: bool) { 47 | if value { 48 | self.insert_flags(other); 49 | } else { 50 | self.remove_flags(other); 51 | } 52 | } 53 | /// Toggles the entry flags. 54 | #[inline] 55 | pub fn toggle_flags(&mut self, other: Flags) { 56 | self.bits ^= other.bits() 57 | } 58 | /// Get entry flags. 59 | #[inline] 60 | pub const fn get_flags(&self) -> Flags { 61 | Flags::from_bits_truncate(self.bits) 62 | } 63 | } 64 | 65 | bitflags::bitflags! { 66 | /// XuanTie 64-bit page table entry flags. 67 | pub struct Flags: u64 { 68 | /// Valid. 69 | const VALID = 1 << 0; 70 | /// Read. 71 | const READABLE = 1 << 1; 72 | /// Write. 73 | const WRITABLE = 1 << 2; 74 | /// Execute. 75 | const EXECUTABLE = 1 << 3; 76 | /// User mode. 77 | const USER = 1 << 4; 78 | /// Global. 79 | const GLOBAL = 1 << 5; 80 | /// Accessed. 81 | const ACCESSED = 1 << 6; 82 | /// Dirty. 83 | const DIRTY = 1 << 7; 84 | /// Secure world trustable. 85 | const TRUSTABLE = 1 << 59; 86 | /// Buffer. 87 | const BUFFER = 1 << 61; 88 | /// Cacheable. 89 | const CACHEABLE = 1 << 62; 90 | /// Strong order. 91 | const STRONG_ORDER = 1 << 63; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/fxcr.rs: -------------------------------------------------------------------------------- 1 | //! fxcr, user extended float pointer control register 2 | 3 | use bit_field::BitField; 4 | use core::arch::asm; 5 | 6 | /// Floating-point control and status register 7 | #[derive(Clone, Copy, Debug)] 8 | pub struct Fxcr { 9 | bits: usize, 10 | } 11 | 12 | bitflags::bitflags! { 13 | /// Fxcr flags 14 | pub struct Flags: usize { 15 | /// Inexact 16 | const NX = 1 << 0; 17 | /// Underflow 18 | const UF = 1 << 1; 19 | /// Overflow 20 | const OF = 1 << 2; 21 | /// Divide by Zero 22 | const DZ = 1 << 3; 23 | /// Invalid Operation 24 | const NV = 1 << 4; 25 | /// Float error accumulator bit 26 | const FE = 1 << 5; 27 | } 28 | } 29 | 30 | /// Rounding Mode 31 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 32 | pub enum RoundingMode { 33 | RoundToNearestEven = 0b000, 34 | RoundTowardsZero = 0b001, 35 | RoundDown = 0b010, 36 | RoundUp = 0b011, 37 | RoundToNearestMaxMagnitude = 0b100, 38 | Invalid = 0b111, 39 | } 40 | 41 | impl Fxcr { 42 | /// Returns the contents of the register as raw bits 43 | pub fn bits(&self) -> usize { 44 | self.bits 45 | } 46 | 47 | /// Accrued Exception Flags 48 | #[inline] 49 | pub fn flags(&self) -> Flags { 50 | Flags::from_bits_truncate(self.bits.get_bits(0..=5)) 51 | } 52 | 53 | /// Output QNaN mode 54 | #[inline] 55 | pub fn dqnan(&self) -> bool { 56 | self.bits.get_bit(23) 57 | } 58 | 59 | /// Rounding Mode 60 | #[inline] 61 | pub fn rm(&self) -> RoundingMode { 62 | match self.bits.get_bits(24..=26) { 63 | 0b000 => RoundingMode::RoundToNearestEven, 64 | 0b001 => RoundingMode::RoundTowardsZero, 65 | 0b010 => RoundingMode::RoundDown, 66 | 0b011 => RoundingMode::RoundUp, 67 | 0b100 => RoundingMode::RoundToNearestMaxMagnitude, 68 | _ => RoundingMode::Invalid, 69 | } 70 | } 71 | } 72 | 73 | read_csr_as!(Fxcr, 0x800); 74 | 75 | set_clear_csr! { 76 | /// Output QNaN mode 77 | , 0x800, set_dqnan, clear_dqnan, 1 << 23 78 | } 79 | 80 | /// Insert float point flags, setting corresponding bits to one. 81 | #[inline] 82 | pub unsafe fn insert_flags(other: Flags) { 83 | asm!("csrs 0x800, {}", in(reg) other.bits()) 84 | } 85 | 86 | /// Remove float point flags, setting corresponding bits to zero 87 | #[inline] 88 | pub unsafe fn remove_flags(other: Flags) { 89 | asm!("csrc 0x800, {}", in(reg) other.bits()) 90 | } 91 | 92 | /// Inserts or removes float point flags depending on the passed value 93 | #[inline] 94 | pub unsafe fn set_flags(other: Flags, value: bool) { 95 | if value { 96 | insert_flags(other); 97 | } else { 98 | remove_flags(other); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /xuantie-riscv/src/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! read_csr_as { 2 | ($register:ident, $csr_number:expr) => { 3 | /// Reads the CSR 4 | #[inline] 5 | pub fn read() -> $register { 6 | match () { 7 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 8 | () => { 9 | let bits: usize; 10 | unsafe { core::arch::asm!(concat!("csrr {}, ",$csr_number), out(reg) bits) }; 11 | $register { bits } 12 | } 13 | #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] 14 | () => { 15 | unimplemented!() 16 | } 17 | } 18 | } 19 | }; 20 | } 21 | 22 | macro_rules! set_csr { 23 | ($(#[$attr:meta])*, $csr_number:expr, $set_field:ident, $e:expr) => { 24 | $(#[$attr])* 25 | #[inline] 26 | pub unsafe fn $set_field() { 27 | match () { 28 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 29 | () => { 30 | core::arch::asm!(concat!("csrs ",$csr_number,", {0}"), in(reg) $e) 31 | } 32 | #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] 33 | () => { 34 | unimplemented!() 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | macro_rules! clear_csr { 42 | ($(#[$attr:meta])*, $csr_number:expr, $clear_field:ident, $e:expr) => { 43 | $(#[$attr])* 44 | #[inline] 45 | pub unsafe fn $clear_field() { 46 | match () { 47 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 48 | () => { 49 | core::arch::asm!(concat!("csrc ",$csr_number,", {0}"), in(reg) $e) 50 | } 51 | #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] 52 | () => { 53 | unimplemented!() 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | macro_rules! set_clear_csr { 61 | ($(#[$attr:meta])*, $csr_number:expr, $set_field:ident, $clear_field:ident, $e:expr) => { 62 | set_csr!($(#[$attr])*, $csr_number, $set_field, $e); 63 | clear_csr!($(#[$attr])*, $csr_number, $clear_field, $e); 64 | } 65 | } 66 | macro_rules! get_csr_value { 67 | ($csr_number:expr) => { 68 | match () { 69 | #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] 70 | () => { 71 | let r: usize; 72 | core::arch::asm!(concat!("csrr {}, ",$csr_number), out(reg) r); 73 | r 74 | } 75 | #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] 76 | () => { 77 | unimplemented!() 78 | } 79 | } 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /xuantie-riscv/src/asm/xtheadsync.rs: -------------------------------------------------------------------------------- 1 | use core::arch::asm; 2 | 3 | // TODO: th.sfence.vmas 4 | 5 | /// Synchronize instruction. 6 | /// 7 | /// Ensures that all instructions before retire earlier than this instruction, 8 | /// and all instructions after retire later than this instruction. 9 | /// 10 | /// # Permissions 11 | /// 12 | /// Can run on M, U mode, or S mode if applicable. 13 | /// 14 | /// # Exceptions 15 | /// 16 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 17 | /// when `mxstatus.theadisaee = 1` but run on U mode. 18 | /// 19 | /// # Platform support 20 | /// 21 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 22 | #[inline] 23 | pub unsafe fn sync() { 24 | // th.sync 25 | asm!(".insn i 0x0B, 0, x0, x0, 0x018") 26 | } 27 | 28 | /// Synchronize and broadcast instruction. 29 | /// 30 | /// Ensures that all instructions before retire earlier than this instruction, 31 | /// and all instructions after retire later than this instruction. 32 | /// This request will be broadcast to all other harts. 33 | /// 34 | /// # Permissions 35 | /// 36 | /// Can run on M, S or U mode. 37 | /// 38 | /// # Exceptions 39 | /// 40 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 41 | /// when `mxstatus.theadisaee = 1` but run on U mode. 42 | /// 43 | /// # Platform support 44 | /// 45 | /// This instruction is supported on Xuantie C910, C907 and C908 cores. 46 | #[inline] 47 | pub unsafe fn sync_s() { 48 | // th.sync.s 49 | asm!(".insn i 0x0B, 0, x0, x0, 0x019") 50 | } 51 | 52 | /// Synchronize and clean instruction. 53 | /// 54 | /// Ensures that all instructions before retire earlier than this instruction, 55 | /// and all instructions after retire later than this instruction. 56 | /// The pipeline is emptied when this instruction retires. 57 | /// 58 | /// # Permissions 59 | /// 60 | /// Can run on M, U mode, or S mode if applicable. 61 | /// 62 | /// # Exceptions 63 | /// 64 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 65 | /// when `mxstatus.theadisaee = 1` but run on U mode. 66 | /// 67 | /// # Platform support 68 | /// 69 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 70 | #[inline] 71 | pub unsafe fn sync_i() { 72 | // th.sync.i 73 | asm!(".insn i 0x0B, 0, x0, x0, 0x01A") 74 | } 75 | 76 | /// Synchronize, clean and broadcast instruction. 77 | /// 78 | /// Ensures that all instructions before retire earlier than this instruction, 79 | /// and all instructions after retire later than this instruction. 80 | /// The pipeline is emptied when this instruction retires. 81 | /// This request will be broadcast to all other harts. 82 | /// 83 | /// # Permissions 84 | /// 85 | /// Can run on M, S or U mode. 86 | /// 87 | /// # Exceptions 88 | /// 89 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 90 | /// when `mxstatus.theadisaee = 1` but run on U mode. 91 | /// 92 | /// # Platform support 93 | /// 94 | /// This instruction is supported on Xuantie C910, C907 and C908 cores. 95 | #[inline] 96 | pub unsafe fn sync_is() { 97 | // th.sync.is 98 | asm!(".insn i 0x0B, 0, x0, x0, 0x01B") 99 | } 100 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mexstatus.rs: -------------------------------------------------------------------------------- 1 | //! mexstatus, machine exception state register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie E907, E906 and E902 cores. 6 | use bit_field::BitField; 7 | use core::arch::asm; 8 | 9 | /// mxstatus register 10 | #[derive(Clone, Copy, Debug)] 11 | pub struct Mexstatus { 12 | bits: usize, 13 | } 14 | 15 | /// Software reset mode 16 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 17 | pub enum RSTMD { 18 | /// No operation required 19 | Nop = 0, 20 | /// Reset core only 21 | ResetCore = 1, 22 | /// Reset whole system 23 | ResetSystem = 2, 24 | // 3: reserved 25 | } 26 | 27 | /// Low power mode 28 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 29 | pub enum LPMD { 30 | /// Deep sleep for next WFI 31 | DeepSleep = 0, 32 | /// Light sleep for next WFI 33 | LightSleep = 1, 34 | } 35 | 36 | impl Mexstatus { 37 | /// Software reset mode 38 | #[inline] 39 | pub fn rstmd(&self) -> RSTMD { 40 | match self.bits.get_bits(0..=1) { 41 | 0b00 => RSTMD::Nop, 42 | 0b01 => RSTMD::ResetCore, 43 | 0b10 => RSTMD::ResetSystem, 44 | _ => unreachable!(), 45 | } 46 | } 47 | /// Low power mode 48 | #[inline] 49 | pub fn lpmd(&self) -> LPMD { 50 | match self.bits.get_bits(2..=3) { 51 | 0b00 => LPMD::DeepSleep, 52 | 0b01 => LPMD::LightSleep, 53 | _ => unreachable!(), 54 | } 55 | } 56 | /// Wait for event mode enble 57 | #[inline] 58 | pub fn wfeen(&self) -> bool { 59 | self.bits.get_bit(4) 60 | } 61 | /// Exception state 62 | #[inline] 63 | pub fn expt(&self) -> bool { 64 | self.bits.get_bit(5) 65 | } 66 | /// Lockup state 67 | #[inline] 68 | pub fn lockup(&self) -> bool { 69 | self.bits.get_bit(6) 70 | } 71 | /// NMI state 72 | #[inline] 73 | pub fn nmi(&self) -> bool { 74 | self.bits.get_bit(7) 75 | } 76 | /// Bus error state 77 | #[inline] 78 | pub fn buserr(&self) -> bool { 79 | self.bits.get_bit(8) 80 | } 81 | /// Interrupt auto push stack enable 82 | #[inline] 83 | pub fn spushen(&self) -> bool { 84 | self.bits.get_bit(16) 85 | } 86 | /// Interrupt auto swap stack enable 87 | #[inline] 88 | pub fn spswapen(&self) -> bool { 89 | self.bits.get_bit(17) 90 | } 91 | } 92 | 93 | read_csr_as!(Mexstatus, 0x7E1); 94 | 95 | set_clear_csr! { 96 | /// Wait for event mode enble 97 | , 0x7E1, set_wfeen, clear_wfeen, 1 << 4 98 | } 99 | set_clear_csr! { 100 | /// Interrupt auto push stack enable 101 | , 0x7E1, set_spushen, clear_spushen, 1 << 16 102 | } 103 | set_clear_csr! { 104 | /// Interrupt auto swap stack enable 105 | , 0x7E1, set_spswapen, clear_spswapen, 1 << 17 106 | } 107 | 108 | /// Set software reset mode 109 | #[inline] 110 | pub unsafe fn set_rstmd(rstmd: RSTMD) { 111 | asm!("csrs 0x7E1, {}", in(reg) rstmd as usize) 112 | } 113 | 114 | /// Set low power mode 115 | #[inline] 116 | pub unsafe fn set_lpmd(lpmd: LPMD) { 117 | let mut value: usize; 118 | asm!("csrr {}, 0x7E1", out(reg) value); 119 | value.set_bits(2..=3, lpmd as usize); 120 | asm!("csrw 0x7E1, {}", in(reg) value); 121 | } 122 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mhcr.rs: -------------------------------------------------------------------------------- 1 | //! mhcr, machine hardware configuration register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie C910, C906, E906 and E902 cores. 6 | use bit_field::BitField; 7 | 8 | /// mhcr register 9 | #[derive(Clone, Copy, Debug)] 10 | pub struct Mhcr { 11 | bits: usize, 12 | } 13 | 14 | impl Mhcr { 15 | /// I-cache enable 16 | /// 17 | /// # Platform support 18 | /// 19 | /// This bit is supported on Xuantie C910, C906, E907, E906 and E902 cores. 20 | #[inline] 21 | pub fn ie(&self) -> bool { 22 | self.bits.get_bit(0) 23 | } 24 | /// D-cache enable 25 | /// 26 | /// # Platform support 27 | /// 28 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 29 | #[inline] 30 | pub fn de(&self) -> bool { 31 | self.bits.get_bit(1) 32 | } 33 | /// Cache write allocate configuration enable 34 | /// 35 | /// # Platform support 36 | /// 37 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 38 | #[inline] 39 | pub fn wa(&self) -> bool { 40 | self.bits.get_bit(2) 41 | } 42 | /// Write back enable; true for write back, false for write through 43 | /// 44 | /// # Platform support 45 | /// 46 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 47 | #[inline] 48 | pub fn wb(&self) -> bool { 49 | self.bits.get_bit(3) 50 | } 51 | /// Return stack enable 52 | /// 53 | /// # Platform support 54 | /// 55 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 56 | #[inline] 57 | pub fn rs(&self) -> bool { 58 | self.bits.get_bit(4) 59 | } 60 | /// Branch predict enable 61 | /// 62 | /// # Platform support 63 | /// 64 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 65 | #[inline] 66 | pub fn bpe(&self) -> bool { 67 | self.bits.get_bit(5) 68 | } 69 | /// Branch target buffer enable 70 | /// 71 | /// # Platform support 72 | /// 73 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 74 | #[inline] 75 | pub fn btb(&self) -> bool { 76 | self.bits.get_bit(6) 77 | } 78 | /// Write bulk transfer enable 79 | #[inline] 80 | pub fn wbr(&self) -> bool { 81 | self.bits.get_bit(8) 82 | } 83 | } 84 | 85 | read_csr_as!(Mhcr, 0x7C1); 86 | 87 | set_clear_csr! { 88 | /// I-cache enable 89 | , 0x7C1, set_ie, clear_ie, 1 << 0 90 | } 91 | set_clear_csr! { 92 | /// D-cache enable 93 | , 0x7C1, set_de, clear_de, 1 << 1 94 | } 95 | set_clear_csr! { 96 | /// Cache write allocate configuration enable 97 | , 0x7C1, set_wa, clear_wa, 1 << 2 98 | } 99 | set_clear_csr! { 100 | /// Write back enable; clear this bit to be write through 101 | , 0x7C1, set_wb, clear_wb, 1 << 3 102 | } 103 | set_clear_csr! { 104 | /// Return stack enable 105 | , 0x7C1, set_rs, clear_rs, 1 << 4 106 | } 107 | set_clear_csr! { 108 | /// Branch predict enable 109 | , 0x7C1, set_bpe, clear_bpe, 1 << 5 110 | } 111 | set_clear_csr! { 112 | /// Branch target buffer enable 113 | , 0x7C1, set_btb, clear_btb, 1 << 6 114 | } 115 | set_clear_csr! { 116 | /// Write bulk transfer enable 117 | , 0x7C1, set_wbr, clear_wbr, 1 << 8 118 | } 119 | -------------------------------------------------------------------------------- /xuantie-riscv/src/peripheral/clint.rs: -------------------------------------------------------------------------------- 1 | //! XuanTie Core Local Interrupt (CLINT) peripheral. 2 | 3 | use volatile_register::RW; 4 | 5 | /// Machine-mode Software Interrupt Pending (MSIP) register. 6 | #[repr(transparent)] 7 | pub struct MSIP(RW); 8 | 9 | /// Machine-mode Timer Compare (MTIMECMP) register group. 10 | #[repr(C)] 11 | pub struct MTIMECMP { 12 | /// Low 32-bit word of MTIMECMP register. 13 | mtimecmpl: RW, 14 | /// High 32-bit word of MTIMECMP register. 15 | mtimecmph: RW, 16 | } 17 | 18 | /// Supervisor-mode Software Interrupt Pending (SSIP) register. 19 | #[repr(transparent)] 20 | pub struct SSIP(RW); 21 | 22 | /// Supervisor-mode Timer Compare (STIMECMP) register group. 23 | #[repr(C)] 24 | pub struct STIMECMP { 25 | /// Low 32-bit word of STIMECMP register. 26 | stimecmpl: RW, 27 | /// High 32-bit word of STIMECMP register. 28 | stimecmph: RW, 29 | } 30 | 31 | /// Register block for XuanTie Core Local Interrupt (CLINT) peripheral. 32 | #[repr(C)] 33 | pub struct THeadClint { 34 | msip: [MSIP; 4096], 35 | mtimecmp: [MTIMECMP; 4096], 36 | ssip: [SSIP; 1024], 37 | stimecmp: [STIMECMP; 1024], 38 | } 39 | 40 | impl THeadClint { 41 | /// Determine whether `hart_idx` has a valid machine mode software interrupt. 42 | #[inline] 43 | pub fn read_msip(&self, hart_idx: usize) -> bool { 44 | self.msip[hart_idx].0.read() != 0 45 | } 46 | 47 | /// Set the machine mode software interrupt of `hart_idx`. 48 | #[inline] 49 | pub fn set_msip(&self, hart_idx: usize) { 50 | unsafe { self.msip[hart_idx].0.write(1) } 51 | } 52 | 53 | /// Clear the machine mode software interrupt of `hart_idx`. 54 | #[inline] 55 | pub fn clear_msip(&self, hart_idx: usize) { 56 | unsafe { self.msip[hart_idx].0.write(0) } 57 | } 58 | 59 | /// Read the mtimecmp register of `hart_idx`. 60 | #[inline] 61 | pub fn read_mtimecmp(&self, hart_idx: usize) -> u64 { 62 | let mtimecmpl = self.mtimecmp[hart_idx].mtimecmpl.read(); 63 | let mtimecmph = self.mtimecmp[hart_idx].mtimecmph.read(); 64 | ((mtimecmph as u64) << 32) | mtimecmpl as u64 65 | } 66 | 67 | /// Write the mtimecmp register of `hart_idx`. 68 | #[inline] 69 | pub fn write_mtimecmp(&self, hart_idx: usize, val: u64) { 70 | let mtimecmpl: u32 = (val & 0xffffffff) as u32; 71 | let mtimecmph: u32 = (val >> 32) as u32; 72 | unsafe { self.mtimecmp[hart_idx].mtimecmpl.write(mtimecmpl) } 73 | unsafe { self.mtimecmp[hart_idx].mtimecmph.write(mtimecmph) } 74 | } 75 | 76 | /// Determine whether `hart_idx` has a valid supervisor mode software interrupt. 77 | #[inline] 78 | pub fn read_ssip(&self, hart_idx: usize) -> bool { 79 | self.ssip[hart_idx].0.read() != 0 80 | } 81 | 82 | /// Set the supervisor mode software interrupt of `hart_idx`. 83 | #[inline] 84 | pub fn set_ssip(&self, hart_idx: usize) { 85 | unsafe { self.ssip[hart_idx].0.write(1) } 86 | } 87 | 88 | /// Clear the supervisor mode software interrupt of `hart_idx`. 89 | #[inline] 90 | pub fn clear_ssip(&self, hart_idx: usize) { 91 | unsafe { self.ssip[hart_idx].0.write(0) } 92 | } 93 | 94 | /// Read the `stimecmp` register of `hart_idx`. 95 | #[inline] 96 | pub fn read_stimecmp(&self, hart_idx: usize) -> u64 { 97 | let stimecmpl = self.stimecmp[hart_idx].stimecmpl.read(); 98 | let stimecmph = self.stimecmp[hart_idx].stimecmph.read(); 99 | ((stimecmph as u64) << 32) | stimecmpl as u64 100 | } 101 | 102 | /// Write the `stimecmp` register of `hart_idx`. 103 | #[inline] 104 | pub fn write_stimecmp(&self, hart_idx: usize, val: u64) { 105 | let stimecmpl: u32 = (val & 0xffffffff) as u32; 106 | let stimecmph: u32 = (val >> 32) as u32; 107 | unsafe { self.stimecmp[hart_idx].stimecmpl.write(stimecmpl) } 108 | unsafe { self.stimecmp[hart_idx].stimecmph.write(stimecmph) } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mhint.rs: -------------------------------------------------------------------------------- 1 | //! mhint, machine hint register 2 | //! 3 | //! # Notes on Accure Exception Enable bit 4 | //! 5 | //! When this bit is set, the processor is in precise exception mode. 6 | //! And when this bit is cleared, the processor is in non-precise exception mode. 7 | //! 8 | //! This bit is set to true on reset, and is supported on Xuantie E907 and E906 cores. 9 | //! 10 | //! ## Precise exception 11 | //! 12 | //! Because the return delay of the bus access error exception signal generated by 13 | //! the load/store instruction accessing the bus is unpredictable, 14 | //! the processor will block the pipeline when executing the load/store instruction, 15 | //! and subsequent instructions will not be issued and executed. 16 | //! 17 | //! Until the exception signal returns to the processor and enters the exception service routine, 18 | //! the `mepc` will save the PC of the load/store instruction that generated the bus access exception, 19 | //! so as to realize the precise exception. 20 | //! 21 | //! ## Non-precise exception 22 | //! 23 | //! The processor will not block the pipeline when executing the load/store instruction. 24 | //! If the subsequent instruction is not a load store instruction (in another word, structural contention) 25 | //! and has no data correlation with the load/store instruction, it can continue to execute. 26 | //! 27 | //! When the bus access error exception signal is sent to the processor and the exception service routine is entered, 28 | //! the `mepc` will save the PC of the instruction being executed in the EX stage of the pipeline, 29 | //! not necessarily the PC of the load/store instruction where the memory access error exception occurred. 30 | //! 31 | //! ## PMP behavior 32 | //! 33 | //! It should be noted that even if this bit is cleared, the memory access error exception caused 34 | //! by the PMP permission mismatch in the execution of the load/store instruction is accurate. 35 | //! In addition, in the non-precise exception mode, the update value of the `mtval` register is accurate, 36 | //! that is, the address that generates the memory access error exception is accurately saved. 37 | //! 38 | //! # Platform support 39 | //! 40 | //! This register is supported on Xuantie C910, C906, E907 and E906 cores. 41 | use bit_field::BitField; 42 | use core::arch::asm; 43 | 44 | /// L1 D-cache write allocation strategy 45 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 46 | pub enum AMR { 47 | /// Depends on WA page entry attibute 48 | DependsOnWA = 0, 49 | /// Don't write to L1 cache after 3 continuous cache line writes 50 | After3Lines = 1, 51 | /// Don't write to L1 cache after 64 continuous cache line writes 52 | After64Lines = 2, 53 | /// Don't write to L1 cache after 128 continuous cache line writes 54 | After128Lines = 3, 55 | } 56 | 57 | /// D-cache prefetch lines 58 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 59 | pub enum PrefN { 60 | /// Prefetch 2 lines 61 | TwoLines = 0, 62 | /// Prefetch 4 lines 63 | FourLines = 1, 64 | /// Prefetch 8 lines 65 | EightLines = 2, 66 | /// Prefetch 16 lines 67 | SixteenLines = 3, 68 | } 69 | 70 | set_clear_csr! { 71 | /// D-cache prefetch enable 72 | , 0x7C5, set_dpld, clear_dpld, 1 << 2 73 | } 74 | set_clear_csr! { 75 | /// I-cache prefetch enable 76 | , 0x7C5, set_ipld, clear_ipld, 1 << 8 77 | } 78 | set_clear_csr! { 79 | /// Accure exception enable 80 | /// 81 | /// # Platform support 82 | /// 83 | /// This bit is supported on Xuantie E907 and E906 cores. 84 | , 0x7C5, set_aee, clear_aee, 1 << 20 85 | } 86 | 87 | /// Set D-cache write allocation strategy 88 | #[inline] 89 | pub unsafe fn set_amr(amr: AMR) { 90 | let mut value: usize; 91 | asm!("csrr {}, 0x7C5", out(reg) value); 92 | value.set_bits(3..=4, amr as usize); 93 | asm!("csrw 0x7C5, {}", in(reg) value); 94 | } 95 | 96 | /// Set D-cache prefetch lines configuration 97 | #[inline] 98 | pub unsafe fn set_prefn(prefn: PrefN) { 99 | let mut value: usize; 100 | asm!("csrr {}, 0x7C5", out(reg) value); 101 | value.set_bits(13..=14, prefn as usize); 102 | asm!("csrw 0x7C5, {}", in(reg) value); 103 | } 104 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mxstatus.rs: -------------------------------------------------------------------------------- 1 | //! mxstatus, machine extended state register 2 | //! 3 | //! # Platform support 4 | //! 5 | //! This register is supported on Xuantie C910, C906, E907, E906 and E902 cores. 6 | use bit_field::BitField; 7 | 8 | /// mxstatus register 9 | #[derive(Clone, Copy, Debug)] 10 | pub struct Mxstatus { 11 | bits: usize, 12 | } 13 | 14 | /// Current privileged mode 15 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 16 | pub enum PM { 17 | Machine = 3, 18 | Supervisor = 1, 19 | User = 0, 20 | } 21 | 22 | impl Mxstatus { 23 | /// User mode performance monitor enable 24 | /// 25 | /// # Platform support 26 | /// 27 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 28 | #[inline] 29 | pub fn pmdu(&self) -> bool { 30 | self.bits.get_bit(10) 31 | } 32 | /// Supervisor mode performance monitor enable 33 | #[inline] 34 | pub fn pmds(&self) -> bool { 35 | self.bits.get_bit(11) 36 | } 37 | /// Machine mode performance monitor enable 38 | /// 39 | /// # Platform support 40 | /// 41 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 42 | #[inline] 43 | pub fn pmdm(&self) -> bool { 44 | self.bits.get_bit(12) 45 | } 46 | /// Is PMP minimum stride 4K bytes 47 | #[inline] 48 | pub fn pmp4k(&self) -> bool { 49 | self.bits.get_bit(14) 50 | } 51 | /// Unaligned access enable 52 | /// 53 | /// # Platform support 54 | /// 55 | /// This bit is supported on Xuantie C910, C906, E907 and E906 cores. 56 | #[inline] 57 | pub fn mm(&self) -> bool { 58 | self.bits.get_bit(15) 59 | } 60 | /// User mode allow extended cache instruction 61 | #[inline] 62 | pub fn ucme(&self) -> bool { 63 | self.bits.get_bit(16) 64 | } 65 | /// CLINT supervisor extension enable 66 | #[inline] 67 | pub fn clintee(&self) -> bool { 68 | self.bits.get_bit(17) 69 | } 70 | /// Hardware refill when TLB item absent enable 71 | #[inline] 72 | pub fn mhrd(&self) -> bool { 73 | self.bits.get_bit(18) 74 | } 75 | /// Extend MMU page table entry address attributes enable 76 | #[inline] 77 | pub fn maee(&self) -> bool { 78 | self.bits.get_bit(21) 79 | } 80 | /// T-Head extended instruction set architecture enable 81 | /// 82 | /// # Platform support 83 | /// 84 | /// This bit is supported on Xuantie C910, C906, E907, E906 and E902 cores. 85 | #[inline] 86 | pub fn theadisaee(&self) -> bool { 87 | self.bits.get_bit(22) 88 | } 89 | /// Current privileged mode 90 | /// 91 | /// # Platform support 92 | /// 93 | /// This bit is supported on Xuantie C910, C906, E907, E906 and E902 cores. 94 | #[inline] 95 | pub fn pm(&self) -> PM { 96 | match self.bits.get_bits(30..=31) { 97 | 0b00 => PM::User, 98 | 0b01 => PM::Supervisor, 99 | 0b11 => PM::Machine, 100 | _ => unreachable!(), 101 | } 102 | } 103 | } 104 | 105 | read_csr_as!(Mxstatus, 0x7C0); 106 | 107 | set_clear_csr! { 108 | /// User mode performance monitor enable 109 | , 0x7C0, set_pmdu, clear_pmdu, 1 << 10 110 | } 111 | set_clear_csr! { 112 | /// Supervisor mode performance monitor enable 113 | , 0x7C0, set_pmds, clear_pmds, 1 << 11 114 | } 115 | set_clear_csr! { 116 | /// Machine mode performance monitor enable 117 | , 0x7C0, set_pmdm, clear_pmdm, 1 << 13 118 | } 119 | set_clear_csr! { 120 | /// Unaligned access enable 121 | , 0x7C0, set_mm, clear_mm, 1 << 15 122 | } 123 | set_clear_csr! { 124 | /// User mode allow extended cache instruction 125 | , 0x7C0, set_ucme, clear_ucme, 1 << 16 126 | } 127 | set_clear_csr! { 128 | /// CLINT supervisor extension enable 129 | , 0x7C0, set_clintee, clear_clintee, 1 << 17 130 | } 131 | set_clear_csr! { 132 | /// Hardware refill when TLB item absent enable 133 | , 0x7C0, set_mhrd, clear_mhrd, 1 << 18 134 | } 135 | set_clear_csr! { 136 | /// Extend MMU page table entry address attributes enable 137 | , 0x7C0, set_maee, clear_maee, 1 << 21 138 | } 139 | set_clear_csr! { 140 | /// T-Head extended instruction set architecture enable 141 | , 0x7C0, set_theadisaee, clear_theadisaee, 1 << 22 142 | } 143 | -------------------------------------------------------------------------------- /xuantie-riscv/src/register/mccr2.rs: -------------------------------------------------------------------------------- 1 | //! mccr2, machine L2-cache control register 2 | use bit_field::BitField; 3 | use core::arch::asm; 4 | 5 | /// mccr2 register 6 | #[derive(Clone, Copy, Debug)] 7 | pub struct Mccr2 { 8 | bits: usize, 9 | } 10 | 11 | /// L2-cache data ram visit latency 12 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 13 | pub enum DLTNCY { 14 | Cycle1 = 0, 15 | Cycle2 = 1, 16 | Cycle3 = 2, 17 | Cycle4 = 3, 18 | Cycle5 = 4, 19 | Cycle6 = 5, 20 | Cycle7 = 6, 21 | Cycle8 = 7, 22 | } 23 | 24 | /// L2-cache tag ram visit latency 25 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 26 | pub enum TLTNCY { 27 | Cycle1 = 0, 28 | Cycle2 = 1, 29 | Cycle3 = 2, 30 | Cycle4 = 3, 31 | Cycle5 = 4, 32 | } 33 | 34 | /// L2-cache instruction prefetch 35 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 36 | pub enum IPRF { 37 | Disabled = 0, 38 | Prefetch1Line = 1, 39 | Prefetch2Lines = 2, 40 | Prefetch3Lines = 3, 41 | } 42 | 43 | impl Mccr2 { 44 | /// Refill enable 45 | #[inline] 46 | pub fn rfe(&self) -> bool { 47 | self.bits.get_bit(0) 48 | } 49 | /// Error correction enable 50 | #[inline] 51 | pub fn eccen(&self) -> bool { 52 | self.bits.get_bit(1) 53 | } 54 | /// L2-cache enable 55 | #[inline] 56 | pub fn l2en(&self) -> bool { 57 | self.bits.get_bit(3) 58 | } 59 | /// L2-cache data ram visit latency configuration 60 | #[inline] 61 | pub fn dltncy(&self) -> DLTNCY { 62 | match self.bits.get_bits(16..=18) { 63 | 0 => DLTNCY::Cycle1, 64 | 1 => DLTNCY::Cycle2, 65 | 2 => DLTNCY::Cycle3, 66 | 3 => DLTNCY::Cycle4, 67 | 4 => DLTNCY::Cycle5, 68 | 5 => DLTNCY::Cycle6, 69 | 6 => DLTNCY::Cycle7, 70 | 7 => DLTNCY::Cycle8, 71 | _ => unreachable!(), 72 | } 73 | } 74 | /// L2-cache data ram setup latency enable 75 | #[inline] 76 | pub fn dsetup(&self) -> bool { 77 | self.bits.get_bit(19) 78 | } 79 | /// L2-cache tag ram visit latency configuration 80 | #[inline] 81 | pub fn tltncy(&self) -> TLTNCY { 82 | match self.bits.get_bits(22..=24) { 83 | 0 => TLTNCY::Cycle1, 84 | 1 => TLTNCY::Cycle2, 85 | 2 => TLTNCY::Cycle3, 86 | 3 => TLTNCY::Cycle4, 87 | 4 => TLTNCY::Cycle5, 88 | _ => unreachable!(), 89 | } 90 | } 91 | /// L2-cache tag ram setup latency enable 92 | #[inline] 93 | pub fn tsetup(&self) -> bool { 94 | self.bits.get_bit(25) 95 | } 96 | /// L2-cache instruction prefetch enable 97 | #[inline] 98 | pub fn iprf(&self) -> IPRF { 99 | match self.bits.get_bits(29..=30) { 100 | 0 => IPRF::Disabled, 101 | 1 => IPRF::Prefetch1Line, 102 | 2 => IPRF::Prefetch2Lines, 103 | 3 => IPRF::Prefetch3Lines, 104 | _ => unreachable!(), 105 | } 106 | } 107 | /// L2-cache TLB prefetch enable 108 | #[inline] 109 | pub fn tprf(&self) -> bool { 110 | self.bits.get_bit(31) 111 | } 112 | } 113 | 114 | read_csr_as!(Mccr2, 0x7C3); 115 | 116 | set_clear_csr! { 117 | /// Refill enable 118 | , 0x7C3, set_rfe, clear_rfe, 1 << 0 119 | } 120 | set_clear_csr! { 121 | /// Error correction enable 122 | , 0x7C3, set_eccen, clear_eccen, 1 << 1 123 | } 124 | set_clear_csr! { 125 | /// L2-cache data ram setup latency enable 126 | , 0x7C3, set_dsetup, clear_dsetup, 1 << 19 127 | } 128 | set_clear_csr! { 129 | /// L2-cache tag ram setup latency enable 130 | , 0x7C3, set_tsetup, clear_tsetup, 1 << 25 131 | } 132 | set_clear_csr! { 133 | /// L2-cache TLB prefetch enable 134 | , 0x7C3, set_tprf, clear_tprf, 1 << 31 135 | } 136 | 137 | /// L2-cache data ram visit latency configuration 138 | #[inline] 139 | pub unsafe fn set_dltncy(dltncy: DLTNCY) { 140 | let mut value: usize; 141 | asm!("csrr {}, 0x7C3", out(reg) value); 142 | value.set_bits(16..=18, dltncy as usize); 143 | asm!("csrw 0x7C3, {}", in(reg) value); 144 | } 145 | 146 | /// L2-cache tag ram visit latency configuration 147 | #[inline] 148 | pub unsafe fn set_tltncy(tltncy: TLTNCY) { 149 | let mut value: usize; 150 | asm!("csrr {}, 0x7C3", out(reg) value); 151 | value.set_bits(22..=24, tltncy as usize); 152 | asm!("csrw 0x7C3, {}", in(reg) value); 153 | } 154 | 155 | /// L2-cache instruction prefetch enable 156 | #[inline] 157 | pub unsafe fn set_iprf(iprf: IPRF) { 158 | let mut value: usize; 159 | asm!("csrr {}, 0x7C3", out(reg) value); 160 | value.set_bits(29..=30, iprf as usize); 161 | asm!("csrw 0x7C3, {}", in(reg) value); 162 | } 163 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mulan Permissive Software License,Version 2 2 | Mulan Permissive Software License,Version 2 (Mulan PSL v2) 3 | 4 | January 2020 http://license.coscl.org.cn/MulanPSL2 5 | 6 | Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 7 | 8 | 0. Definition 9 | 10 | Software means the program and related documents which are licensed under this License and comprise all Contribution(s). 11 | 12 | Contribution means the copyrightable work licensed by a particular Contributor under this License. 13 | 14 | Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. 15 | 16 | Legal Entity means the entity making a Contribution and all its Affiliates. 17 | 18 | Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 19 | 20 | 1. Grant of Copyright License 21 | 22 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 23 | 24 | 2. Grant of Patent License 25 | 26 | Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 27 | 28 | 3. No Trademark License 29 | 30 | No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4. 31 | 32 | 4. Distribution Restriction 33 | 34 | You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 35 | 36 | 5. Disclaimer of Warranty and Limitation of Liability 37 | 38 | THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 39 | 40 | 6. Language 41 | 42 | THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. 43 | 44 | END OF THE TERMS AND CONDITIONS 45 | 46 | How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software 47 | 48 | To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: 49 | 50 | Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; 51 | Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package; 52 | Attach the statement to the appropriate annotated syntax at the beginning of each source file. 53 | Copyright (c) [Year] [name of copyright holder] 54 | [Software Name] is licensed under Mulan PSL v2. 55 | You can use this software according to the terms and conditions of the Mulan PSL v2. 56 | You may obtain a copy of Mulan PSL v2 at: 57 | http://license.coscl.org.cn/MulanPSL2 58 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 59 | EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 60 | MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 61 | See the Mulan PSL v2 for more details. 62 | -------------------------------------------------------------------------------- /xuantie-riscv/src/peripheral/plic.rs: -------------------------------------------------------------------------------- 1 | //! XuanTie Platform Local Interrupt Controller (PLIC). 2 | 3 | use core::{ 4 | num::NonZeroU32, 5 | ptr::{read_volatile, write_volatile}, 6 | }; 7 | use plic::{HartContext, InterruptSource}; 8 | 9 | const PLIC_CTRL_OFFSET: usize = 0x01F_FFFC; 10 | const PLIC_CTRL_S_PER_ENABLED: u32 = 0x1; 11 | const PLIC_CTRL_S_PER_DISABLED: u32 = 0x0; 12 | const PLIC_CTRL_S_PER_BIT: u32 = 0x1; 13 | 14 | /// Register block for XuanTie Platform Local Interrupt Controller (PLIC). 15 | #[repr(C, align(4096))] 16 | pub struct Plic { 17 | inner: plic::Plic, 18 | } 19 | 20 | impl Plic { 21 | /// Enable supervisor access to all the PLIC registers. 22 | #[inline] 23 | pub fn enable_supervisor_access(&self) { 24 | let plic_ctrl = 25 | unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *mut u32 }; 26 | unsafe { write_volatile(plic_ctrl, PLIC_CTRL_S_PER_ENABLED) }; 27 | } 28 | 29 | /// Disable supervisor access to all the PLIC registers. 30 | #[inline] 31 | pub fn disable_supervisor_access(&self) { 32 | let plic_ctrl = 33 | unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *mut u32 }; 34 | unsafe { write_volatile(plic_ctrl, PLIC_CTRL_S_PER_DISABLED) }; 35 | } 36 | 37 | /// Check if supervisor access to all the PLIC registers is enabled. 38 | #[inline] 39 | pub fn is_supervisor_access_enabled(&self) -> bool { 40 | let plic_ctrl = 41 | unsafe { (&self.inner as *const _ as *const u8).add(PLIC_CTRL_OFFSET) as *const u32 }; 42 | let val = unsafe { read_volatile(plic_ctrl) }; 43 | val & PLIC_CTRL_S_PER_BIT != 0 44 | } 45 | } 46 | 47 | impl Plic { 48 | /// Sets priority for interrupt `source` to `value`. 49 | #[inline] 50 | pub fn set_priority(&self, source: S, value: u32) 51 | where 52 | S: InterruptSource, 53 | { 54 | self.inner.set_priority(source, value); 55 | } 56 | 57 | /// Gets priority for interrupt `source`. 58 | #[inline] 59 | pub fn get_priority(&self, source: S) -> u32 60 | where 61 | S: InterruptSource, 62 | { 63 | self.inner.get_priority(source) 64 | } 65 | 66 | /// Probe maximum level of priority for interrupt `source`. 67 | // Note: we detect them in any situation even when we already know how many bits 68 | // are there in the T-Head Xuantie core, in case this structure is misused onto 69 | // other non-Xuantie cores. 70 | #[inline] 71 | pub fn probe_priority_bits(&self, source: S) -> u32 72 | where 73 | S: InterruptSource, 74 | { 75 | self.inner.probe_priority_bits(source) 76 | } 77 | 78 | /// Check if interrupt `source` is pending. 79 | #[inline] 80 | pub fn is_pending(&self, source: S) -> bool 81 | where 82 | S: InterruptSource, 83 | { 84 | self.inner.is_pending(source) 85 | } 86 | 87 | /// Enable interrupt `source` in `context`. 88 | #[inline] 89 | pub fn enable(&self, source: S, context: C) 90 | where 91 | S: InterruptSource, 92 | C: HartContext, 93 | { 94 | self.inner.enable(source, context); 95 | } 96 | 97 | /// Disable interrupt `source` in `context`. 98 | #[inline] 99 | pub fn disable(&self, source: S, context: C) 100 | where 101 | S: InterruptSource, 102 | C: HartContext, 103 | { 104 | self.inner.disable(source, context); 105 | } 106 | 107 | /// Check if interrupt `source` is enabled in `context`. 108 | #[inline] 109 | pub fn is_enabled(&self, source: S, context: C) -> bool 110 | where 111 | S: InterruptSource, 112 | C: HartContext, 113 | { 114 | self.inner.is_enabled(source, context) 115 | } 116 | 117 | /// Get interrupt threshold in `context`. 118 | #[inline] 119 | pub fn get_threshold(&self, context: C) -> u32 120 | where 121 | C: HartContext, 122 | { 123 | self.inner.get_threshold(context) 124 | } 125 | 126 | /// Set interrupt threshold for `context` to `value`. 127 | #[inline] 128 | pub fn set_threshold(&self, context: C, value: u32) 129 | where 130 | C: HartContext, 131 | { 132 | self.inner.set_threshold(context, value); 133 | } 134 | 135 | /// Probe maximum supported threshold value the `context` supports. 136 | // Note: we detect them in any situation even when we already know how many bits 137 | // are there in the T-Head Xuantie core, in case this structure is misused onto 138 | // other non-Xuantie cores. 139 | #[inline] 140 | pub fn probe_threshold_bits(&self, context: C) -> u32 141 | where 142 | C: HartContext, 143 | { 144 | self.inner.probe_threshold_bits(context) 145 | } 146 | 147 | /// Claim an interrupt in `context`, returning its source. 148 | #[inline] 149 | pub fn claim(&self, context: C) -> Option 150 | where 151 | C: HartContext, 152 | { 153 | self.inner.claim(context) 154 | } 155 | 156 | /// Mark that interrupt identified by `source` is completed in `context`. 157 | #[inline] 158 | pub fn complete(&self, context: C, source: S) 159 | where 160 | C: HartContext, 161 | S: InterruptSource, 162 | { 163 | self.inner.complete(context, source); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /xuantie-riscv/src/asm/xtheadcmo.rs: -------------------------------------------------------------------------------- 1 | use core::arch::asm; 2 | 3 | /// D-cache clean all dirty items instruction. 4 | /// 5 | /// Clears all L1 D-cache table items, write all dirty items to next level storage. 6 | /// 7 | /// # Permissions 8 | /// 9 | /// Can run on M mode, or S mode if applicable. 10 | /// 11 | /// # Exceptions 12 | /// 13 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 14 | /// when `mxstatus.theadisaee = 1` but run on U mode. 15 | /// 16 | /// # Platform support 17 | /// 18 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 19 | #[inline] 20 | pub unsafe fn dcache_call() { 21 | // th.dcache.call 22 | asm!(".insn i 0x0B, 0, x0, x0, 0x001") 23 | } 24 | 25 | /// D-cache invalid all items instruction. 26 | /// 27 | /// Invalidates all L1 D-cache table items. This instruction only operates on the current hart. 28 | /// 29 | /// # Permissions 30 | /// 31 | /// Can run on M mode, or S mode if applicable. 32 | /// 33 | /// # Exceptions 34 | /// 35 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 36 | /// when `mxstatus.theadisaee = 1` but run on U mode. 37 | /// 38 | /// # Platform support 39 | /// 40 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 41 | #[inline] 42 | pub unsafe fn dcache_iall() { 43 | // th.dcache.iall 44 | asm!(".insn i 0x0B, 0, x0, x0, 0x002") 45 | } 46 | 47 | /// D-cache clean all dirty and invalid item instruction. 48 | /// 49 | /// Writes all L1 D-cache dirty items to next level storage, and invalidate all L1 D-cache table items. 50 | /// 51 | /// # Permissions 52 | /// 53 | /// Can run on M mode, or S mode if applicable. 54 | /// 55 | /// # Exceptions 56 | /// 57 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 58 | /// when `mxstatus.theadisaee = 1` but run on U mode. 59 | /// 60 | /// # Platform support 61 | /// 62 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 63 | #[inline] 64 | pub unsafe fn dcache_ciall() { 65 | // th.dcache.ciall 66 | asm!(".insn i 0x0B, 0, x0, x0, 0x003") 67 | } 68 | 69 | /// I-cache invalid all items instruction. 70 | /// 71 | /// Invalidates all I-cache table items. This instruction only operates on the current hart. 72 | /// 73 | /// # Permissions 74 | /// 75 | /// Can run on M mode, or S mode if applicable. 76 | /// 77 | /// # Exceptions 78 | /// 79 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 80 | /// when `mxstatus.theadisaee = 1` but run on U mode. 81 | /// 82 | /// # Platform support 83 | /// 84 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907, E906 and E902 cores. 85 | #[inline] 86 | pub unsafe fn icache_iall() { 87 | // th.icache.iall 88 | asm!(".insn i 0x0B, 0, x0, x0, 0x010") 89 | } 90 | 91 | /// I-cache broadcast all harts to invalid all items instruction. 92 | /// 93 | /// Invalidates all I-cache table items, and broadcast other harts to invalid all I-cache items. 94 | /// This operation operates on I-cache on all harts. 95 | /// 96 | /// # Permissions 97 | /// 98 | /// Can run on M or S mode. 99 | /// 100 | /// # Exceptions 101 | /// 102 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 103 | /// when `mxstatus.theadisaee = 1` but run on U mode. 104 | /// 105 | /// # Platform support 106 | /// 107 | /// This instruction is supported on Xuantie C910, C906, C907 and C908 cores. 108 | #[inline] 109 | pub unsafe fn icache_ialls() { 110 | // th.icache.ialls 111 | asm!(".insn i 0x0B, 0, x0, x0, 0x011") 112 | } 113 | 114 | /// L2-cache clean all dirty items instruction. 115 | /// 116 | /// Clears all L2-cache table items, write all dirty items to next level storage. 117 | /// 118 | /// # Permissions 119 | /// 120 | /// Must run on M or S mode. 121 | /// 122 | /// # Exceptions 123 | /// 124 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 125 | /// when `mxstatus.theadisaee = 1` but run on U mode. 126 | /// 127 | /// # Platform support 128 | /// 129 | /// This instruction is supported on Xuantie C910 core. 130 | #[inline] 131 | pub unsafe fn l2cache_call() { 132 | // th.l2cache.call 133 | asm!(".insn i 0x0B, 0, x0, x0, 0x015") 134 | } 135 | 136 | /// L2-cache invalid all items instruction. 137 | /// 138 | /// Invalidates all L2-cache table items. 139 | /// 140 | /// # Permissions 141 | /// 142 | /// Can run on M or S mode. 143 | /// 144 | /// # Exceptions 145 | /// 146 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 147 | /// when `mxstatus.theadisaee = 1` but run on U mode. 148 | /// 149 | /// # Platform support 150 | /// 151 | /// This instruction is supported on Xuantie C910 and C906 cores. 152 | #[inline] 153 | pub unsafe fn l2cache_iall() { 154 | // th.l2cache.iall 155 | asm!(".insn i 0x0B, 0, x0, x0, 0x016") 156 | } 157 | 158 | /// L2-cache clean all dirty and invalid item instruction. 159 | /// 160 | /// Writes all L2-cache dirty items to next level storage, and invalidate all L2-cache table items. 161 | /// 162 | /// # Permissions 163 | /// 164 | /// Can run on M or S mode. 165 | /// 166 | /// # Exceptions 167 | /// 168 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 169 | /// when `mxstatus.theadisaee = 1` but run on U mode. 170 | /// 171 | /// # Platform support 172 | /// 173 | /// This instruction is supported on Xuantie C910 core. 174 | #[inline] 175 | pub unsafe fn l2cache_ciall() { 176 | // th.l2cache.ciall 177 | asm!(".insn i 0x0B, 0, x0, x0, 0x017") 178 | } 179 | 180 | /// D-cache clean dirty item on way and set instruction. 181 | /// 182 | /// Writes D-cache dirty table item corresponding to given way and set to next level storage. 183 | /// 184 | /// # Permissions 185 | /// 186 | /// Can run on M mode, or S mode if applicable. 187 | /// 188 | /// # Exceptions 189 | /// 190 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 191 | /// when `mxstatus.theadisaee = 1` but run on U mode. 192 | /// 193 | /// # Platform support 194 | /// 195 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 196 | /// 197 | /// The C910 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 198 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 199 | /// when configured 64 Kibibytes, `w` equals 14. 200 | /// 201 | /// The C906 core has a 4-way set-associative D-cache. Input variable `rs1[31:30]` represents number of way, 202 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 203 | /// when configured 64 Kibibytes, `w` equals 14. 204 | /// 205 | /// The C907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 206 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 207 | /// when configured 64 Kibibytes, `w` equals 14. 208 | /// 209 | /// The C908 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 210 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 211 | /// when configured 64 Kibibytes, `w` equals 14. 212 | /// 213 | /// The E907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 214 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 215 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 216 | /// 217 | /// The E906 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 218 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 219 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 220 | #[inline] 221 | pub unsafe fn dcache_csw(way_and_set: usize) { 222 | // th.dcache.csw {} 223 | asm!(".insn i 0x0B, 0, x0, {}, 0x021", in(reg) way_and_set) 224 | } 225 | 226 | /// D-cache invalid item for way and set instruction. 227 | /// 228 | /// Invalidate D-cache dirty table item corresponding to given way and set. 229 | /// 230 | /// # Permissions 231 | /// 232 | /// Can run on M mode, or S mode if applicable. 233 | /// 234 | /// # Exceptions 235 | /// 236 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 237 | /// when `mxstatus.theadisaee = 1` but run on U mode. 238 | /// 239 | /// # Platform support 240 | /// 241 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 242 | /// 243 | /// The C910 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 244 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 245 | /// when configured 64 Kibibytes, `w` equals 14. 246 | /// 247 | /// The C906 core has a 4-way set-associative D-cache. Input variable `rs1[31:30]` represents number of way, 248 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 249 | /// when configured 64 Kibibytes, `w` equals 14. 250 | /// 251 | /// The C907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 252 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 253 | /// when configured 64 Kibibytes, `w` equals 14. 254 | /// 255 | /// The C908 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 256 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 257 | /// when configured 64 Kibibytes, `w` equals 14. 258 | /// 259 | /// The E907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 260 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 261 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 262 | /// 263 | /// The E906 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 264 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 265 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 266 | #[inline] 267 | pub unsafe fn dcache_isw(way_and_set: usize) { 268 | // th.dcache.isw 269 | asm!(".insn i 0x0B, 0, x0, {}, 0x022", in(reg) way_and_set) 270 | } 271 | 272 | /// D-cache clean dirty and invalid for way and set instruction. 273 | /// 274 | /// Writes L1 D-cache dirty item corresponding to given way and set to next level storage, 275 | /// and invalidate this table item. 276 | /// This instruction only operates on the current hart. 277 | /// 278 | /// # Permissions 279 | /// 280 | /// Can run on M mode, or S mode if applicable. 281 | /// 282 | /// # Exceptions 283 | /// 284 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 285 | /// when `mxstatus.theadisaee = 1` but run on U mode. 286 | /// 287 | /// # Platform support 288 | /// 289 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 290 | /// 291 | /// The C910 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 292 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 293 | /// when configured 64 Kibibytes, `w` equals 14. 294 | /// 295 | /// The C906 core has a 4-way set-associative D-cache. Input variable `rs1[31:30]` represents number of way, 296 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 297 | /// when configured 64 Kibibytes, `w` equals 14. 298 | /// 299 | /// The C907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 300 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 301 | /// when configured 64 Kibibytes, `w` equals 14. 302 | /// 303 | /// The C908 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 304 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 305 | /// when configured 64 Kibibytes, `w` equals 14. 306 | /// 307 | /// The E907 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 308 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 309 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 310 | /// 311 | /// The E906 core has a 2-way set-associative D-cache. Input variable `rs1[31]` represents number of way, 312 | /// while `rs1[w:6]` represents number of set. When D-cache is configured 32 Kibibytes, `w` equals 13; 313 | /// when configured 16 Kibibytes, `w` equals 12, and so on. 314 | #[inline] 315 | pub unsafe fn dcache_cisw(way_and_set: usize) { 316 | // th.dcache.cisw 317 | asm!(".insn i 0x0B, 0, x0, {}, 0x023", in(reg) way_and_set) 318 | } 319 | 320 | /// L1 D-cache clean dirty item for virtual address instruction. 321 | /// 322 | /// Writes D-cache table item corresponding to virtual address `va` to next level storage. 323 | /// This operation effects on L1-cache on all harts. 324 | /// 325 | /// # Permissions 326 | /// 327 | /// Can run on M, S or U mode. 328 | /// 329 | /// # Exceptions 330 | /// 331 | /// Raises illegal instruction exception, or load page fault exception. 332 | /// 333 | /// - When `mxstatus.theadisaee = 0`, this instruction always raise illegal instruction exception. 334 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 1`, this instruction can be run on U mode. 335 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 0`, 336 | /// this instruction will raise illegal instruction when being run on U mode. 337 | /// 338 | /// # Platform support 339 | /// 340 | /// This instruction is supported on Xuantie C910, C906, C907 and C908 cores. 341 | /// On Xuantie C906 User Manual, this instruction is named `DCACHE.CVA`. 342 | #[inline] 343 | pub unsafe fn dcache_cval1(va: usize) { 344 | // th.dcache.cval1 345 | asm!(".insn i 0x0B, 0, x0, {}, 0x024", in(reg) va) 346 | } 347 | 348 | /// D-cache clean dirty item for virtual address instruction. 349 | /// 350 | /// Writes D-cache and L2-cache table item corresponding to virtual address `va` to next level storage. 351 | /// This operation effects on all harts and the L2-cache. 352 | /// 353 | /// # Permissions 354 | /// 355 | /// Can run on M or S mode. 356 | /// 357 | /// # Exceptions 358 | /// 359 | /// Raises illegal instruction exception, or load page fault exception. 360 | /// 361 | /// - When `mxstatus.theadisaee = 0`, this instruction always raise illegal instruction exception. 362 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 1`, this instruction can be run on U mode. 363 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 0`, 364 | /// this instruction will raise illegal instruction when being run on U mode. 365 | /// 366 | /// # Platform support 367 | /// 368 | /// This instruction is supported on Xuantie C910, C907 and C908 cores. 369 | /// 370 | /// The Xuantie C906 User Manual names `DCACHE.CVAL1` as `DCACHE.CVA`; to clean dirty item on 371 | /// C906 you may need to use function [`dcache_cval1`] on this library. 372 | #[inline] 373 | pub unsafe fn dcache_cva(va: usize) { 374 | // th.dcache.cva 375 | asm!(".insn i 0x0B, 0, x0, {}, 0x025", in(reg) va) 376 | } 377 | 378 | /// D-cache invalid item for virtual address instruction. 379 | /// 380 | /// Invalidates D-cache or L2-cache (if applicable) table item corresponding to virtual address `va`. 381 | /// 382 | /// This instruction operates on the current hart. If applicable, this instruction will 383 | /// operates on L2-cache, and decide whether to broadcast to other harts according to 384 | /// the share attribute of the virtual address. 385 | /// 386 | /// # Permissions 387 | /// 388 | /// Can run on M or S mode. 389 | /// 390 | /// # Exceptions 391 | /// 392 | /// Raises illegal instruction exception, or load page fault exception. 393 | /// 394 | /// - When `mxstatus.theadisaee = 0`, this instruction always raise illegal instruction exception. 395 | /// - When `mxstatus.theadisaee = 1`, this instruction will raise illegal instruction when being run on U mode. 396 | /// 397 | /// # Platform support 398 | /// 399 | /// This instruction is supported on Xuantie C910, C906, C907 and C908 cores. 400 | #[inline] 401 | pub unsafe fn dcache_iva(va: usize) { 402 | // th.dcache.iva 403 | asm!(".insn i 0x0B, 0, x0, {}, 0x026", in(reg) va) 404 | } 405 | 406 | /// D-cache clean dirty and invalid for virtual address instruction. 407 | /// 408 | /// Write D-cache or L2-cache (if applicable) table item corresponding to virtual address `va` 409 | /// to next level storage, and invalidate this table item. 410 | /// 411 | /// This instruction operates on the current hart. If applicable, this instruction will 412 | /// operates on L2-cache, and decide whether to broadcast to other harts according to 413 | /// the share attribute of the virtual address. 414 | /// 415 | /// # Permissions 416 | /// 417 | /// Can run on M or S mode. 418 | /// 419 | /// # Exceptions 420 | /// 421 | /// Raises illegal instruction exception, or load page fault exception. 422 | /// 423 | /// - When `mxstatus.theadisaee = 0`, this instruction always raise illegal instruction exception. 424 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 1`, this instruction can be run on U mode. 425 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 0`, 426 | /// this instruction will raise illegal instruction when being run on U mode. 427 | /// 428 | /// # Platform support 429 | /// 430 | /// This instruction is supported on Xuantie C910, C906, C907 and C908 cores. 431 | #[inline] 432 | pub unsafe fn dcache_civa(va: usize) { 433 | // th.dcache.civa 434 | asm!(".insn i 0x0B, 0, x0, {}, 0x027", in(reg) va) 435 | } 436 | 437 | /// L1 D-cache clean dirty item for physical address instruction. 438 | /// 439 | /// Writes D-cache table item corresponding to physical address `pa` to next level storage. 440 | /// This operation effects on L1-cache for all harts. 441 | /// 442 | /// # Permissions 443 | /// 444 | /// Can run on M mode, or S mode if applicable. 445 | /// 446 | /// # Exceptions 447 | /// 448 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 449 | /// when `mxstatus.theadisaee = 1` but run on U mode. 450 | /// 451 | /// # Platform support 452 | /// 453 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 454 | /// On Xuantie C906 User Manual, Xuantie E907 User Manual and Xuantie E906 User Manual, 455 | /// this instruction is named `DCACHE.CPA`. 456 | #[inline] 457 | pub unsafe fn dcache_cpal1(pa: usize) { 458 | // th.dcache.cpal1 459 | asm!(".insn i 0x0B, 0, x0, {}, 0x028", in(reg) pa) 460 | } 461 | 462 | /// D-cache clean dirty item for physical address instruction. 463 | /// 464 | /// Writes D-cache and L2-cache table item corresponding to physical address `pa` to next level storage. 465 | /// This operation effects on all harts and the L2-cache. 466 | /// 467 | /// # Permissions 468 | /// 469 | /// Can run on M or S mode. 470 | /// 471 | /// # Exceptions 472 | /// 473 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 474 | /// when `mxstatus.theadisaee = 1` but run on U mode. 475 | /// 476 | /// # Platform support 477 | /// 478 | /// This instruction is supported on Xuantie C910, C907 and C908 cores. 479 | /// 480 | /// The Xuantie C906 User Manual, Xuantie E907 User Manual and Xuantie E906 User Manual 481 | /// names `DCACHE.CPAL1` as `DCACHE.CPA`; to clean dirty item on 482 | /// these cores you may need to use function [`dcache_cpal1`] on this library. 483 | #[inline] 484 | pub unsafe fn dcache_cpa(pa: usize) { 485 | // th.dcache.cpa 486 | asm!(".insn i 0x0B, 0, x0, {}, 0x029", in(reg) pa) 487 | } 488 | 489 | #[inline] 490 | /// D-cache invalid item for physical address instruction. 491 | /// 492 | /// Invalidates D-cache table item corresponding to physical address `pa`. 493 | /// 494 | /// # Permissions 495 | /// 496 | /// Can run on M mode, or S mode if applicable. 497 | /// 498 | /// # Exceptions 499 | /// 500 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 501 | /// when `mxstatus.theadisaee = 1` but run on U mode. 502 | /// 503 | /// # Platform support 504 | /// 505 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 506 | pub unsafe fn dcache_ipa(pa: usize) { 507 | // th.dcache.ipa 508 | asm!(".insn i 0x0B, 0, x0, {}, 0x02A", in(reg) pa) 509 | } 510 | 511 | /// D-cache clean dirty and invalid for physical address instruction. 512 | /// 513 | /// Writes D-cache or L2-cache (if applicable) table item corresponding to physical address `pa` 514 | /// to next level storage, and invalidate this table item. 515 | /// If applicable, this instruction operates on all harts and the L2-cache. 516 | /// 517 | /// # Permissions 518 | /// 519 | /// Can run on M mode, or S mode if applicable. 520 | /// 521 | /// # Exceptions 522 | /// 523 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 524 | /// when `mxstatus.theadisaee = 1` but run on U mode. 525 | /// 526 | /// # Platform support 527 | /// 528 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907 and E906 cores. 529 | #[inline] 530 | pub unsafe fn dcache_cipa(pa: usize) { 531 | // th.dcache.cipa 532 | asm!(".insn i 0x0B, 0, x0, {}, 0x02B", in(reg) pa) 533 | } 534 | 535 | /// I-cache invalid item for virtual address instruction. 536 | /// 537 | /// Invalidates the I-cache table item corresponding to virtual address `va`. 538 | /// 539 | /// This instruction operates on the current hart. If applicable, this instruction will 540 | /// operates on L2-cache, and decide whether to broadcast to other harts according to 541 | /// the share attribute of the virtual address. 542 | /// 543 | /// # Permissions 544 | /// 545 | /// Can run on M, S or U mode. 546 | /// 547 | /// # Exceptions 548 | /// 549 | /// Raises illegal instruction exception, or load page fault exception. 550 | /// 551 | /// - When `mxstatus.theadisaee = 0`, this instruction always raise illegal instruction exception. 552 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 1`, this instruction can be run on U mode. 553 | /// - When `mxstatus.theadisaee = 1`, and `mxstatus.ucme = 0`, 554 | /// this instruction will raise illegal instruction when being run on U mode. 555 | /// 556 | /// # Platform support 557 | /// 558 | /// This instruction is supported on Xuantie C910, C906, C907 and C908 cores. 559 | #[inline] 560 | pub unsafe fn icache_iva(va: usize) { 561 | // th.icache.iva 562 | asm!(".insn i 0x0B, 0, x0, {}, 0x030", in(reg) va) 563 | } 564 | 565 | /// I-cache invalid item for physical address instruction. 566 | /// 567 | /// Invalidates I-cache table item corresponding to physical address `pa`. 568 | /// If applicable, this instruction operates on all harts. 569 | /// 570 | /// # Permissions 571 | /// 572 | /// Can run on M mode, or S mode if applicable. 573 | /// 574 | /// # Exceptions 575 | /// 576 | /// Raises illegal instruction exception when `mxstatus.theadisaee = 0`, or 577 | /// when `mxstatus.theadisaee = 1` but run on U mode. 578 | /// 579 | /// # Platform support 580 | /// 581 | /// This instruction is supported on Xuantie C910, C906, C907, C908, E907, E906 and E902 cores. 582 | #[inline] 583 | pub unsafe fn icache_ipa(pa: usize) { 584 | // th.icache.ipa 585 | asm!(".insn i 0x0B, 0, x0, {}, 0x038", in(reg) pa) 586 | } 587 | -------------------------------------------------------------------------------- /xuantie-riscv/src/asm/dsp0p9.rs: -------------------------------------------------------------------------------- 1 | //! RISC-V "P" Extension Proposal Version 0.9 2 | use core::arch::asm; 3 | 4 | /// Adds packed 16-bit signed numbers, discarding overflow bits. 5 | #[inline] 6 | pub fn add16(a: usize, b: usize) -> usize { 7 | let value: usize; 8 | unsafe { 9 | asm!(".insn r 0x77, 0x0, 0x20, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 10 | } 11 | value 12 | } 13 | 14 | /// Halves the sum of packed 16-bit signed numbers, dropping least bits. 15 | #[inline] 16 | pub fn radd16(a: usize, b: usize) -> usize { 17 | let value: usize; 18 | unsafe { 19 | asm!(".insn r 0x77, 0x0, 0x00, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 20 | } 21 | value 22 | } 23 | 24 | /// Halves the sum of packed 16-bit unsigned numbers, dropping least bits. 25 | #[inline] 26 | pub fn uradd16(a: usize, b: usize) -> usize { 27 | let value: usize; 28 | unsafe { 29 | asm!(".insn r 0x77, 0x0, 0x10, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 30 | } 31 | value 32 | } 33 | 34 | /// Adds packed 16-bit signed numbers, saturating at the numeric bounds. 35 | #[inline] 36 | pub fn kadd16(a: usize, b: usize) -> usize { 37 | let value: usize; 38 | unsafe { 39 | asm!(".insn r 0x77, 0x0, 0x08, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 40 | } 41 | value 42 | } 43 | 44 | /// Adds packed 16-bit unsigned numbers, saturating at the numeric bounds. 45 | #[inline] 46 | pub fn ukadd16(a: usize, b: usize) -> usize { 47 | let value: usize; 48 | unsafe { 49 | asm!(".insn r 0x77, 0x0, 0x18, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 50 | } 51 | value 52 | } 53 | 54 | /// Subtracts packed 16-bit signed numbers, discarding overflow bits. 55 | #[inline] 56 | pub fn sub16(a: usize, b: usize) -> usize { 57 | let value: usize; 58 | unsafe { 59 | asm!(".insn r 0x77, 0x0, 0x21, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 60 | } 61 | value 62 | } 63 | 64 | /// Halves the subtraction result of packed 16-bit signed numbers, dropping least bits. 65 | #[inline] 66 | pub fn rsub16(a: usize, b: usize) -> usize { 67 | let value: usize; 68 | unsafe { 69 | asm!(".insn r 0x77, 0x0, 0x01, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 70 | } 71 | value 72 | } 73 | 74 | /// Halves the subtraction result of packed 16-bit unsigned numbers, dropping least bits. 75 | #[inline] 76 | pub fn ursub16(a: usize, b: usize) -> usize { 77 | let value: usize; 78 | unsafe { 79 | asm!(".insn r 0x77, 0x0, 0x11, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 80 | } 81 | value 82 | } 83 | 84 | /// Subtracts packed 16-bit signed numbers, saturating at the numeric bounds. 85 | #[inline] 86 | pub fn ksub16(a: usize, b: usize) -> usize { 87 | let value: usize; 88 | unsafe { 89 | asm!(".insn r 0x77, 0x0, 0x09, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 90 | } 91 | value 92 | } 93 | 94 | /// Subtracts packed 16-bit unsigned numbers, saturating at the numeric bounds. 95 | #[inline] 96 | pub fn uksub16(a: usize, b: usize) -> usize { 97 | let value: usize; 98 | unsafe { 99 | asm!(".insn r 0x77, 0x0, 0x19, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 100 | } 101 | value 102 | } 103 | 104 | /// Cross adds and subtracts packed 16-bit signed numbers, discarding overflow bits. 105 | #[inline] 106 | pub fn cras16(a: usize, b: usize) -> usize { 107 | let value: usize; 108 | unsafe { 109 | asm!(".insn r 0x77, 0x0, 0x22, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 110 | } 111 | value 112 | } 113 | 114 | /// Cross halves of adds and subtracts packed 16-bit signed numbers, dropping least bits. 115 | #[inline] 116 | pub fn rcras16(a: usize, b: usize) -> usize { 117 | let value: usize; 118 | unsafe { 119 | asm!(".insn r 0x77, 0x0, 0x02, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 120 | } 121 | value 122 | } 123 | 124 | /// Cross halves of adds and subtracts packed 16-bit unsigned numbers, dropping least bits. 125 | #[inline] 126 | pub fn urcras16(a: usize, b: usize) -> usize { 127 | let value: usize; 128 | unsafe { 129 | asm!(".insn r 0x77, 0x0, 0x12, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 130 | } 131 | value 132 | } 133 | 134 | /// Cross adds and subtracts packed 16-bit signed numbers, saturating at the numeric bounds. 135 | #[inline] 136 | pub fn kcras16(a: usize, b: usize) -> usize { 137 | let value: usize; 138 | unsafe { 139 | asm!(".insn r 0x77, 0x0, 0x0A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 140 | } 141 | value 142 | } 143 | 144 | /// Cross adds and subtracts packed 16-bit unsigned numbers, saturating at the numeric bounds. 145 | #[inline] 146 | pub fn ukcras16(a: usize, b: usize) -> usize { 147 | let value: usize; 148 | unsafe { 149 | asm!(".insn r 0x77, 0x0, 0x1A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 150 | } 151 | value 152 | } 153 | 154 | /// Cross subtracts and adds packed 16-bit signed numbers, discarding overflow bits. 155 | #[inline] 156 | pub fn crsa16(a: usize, b: usize) -> usize { 157 | let value: usize; 158 | unsafe { 159 | asm!(".insn r 0x77, 0x0, 0x23, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 160 | } 161 | value 162 | } 163 | 164 | /// Cross halves of subtracts and adds packed 16-bit signed numbers, dropping least bits. 165 | #[inline] 166 | pub fn rcrsa16(a: usize, b: usize) -> usize { 167 | let value: usize; 168 | unsafe { 169 | asm!(".insn r 0x77, 0x0, 0x03, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 170 | } 171 | value 172 | } 173 | 174 | /// Cross halves of subtracts and adds packed 16-bit unsigned numbers, dropping least bits. 175 | #[inline] 176 | pub fn urcrsa16(a: usize, b: usize) -> usize { 177 | let value: usize; 178 | unsafe { 179 | asm!(".insn r 0x77, 0x0, 0x13, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 180 | } 181 | value 182 | } 183 | 184 | /// Cross subtracts and adds packed 16-bit signed numbers, saturating at the numeric bounds. 185 | #[inline] 186 | pub fn kcrsa16(a: usize, b: usize) -> usize { 187 | let value: usize; 188 | unsafe { 189 | asm!(".insn r 0x77, 0x0, 0x0B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 190 | } 191 | value 192 | } 193 | 194 | /// Cross subtracts and adds packed 16-bit unsigned numbers, saturating at the numeric bounds. 195 | #[inline] 196 | pub fn ukcrsa16(a: usize, b: usize) -> usize { 197 | let value: usize; 198 | unsafe { 199 | asm!(".insn r 0x77, 0x0, 0x1B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 200 | } 201 | value 202 | } 203 | 204 | /// Straight adds and subtracts packed 16-bit signed numbers, discarding overflow bits. 205 | #[inline] 206 | pub fn stas16(a: usize, b: usize) -> usize { 207 | let value: usize; 208 | unsafe { 209 | asm!(".insn r 0x77, 0x0, 0x7A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 210 | } 211 | value 212 | } 213 | 214 | /// Straight halves of adds and subtracts packed 16-bit signed numbers, dropping least bits. 215 | #[inline] 216 | pub fn rstas16(a: usize, b: usize) -> usize { 217 | let value: usize; 218 | unsafe { 219 | asm!(".insn r 0x77, 0x0, 0x5A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 220 | } 221 | value 222 | } 223 | 224 | /// Straight halves of adds and subtracts packed 16-bit unsigned numbers, dropping least bits. 225 | #[inline] 226 | pub fn urstas16(a: usize, b: usize) -> usize { 227 | let value: usize; 228 | unsafe { 229 | asm!(".insn r 0x77, 0x0, 0x6A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 230 | } 231 | value 232 | } 233 | 234 | /// Straight adds and subtracts packed 16-bit signed numbers, saturating at the numeric bounds. 235 | #[inline] 236 | pub fn kstas16(a: usize, b: usize) -> usize { 237 | let value: usize; 238 | unsafe { 239 | asm!(".insn r 0x77, 0x0, 0x62, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 240 | } 241 | value 242 | } 243 | 244 | /// Straight adds and subtracts packed 16-bit unsigned numbers, saturating at the numeric bounds. 245 | #[inline] 246 | pub fn ukstas16(a: usize, b: usize) -> usize { 247 | let value: usize; 248 | unsafe { 249 | asm!(".insn r 0x77, 0x0, 0x72, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 250 | } 251 | value 252 | } 253 | 254 | /// Straight subtracts and adds packed 16-bit signed numbers, discarding overflow bits. 255 | #[inline] 256 | pub fn stsa16(a: usize, b: usize) -> usize { 257 | let value: usize; 258 | unsafe { 259 | asm!(".insn r 0x77, 0x0, 0x7B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 260 | } 261 | value 262 | } 263 | 264 | /// Straight halves of subtracts and adds packed 16-bit signed numbers, dropping least bits. 265 | #[inline] 266 | pub fn rstsa16(a: usize, b: usize) -> usize { 267 | let value: usize; 268 | unsafe { 269 | asm!(".insn r 0x77, 0x0, 0x5B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 270 | } 271 | value 272 | } 273 | 274 | /// Straight halves of subtracts and adds packed 16-bit unsigned numbers, dropping least bits. 275 | #[inline] 276 | pub fn urstsa16(a: usize, b: usize) -> usize { 277 | let value: usize; 278 | unsafe { 279 | asm!(".insn r 0x77, 0x0, 0x6B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 280 | } 281 | value 282 | } 283 | 284 | /// Straight subtracts and adds packed 16-bit signed numbers, saturating at the numeric bounds. 285 | #[inline] 286 | pub fn kstsa16(a: usize, b: usize) -> usize { 287 | let value: usize; 288 | unsafe { 289 | asm!(".insn r 0x77, 0x0, 0x63, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 290 | } 291 | value 292 | } 293 | 294 | /// Straight subtracts and adds packed 16-bit unsigned numbers, saturating at the numeric bounds. 295 | #[inline] 296 | pub fn ukstsa16(a: usize, b: usize) -> usize { 297 | let value: usize; 298 | unsafe { 299 | asm!(".insn r 0x77, 0x0, 0x73, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 300 | } 301 | value 302 | } 303 | 304 | /// Adds packed 8-bit signed numbers, discarding overflow bits. 305 | #[inline] 306 | pub fn add8(a: usize, b: usize) -> usize { 307 | let value: usize; 308 | unsafe { 309 | asm!(".insn r 0x77, 0x0, 0x24, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 310 | } 311 | value 312 | } 313 | 314 | /// Halves the sum of packed 8-bit signed numbers, dropping least bits. 315 | #[inline] 316 | pub fn radd8(a: usize, b: usize) -> usize { 317 | let value: usize; 318 | unsafe { 319 | asm!(".insn r 0x77, 0x0, 0x04, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 320 | } 321 | value 322 | } 323 | 324 | /// Halves the sum of packed 8-bit unsigned numbers, dropping least bits. 325 | #[inline] 326 | pub fn uradd8(a: usize, b: usize) -> usize { 327 | let value: usize; 328 | unsafe { 329 | asm!(".insn r 0x77, 0x0, 0x14, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 330 | } 331 | value 332 | } 333 | 334 | /// Adds packed 8-bit signed numbers, saturating at the numeric bounds. 335 | #[inline] 336 | pub fn kadd8(a: usize, b: usize) -> usize { 337 | let value: usize; 338 | unsafe { 339 | asm!(".insn r 0x77, 0x0, 0x0C, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 340 | } 341 | value 342 | } 343 | 344 | /// Adds packed 8-bit unsigned numbers, saturating at the numeric bounds. 345 | #[inline] 346 | pub fn ukadd8(a: usize, b: usize) -> usize { 347 | let value: usize; 348 | unsafe { 349 | asm!(".insn r 0x77, 0x0, 0x1C, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 350 | } 351 | value 352 | } 353 | 354 | /// Subtracts packed 8-bit signed numbers, discarding overflow bits. 355 | #[inline] 356 | pub fn sub8(a: usize, b: usize) -> usize { 357 | let value: usize; 358 | unsafe { 359 | asm!(".insn r 0x77, 0x0, 0x25, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 360 | } 361 | value 362 | } 363 | 364 | /// Halves the subtraction result of packed 8-bit signed numbers, dropping least bits. 365 | #[inline] 366 | pub fn rsub8(a: usize, b: usize) -> usize { 367 | let value: usize; 368 | unsafe { 369 | asm!(".insn r 0x77, 0x0, 0x05, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 370 | } 371 | value 372 | } 373 | 374 | /// Halves the subtraction result of packed 8-bit unsigned numbers, dropping least bits. 375 | #[inline] 376 | pub fn ursub8(a: usize, b: usize) -> usize { 377 | let value: usize; 378 | unsafe { 379 | asm!(".insn r 0x77, 0x0, 0x15, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 380 | } 381 | value 382 | } 383 | 384 | /// Subtracts packed 8-bit signed numbers, saturating at the numeric bounds. 385 | #[inline] 386 | pub fn ksub8(a: usize, b: usize) -> usize { 387 | let value: usize; 388 | unsafe { 389 | asm!(".insn r 0x77, 0x0, 0x0D, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 390 | } 391 | value 392 | } 393 | 394 | /// Subtracts packed 8-bit unsigned numbers, saturating at the numeric bounds. 395 | #[inline] 396 | pub fn uksub8(a: usize, b: usize) -> usize { 397 | let value: usize; 398 | unsafe { 399 | asm!(".insn r 0x77, 0x0, 0x1D, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 400 | } 401 | value 402 | } 403 | 404 | /// Arithmetic right shift packed 16-bit elements without rounding up. 405 | #[inline] 406 | pub fn sra16(a: usize, b: u32) -> usize { 407 | let value: usize; 408 | unsafe { 409 | asm!(".insn r 0x77, 0x0, 0x28, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 410 | } 411 | value 412 | } 413 | 414 | /// Arithmetic right shift packed 16-bit elements with rounding up. 415 | #[inline] 416 | pub fn sra16u(a: usize, b: u32) -> usize { 417 | let value: usize; 418 | unsafe { 419 | asm!(".insn r 0x77, 0x0, 0x30, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 420 | } 421 | value 422 | } 423 | 424 | /// Logical right shift packed 16-bit elements without rounding up. 425 | #[inline] 426 | pub fn srl16(a: usize, b: u32) -> usize { 427 | let value: usize; 428 | unsafe { 429 | asm!(".insn r 0x77, 0x0, 0x29, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 430 | } 431 | value 432 | } 433 | 434 | /// Logical right shift packed 16-bit elements with rounding up. 435 | #[inline] 436 | pub fn srl16u(a: usize, b: u32) -> usize { 437 | let value: usize; 438 | unsafe { 439 | asm!(".insn r 0x77, 0x0, 0x31, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 440 | } 441 | value 442 | } 443 | 444 | /// Logical left shift packed 16-bit elements, discarding overflow bits. 445 | #[inline] 446 | pub fn sll16(a: usize, b: u32) -> usize { 447 | let value: usize; 448 | unsafe { 449 | asm!(".insn r 0x77, 0x0, 0x2A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 450 | } 451 | value 452 | } 453 | 454 | /// Logical left shift packed 16-bit elements, saturating at the numeric bounds. 455 | #[inline] 456 | pub fn ksll16(a: usize, b: u32) -> usize { 457 | let value: usize; 458 | unsafe { 459 | asm!(".insn r 0x77, 0x0, 0x32, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 460 | } 461 | value 462 | } 463 | 464 | /// Logical saturating left then arithmetic right shift packed 16-bit elements. 465 | #[inline] 466 | pub fn kslra16(a: usize, b: i32) -> usize { 467 | let value: usize; 468 | unsafe { 469 | asm!(".insn r 0x77, 0x0, 0x2B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 470 | } 471 | value 472 | } 473 | 474 | /// Logical saturating left then arithmetic right shift packed 16-bit elements. 475 | #[inline] 476 | pub fn kslra16u(a: usize, b: i32) -> usize { 477 | let value: usize; 478 | unsafe { 479 | asm!(".insn r 0x77, 0x0, 0x33, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 480 | } 481 | value 482 | } 483 | 484 | /// Arithmetic right shift packed 8-bit elements without rounding up. 485 | #[inline] 486 | pub fn sra8(a: usize, b: u32) -> usize { 487 | let value: usize; 488 | unsafe { 489 | asm!(".insn r 0x77, 0x0, 0x2C, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 490 | } 491 | value 492 | } 493 | 494 | /// Arithmetic right shift packed 8-bit elements with rounding up. 495 | #[inline] 496 | pub fn sra8u(a: usize, b: u32) -> usize { 497 | let value: usize; 498 | unsafe { 499 | asm!(".insn r 0x77, 0x0, 0x34, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 500 | } 501 | value 502 | } 503 | 504 | /// Logical right shift packed 8-bit elements without rounding up. 505 | #[inline] 506 | pub fn srl8(a: usize, b: u32) -> usize { 507 | let value: usize; 508 | unsafe { 509 | asm!(".insn r 0x77, 0x0, 0x2D, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 510 | } 511 | value 512 | } 513 | 514 | /// Logical right shift packed 8-bit elements with rounding up. 515 | #[inline] 516 | pub fn srl8u(a: usize, b: u32) -> usize { 517 | let value: usize; 518 | unsafe { 519 | asm!(".insn r 0x77, 0x0, 0x35, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 520 | } 521 | value 522 | } 523 | 524 | /// Logical left shift packed 8-bit elements, discarding overflow bits. 525 | #[inline] 526 | pub fn sll8(a: usize, b: u32) -> usize { 527 | let value: usize; 528 | unsafe { 529 | asm!(".insn r 0x77, 0x0, 0x2E, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 530 | } 531 | value 532 | } 533 | 534 | /// Logical left shift packed 8-bit elements, saturating at the numeric bounds. 535 | #[inline] 536 | pub fn ksll8(a: usize, b: u32) -> usize { 537 | let value: usize; 538 | unsafe { 539 | asm!(".insn r 0x77, 0x0, 0x36, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 540 | } 541 | value 542 | } 543 | 544 | /// Logical saturating left then arithmetic right shift packed 8-bit elements. 545 | #[inline] 546 | pub fn kslra8(a: usize, b: i32) -> usize { 547 | let value: usize; 548 | unsafe { 549 | asm!(".insn r 0x77, 0x0, 0x2F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 550 | } 551 | value 552 | } 553 | 554 | /// Logical saturating left then arithmetic right shift packed 8-bit elements. 555 | #[inline] 556 | pub fn kslra8u(a: usize, b: i32) -> usize { 557 | let value: usize; 558 | unsafe { 559 | asm!(".insn r 0x77, 0x0, 0x37, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 560 | } 561 | value 562 | } 563 | 564 | /// Compare equality for packed 16-bit elements. 565 | #[inline] 566 | pub fn cmpeq16(a: usize, b: usize) -> usize { 567 | let value: usize; 568 | unsafe { 569 | asm!(".insn r 0x77, 0x0, 0x26, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 570 | } 571 | value 572 | } 573 | 574 | /// Compare whether 16-bit packed signed integers are less than the others. 575 | #[inline] 576 | pub fn scmplt16(a: usize, b: usize) -> usize { 577 | let value: usize; 578 | unsafe { 579 | asm!(".insn r 0x77, 0x0, 0x06, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 580 | } 581 | value 582 | } 583 | 584 | /// Compare whether 16-bit packed signed integers are less than or equal to the others. 585 | #[inline] 586 | pub fn scmple16(a: usize, b: usize) -> usize { 587 | let value: usize; 588 | unsafe { 589 | asm!(".insn r 0x77, 0x0, 0x0E, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 590 | } 591 | value 592 | } 593 | 594 | /// Compare whether 16-bit packed unsigned integers are less than the others. 595 | #[inline] 596 | pub fn ucmplt16(a: usize, b: usize) -> usize { 597 | let value: usize; 598 | unsafe { 599 | asm!(".insn r 0x77, 0x0, 0x16, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 600 | } 601 | value 602 | } 603 | 604 | /// Compare whether 16-bit packed unsigned integers are less than or equal to the others. 605 | #[inline] 606 | pub fn ucmple16(a: usize, b: usize) -> usize { 607 | let value: usize; 608 | unsafe { 609 | asm!(".insn r 0x77, 0x0, 0x1E, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 610 | } 611 | value 612 | } 613 | 614 | /// Compare equality for packed 8-bit elements. 615 | #[inline] 616 | pub fn cmpeq8(a: usize, b: usize) -> usize { 617 | let value: usize; 618 | unsafe { 619 | asm!(".insn r 0x77, 0x0, 0x27, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 620 | } 621 | value 622 | } 623 | 624 | /// Compare whether 8-bit packed signed integers are less than the others. 625 | #[inline] 626 | pub fn scmplt8(a: usize, b: usize) -> usize { 627 | let value: usize; 628 | unsafe { 629 | asm!(".insn r 0x77, 0x0, 0x07, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 630 | } 631 | value 632 | } 633 | 634 | /// Compare whether 8-bit packed signed integers are less than or equal to the others. 635 | #[inline] 636 | pub fn scmple8(a: usize, b: usize) -> usize { 637 | let value: usize; 638 | unsafe { 639 | asm!(".insn r 0x77, 0x0, 0x0F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 640 | } 641 | value 642 | } 643 | 644 | /// Compare whether 8-bit packed unsigned integers are less than the others. 645 | #[inline] 646 | pub fn ucmplt8(a: usize, b: usize) -> usize { 647 | let value: usize; 648 | unsafe { 649 | asm!(".insn r 0x77, 0x0, 0x17, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 650 | } 651 | value 652 | } 653 | 654 | /// Compare whether 8-bit packed unsigned integers are less than or equal to the others. 655 | #[inline] 656 | pub fn ucmple8(a: usize, b: usize) -> usize { 657 | let value: usize; 658 | unsafe { 659 | asm!(".insn r 0x77, 0x0, 0x1F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 660 | } 661 | value 662 | } 663 | 664 | /// Get minimum values from 16-bit packed signed integers. 665 | #[inline] 666 | pub fn smin16(a: usize, b: usize) -> usize { 667 | let value: usize; 668 | unsafe { 669 | asm!(".insn r 0x77, 0x0, 0x40, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 670 | } 671 | value 672 | } 673 | 674 | /// Get minimum values from 16-bit packed unsigned integers. 675 | #[inline] 676 | pub fn umin16(a: usize, b: usize) -> usize { 677 | let value: usize; 678 | unsafe { 679 | asm!(".insn r 0x77, 0x0, 0x48, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 680 | } 681 | value 682 | } 683 | 684 | /// Get maximum values from 16-bit packed signed integers. 685 | #[inline] 686 | pub fn smax16(a: usize, b: usize) -> usize { 687 | let value: usize; 688 | unsafe { 689 | asm!(".insn r 0x77, 0x0, 0x41, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 690 | } 691 | value 692 | } 693 | 694 | /// Get maximum values from 16-bit packed unsigned integers. 695 | #[inline] 696 | pub fn umax16(a: usize, b: usize) -> usize { 697 | let value: usize; 698 | unsafe { 699 | asm!(".insn r 0x77, 0x0, 0x49, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 700 | } 701 | value 702 | } 703 | 704 | /* todo: sclip16, uclip16 */ 705 | 706 | /// Compute the absolute value of packed 16-bit signed integers. 707 | #[inline] 708 | pub fn kabs16(a: usize) -> usize { 709 | let value: usize; 710 | unsafe { 711 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAD1", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 712 | } 713 | value 714 | } 715 | 716 | /// Count the number of redundant sign bits of the packed 16-bit elements. 717 | #[inline] 718 | pub fn clrs16(a: usize) -> usize { 719 | let value: usize; 720 | unsafe { 721 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAE8", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 722 | } 723 | value 724 | } 725 | 726 | /// Count the number of leading zero bits of the packed 16-bit elements. 727 | #[inline] 728 | pub fn clz16(a: usize) -> usize { 729 | let value: usize; 730 | unsafe { 731 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAE9", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 732 | } 733 | value 734 | } 735 | 736 | /// Swap the 16-bit halfwords within each 32-bit word of a register. 737 | #[inline] 738 | pub fn swap16(a: usize) -> usize { 739 | let value: usize; 740 | // this instruction is an alias for `pkbt rd, rs1, rs1`. 741 | unsafe { 742 | asm!(".insn r 0x77, 0x0, 0x0F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) a, options(pure, nomem, nostack)) 743 | } 744 | value 745 | } 746 | 747 | /// Get minimum values from 8-bit packed signed integers. 748 | #[inline] 749 | pub fn smin8(a: usize, b: usize) -> usize { 750 | let value: usize; 751 | unsafe { 752 | asm!(".insn r 0x77, 0x0, 0x44, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 753 | } 754 | value 755 | } 756 | 757 | /// Get minimum values from 8-bit packed unsigned integers. 758 | #[inline] 759 | pub fn umin8(a: usize, b: usize) -> usize { 760 | let value: usize; 761 | unsafe { 762 | asm!(".insn r 0x77, 0x0, 0x4C, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 763 | } 764 | value 765 | } 766 | 767 | /// Get maximum values from 8-bit packed signed integers. 768 | #[inline] 769 | pub fn smax8(a: usize, b: usize) -> usize { 770 | let value: usize; 771 | unsafe { 772 | asm!(".insn r 0x77, 0x0, 0x45, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 773 | } 774 | value 775 | } 776 | 777 | /// Get maximum values from 8-bit packed unsigned integers. 778 | #[inline] 779 | pub fn umax8(a: usize, b: usize) -> usize { 780 | let value: usize; 781 | unsafe { 782 | asm!(".insn r 0x77, 0x0, 0x4D, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 783 | } 784 | value 785 | } 786 | 787 | /* todo: sclip8, uclip8 */ 788 | 789 | /// Compute the absolute value of packed 8-bit signed integers. 790 | #[inline] 791 | pub fn kabs8(a: usize) -> usize { 792 | let value: usize; 793 | unsafe { 794 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAD0", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 795 | } 796 | value 797 | } 798 | 799 | /// Count the number of redundant sign bits of the packed 8-bit elements. 800 | #[inline] 801 | pub fn clrs8(a: usize) -> usize { 802 | let value: usize; 803 | unsafe { 804 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAE0", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 805 | } 806 | value 807 | } 808 | 809 | /// Count the number of leading zero bits of the packed 8-bit elements. 810 | #[inline] 811 | pub fn clz8(a: usize) -> usize { 812 | let value: usize; 813 | unsafe { 814 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAE1", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 815 | } 816 | value 817 | } 818 | 819 | /// Swap the 8-bit bytes within each 16-bit halfword of a register.. 820 | #[inline] 821 | pub fn swap8(a: usize) -> usize { 822 | let value: usize; 823 | unsafe { 824 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAD8", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 825 | } 826 | value 827 | } 828 | 829 | /// Unpack first and zeroth into two 16-bit signed halfwords in each 32-bit chunk. 830 | #[inline] 831 | pub fn sunpkd810(a: usize) -> usize { 832 | let value: usize; 833 | unsafe { 834 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAC8", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 835 | } 836 | value 837 | } 838 | 839 | /// Unpack second and zeroth into two 16-bit signed halfwords in each 32-bit chunk. 840 | #[inline] 841 | pub fn sunpkd820(a: usize) -> usize { 842 | let value: usize; 843 | unsafe { 844 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAC9", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 845 | } 846 | value 847 | } 848 | 849 | /// Unpack third and zeroth into two 16-bit signed halfwords in each 32-bit chunk. 850 | #[inline] 851 | pub fn sunpkd830(a: usize) -> usize { 852 | let value: usize; 853 | unsafe { 854 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACA", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 855 | } 856 | value 857 | } 858 | 859 | /// Unpack third and first into two 16-bit signed halfwords in each 32-bit chunk. 860 | #[inline] 861 | pub fn sunpkd831(a: usize) -> usize { 862 | let value: usize; 863 | unsafe { 864 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACB", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 865 | } 866 | value 867 | } 868 | 869 | /// Unpack third and second into two 16-bit signed halfwords in each 32-bit chunk. 870 | #[inline] 871 | pub fn sunpkd832(a: usize) -> usize { 872 | let value: usize; 873 | unsafe { 874 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAD3", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 875 | } 876 | value 877 | } 878 | 879 | /// Unpack first and zeroth into two 16-bit unsigned halfwords in each 32-bit chunk. 880 | #[inline] 881 | pub fn zunpkd810(a: usize) -> usize { 882 | let value: usize; 883 | unsafe { 884 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACC", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 885 | } 886 | value 887 | } 888 | 889 | /// Unpack second and zeroth into two 16-bit unsigned halfwords in each 32-bit chunk. 890 | #[inline] 891 | pub fn zunpkd820(a: usize) -> usize { 892 | let value: usize; 893 | unsafe { 894 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACD", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 895 | } 896 | value 897 | } 898 | 899 | /// Unpack third and zeroth into two 16-bit unsigned halfwords in each 32-bit chunk. 900 | #[inline] 901 | pub fn zunpkd830(a: usize) -> usize { 902 | let value: usize; 903 | unsafe { 904 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACE", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 905 | } 906 | value 907 | } 908 | 909 | /// Unpack third and first into two 16-bit unsigned halfwords in each 32-bit chunk. 910 | #[inline] 911 | pub fn zunpkd831(a: usize) -> usize { 912 | let value: usize; 913 | unsafe { 914 | asm!(".insn i 0x77, 0x0, {}, {}, 0xACF", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 915 | } 916 | value 917 | } 918 | 919 | /// Unpack third and second into two 16-bit unsigned halfwords in each 32-bit chunk. 920 | #[inline] 921 | pub fn zunpkd832(a: usize) -> usize { 922 | let value: usize; 923 | unsafe { 924 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAD7", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 925 | } 926 | value 927 | } 928 | 929 | // todo: pkbb16, pktt16 930 | 931 | /// Pack two 16-bit data from bottom and top half from 32-bit chunks. 932 | #[inline] 933 | pub fn pkbt16(a: usize, b: usize) -> usize { 934 | let value: usize; 935 | unsafe { 936 | asm!(".insn r 0x77, 0x1, 0x0F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 937 | } 938 | value 939 | } 940 | 941 | /// Pack two 16-bit data from top and bottom half from 32-bit chunks. 942 | #[inline] 943 | pub fn pktb16(a: usize, b: usize) -> usize { 944 | let value: usize; 945 | unsafe { 946 | asm!(".insn r 0x77, 0x1, 0x1F, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 947 | } 948 | value 949 | } 950 | 951 | /// Count the number of redundant sign bits of the packed 32-bit elements. 952 | #[inline] 953 | pub fn clrs32(a: usize) -> usize { 954 | let value: usize; 955 | unsafe { 956 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAF8", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 957 | } 958 | value 959 | } 960 | 961 | /// Count the number of leading zero bits of the packed 32-bit elements. 962 | #[inline] 963 | pub fn clz32(a: usize) -> usize { 964 | let value: usize; 965 | unsafe { 966 | asm!(".insn i 0x77, 0x0, {}, {}, 0xAF9", lateout(reg) value, in(reg) a, options(pure, nomem, nostack)) 967 | } 968 | value 969 | } 970 | 971 | /// Calculate the sum of absolute difference of unsigned 8-bit data elements. 972 | #[inline] 973 | pub fn pbsad(a: usize, b: usize) -> usize { 974 | let value: usize; 975 | unsafe { 976 | asm!(".insn r 0x77, 0x0, 0x7E, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 977 | } 978 | value 979 | } 980 | 981 | /// Calculate and accumulate the sum of absolute difference of unsigned 8-bit data elements. 982 | #[inline] 983 | pub fn pbsada(t: usize, a: usize, b: usize) -> usize { 984 | let mut value: usize; 985 | unsafe { 986 | asm!(".insn r 0x77, 0x0, 0x7F, {}, {}, {}", inlateout(reg) t => value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 987 | } 988 | value 989 | } 990 | 991 | /// Multiply signed 8-bit elements and add 16-bit elements on results for packed 32-bit chunks. 992 | #[inline] 993 | pub fn smaqa(t: usize, a: usize, b: usize) -> usize { 994 | let mut value: usize; 995 | unsafe { 996 | asm!(".insn r 0x77, 0x0, 0x64, {}, {}, {}", inlateout(reg) t => value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 997 | } 998 | value 999 | } 1000 | 1001 | /// Multiply unsigned 8-bit elements and add 16-bit elements on results for packed 32-bit chunks. 1002 | #[inline] 1003 | pub fn umaqa(t: usize, a: usize, b: usize) -> usize { 1004 | let mut value: usize; 1005 | unsafe { 1006 | asm!(".insn r 0x77, 0x0, 0x66, {}, {}, {}", inlateout(reg) t => value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1007 | } 1008 | value 1009 | } 1010 | 1011 | /// Multiply signed to unsigned 8-bit and add 16-bit elements on results for packed 32-bit chunks. 1012 | #[inline] 1013 | pub fn smaqasu(t: usize, a: usize, b: usize) -> usize { 1014 | let mut value: usize; 1015 | unsafe { 1016 | asm!(".insn r 0x77, 0x0, 0x65, {}, {}, {}", inlateout(reg) t => value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1017 | } 1018 | value 1019 | } 1020 | 1021 | /// Adds signed lower 16-bit content of two registers with Q15 saturation. 1022 | #[inline] 1023 | pub fn kaddh(a: usize, b: usize) -> usize { 1024 | let value: usize; 1025 | unsafe { 1026 | asm!(".insn r 0x77, 0x1, 0x02, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1027 | } 1028 | value 1029 | } 1030 | 1031 | /// Subtracts signed lower 16-bit content of two registers with Q15 saturation. 1032 | #[inline] 1033 | pub fn ksubh(a: usize, b: usize) -> usize { 1034 | let value: usize; 1035 | unsafe { 1036 | asm!(".insn r 0x77, 0x1, 0x03, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1037 | } 1038 | value 1039 | } 1040 | 1041 | /// Adds signed lower 16-bit content of two registers with U16 saturation. 1042 | #[inline] 1043 | pub fn ukaddh(a: usize, b: usize) -> usize { 1044 | let value: usize; 1045 | unsafe { 1046 | asm!(".insn r 0x77, 0x1, 0x0A, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1047 | } 1048 | value 1049 | } 1050 | 1051 | /// Subtracts signed lower 16-bit content of two registers with U16 saturation. 1052 | #[inline] 1053 | pub fn uksubh(a: usize, b: usize) -> usize { 1054 | let value: usize; 1055 | unsafe { 1056 | asm!(".insn r 0x77, 0x1, 0x0B, {}, {}, {}", lateout(reg) value, in(reg) a, in(reg) b, options(pure, nomem, nostack)) 1057 | } 1058 | value 1059 | } 1060 | --------------------------------------------------------------------------------