pub enum ConfigurationChange {
SelfProgramming,
ProtectedRegister
}
pub trait Cpu {
unsafe fn write_protected(&mut self, change: ConfigurationChange,
register: &mut u8, value: u8 );
fn read_sp(&self) -> u16;
unsafe fn write_sp(&mut self, sp: u16);
fn read_sreg(&self) -> u8;
unsafe fn write_sreg(&mut self, sp: u8);
fn interrupts_enabled(&self) -> bool;
}
pub trait ClockControl {
unsafe fn clk_per_prescaler(&mut self, scaler: u8);
}
pub(crate) mod private {
pub struct PermitStandbyToken;
pub struct PermitIdleToken;
}
pub trait SleepControl {
unsafe fn reset(&mut self);
fn inhibit_standby(&mut self) -> private::PermitStandbyToken;
fn permit_standby(&mut self, token: private::PermitStandbyToken);
fn standby_permitted(&self) -> bool;
fn inhibit_idle(&mut self) -> private::PermitIdleToken;
fn permit_idle(&mut self, token: private::PermitIdleToken);
fn idle_permitted(&self) -> bool;
}
#[cfg(target_arch="avr")]
pub mod base {
use avr_oxide::{v_read,v_write};
use avr_oxide::hal::generic::cpu::{ConfigurationChange, Cpu, ClockControl, SleepControl, private::PermitIdleToken, private::PermitStandbyToken};
#[repr(C)]
pub struct AvrCpuControlBlock {
reserved_0: [u8; 4],
pub(crate) ccp: u8,
reserved_1: [u8; 8],
pub(crate) sp: u16,
pub(crate) sreg: u8
}
#[repr(C)]
pub struct AvrClockControlBlock {
pub(crate) mclkctrla: u8,
pub(crate) mclkctrlb: u8,
pub(crate) mclklock: u8,
pub(crate) mclkstatus: u8,
reserved_0: [u8; 12],
pub(crate) osc20mctrla: u8,
pub(crate) osc20mcaliba: u8,
pub(crate) osc20mcalibb: u8,
reserved_1: [u8; 5],
pub(crate) osc32kctrla: u8,
reserved_2: [u8; 3],
pub(crate) xosc32kctrla: u8
}
#[repr(C)]
pub struct AvrSleepControlBlock {
pub(crate) ctrla: u8
}
pub struct AvrSleepController {
pub(crate) scb: &'static mut AvrSleepControlBlock,
pub(crate) idle_inhibits: u8,
pub(crate) sleep_inhibits: u8
}
extern "C" {
fn ccp_io_write(ioaddr: *mut u8, value: u8);
fn ccp_spm_write(ioaddr: *mut u8, value: u8);
}
impl Cpu for AvrCpuControlBlock {
unsafe fn write_protected(&mut self, change: ConfigurationChange, register: &mut u8, value: u8) {
match change {
ConfigurationChange::SelfProgramming =>
ccp_spm_write(register as *mut u8, value),
ConfigurationChange::ProtectedRegister =>
ccp_io_write(register as *mut u8, value),
}
}
#[inline(always)]
fn read_sp(&self) -> u16 {
unsafe {
v_read!(u16, self.sp)
}
}
#[inline(always)]
unsafe fn write_sp(&mut self, sp: u16) {
v_write!(u16, self.sp, sp)
}
#[inline(always)]
fn read_sreg(&self) -> u8 {
unsafe {
v_read!(u8, self.sreg)
}
}
#[inline(always)]
unsafe fn write_sreg(&mut self, sreg:u8) {
v_write!(u8, self.sreg, sreg);
}
#[inline(always)]
fn interrupts_enabled(&self) -> bool {
unsafe {
(v_read!(u8, self.sreg) & 0b10000000) > 0
}
}
}
impl ClockControl for AvrClockControlBlock {
unsafe fn clk_per_prescaler(&mut self, scaler: u8) {
if scaler == 0 {
ccp_io_write(&mut self.mclkctrlb as *mut u8, 0x00);
} else {
let pdiv_pen_val = match scaler {
1 => 0x00,
2 => (0x00 << 1) | 0x01,
4 => (0x01 << 1) | 0x01,
8 => (0x02 << 1) | 0x01,
16 => (0x03 << 1) | 0x01,
32 => (0x04 << 1) | 0x01,
64 => (0x05 << 1) | 0x01,
6 => (0x08 << 1) | 0x01,
10 => (0x09 << 1) | 0x01,
12 => (0x0A << 1) | 0x01,
24 => (0x0B << 1) | 0x01,
48 => (0x0C << 1) | 0x01,
_ => panic!()
};
ccp_io_write(&mut self.mclkctrlb as *mut u8, pdiv_pen_val);
}
}
}
impl AvrSleepController {
fn set_sleep_state(&mut self) {
unsafe {
v_write!(u8, self.scb.ctrla, match (self.standby_permitted(), self.idle_permitted()) {
(true, true) => 0b00000011, (false, true) => 0b00000001, _ => 0b00000000 });
}
}
}
impl SleepControl for AvrSleepController {
unsafe fn reset(&mut self) {
self.sleep_inhibits = 0;
self.idle_inhibits = 0;
self.set_sleep_state();
}
fn inhibit_standby(&mut self) -> PermitStandbyToken {
if self.sleep_inhibits == u8::MAX {
panic!();
}
self.sleep_inhibits += 1;
self.set_sleep_state();
PermitStandbyToken
}
fn permit_standby(&mut self, _token: PermitStandbyToken) {
if self.sleep_inhibits > 0 {
self.sleep_inhibits -= 1;
}
self.set_sleep_state();
}
fn standby_permitted(&self) -> bool {
self.sleep_inhibits == 0
}
fn inhibit_idle(&mut self) -> PermitIdleToken {
if self.idle_inhibits == u8::MAX {
panic!();
}
self.idle_inhibits += 1;
self.set_sleep_state();
PermitIdleToken
}
fn permit_idle(&mut self, _token: PermitIdleToken) {
if self.idle_inhibits > 0 {
self.idle_inhibits -= 1;
}
self.set_sleep_state();
}
fn idle_permitted(&self) -> bool {
self.idle_inhibits == 0
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_cpu_tpl {
($cpuref:expr,$clkref:expr,$slpref:expr) => {
use avr_oxide::hal::generic::cpu::base::{AvrCpuControlBlock,AvrClockControlBlock,AvrSleepController};
use avr_oxide::mut_singleton;
pub type CpuImpl = AvrCpuControlBlock;
pub type ClockImpl = AvrClockControlBlock;
pub type SleepImpl = AvrSleepController;
#[inline(always)]
pub fn instance() -> &'static mut CpuImpl {
unsafe {
core::mem::transmute($cpuref)
}
}
#[inline(always)]
pub fn clock() -> &'static mut ClockImpl {
unsafe {
core::mem::transmute($clkref)
}
}
mut_singleton!(
SleepImpl,
SLEEPCTRLINSTANCE,
sleepctrl,
AvrSleepController {
scb: core::mem::transmute($slpref),
idle_inhibits: 0,
sleep_inhibits: 0
});
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod dummy {
use avr_oxide::hal::generic::cpu::{ConfigurationChange, Cpu, ClockControl, SleepControl};
use avr_oxide::hal::generic::cpu::private::{PermitIdleToken, PermitStandbyToken};
pub struct DummyCpuControlBlock {
pub(crate) sreg: u8
}
pub struct DummyClockControl {}
impl Cpu for DummyCpuControlBlock {
unsafe fn write_protected(&mut self, _change: ConfigurationChange, register: &mut u8, value: u8) {
println!("*** CPU: Protected register write: @{} <- {}", register, value);
}
fn read_sp(&self) -> u16 {
unimplemented!()
}
unsafe fn write_sp(&mut self, _sp: u16) {
unimplemented!()
}
fn read_sreg(&self) -> u8 {
println!("*** CPU: Read SREG: {}", self.sreg);
self.sreg
}
unsafe fn write_sreg(&mut self, sreg: u8) {
println!("*** CPU: Write SREG: {}", sreg);
self.sreg = sreg;
}
fn interrupts_enabled(&self) -> bool {
true
}
}
impl ClockControl for DummyClockControl {
unsafe fn clk_per_prescaler(&mut self, scaler: u8) {
println!("*** CPU: Set clock prescaler to: {}", scaler);
}
}
pub struct DummySleepControl {}
impl SleepControl for DummySleepControl {
unsafe fn reset(&mut self) {
unimplemented!()
}
fn inhibit_standby(&mut self) -> PermitStandbyToken {
unimplemented!()
}
fn permit_standby(&mut self, token: PermitStandbyToken) {
unimplemented!()
}
fn standby_permitted(&self) -> bool {
unimplemented!()
}
fn inhibit_idle(&mut self) -> PermitIdleToken {
unimplemented!()
}
fn permit_idle(&mut self, token: PermitIdleToken) {
unimplemented!()
}
fn idle_permitted(&self) -> bool {
unimplemented!()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_cpu_tpl {
($cpuref:expr,$clkref:expr,$sleepref:expr) => {
use avr_oxide::hal::generic::cpu::dummy::{DummyCpuControlBlock,DummyClockControl,DummySleepControl};
use avr_oxide::mut_singleton;
pub type CpuImpl = DummyCpuControlBlock;
pub type ClockImpl = DummyClockControl;
pub type SleepImpl = DummySleepControl;
static mut DUMMY_CPU: DummyCpuControlBlock = DummyCpuControlBlock {
sreg: 0
};
static mut DUMMY_CLOCK: DummyClockControl = DummyClockControl {};
#[inline(always)]
pub fn instance() -> &'static mut DummyCpuControlBlock {
unsafe {
&mut DUMMY_CPU
}
}
#[inline(always)]
pub fn clock() -> &'static mut DummyClockControl {
unsafe {
&mut DUMMY_CLOCK
}
}
mut_singleton!(
SleepImpl,
SLEEPCTRLINSTANCE,
sleepctrl,
DummySleepControl {
});
}
}
}