game_toolkit_dosaudio/dma/
playback.rs1use std::{collections::VecDeque, sync::Arc};
2
3use crate::device::sb::{DacState, SbControl};
4use crate::{
5 ConventionalMemory, DmaChannel, DmaController, DmaUnit, Error, IrqRequest, Result, Tick,
6};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub struct DmaCompletion {
15 pub at: Tick,
17 pub irq: IrqRequest,
19 pub channel: DmaChannel,
21 pub block: u64,
23}
24
25pub(crate) struct MemoryPlayback {
26 pub controller: DmaController,
27 pub memory: Arc<ConventionalMemory>,
28 completions: VecDeque<DmaCompletion>,
29 capacity: usize,
30}
31
32#[derive(Clone, Copy)]
33pub(crate) struct MemoryPlan {
34 pub sb: SbControl,
35 pub controller: DmaController,
36 pub commands: usize,
37}
38
39impl MemoryPlayback {
40 pub(crate) fn new(memory: Arc<ConventionalMemory>, capacity: usize) -> Self {
41 Self {
42 controller: DmaController::new(),
43 memory,
44 completions: VecDeque::with_capacity(capacity),
45 capacity,
46 }
47 }
48
49 fn walk(
50 memory: &ConventionalMemory,
51 mut sb: SbControl,
52 mut controller: DmaController,
53 span: (Tick, Tick),
54 mut emit: impl FnMut(Tick, DacState),
55 mut complete: impl FnMut(DmaCompletion) -> Result<()>,
56 ) -> Result<MemoryPlan> {
57 let (from, to) = span;
58 let mut commands = 0_usize;
59 while let Some(next) = sb.next_dma_tick() {
60 let due = next.max(from);
63 if due > to {
64 break;
65 }
66 let Some(request) = sb.dma_request(due) else {
67 break;
68 };
69 let Some(unit) = controller.transfer(request, memory)? else {
70 break;
71 };
72 let before = sb.completed_blocks();
73 let state = match unit {
74 DmaUnit::Byte(value) => sb.dma_write(due, request.channel, value)?,
75 DmaUnit::Word(value) => sb.dma_write16(due, request.channel, value)?,
76 };
77 commands = commands.checked_add(1).ok_or(Error::TooLarge)?;
78 emit(due, state);
79 if sb.completed_blocks() != before {
80 complete(DmaCompletion {
81 at: due,
82 irq: sb.irq_request(),
83 channel: request.channel,
84 block: sb.completed_blocks(),
85 })?;
86 }
87 }
88 Ok(MemoryPlan {
89 sb,
90 controller,
91 commands,
92 })
93 }
94
95 pub(crate) fn plan(&self, sb: SbControl, from: Tick, to: Tick) -> Result<MemoryPlan> {
96 let mut pending = self.completions.len();
97 Self::walk(
98 &self.memory,
99 sb,
100 self.controller,
101 (from, to),
102 |_, _| {},
103 |_| {
104 pending = pending.checked_add(1).ok_or(Error::TooLarge)?;
105 if pending > self.capacity {
106 Err(Error::IrqQueueFull)
107 } else {
108 Ok(())
109 }
110 },
111 )
112 }
113
114 pub(crate) fn commit(
115 &mut self,
116 sb: &mut SbControl,
117 from: Tick,
118 to: Tick,
119 emit: impl FnMut(Tick, DacState),
120 ) -> Result<()> {
121 self.plan(*sb, from, to)?;
125 let completions = &mut self.completions;
126 let plan = Self::walk(
127 &self.memory,
128 *sb,
129 self.controller,
130 (from, to),
131 emit,
132 |event| {
133 completions.push_back(event);
134 Ok(())
135 },
136 )?;
137 *sb = plan.sb;
138 self.controller = plan.controller;
139 Ok(())
140 }
141
142 pub(crate) fn next(&self, sb: &SbControl, now: Tick) -> Option<Tick> {
143 let due = sb.next_dma_tick()?.max(now);
144 let request = sb.dma_request(due)?;
145 let mut controller = self.controller;
146 match controller.transfer(request, &self.memory) {
147 Ok(None) => None,
148 Ok(Some(_)) | Err(_) => Some(due),
151 }
152 }
153
154 pub(crate) fn poll(&mut self) -> Option<DmaCompletion> {
155 self.completions.pop_front()
156 }
157}