avr-oxide 0.3.1

An extremely simple Rusty operating system for AVR microcontrollers
/* datatypes.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Hardware-specific datatype imlementations


// Imports ===================================================================
use core::arch::asm;
use avr_oxide::concurrency::Isolated;
use avr_oxide::util::datatypes::{BitFieldAccess, BitIndex, BitMaskable};

// Declarations ==============================================================
/**
 * A memory location stored within processor I/O space, that we can access
 * more efficiently using the AVR's I/O specific atomic instructions like
 * `sbi` and `cbi`
 */
pub struct IOSpaceU8<const IOADDR:u8>();

// Code ======================================================================
#[cfg(target_arch="avr")]
impl<const IOADDR:u8> IOSpaceU8<IOADDR> {
  pub const fn get() -> Self {
    IOSpaceU8()
  }


  #[inline(always)]
  pub fn set_c<const BIT: u8>(&mut self) {
    if IOADDR <= avr_oxide::hardware::cpu::cpuregs::MAX_BIT_ADDRESSABLE {
      unsafe {
        asm!(
        "sbi {ioaddr},{bit}",
        bit     = const BIT,
        ioaddr  = const IOADDR,
        options(nostack,preserves_flags)
        );
      }
    } else {
      self.set(BitIndex::bit(BIT as usize))
    }
  }
  #[inline(always)]
  pub fn clr_c<const BIT: u8>(&mut self) {
    if IOADDR <= avr_oxide::hardware::cpu::cpuregs::MAX_BIT_ADDRESSABLE {
      unsafe {
        asm!(
        "cbi {ioaddr},{bit}",
        bit     = const BIT,
        ioaddr  = const IOADDR,
        options(nostack,preserves_flags)
        );
      }
    } else {
      self.clr(BitIndex::bit(BIT as usize))
    }
  }
  #[inline(always)]
  pub fn is_set_c<const BIT: u8>(&self) -> bool {
    if IOADDR <= avr_oxide::hardware::cpu::cpuregs::MAX_BIT_ADDRESSABLE {
      let val: u8;

      unsafe {
        asm!(
          "clr {reg_val}",
          "sbic {ioaddr},{bit}",
          "ldi {reg_val},0x01",
          bit     = const BIT,
          ioaddr  = const IOADDR,
          reg_val = out(reg_upper) val,
          options(nostack,preserves_flags)
        );
      }

      val != 0
    } else {
      self.is_set(BitIndex::bit(BIT as usize))
    }
  }
  #[inline(always)]
  pub fn is_clr_c<const BIT: u8>(&self) -> bool {
    if IOADDR <= avr_oxide::hardware::cpu::cpuregs::MAX_BIT_ADDRESSABLE {
      let val: u8;

      unsafe {
        asm!(
          "clr {reg_val}",
          "sbic {ioaddr},{bit}",
          "ldi {reg_val},0x01",
          bit     = const BIT,
          ioaddr  = const IOADDR,
          reg_val = out(reg_upper) val,
          options(nostack,preserves_flags)
        );
      }

      val != 0
    } else {
      self.is_clr(BitIndex::bit(BIT as usize))
    }
  }
}

#[cfg(target_arch="avr")]
impl<const IOADDR:u8> BitFieldAccess for IOSpaceU8<IOADDR> {
  #[inline(always)]
  fn read_byte(&self) -> u8 {
    let val: u8;

    unsafe {
      asm!(
        "in {reg_val},{ioaddr}",
        reg_val = out(reg) val,
        ioaddr = const IOADDR,
        options(nostack,preserves_flags)
      );
    }

    val
  }

  #[inline(always)]
  fn write_byte(&mut self, val: u8) {
    unsafe {
      asm!(
        "out {ioaddr},{reg_val}",
        reg_val = in(reg) val,
        ioaddr = const IOADDR,
        options(nostack,preserves_flags)
      );
    }
  }

