use crate::dma::{BlockMode, Chop, Direction, Error, Step, TransferMode};
use crate::hw::{MemRegister, Register};
type Result<T> = core::result::Result<T, Error>;
const STEP: u32 = 1;
const CHOP: u32 = 8;
const TRANFER_MODE: u32 = 9;
const DMA_WIN: u32 = 16;
const CPU_WIN: u32 = 20;
const BUSY: u32 = 24;
const TRIGGER: u32 = 28;
const ADDRESS_MASK: u32 = 0x00FF_FFFF;
#[derive(Debug)]
pub enum Name {
MDECIn = 0,
MDECOut,
GPU,
CDROM,
SPU,
PIO,
OTC,
}
pub mod mdec_in {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_1080>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_1084>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_1088>;
impl ChannelControl for Control {
const NAME: Name = Name::MDECIn;
}
}
pub mod mdec_out {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_1090>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_1094>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_1098>;
impl ChannelControl for Control {
const NAME: Name = Name::MDECOut;
}
}
pub mod gpu {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_10A0>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_10A4>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_10A8>;
impl ChannelControl for Control {
const NAME: Name = Name::GPU;
}
}
pub mod cdrom {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_10B0>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_10B4>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_10B8>;
impl ChannelControl for Control {
const NAME: Name = Name::CDROM;
}
}
pub mod spu {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_10C0>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_10C4>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_10C8>;
impl ChannelControl for Control {
const NAME: Name = Name::SPU;
}
}
pub mod pio {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_10D0>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_10D4>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_10D8>;
impl ChannelControl for Control {
const NAME: Name = Name::PIO;
}
}
pub mod otc {
use super::{BlockControl, ChannelControl, MemoryAddress};
use crate::hw::dma::Name;
use crate::hw::MemRegister;
pub type Address = MemRegister<u32, 0x1F80_10E0>;
impl MemoryAddress for Address {}
pub type Block = MemRegister<u32, 0x1F80_10E4>;
impl BlockControl for Block {}
pub type Control = MemRegister<u32, 0x1F80_10E8>;
impl ChannelControl for Control {
const NAME: Name = Name::OTC;
}
}
pub type GlobalControl = MemRegister<u32, 0x1F80_10F0>;
pub type Interrupt = MemRegister<u32, 0x1F80_10F4>;
pub trait MemoryAddress: Register<u32> {
fn get_address(&self) -> *const u32 {
(self.as_ref() & ADDRESS_MASK) as *const u32
}
fn set_address(&mut self, ptr: &u32) -> &mut Self {
let val = (ptr as *const u32 as u32) & ADDRESS_MASK;
self.assign(val)
}
}
pub trait BlockControl: Register<u32> {
fn get_block(&self, transfer_mode: TransferMode) -> Option<BlockMode> {
match transfer_mode {
TransferMode::Immediate => match self.as_ref() {
0 => Some(BlockMode::Single(0x1_0000u32)),
1..=0xFFFF => Some(BlockMode::Single(*self.as_ref())),
_ => None,
},
TransferMode::Request => Some(BlockMode::Multi {
words: *self.as_ref() as u16,
blocks: (self.as_ref() >> 16) as u16,
}),
TransferMode::LinkedList => Some(BlockMode::LinkedList),
}
}
fn set_block<B>(&mut self, block_mode: B) -> Result<&mut Self>
where BlockMode: From<B> {
match block_mode.into() {
BlockMode::Single(words) => {
let words = match words {
0..=0xFFFF => words,
0x1_0000 => 0,
_ => return Err(Error::OversizedBlock),
};
Ok(self.assign(words))
},
BlockMode::Multi { words, blocks } => {
let value = words as u32 | ((blocks as u32) << 16);
Ok(self.assign(value))
},
BlockMode::LinkedList => Ok(self),
}
}
}
pub trait ChannelControl: Register<u32> {
const NAME: Name;
fn wait(&mut self) -> &mut Self {
self.load();
while self.busy() {
self.load();
}
self
}
fn busy(&self) -> bool {
self.all_set(1 << BUSY)
}
fn get_mode(&self) -> Option<TransferMode> {
match (self.as_ref() >> TRANFER_MODE) & 0b11 {
0 => Some(TransferMode::Immediate),
1 => Some(TransferMode::Request),
2 => Some(TransferMode::LinkedList),
_ => None,
}
}
fn get_direction(&self) -> Direction {
if self.all_set(1) {
Direction::FromMemory
} else {
Direction::ToMemory
}
}
fn get_step(&self) -> Step {
if self.all_set(1 << STEP) {
Step::Backward
} else {
Step::Forward
}
}
fn get_chop(&self) -> Option<Chop> {
if self.all_set(1 << CHOP) {
let cpu_window = self.as_ref() >> CPU_WIN;
let dma_window = self.as_ref() >> DMA_WIN;
if cpu_window & 0b111 != 0 {
return None
}
if dma_window & 0b111 != 0 {
return None
}
Some(Chop {
cpu_window,
dma_window,
})
} else {
None
}
}
fn set_direction(&mut self, direction: Direction) -> &mut Self {
self.clear_bits(1).set_bits(direction as u32)
}
fn set_step(&mut self, step: Step) -> &mut Self {
self.clear_bits(1 << STEP).set_bits((step as u32) << STEP)
}
fn set_chop(&mut self, chop: Option<Chop>) -> Option<&mut Self> {
match chop {
Some(chop) => {
if chop.cpu_window & !0b111 != 0 {
return None
}
if chop.dma_window & !0b111 != 0 {
return None
}
Some(
self.clear_bits(0b111 << CPU_WIN | 0b111 << DMA_WIN)
.set_bits(
1 << CHOP | chop.cpu_window << CPU_WIN | chop.dma_window << DMA_WIN,
),
)
},
None => Some(self.clear_bits(1 << CHOP)),
}
}
fn set_mode(&mut self, mode: TransferMode) -> &mut Self {
self.clear_bits(0b11 << TRANFER_MODE)
.set_bits((mode as u32) << TRANFER_MODE)
}
fn start(&mut self) -> &mut Self {
if let Some(TransferMode::Immediate) = self.get_mode() {
self.set_bits(1 << TRIGGER);
}
self.set_bits(1 << BUSY)
}
fn stop(&mut self) -> &mut Self {
self.clear_bits(1 << BUSY)
}
}
impl GlobalControl {
const fn enable_bit(channel: Name) -> u32 {
let bit = (channel as u32 * 4) + 3;
1 << bit
}
const fn all_channels() -> u32 {
Self::enable_bit(Name::MDECIn) |
Self::enable_bit(Name::MDECOut) |
Self::enable_bit(Name::GPU) |
Self::enable_bit(Name::CDROM) |
Self::enable_bit(Name::SPU) |
Self::enable_bit(Name::PIO) |
Self::enable_bit(Name::OTC)
}
pub fn enabled(&self, channel: Name) -> bool {
self.all_set(Self::enable_bit(channel))
}
pub fn enable(&mut self, channel: Name) -> &mut Self {
self.set_bits(Self::enable_bit(channel))
}
pub fn disable(&mut self, channel: Name) -> &mut Self {
self.clear_bits(Self::enable_bit(channel))
}
pub fn enable_all(&mut self) -> &mut Self {
self.set_bits(Self::all_channels())
}
pub fn disable_all(&mut self) -> &mut Self {
self.clear_bits(Self::all_channels())
}
}