forked from M-Labs/zynq-rs
Compare commits
7 Commits
master
...
feature/co
Author | SHA1 | Date |
---|---|---|
Brad Bondurant | c7a5c2cf00 | |
Brad Bondurant | 6a5fd192df | |
Brad Bondurant | ddc184cd89 | |
Brad Bondurant | efa9a17cd2 | |
Brad Bondurant | 4b139cfc2f | |
Brad Bondurant | ab6d14f492 | |
Brad Bondurant | 4ae8ffa640 |
|
@ -126,6 +126,16 @@ dependencies = [
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcortex_r5"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bit_field",
|
||||||
|
"libcortex_a9",
|
||||||
|
"libregister",
|
||||||
|
"volatile-register",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
members = [
|
members = [
|
||||||
"libregister",
|
"libregister",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
"libcortex_r5",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
"libasync",
|
"libasync",
|
||||||
|
|
|
@ -125,8 +125,8 @@ pub fn dcciall() {
|
||||||
dsb();
|
dsb();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CACHE_LINE: usize = 0x20;
|
pub const CACHE_LINE: usize = 0x20;
|
||||||
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
pub const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cache_line_addrs(first_addr: usize, beyond_addr: usize) -> impl Iterator<Item = usize> {
|
fn cache_line_addrs(first_addr: usize, beyond_addr: usize) -> impl Iterator<Item = usize> {
|
||||||
|
@ -136,13 +136,13 @@ fn cache_line_addrs(first_addr: usize, beyond_addr: usize) -> impl Iterator<Item
|
||||||
(first_addr..beyond_addr).step_by(CACHE_LINE)
|
(first_addr..beyond_addr).step_by(CACHE_LINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_cache_line_addrs<T>(object: &T) -> impl Iterator<Item = usize> {
|
pub fn object_cache_line_addrs<T>(object: &T) -> impl Iterator<Item = usize> {
|
||||||
let first_addr = object as *const _ as usize;
|
let first_addr = object as *const _ as usize;
|
||||||
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
||||||
cache_line_addrs(first_addr, beyond_addr)
|
cache_line_addrs(first_addr, beyond_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
pub fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
||||||
let first_addr = &slice[0] as *const _ as usize;
|
let first_addr = &slice[0] as *const _ as usize;
|
||||||
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) +
|
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) +
|
||||||
core::mem::size_of_val(&slice[slice.len() - 1]);
|
core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||||
|
|
|
@ -3,6 +3,7 @@ use libregister::{
|
||||||
RegisterR, RegisterW, RegisterRW,
|
RegisterR, RegisterW, RegisterRW,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! def_reg_r {
|
macro_rules! def_reg_r {
|
||||||
($name:tt, $type: ty, $asm_instr:tt) => {
|
($name:tt, $type: ty, $asm_instr:tt) => {
|
||||||
impl RegisterR for $name {
|
impl RegisterR for $name {
|
||||||
|
@ -18,6 +19,7 @@ macro_rules! def_reg_r {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! def_reg_w {
|
macro_rules! def_reg_w {
|
||||||
($name:ty, $type:ty, $asm_instr:tt) => {
|
($name:ty, $type:ty, $asm_instr:tt) => {
|
||||||
impl RegisterW for $name {
|
impl RegisterW for $name {
|
||||||
|
@ -37,6 +39,7 @@ macro_rules! def_reg_w {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! wrap_reg {
|
macro_rules! wrap_reg {
|
||||||
($mod_name: ident) => {
|
($mod_name: ident) => {
|
||||||
pub mod $mod_name {
|
pub mod $mod_name {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "libcortex_r5"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
power_saving = []
|
||||||
|
default = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bit_field = "0.10"
|
||||||
|
volatile-register = "0.2"
|
||||||
|
libregister = { path = "../libregister" }
|
||||||
|
libcortex_a9 = { path = "../libcortex_a9" }
|
|
@ -0,0 +1 @@
|
||||||
|
pub use libcortex_a9::asm::*;
|
|
@ -0,0 +1,87 @@
|
||||||
|
/// Basically same as the Cortex A9 but with no L2
|
||||||
|
pub use libcortex_a9::cache::{
|
||||||
|
iciallu,
|
||||||
|
dcisw,
|
||||||
|
dccsw,
|
||||||
|
dccisw,
|
||||||
|
dccimvac,
|
||||||
|
dccmvac,
|
||||||
|
dcimvac,
|
||||||
|
object_cache_line_addrs,
|
||||||
|
slice_cache_line_addrs,
|
||||||
|
CACHE_LINE,
|
||||||
|
CACHE_LINE_MASK
|
||||||
|
};
|
||||||
|
use super::asm::{dmb, dsb};
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dciall() {
|
||||||
|
unsafe {
|
||||||
|
llvm_asm!("mcr p15, 0, $0, c15, c5, 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// D$ clean and invalidate
|
||||||
|
pub fn dcci<T>(object: &T) {
|
||||||
|
dmb();
|
||||||
|
for addr in object_cache_line_addrs(object) {
|
||||||
|
dccimvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dcci_slice<T>(slice: &[T]) {
|
||||||
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
dccimvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
// D$ clean
|
||||||
|
pub fn dcc<T>(object: &T) {
|
||||||
|
dmb();
|
||||||
|
for addr in object_cache_line_addrs(object) {
|
||||||
|
dccmvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dcc_slice<T>(slice: &[T]) {
|
||||||
|
if slice.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
dccmvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
// D$ invalidate
|
||||||
|
pub unsafe fn dci<T>(object: &mut T) {
|
||||||
|
let first_addr = object as *const _ as usize;
|
||||||
|
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
||||||
|
assert_eq!(first_addr & CACHE_LINE_MASK, 0, "dci object first_addr must be aligned");
|
||||||
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
||||||
|
|
||||||
|
dmb();
|
||||||
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
|
dcimvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn dci_slice<T>(slice: &mut [T]) {
|
||||||
|
let first_addr = &slice[0] as *const _ as usize;
|
||||||
|
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) +
|
||||||
|
core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||||
|
assert_eq!(first_addr & CACHE_LINE_MASK, 0, "dci slice first_addr must be aligned");
|
||||||
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
||||||
|
|
||||||
|
dmb();
|
||||||
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
|
dcimvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(llvm_asm, global_asm)]
|
||||||
|
#![feature(never_type)]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub mod asm;
|
||||||
|
pub mod regs;
|
||||||
|
pub mod cache;
|
|
@ -0,0 +1,374 @@
|
||||||
|
use libregister::{
|
||||||
|
register_bit, register_bits,
|
||||||
|
RegisterR, RegisterW, RegisterRW,
|
||||||
|
};
|
||||||
|
use libcortex_a9::{def_reg_r, def_reg_w, wrap_reg};
|
||||||
|
pub use libcortex_a9::regs::{SP, LR};
|
||||||
|
|
||||||
|
|
||||||
|
/// Multiprocessor Affinity Register
|
||||||
|
pub struct MPIDR;
|
||||||
|
wrap_reg!(mpidr);
|
||||||
|
def_reg_r!(MPIDR, mpidr::Read, "mrc p15, 0, $0, c0, c0, 5");
|
||||||
|
// CPU ID
|
||||||
|
register_bits!(mpidr, cpu_id, u8, 0, 7);
|
||||||
|
// group ID
|
||||||
|
register_bits!(mpidr, group_id, u8, 8, 15);
|
||||||
|
// 0b11 if part of uniprocessor system
|
||||||
|
register_bits!(mpidr, u, u8, 30, 31);
|
||||||
|
|
||||||
|
/// System Control Register
|
||||||
|
pub struct SCTLR;
|
||||||
|
wrap_reg!(sctlr);
|
||||||
|
def_reg_r!(SCTLR, sctlr::Read, "mrc p15, 0, $0, c1, c0, 0");
|
||||||
|
def_reg_w!(SCTLR, sctlr::Write, "mrc p15, 0, $0, c1, c0, 0");
|
||||||
|
// MPU enable
|
||||||
|
register_bit!(sctlr, m, 0);
|
||||||
|
// strict alignment
|
||||||
|
register_bit!(sctlr, a, 1);
|
||||||
|
// L1 data cache enable
|
||||||
|
register_bit!(sctlr, c, 2);
|
||||||
|
// enable SWP and SWPB instructions
|
||||||
|
register_bit!(sctlr, sw, 10);
|
||||||
|
// enable branch prediction (SBO)
|
||||||
|
register_bit!(sctlr, z, 11);
|
||||||
|
// L1 instruction cache enable
|
||||||
|
register_bit!(sctlr, i, 12);
|
||||||
|
// Determines the location of exception vectors:
|
||||||
|
// 0 = normal exception vectors selected, address range = 0x00000000-0x0000001C
|
||||||
|
// 1 = high exception vectors (HIVECS) selected, address range = 0xFFFF0000-0xFFFF001C.
|
||||||
|
// The primary input VINITHIm defines the reset value.
|
||||||
|
register_bit!(sctlr, v, 13);
|
||||||
|
// Round-robin bit, controls replacement strategy for instruction and data caches:
|
||||||
|
// 0 = random replacement strategy
|
||||||
|
// 1 = round-robin replacement strategy.
|
||||||
|
// The reset value of this bit is 0. The processor always uses a random replacement strategy, regardless of the state
|
||||||
|
// of this bit.
|
||||||
|
register_bit!(sctlr, rr, 14);
|
||||||
|
// MPU background region enable
|
||||||
|
register_bit!(sctlr, br, 17);
|
||||||
|
// Divide by zero:
|
||||||
|
// 0 = do not generate an Undefined Instruction exception
|
||||||
|
// 1 = generate an Undefined Instruction exception.
|
||||||
|
// The reset value of this bit is 0
|
||||||
|
register_bit!(sctlr, dz, 19);
|
||||||
|
// Fast Interrupts enable.
|
||||||
|
// On the processor Fast Interrupts are always enabled. This bit is SBO
|
||||||
|
register_bit!(sctlr, fi, 21);
|
||||||
|
// Configures vectored interrupt:
|
||||||
|
// 0 = exception vector address for IRQ is 0x00000018 or 0xFFFF0018. See V bit.
|
||||||
|
// 1 = VIC controller provides handler address for IRQ.
|
||||||
|
// The reset value of this bit is 0.
|
||||||
|
register_bit!(sctlr, ve, 24);
|
||||||
|
// Determines how the E bit in the CPSR is set on an exception:
|
||||||
|
// 0 = CPSR E bit is set to 0 on an exception
|
||||||
|
// 1 = CPSR E bit is set to 1 on an exception.
|
||||||
|
// The primary input CFGEE defines the reset value.
|
||||||
|
register_bit!(sctlr, ee, 25);
|
||||||
|
// NMFI, non-maskable fast interrupt enable:
|
||||||
|
// 0 = Software can disable FIQs
|
||||||
|
// 1 = Software cannot disable FIQs.
|
||||||
|
// This bit is read-only. The configuration input CFGNMFIm defines its value.
|
||||||
|
register_bit!(sctlr, nmfi, 27);
|
||||||
|
// TEX Remap Enable. On the processor this bit is SBZ.
|
||||||
|
register_bit!(sctlr, tre, 28);
|
||||||
|
// Access Flag Enable. On the processor this bit is SBZ.
|
||||||
|
register_bit!(sctlr, afe, 29);
|
||||||
|
// Thumb exception enable:
|
||||||
|
// 0 = enable ARM exception generation
|
||||||
|
// 1 = enable Thumb exception generation.
|
||||||
|
// The primary input TEINIT defines the reset value
|
||||||
|
register_bit!(sctlr, te, 30);
|
||||||
|
// Identifies little or big instruction endianness in use:
|
||||||
|
// 0 = little-endianness
|
||||||
|
// 1 = big-endianness.
|
||||||
|
// The primary input CFGIE defines the value. This bit is read-only
|
||||||
|
register_bit!(sctlr, ie, 31);
|
||||||
|
|
||||||
|
/// Auxiliary Control Register
|
||||||
|
pub struct ACTLR;
|
||||||
|
wrap_reg!(actlr);
|
||||||
|
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, $0, c1, c0, 1");
|
||||||
|
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, $0, c1, c0, 1");
|
||||||
|
// A(B0/1)TCM external error enable:
|
||||||
|
// 0 = Disabled
|
||||||
|
// 1 = Enabled.
|
||||||
|
// The primary input ERRENRAMm[0] defines the reset value.
|
||||||
|
register_bit!(actlr, atcmecen, 0);
|
||||||
|
register_bit!(actlr, b0tcmecen, 1);
|
||||||
|
register_bit!(actlr, b1tcmecen, 2);
|
||||||
|
// Cache error control for cache parity and ECC errors
|
||||||
|
register_bits!(actlr, cec, u8, 3, 5);
|
||||||
|
// Disable low interrupt latency on all load/store instructions
|
||||||
|
register_bit!(actlr, dils, 6);
|
||||||
|
// sMOV of a divide does not complete out of order.
|
||||||
|
// No other instruction is issued until the divide is finished
|
||||||
|
register_bit!(actlr, smov, 7);
|
||||||
|
// Force D-side to not-shared when MPU is off:
|
||||||
|
// 0 = Normal operation. This is the reset value.
|
||||||
|
// 1 = D-side normal Non-cacheable forced to Non-shared when MPU is off.
|
||||||
|
register_bit!(actlr, fdsns, 8);
|
||||||
|
// Force write-through (WT) for write-back (WB) regions:
|
||||||
|
// 0 = No forcing of WT. This is the reset value.
|
||||||
|
// 1 = WT forced for WB regions
|
||||||
|
register_bit!(actlr, fwt, 9);
|
||||||
|
// Force outer read allocate (ORA) for outer write allocate (OWA) regions:
|
||||||
|
// 0 = No forcing of ORA. This is the reset value.
|
||||||
|
// 1 = ORA forced for OWA regions
|
||||||
|
register_bit!(actlr, fora, 10);
|
||||||
|
// Disable data forwarding for Non-cacheable accesses in the AXI master:
|
||||||
|
// 0 = Normal operation. This is the reset value.
|
||||||
|
// 1 = Disable data forwarding for Non-cacheable accesses
|
||||||
|
register_bit!(actlr, dnch, 11);
|
||||||
|
// Enable random parity error generation:
|
||||||
|
// 0 = Random parity error generation disabled. This is the reset value.
|
||||||
|
// 1 = Enable random parity error generation in the cache RAMs.
|
||||||
|
register_bit!(actlr, erpeg, 12);
|
||||||
|
// Disable linefill optimization in the AXI master:
|
||||||
|
// 0 = Normal operation. This is the reset value.
|
||||||
|
// 1 = Limits the number of outstanding data linefills to two
|
||||||
|
register_bit!(actlr, dlfo, 13);
|
||||||
|
// Disable write burst in the AXI master:
|
||||||
|
// 0 = Normal operation. This is the reset value.
|
||||||
|
// 1 = Disable write burst optimization
|
||||||
|
register_bit!(actlr, dbwr, 14);
|
||||||
|
// This field controls the branch prediction policy:
|
||||||
|
// b00 = Normal operation. This is the reset value.
|
||||||
|
// b01 = Branch always taken and history table updates disabled.
|
||||||
|
// b10 = Branch always not taken and history table updates disabled.
|
||||||
|
// b11 = Reserved. Behavior is Unpredictable if this field is set to b11
|
||||||
|
register_bits!(actlr, bp, u8, 15, 16);
|
||||||
|
// Return stack disable:
|
||||||
|
// 0 = Normal return stack operation. This is the reset value.
|
||||||
|
// 1 = Return stack disabled.
|
||||||
|
register_bit!(actlr, rsdis, 17);
|
||||||
|
// Fetch rate control disable:
|
||||||
|
// 0 = Normal fetch rate control operation. This is the reset value.
|
||||||
|
// 1 = Fetch rate control disabled.
|
||||||
|
register_bit!(actlr, frcdis, 19);
|
||||||
|
// Disable Branch History (BH) extension:
|
||||||
|
// 0 = Enable the extension. This is the reset value.
|
||||||
|
// 1 = Disable the extension
|
||||||
|
register_bit!(actlr, dbhe, 20);
|
||||||
|
// Disable end of loop prediction:
|
||||||
|
// 0 = Enable loop prediction. This is the reset value.
|
||||||
|
// 1 = Disable loop prediction.
|
||||||
|
register_bit!(actlr, deolp, 21);
|
||||||
|
// Disable Low Interrupt Latency (LIL) on load/store multiples:
|
||||||
|
// 0 = Enable LIL on load/store multiples. This is the reset value.
|
||||||
|
// 1 = Disable LIL on all load/store multiples.
|
||||||
|
register_bit!(actlr, dilsm, 22);
|
||||||
|
// AXI slave cache RAM non-privileged access enable:
|
||||||
|
// 0 = Disabled. This is the reset value.
|
||||||
|
// 1 = Enabled
|
||||||
|
register_bit!(actlr, axiscuen, 23);
|
||||||
|
// AXI slave cache RAM access enable:
|
||||||
|
// 0 = Disabled. This is the reset value.
|
||||||
|
// 1 = Enabled
|
||||||
|
register_bit!(actlr, axiscen, 24);
|
||||||
|
// A(B0/1)TCM ECC check enable:
|
||||||
|
// 0 = Disabled
|
||||||
|
// 1 = Enabled
|
||||||
|
// The primary input PARECCENRAMm[0] defines the reset value
|
||||||
|
register_bit!(actlr, atcmpcen, 25);
|
||||||
|
register_bit!(actlr, b0tcmpcen, 26);
|
||||||
|
register_bit!(actlr, b1tcmpcen, 27);
|
||||||
|
// Case A(B1, B2, C) dual issue control:
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled.
|
||||||
|
register_bit!(actlr, diadi, 28);
|
||||||
|
register_bit!(actlr, dib1di, 29);
|
||||||
|
register_bit!(actlr, dib2di, 30);
|
||||||
|
register_bit!(actlr, dicdi, 31);
|
||||||
|
|
||||||
|
/// Secondary Auxiliary Control Register
|
||||||
|
pub struct SACTLR;
|
||||||
|
wrap_reg!(sactlr);
|
||||||
|
def_reg_r!(SACTLR, sactlr::Read, "mrc p15, 0, $0, c15, c0, 0");
|
||||||
|
def_reg_w!(SACTLR, sactlr::Write, "mcr p15, 0, $0, c15, c0, 0");
|
||||||
|
// Enables 64-bit stores for the ATCM. When enabled, the processor uses read-modify-write to ensure that all
|
||||||
|
// reads and writes presented on the ATCM port are 64 bits wide.
|
||||||
|
// 0 = Disabled
|
||||||
|
// 1 = Enabled.
|
||||||
|
// The primary input RMWENRAMm[0] defines the reset value.
|
||||||
|
register_bit!(sactlr, atcmrmw, 0);
|
||||||
|
register_bit!(sactlr, btcmrmw, 1);
|
||||||
|
// Correction for internal ECC logic on ATCM port.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled
|
||||||
|
register_bit!(sactlr, atcmecc, 2);
|
||||||
|
register_bit!(sactlr, btcmecc, 3);
|
||||||
|
// Floating-point input denormal exception output mask.
|
||||||
|
// 0 = Mask floating-point input denormal exception output. The output FPIDCm is forced to zero. This is
|
||||||
|
// the reset value.
|
||||||
|
// 1 = Propagate floating-point input denormal exception flag FPSCR.IDC to output FPIDCm
|
||||||
|
register_bit!(sactlr, idc, 8);
|
||||||
|
// Floating-point divide-by-zero exception output mask.
|
||||||
|
// 0 = Mask floating-point divide-by-zero exception output. The output FPDZCm is forced to zero. This is
|
||||||
|
// the reset value.
|
||||||
|
// 1 = Propagate floating-point divide-by-zero exception flag FPSCR.DZC to output FPDZCm
|
||||||
|
register_bit!(sactlr, dzc, 9);
|
||||||
|
// Floating-point invalid operation exception output mask.
|
||||||
|
// 0 = Mask floating-point invalid operation exception output. The output FPIOCm is forced to zero. This is
|
||||||
|
// the reset value.
|
||||||
|
// 1 = Propagate floating-point invalid operation exception flag FPSCR.IOC to output FPIOCm.
|
||||||
|
register_bit!(sactlr, ioc, 10);
|
||||||
|
// Floating-point underflow exception output mask.
|
||||||
|
// 0 = Mask floating-point underflow exception output. The output FPUFCm is forced to zero. This is the
|
||||||
|
// reset value.
|
||||||
|
// 1 = Propagate floating-point underflow exception flag FPSCR.UFC to output FPUFCm
|
||||||
|
register_bit!(sactlr, ufc, 11);
|
||||||
|
// Floating-point overflow exception output mask.
|
||||||
|
// 0 = Mask floating-point overflow exception output. The output FPOFCm is forced to zero. This is the reset
|
||||||
|
// value.
|
||||||
|
// 1 = Propagate floating-point overflow exception flag FPSCR.OFC to output FPOFCm
|
||||||
|
register_bit!(sactlr, ofc, 12);
|
||||||
|
// Floating-point inexact exception output mask.
|
||||||
|
// 0 = Mask floating-point inexact exception output. The output FPIXCm is forced to zero. This is the reset
|
||||||
|
// value.
|
||||||
|
// 1 = Propagate floating point inexact exception flag FPSCR.IXC to output FPIXCm
|
||||||
|
register_bit!(sactlr, ixc, 13);
|
||||||
|
// Out-of-order FMACS control.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled
|
||||||
|
register_bit!(sactlr, doofmacs, 16);
|
||||||
|
// Out-of-order double-precision floating point instruction control.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled.
|
||||||
|
register_bit!(sactlr, doodpfp, 17);
|
||||||
|
// F1/F3/F4dual issue control.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled.
|
||||||
|
register_bit!(sactlr, ddi, 18);
|
||||||
|
// F2_Id/F2_st/F2D dual issue control.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled
|
||||||
|
register_bit!(sactlr, df2di, 19);
|
||||||
|
// F6 dual issue control.
|
||||||
|
// 0 = Enabled. This is the reset value.
|
||||||
|
// 1 = Disabled
|
||||||
|
register_bit!(sactlr, df6di, 20);
|
||||||
|
// Enable random 2-bit error generation in cache RAMs. This bit has no effect unless ECC is configured, see
|
||||||
|
// Configurable options on page 1-6.
|
||||||
|
// 0 = Disabled. This is the reset value.
|
||||||
|
// 1 = Enabled.
|
||||||
|
register_bit!(sactlr, dr2b, 21);
|
||||||
|
// Disable hard-error support in the caches.
|
||||||
|
// 0 = Enabled. The cache logic recovers from some hard errors.
|
||||||
|
// 1 = Disabled. Most hard errors in the caches are fatal. This is the reset value
|
||||||
|
register_bit!(sactlr, dche, 22);
|
||||||
|
|
||||||
|
/// Data Fault Status Register
|
||||||
|
pub struct DFSR;
|
||||||
|
wrap_reg!(dfsr);
|
||||||
|
def_reg_r!(DFSR, dfsr::Read, "mrc p15, 0, $0, c5, c0, 0");
|
||||||
|
// Indicates the type of fault generated. To determine the data fault, you must use bit [12] and bit [10] in
|
||||||
|
// conjunction with bits [3:0].
|
||||||
|
register_bits!(dfsr, status, u8, 0, 3);
|
||||||
|
register_bit!(dfsr, s, 10);
|
||||||
|
// Indicates whether a read or write access caused an abort:
|
||||||
|
// 0 = read access caused the abort
|
||||||
|
// 1 = write access caused the abort.
|
||||||
|
register_bit!(dfsr, rw, 11);
|
||||||
|
// Distinguishes between an AXI Decode or Slave error on an external abort. This bit is only valid for external
|
||||||
|
// aborts. For all other aborts types of abort, this bit is set to zero:
|
||||||
|
// 0 = AXI Decode error (DECERR), or AHB error, caused the abort
|
||||||
|
// 1 = AXI Slave error (SLVERR), or unsupported exclusive access, for example exclusive access using the AHB
|
||||||
|
// peripheral port, caused the abort.
|
||||||
|
register_bit!(dfsr, sd, 12);
|
||||||
|
|
||||||
|
/// Data Fault Address Register
|
||||||
|
pub struct DFAR;
|
||||||
|
def_reg_r!(DFAR, u32, "mrc p15, 0, $0, c6, c0, 0");
|
||||||
|
|
||||||
|
/// MPU Type Register
|
||||||
|
pub struct MPUIR;
|
||||||
|
wrap_reg!(mpuir);
|
||||||
|
def_reg_r!(MPUIR, mpuir::Read, "mrc p15, 0, $0, c0, c0, 4");
|
||||||
|
// number of unified MPU regions (0, 12, or 16)
|
||||||
|
register_bits!(mpuir, d_region, u8, 8, 15);
|
||||||
|
|
||||||
|
/// MPU Region Number Register
|
||||||
|
pub struct RGNR;
|
||||||
|
wrap_reg!(rgnr);
|
||||||
|
def_reg_r!(RGNR, rgnr::Read, "mrc p15, 0, $0, c6, c2, 0");
|
||||||
|
def_reg_w!(RGNR, rgnr::Write, "mcr p15, 0, $0, c6, c2, 0");
|
||||||
|
register_bits!(rgnr, region, u8, 0, 3);
|
||||||
|
|
||||||
|
/// MPU Region Access Control Registers
|
||||||
|
pub struct RACTLR;
|
||||||
|
wrap_reg!(ractlr);
|
||||||
|
def_reg_r!(RACTLR, ractlr::Read, "mrc p15, 0, $0, c6, c1, 4");
|
||||||
|
def_reg_w!(RACTLR, ractlr::Write, "mcr p15, 0, $0, c6, c1, 4");
|
||||||
|
// bufferable
|
||||||
|
register_bit!(ractlr, b, 0);
|
||||||
|
// cacheable
|
||||||
|
register_bit!(ractlr, c, 1);
|
||||||
|
// shareable
|
||||||
|
register_bit!(ractlr, s, 2);
|
||||||
|
// type extension
|
||||||
|
register_bits!(ractlr, tex, u8, 3, 5);
|
||||||
|
// Access permission
|
||||||
|
register_bits!(ractlr, ap, u8, 8, 10);
|
||||||
|
// Execute Never. Determines if a region of memory is executable:
|
||||||
|
// 0 = all instruction fetches enabled
|
||||||
|
// 1 = no instruction fetches enabled.
|
||||||
|
register_bit!(ractlr, xn, 12);
|
||||||
|
|
||||||
|
/// MPU Region Size and Enable Registers
|
||||||
|
pub struct RSER;
|
||||||
|
wrap_reg!(rser);
|
||||||
|
def_reg_r!(RSER, rser::Read, "mrc p15, 0, $0, c6, c1, 2");
|
||||||
|
def_reg_w!(RSER, rser::Write, "mcr p15, 0, $0, c6, c1, 2");
|
||||||
|
// enable region
|
||||||
|
register_bit!(rser, enable, 0);
|
||||||
|
// Defines the region size:
|
||||||
|
// b00000 - b00011=Unpredictable
|
||||||
|
// b00100 = 32 bytes
|
||||||
|
// b00101 = 64 bytes
|
||||||
|
// b00110 = 128 bytes
|
||||||
|
// b00111 = 256 bytes
|
||||||
|
// b01000 = 512 bytes
|
||||||
|
// b01001 = 1KB
|
||||||
|
// b01010 = 2KB
|
||||||
|
// b01011 = 4KB
|
||||||
|
// b01100 = 8KB
|
||||||
|
// b01101 = 16KB
|
||||||
|
// b01110 = 32KB
|
||||||
|
// b01111 = 64KB
|
||||||
|
// b10000 = 128KB
|
||||||
|
// b10001 = 256KB
|
||||||
|
// b10010 = 512KB
|
||||||
|
// b10011 = 1MB
|
||||||
|
// b10100 = 2MB
|
||||||
|
// b10101 = 4MB
|
||||||
|
// b10110 = 8MB
|
||||||
|
// b10111 = 16MB
|
||||||
|
// b11000 = 32MB
|
||||||
|
// b11001 = 64MB
|
||||||
|
// b11010 = 128MB
|
||||||
|
// b11011 = 256MB
|
||||||
|
// b11100 = 512MB
|
||||||
|
// b11101 = 1GB
|
||||||
|
// b11110 = 2GB
|
||||||
|
// b11111 = 4GB
|
||||||
|
register_bits!(rser, region_size, u8, 1, 5);
|
||||||
|
// Each bit position represents a sub-region, 0-7.
|
||||||
|
// Bit [8] corresponds to sub-region 0
|
||||||
|
// ...
|
||||||
|
// Bit [15] corresponds to sub-region 7
|
||||||
|
// The meaning of each bit is:
|
||||||
|
// 0 = address range is part of this region
|
||||||
|
// 1 = address range is not part of this region
|
||||||
|
register_bits!(rser, subregion_disable, u8, 8, 15);
|
||||||
|
|
||||||
|
/// MPU Region Base Address Registers
|
||||||
|
pub struct RBAR;
|
||||||
|
wrap_reg!(rbar);
|
||||||
|
def_reg_r!(RBAR, rbar::Read, "mrc p15, 0, $0, c6, c1, 0");
|
||||||
|
def_reg_w!(RBAR, rbar::Write, "mcr p15, 0, $0, c6, c1, 0");
|
||||||
|
// base address
|
||||||
|
register_bits!(rbar, base_address, u32, 5, 31);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: TCM registers (R5 TRM sec 4.3.23-25)
|
Loading…
Reference in New Issue