  #[inline(always)]
  fn is_set(&self, bit: BitIndex) -> bool {
    let mut flag: u8;

    flag = bit.positive_byte_mask();

    unsafe {
      asm!(
        "in {reg_scratch},{ioaddr}",
        "and {reg_flag},{reg_scratch}",
        reg_scratch = out(reg) _,
        reg_flag = inout(reg) flag,
        ioaddr = const IOADDR,
        options(nostack)
      );
    }

    flag != 0
  }

  #[inline(always)]
  fn is_clr(&self, bit: BitIndex) -> bool {
    let mut flag: u8;

    flag = bit.positive_byte_mask();

    unsafe {
      asm!(
        "in {reg_scratch},{ioaddr}",
        "and {reg_flag},{reg_scratch}",
        reg_scratch = out(reg) _,
        reg_flag = inout(reg) flag,
        ioaddr = const IOADDR,
        options(nostack)
      );
    }

    flag == 0
  }

  #[inline(always)]
  fn set_isolated<B: BitMaskable>(&mut self, _isotoken: Isolated, bits: B) {
    let mask: u8 = bits.positive_byte_mask();

    unsafe {
      asm!(
        "in {reg_scratch},{ioaddr}",
        "or {reg_scratch},{reg_mask}",
        "out {ioaddr},{reg_scratch}",
        reg_scratch = out(reg) _,
        reg_mask = in(reg) mask,
        ioaddr = const IOADDR,
        options(nostack)
      );
    }
  }


  #[inline(always)]
  fn set_all(&mut self) {
    unsafe {
      asm!(
        "ldi {reg_scratch},0xff",
        "out {ioaddr},{reg_scratch}",
        reg_scratch = out(reg_upper) _,
        ioaddr = const IOADDR,
        options(nostack,preserves_flags)
      )
    }
  }

  #[inline(always)]
  fn clr_all(&mut self) {
    unsafe {
      asm!(
        "out {ioaddr},r1", // R1 should always be zero according to our ABI
        ioaddr = const IOADDR,
        options(nostack,preserves_flags)
      )
    }
  }

  #[inline(always)]
  fn clr_isolated<B: BitMaskable>(&mut self, _isotoken: Isolated, bits: B) {
    let mask: u8 = bits.positive_byte_mask();

    unsafe {
      asm!(
        "in {reg_scratch},{ioaddr}",
        "and {reg_scratch},{reg_mask}",
        "out {ioaddr},{reg_scratch}",
        reg_scratch = out(reg) _,
        reg_mask = in(reg) mask,
        ioaddr = const IOADDR,
        options(nostack)
      );
    }
  }
}

// Tests =====================================================================
#[cfg(not(target_arch="avr"))]
impl<const IOADDR:u8> IOSpaceU8<IOADDR> {
  pub const fn get() -> Self {
    IOSpaceU8()
  }

  pub fn set_c<const BIT: u8>(&mut self) {
    unimplemented!()
  }

  pub fn clr_c<const BIT: u8>(&mut self) {
    unimplemented!()
  }

  pub fn is_set_c<const BIT: u8>(&self) -> bool {
    unimplemented!()
  }

  pub fn is_clr_c<const BIT: u8>(&self) -> bool {
    unimplemented!()
  }
}

#[cfg(not(target_arch="avr"))]
impl<const IOADDR:u8> BitFieldAccess for IOSpaceU8<IOADDR> {
  fn read_byte(&self) -> u8 {
    unimplemented!()
  }

  fn write_byte(&mut self, val: u8) {
    unimplemented!()
  }

  fn is_set(&self, bit: BitIndex) -> bool {
    unimplemented!()
  }

  fn is_clr(&self, bit: BitIndex) -> bool {
    unimplemented!()
  }

  fn set_isolated<B: BitMaskable>(&mut self, _isotoken: Isolated, bits: B) {
    unimplemented!()
  }

  fn set_all(&mut self) {
    unimplemented!()
  }

  fn clr_all(&mut self) {
    unimplemented!()
  }

  fn clr_isolated<B: BitMaskable>(&mut self, _isotoken: Isolated, bits: B) {
    unimplemented!()
  }
}