mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 03:21:30 +11:00
fix irq example, part of https://github.com/rust-console/gba/issues/129
This commit is contained in:
parent
0d21b4c899
commit
e595270bfe
|
@ -2,7 +2,7 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(isa_attribute)]
|
#![feature(isa_attribute)]
|
||||||
|
|
||||||
use gba::prelude::*;
|
use gba::{prelude::*, warn};
|
||||||
|
|
||||||
const BLACK: Color = Color::from_rgb(0, 0, 0);
|
const BLACK: Color = Color::from_rgb(0, 0, 0);
|
||||||
const RED: Color = Color::from_rgb(31, 0, 0);
|
const RED: Color = Color::from_rgb(31, 0, 0);
|
||||||
|
@ -70,6 +70,7 @@ fn main() -> ! {
|
||||||
flags = flags.with_timer1(true);
|
flags = flags.with_timer1(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn!("IM = {:?}", flags);
|
||||||
unsafe { IE.write(flags) };
|
unsafe { IE.write(flags) };
|
||||||
|
|
||||||
// Puts the CPU into low power mode until a VBlank IRQ is received. This
|
// Puts the CPU into low power mode until a VBlank IRQ is received. This
|
||||||
|
@ -98,53 +99,65 @@ extern "C" fn irq_handler_a32() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irq_handler_t32() {
|
fn irq_handler_t32() {
|
||||||
let flags = IRQ_PENDING.read();
|
// disable Interrupt Master Enable to prevent an interrupt during the handler
|
||||||
|
unsafe { IME.write(false) };
|
||||||
|
|
||||||
if flags.vblank() {
|
// read which interrupts are pending, and "filter" the selection by which are
|
||||||
|
// supposed to be enabled.
|
||||||
|
let which_interrupts_to_handle = IRQ_PENDING.read() & IE.read();
|
||||||
|
|
||||||
|
// read the current IntrWait value. It sorta works like a running total, so
|
||||||
|
// any interrupts we process we'll enable in this value, which we write back
|
||||||
|
// at the end.
|
||||||
|
let mut intr_wait_flags = INTR_WAIT_ACKNOWLEDGE.read();
|
||||||
|
|
||||||
|
if which_interrupts_to_handle.vblank() {
|
||||||
vblank_handler();
|
vblank_handler();
|
||||||
|
intr_wait_flags.set_vblank(true);
|
||||||
}
|
}
|
||||||
if flags.hblank() {
|
if which_interrupts_to_handle.hblank() {
|
||||||
hblank_handler();
|
hblank_handler();
|
||||||
|
intr_wait_flags.set_hblank(true);
|
||||||
}
|
}
|
||||||
if flags.vcount() {
|
if which_interrupts_to_handle.vcount() {
|
||||||
vcount_handler();
|
vcount_handler();
|
||||||
|
intr_wait_flags.set_vcount(true);
|
||||||
}
|
}
|
||||||
if flags.timer0() {
|
if which_interrupts_to_handle.timer0() {
|
||||||
timer0_handler();
|
timer0_handler();
|
||||||
|
intr_wait_flags.set_timer0(true);
|
||||||
}
|
}
|
||||||
if flags.timer1() {
|
if which_interrupts_to_handle.timer1() {
|
||||||
timer1_handler();
|
timer1_handler();
|
||||||
|
intr_wait_flags.set_timer1(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// acknowledge that we did stuff.
|
||||||
|
IRQ_ACKNOWLEDGE.write(which_interrupts_to_handle);
|
||||||
|
|
||||||
|
// write out any IntrWait changes.
|
||||||
|
unsafe { INTR_WAIT_ACKNOWLEDGE.write(intr_wait_flags) };
|
||||||
|
|
||||||
|
// re-enable as we go out.
|
||||||
|
unsafe { IME.write(true) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vblank_handler() {
|
fn vblank_handler() {
|
||||||
write_pixel(BLUE);
|
write_pixel(BLUE);
|
||||||
|
|
||||||
// When using `interrupt_wait()` or `vblank_interrupt_wait()`, IRQ handlers must acknowledge
|
|
||||||
// the IRQ on the BIOS Interrupt Flags register.
|
|
||||||
unsafe { INTR_WAIT_ACKNOWLEDGE.write(INTR_WAIT_ACKNOWLEDGE.read().with_vblank(true)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hblank_handler() {
|
fn hblank_handler() {
|
||||||
write_pixel(GREEN);
|
write_pixel(GREEN);
|
||||||
|
|
||||||
unsafe { INTR_WAIT_ACKNOWLEDGE.write(INTR_WAIT_ACKNOWLEDGE.read().with_hblank(true)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vcount_handler() {
|
fn vcount_handler() {
|
||||||
write_pixel(RED);
|
write_pixel(RED);
|
||||||
|
|
||||||
unsafe { INTR_WAIT_ACKNOWLEDGE.write(INTR_WAIT_ACKNOWLEDGE.read().with_vcount(true)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer0_handler() {
|
fn timer0_handler() {
|
||||||
write_pixel(YELLOW);
|
write_pixel(YELLOW);
|
||||||
|
|
||||||
unsafe { INTR_WAIT_ACKNOWLEDGE.write(INTR_WAIT_ACKNOWLEDGE.read().with_timer0(true)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer1_handler() {
|
fn timer1_handler() {
|
||||||
write_pixel(PINK);
|
write_pixel(PINK);
|
||||||
|
|
||||||
unsafe { INTR_WAIT_ACKNOWLEDGE.write(INTR_WAIT_ACKNOWLEDGE.read().with_timer1(true)) };
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,60 @@ macro_rules! bitfield_bool {
|
||||||
}
|
}
|
||||||
pub(crate) use bitfield_bool;
|
pub(crate) use bitfield_bool;
|
||||||
|
|
||||||
|
/// Adds bitwise ops for this type
|
||||||
|
macro_rules! impl_bitwise_ops {
|
||||||
|
($outer:ty) => {
|
||||||
|
impl core::ops::Not for $outer {
|
||||||
|
type Output = Self;
|
||||||
|
#[inline]
|
||||||
|
fn not(self) -> Self {
|
||||||
|
Self(!self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::BitAnd for $outer {
|
||||||
|
type Output = $outer;
|
||||||
|
#[inline]
|
||||||
|
fn bitand(self, rhs: Self) -> Self {
|
||||||
|
Self(self.0 & rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::BitOr for $outer {
|
||||||
|
type Output = $outer;
|
||||||
|
#[inline]
|
||||||
|
fn bitor(self, rhs: Self) -> Self {
|
||||||
|
Self(self.0 | rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::BitXor for $outer {
|
||||||
|
type Output = $outer;
|
||||||
|
#[inline]
|
||||||
|
fn bitxor(self, rhs: Self) -> Self {
|
||||||
|
Self(self.0 ^ rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// // // // //
|
||||||
|
impl core::ops::BitAndAssign for $outer {
|
||||||
|
#[inline]
|
||||||
|
fn bitand_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 &= rhs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::BitOrAssign for $outer {
|
||||||
|
#[inline]
|
||||||
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 |= rhs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::BitXorAssign for $outer {
|
||||||
|
#[inline]
|
||||||
|
fn bitxor_assign(&mut self, rhs: Self) {
|
||||||
|
self.0 ^= rhs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub(crate) use impl_bitwise_ops;
|
||||||
|
|
||||||
mod display_control;
|
mod display_control;
|
||||||
pub use display_control::*;
|
pub use display_control::*;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct InterruptFlags(pub(crate) u16);
|
pub struct InterruptFlags(pub(crate) u16);
|
||||||
impl InterruptFlags {
|
impl InterruptFlags {
|
||||||
|
@ -20,4 +20,53 @@ impl InterruptFlags {
|
||||||
bitfield_bool!(u16; 12, keypad, with_keypad, set_keypad);
|
bitfield_bool!(u16; 12, keypad, with_keypad, set_keypad);
|
||||||
bitfield_bool!(u16; 13, gamepak, with_gamepak, set_gamepak);
|
bitfield_bool!(u16; 13, gamepak, with_gamepak, set_gamepak);
|
||||||
}
|
}
|
||||||
// TODO: bit ops for interrupt flags
|
impl_bitwise_ops!(InterruptFlags);
|
||||||
|
impl core::fmt::Debug for InterruptFlags {
|
||||||
|
#[inline(never)]
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
|
write!(f, "InterruptFlags {{")?;
|
||||||
|
if self.vblank() {
|
||||||
|
write!(f, "vblank,")?;
|
||||||
|
}
|
||||||
|
if self.hblank() {
|
||||||
|
write!(f, "hblank,")?;
|
||||||
|
}
|
||||||
|
if self.vcount() {
|
||||||
|
write!(f, "vcount,")?;
|
||||||
|
}
|
||||||
|
if self.timer0() {
|
||||||
|
write!(f, "timer0,")?;
|
||||||
|
}
|
||||||
|
if self.timer1() {
|
||||||
|
write!(f, "timer1,")?;
|
||||||
|
}
|
||||||
|
if self.timer2() {
|
||||||
|
write!(f, "timer2,")?;
|
||||||
|
}
|
||||||
|
if self.timer3() {
|
||||||
|
write!(f, "timer3,")?;
|
||||||
|
}
|
||||||
|
if self.serial() {
|
||||||
|
write!(f, "serial,")?;
|
||||||
|
}
|
||||||
|
if self.dma0() {
|
||||||
|
write!(f, "dma0,")?;
|
||||||
|
}
|
||||||
|
if self.dma1() {
|
||||||
|
write!(f, "dma1,")?;
|
||||||
|
}
|
||||||
|
if self.dma2() {
|
||||||
|
write!(f, "dma2,")?;
|
||||||
|
}
|
||||||
|
if self.dma3() {
|
||||||
|
write!(f, "dma3,")?;
|
||||||
|
}
|
||||||
|
if self.keypad() {
|
||||||
|
write!(f, "keypad,")?;
|
||||||
|
}
|
||||||
|
if self.gamepak() {
|
||||||
|
write!(f, "gamepak,")?;
|
||||||
|
}
|
||||||
|
write!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue