use avr_oxide::hal::generic::cpu::private::{PermitIdleToken, PermitStandbyToken};
use avr_oxide::hal::generic::cpu::{ClockControl, ConfigurationChange, ContextSaveRestore, Cpu, SleepControl, ProcessorContext};
use avr_oxide::mut_singleton;
use avr_oxide::concurrency::interrupt;
use avr_oxide::hal::atmega328p::{ADDR_CLKPR, ADDR_CPU};
use avr_oxide::util::datatypes::{BitField, BitFieldAccess, BitIndex, Volatile};
pub mod cpuregs {
use avr_oxide::hal::generic::datatypes::IOSpaceU8;
pub const MAX_BIT_ADDRESSABLE: u8 = 0x1F;
pub const IOADR_SPL: u8 = 0x3D;
pub const IOADR_SPH: u8 = 0x3E;
pub const IOADR_SREG: u8 = 0x3F;
pub const RAMTOP: u16 = 0x08FF;
pub const ADDR_CURRENT_CONTEXT_LO: usize = 0x004A;
pub const ADDR_CURRENT_CONTEXT_HI: usize = 0x004B;
pub const IOADR_CONTEXT_FLAGS: u8 = 0x1E;
pub(crate) static mut IOREG_SREG : IOSpaceU8<IOADR_SREG> = IOSpaceU8::get();
pub(crate) static mut IOREG_CONTEXT_FLAGS : IOSpaceU8<IOADR_CONTEXT_FLAGS> = IOSpaceU8::get();
}
#[repr(C)]
pub struct Atmega328PControlRegisters {
pub(crate) sp: u16,
pub(crate) sreg: u8
}
#[repr(C)]
pub struct Atmega328PClockPrescaleRegister {
pub(crate) clkpr: u8
}
pub struct NullSleepController;
impl Cpu for Atmega328PControlRegisters {
unsafe fn write_protected(&mut self, change: ConfigurationChange, register: &mut u8, value: u8) {
*register = value;
}
}
impl ContextSaveRestore for Atmega328PControlRegisters {
unsafe fn get_processor_context(&self, _isotoken: interrupt::token::Isolated) -> &mut ProcessorContext {
let acc_lo : *mut u8 = core::mem::transmute(cpuregs::ADDR_CURRENT_CONTEXT_LO);
let acc_hi : *mut u8 = core::mem::transmute(cpuregs::ADDR_CURRENT_CONTEXT_HI);
let context_addr =
((core::ptr::read_volatile(acc_hi) as usize) << 8) |
(core::ptr::read_volatile(acc_lo) as usize);
&mut *(context_addr as *mut ProcessorContext)
}
#[inline(always)]
fn was_thread_restored(&self) -> bool {
unsafe {
cpuregs::IOREG_CONTEXT_FLAGS.is_set_c::<0>()
}
}
}
#[inline(always)]
pub fn instance() -> &'static mut Atmega328PControlRegisters {
unsafe {
core::mem::transmute(ADDR_CPU)
}
}
pub fn clock() -> &'static mut Atmega328PClockPrescaleRegister {
unsafe {
core::mem::transmute(ADDR_CLKPR)
}
}
impl ClockControl for Atmega328PClockPrescaleRegister {
unsafe fn clk_per_prescaler(&mut self, scaler: u8) {
extern "C" {
fn ccp_clkper_write(ioaddr: *mut u8, value: u8);
}
let clkps_val = match scaler {
1 => 0x00,
2 => 0x01,
4 => 0x02,
8 => 0x03,
16 => 0x04,
32 => 0x05,
64 => 0x06,
128 => 0x07,
_ => panic!()
};
ccp_clkper_write(&mut self.clkpr as *mut u8, clkps_val);
}
}
#[macro_export]
macro_rules! cpu {
() => {
avr_oxide::hal::atmega328p::cpu::instance()
}
}
impl SleepControl for NullSleepController {
unsafe fn reset(&mut self) {
}
fn inhibit_standby(&mut self) -> PermitStandbyToken {
PermitStandbyToken
}
fn permit_standby(&mut self, token: PermitStandbyToken) {
}
fn standby_permitted(&self) -> bool {
false
}
fn inhibit_idle(&mut self) -> PermitIdleToken {
PermitIdleToken
}
fn permit_idle(&mut self, token: PermitIdleToken) {
}
fn idle_permitted(&self) -> bool {
false
}
}
mut_singleton!(
NullSleepController,
__SLEEPCTRLINSTANCE,
sleepctrl, sleepctrl_isolated,
NullSleepController {
});
#[macro_export]
macro_rules! sleepctrl {
($isotoken:expr) => {
avr_oxide::hal::atmega328p::cpu::sleepctrl_isolated($isotoken)
};
() => {
avr_oxide::hal::atmega328p::cpu::sleepctrl()
};
}