1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker // Based heavily on GCE VMM's pit.cc.
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Error as IoError;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
11*bb4ee6a4SAndroid Build Coastguard Worker
12*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::Descriptor;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Error as SysError;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
19*bb4ee6a4SAndroid Build Coastguard Worker use bit_field::BitField1;
20*bb4ee6a4SAndroid Build Coastguard Worker use bit_field::*;
21*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitChannelState;
22*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitRWMode;
23*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitRWState;
24*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitState;
25*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
26*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
27*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
28*bb4ee6a4SAndroid Build Coastguard Worker
29*bb4ee6a4SAndroid Build Coastguard Worker cfg_if::cfg_if! {
30*bb4ee6a4SAndroid Build Coastguard Worker if #[cfg(test)] {
31*bb4ee6a4SAndroid Build Coastguard Worker use base::FakeClock as Clock;
32*bb4ee6a4SAndroid Build Coastguard Worker use base::FakeTimer as Timer;
33*bb4ee6a4SAndroid Build Coastguard Worker } else {
34*bb4ee6a4SAndroid Build Coastguard Worker use base::Clock;
35*bb4ee6a4SAndroid Build Coastguard Worker use base::Timer;
36*bb4ee6a4SAndroid Build Coastguard Worker }
37*bb4ee6a4SAndroid Build Coastguard Worker }
38*bb4ee6a4SAndroid Build Coastguard Worker use base::TimerTrait;
39*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
40*bb4ee6a4SAndroid Build Coastguard Worker
41*bb4ee6a4SAndroid Build Coastguard Worker use crate::bus::BusAccessInfo;
42*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::CrosvmDeviceId;
43*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
44*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
45*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqEdgeEvent;
46*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
47*bb4ee6a4SAndroid Build Coastguard Worker
48*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant
49*bb4ee6a4SAndroid Build Coastguard Worker // names are kept the same as Intel PIT data sheet.
50*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
51*bb4ee6a4SAndroid Build Coastguard Worker enum CommandBit {
52*bb4ee6a4SAndroid Build Coastguard Worker CommandBCD = 0x01, // Binary/BCD input. x86 only uses binary mode.
53*bb4ee6a4SAndroid Build Coastguard Worker CommandMode = 0x0e, // Operating Mode (mode 0-5).
54*bb4ee6a4SAndroid Build Coastguard Worker CommandRW = 0x30, // Access mode: Choose high/low byte(s) to Read/Write.
55*bb4ee6a4SAndroid Build Coastguard Worker CommandSC = 0xc0, // Select Counter/Read-back command.
56*bb4ee6a4SAndroid Build Coastguard Worker }
57*bb4ee6a4SAndroid Build Coastguard Worker
58*bb4ee6a4SAndroid Build Coastguard Worker // Selects which counter is to be used by the associated command in the lower
59*bb4ee6a4SAndroid Build Coastguard Worker // six bits of the byte. However, if 0xc0 is specified, it indicates that the
60*bb4ee6a4SAndroid Build Coastguard Worker // command is a "Read-Back", which can latch count and/or status of the
61*bb4ee6a4SAndroid Build Coastguard Worker // counters selected in the lower bits. See Intel 8254 data sheet for details.
62*bb4ee6a4SAndroid Build Coastguard Worker #[allow(dead_code)]
63*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
64*bb4ee6a4SAndroid Build Coastguard Worker enum CommandCounter {
65*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter0 = 0x00, // Select counter 0.
66*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter1 = 0x40, // Select counter 1.
67*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter2 = 0x80, // Select counter 2.
68*bb4ee6a4SAndroid Build Coastguard Worker CommandReadBack = 0xc0, // Execute Read-Back.
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker
71*bb4ee6a4SAndroid Build Coastguard Worker // Used for both CommandRW and ReadBackAccess.
72*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
73*bb4ee6a4SAndroid Build Coastguard Worker enum CommandAccess {
74*bb4ee6a4SAndroid Build Coastguard Worker CommandLatch = 0x00, // Latch specified counter.
75*bb4ee6a4SAndroid Build Coastguard Worker CommandRWLeast = 0x10, // Read/Write least significant byte.
76*bb4ee6a4SAndroid Build Coastguard Worker CommandRWMost = 0x20, // Read/Write most significant byte.
77*bb4ee6a4SAndroid Build Coastguard Worker CommandRWBoth = 0x30, // Read/Write both bytes.
78*bb4ee6a4SAndroid Build Coastguard Worker }
79*bb4ee6a4SAndroid Build Coastguard Worker
80*bb4ee6a4SAndroid Build Coastguard Worker // Used for both CommandMode and ReadBackMode.
81*bb4ee6a4SAndroid Build Coastguard Worker // For mode 2 & 3, bit 3 is don't care bit (does not matter to be 0 or 1) but
82*bb4ee6a4SAndroid Build Coastguard Worker // per 8254 spec, should be 0 to insure compatibility with future Intel
83*bb4ee6a4SAndroid Build Coastguard Worker // products.
84*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
85*bb4ee6a4SAndroid Build Coastguard Worker enum CommandMode {
86*bb4ee6a4SAndroid Build Coastguard Worker // NOTE: No h/w modes are currently implemented.
87*bb4ee6a4SAndroid Build Coastguard Worker CommandInterrupt = 0x00, // Mode 0, interrupt on terminal count.
88*bb4ee6a4SAndroid Build Coastguard Worker CommandHWOneShot = 0x02, // Mode 1, h/w re-triggerable one-shot.
89*bb4ee6a4SAndroid Build Coastguard Worker CommandRateGen = 0x04, // Mode 2, rate generator.
90*bb4ee6a4SAndroid Build Coastguard Worker CommandSquareWaveGen = 0x06, // Mode 3, square wave generator.
91*bb4ee6a4SAndroid Build Coastguard Worker CommandSWStrobe = 0x08, // Mode 4, s/w triggered strobe.
92*bb4ee6a4SAndroid Build Coastguard Worker CommandHWStrobe = 0x0a, // Mode 5, h/w triggered strobe.
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker
95*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for the latch portion of the ReadBack command.
96*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
97*bb4ee6a4SAndroid Build Coastguard Worker #[rustfmt::skip] // rustfmt mangles comment indentation for trailing line comments.
98*bb4ee6a4SAndroid Build Coastguard Worker enum CommandReadBackLatch {
99*bb4ee6a4SAndroid Build Coastguard Worker CommandRBLatchBits = 0x30, // Mask bits that determine latching.
100*bb4ee6a4SAndroid Build Coastguard Worker CommandRBLatchBoth = 0x00, // Latch both count and status. This should
101*bb4ee6a4SAndroid Build Coastguard Worker // never happen in device, since bit 4 and 5 in
102*bb4ee6a4SAndroid Build Coastguard Worker // read back command are inverted.
103*bb4ee6a4SAndroid Build Coastguard Worker CommandRBLatchCount = 0x10, // Latch count.
104*bb4ee6a4SAndroid Build Coastguard Worker CommandRBLatchStatus = 0x20, // Latch status.
105*bb4ee6a4SAndroid Build Coastguard Worker }
106*bb4ee6a4SAndroid Build Coastguard Worker
107*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for the counter portion of the ReadBack command.
108*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
109*bb4ee6a4SAndroid Build Coastguard Worker enum CommandReadBackCounters {
110*bb4ee6a4SAndroid Build Coastguard Worker //CommandRBCounters = 0x0e, // Counters for which to provide ReadBack info.
111*bb4ee6a4SAndroid Build Coastguard Worker CommandRBCounter2 = 0x08,
112*bb4ee6a4SAndroid Build Coastguard Worker CommandRBCounter1 = 0x04,
113*bb4ee6a4SAndroid Build Coastguard Worker CommandRBCounter0 = 0x02,
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker
116*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for the ReadBack status command.
117*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
118*bb4ee6a4SAndroid Build Coastguard Worker #[rustfmt::skip] // rustfmt mangles comment indentation for last line of this enum.
119*bb4ee6a4SAndroid Build Coastguard Worker enum ReadBackData {
120*bb4ee6a4SAndroid Build Coastguard Worker // Output format for ReadBack command.
121*bb4ee6a4SAndroid Build Coastguard Worker ReadBackOutput = 0x80, // Output pin status.
122*bb4ee6a4SAndroid Build Coastguard Worker ReadBackNullCount = 0x40, // Whether counter has value.
123*bb4ee6a4SAndroid Build Coastguard Worker // ReadBackAccess, ReadBackMode, and ReadBackBCD intentionally omitted.
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker // I/O Port mappings in I/O bus.
127*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
128*bb4ee6a4SAndroid Build Coastguard Worker enum PortIOSpace {
129*bb4ee6a4SAndroid Build Coastguard Worker PortCounter0Data = 0x40, // Read/write.
130*bb4ee6a4SAndroid Build Coastguard Worker PortCounter1Data = 0x41, // Read/write.
131*bb4ee6a4SAndroid Build Coastguard Worker PortCounter2Data = 0x42, // Read/write.
132*bb4ee6a4SAndroid Build Coastguard Worker PortCommand = 0x43, // Write only.
133*bb4ee6a4SAndroid Build Coastguard Worker PortSpeaker = 0x61, // Read/write.
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield]
137*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, PartialEq, Eq)]
138*bb4ee6a4SAndroid Build Coastguard Worker pub struct SpeakerPortFields {
139*bb4ee6a4SAndroid Build Coastguard Worker // This field is documented in the chipset spec as NMI status and control
140*bb4ee6a4SAndroid Build Coastguard Worker // register. Bits 2, 3, 6, 7 and low level hardware bits that need no
141*bb4ee6a4SAndroid Build Coastguard Worker // emulation for virtualized environments. We call it speaker port because
142*bb4ee6a4SAndroid Build Coastguard Worker // kvm, qemu, linux, and plan9 still call it speaker port, even though it
143*bb4ee6a4SAndroid Build Coastguard Worker // has these other uses and is called something differently in the spec.
144*bb4ee6a4SAndroid Build Coastguard Worker gate: BitField1,
145*bb4ee6a4SAndroid Build Coastguard Worker speaker_on: BitField1,
146*bb4ee6a4SAndroid Build Coastguard Worker pic_serr: BitField1,
147*bb4ee6a4SAndroid Build Coastguard Worker iochk_enable: BitField1,
148*bb4ee6a4SAndroid Build Coastguard Worker // This value changes as part of the refresh frequency of the board for
149*bb4ee6a4SAndroid Build Coastguard Worker // piix4, this is about 1/15us.
150*bb4ee6a4SAndroid Build Coastguard Worker refresh_clock: BitField1,
151*bb4ee6a4SAndroid Build Coastguard Worker output: BitField1,
152*bb4ee6a4SAndroid Build Coastguard Worker iochk_nmi: BitField1,
153*bb4ee6a4SAndroid Build Coastguard Worker serr_nmi: BitField1,
154*bb4ee6a4SAndroid Build Coastguard Worker }
155*bb4ee6a4SAndroid Build Coastguard Worker
156*bb4ee6a4SAndroid Build Coastguard Worker // PIT frequency (in Hertz). See http://wiki.osdev.org/pit.
157*bb4ee6a4SAndroid Build Coastguard Worker const FREQUENCY_HZ: u64 = 1193182;
158*bb4ee6a4SAndroid Build Coastguard Worker
159*bb4ee6a4SAndroid Build Coastguard Worker const NUM_OF_COUNTERS: usize = 3;
160*bb4ee6a4SAndroid Build Coastguard Worker
161*bb4ee6a4SAndroid Build Coastguard Worker const NANOS_PER_SEC: u64 = 1_000_000_000;
162*bb4ee6a4SAndroid Build Coastguard Worker
163*bb4ee6a4SAndroid Build Coastguard Worker const MAX_TIMER_FREQ: u32 = 65536;
164*bb4ee6a4SAndroid Build Coastguard Worker
165*bb4ee6a4SAndroid Build Coastguard Worker #[derive(EventToken)]
166*bb4ee6a4SAndroid Build Coastguard Worker enum Token {
167*bb4ee6a4SAndroid Build Coastguard Worker // The timer expired.
168*bb4ee6a4SAndroid Build Coastguard Worker TimerExpire,
169*bb4ee6a4SAndroid Build Coastguard Worker // The parent thread requested an exit.
170*bb4ee6a4SAndroid Build Coastguard Worker Kill,
171*bb4ee6a4SAndroid Build Coastguard Worker }
172*bb4ee6a4SAndroid Build Coastguard Worker
173*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
174*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
175*bb4ee6a4SAndroid Build Coastguard Worker pub enum PitError {
176*bb4ee6a4SAndroid Build Coastguard Worker /// Error while cloning event for worker thread.
177*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to clone event: {0}")]
178*bb4ee6a4SAndroid Build Coastguard Worker CloneEvent(SysError),
179*bb4ee6a4SAndroid Build Coastguard Worker /// Error while creating event.
180*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to create event: {0}")]
181*bb4ee6a4SAndroid Build Coastguard Worker CreateEvent(SysError),
182*bb4ee6a4SAndroid Build Coastguard Worker /// Creating WaitContext failed.
183*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to create poll context: {0}")]
184*bb4ee6a4SAndroid Build Coastguard Worker CreateWaitContext(SysError),
185*bb4ee6a4SAndroid Build Coastguard Worker /// Error while trying to create worker thread.
186*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to spawn thread: {0}")]
187*bb4ee6a4SAndroid Build Coastguard Worker SpawnThread(IoError),
188*bb4ee6a4SAndroid Build Coastguard Worker /// Error while trying to create timer.
189*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to create pit counter due to timer fd: {0}")]
190*bb4ee6a4SAndroid Build Coastguard Worker TimerCreateError(SysError),
191*bb4ee6a4SAndroid Build Coastguard Worker /// Error while waiting for events.
192*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to wait for events: {0}")]
193*bb4ee6a4SAndroid Build Coastguard Worker WaitError(SysError),
194*bb4ee6a4SAndroid Build Coastguard Worker }
195*bb4ee6a4SAndroid Build Coastguard Worker
196*bb4ee6a4SAndroid Build Coastguard Worker type PitResult<T> = std::result::Result<T, PitError>;
197*bb4ee6a4SAndroid Build Coastguard Worker
198*bb4ee6a4SAndroid Build Coastguard Worker pub struct Pit {
199*bb4ee6a4SAndroid Build Coastguard Worker // Structs that store each counter's state.
200*bb4ee6a4SAndroid Build Coastguard Worker counters: Vec<Arc<Mutex<PitCounter>>>,
201*bb4ee6a4SAndroid Build Coastguard Worker // Worker thread to update counter 0's state asynchronously. Counter 0 needs to send interrupts
202*bb4ee6a4SAndroid Build Coastguard Worker // when timers expire, so it needs asynchronous updates. All other counters need only update
203*bb4ee6a4SAndroid Build Coastguard Worker // when queried directly by the guest.
204*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: Option<WorkerThread<PitResult<()>>>,
205*bb4ee6a4SAndroid Build Coastguard Worker activated: bool,
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker
208*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for Pit {
debug_label(&self) -> String209*bb4ee6a4SAndroid Build Coastguard Worker fn debug_label(&self) -> String {
210*bb4ee6a4SAndroid Build Coastguard Worker "userspace PIT".to_string()
211*bb4ee6a4SAndroid Build Coastguard Worker }
212*bb4ee6a4SAndroid Build Coastguard Worker
device_id(&self) -> DeviceId213*bb4ee6a4SAndroid Build Coastguard Worker fn device_id(&self) -> DeviceId {
214*bb4ee6a4SAndroid Build Coastguard Worker CrosvmDeviceId::Pit.into()
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker
write(&mut self, info: BusAccessInfo, data: &[u8])217*bb4ee6a4SAndroid Build Coastguard Worker fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
218*bb4ee6a4SAndroid Build Coastguard Worker self.ensure_started();
219*bb4ee6a4SAndroid Build Coastguard Worker
220*bb4ee6a4SAndroid Build Coastguard Worker if data.len() != 1 {
221*bb4ee6a4SAndroid Build Coastguard Worker warn!("Bad write size for Pit: {}", data.len());
222*bb4ee6a4SAndroid Build Coastguard Worker return;
223*bb4ee6a4SAndroid Build Coastguard Worker }
224*bb4ee6a4SAndroid Build Coastguard Worker match PortIOSpace::n(info.address as i64) {
225*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().write_counter(data[0]),
226*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().write_counter(data[0]),
227*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().write_counter(data[0]),
228*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCommand) => self.command_write(data[0]),
229*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().write_speaker(data[0]),
230*bb4ee6a4SAndroid Build Coastguard Worker None => warn!("PIT: bad write to {}", info),
231*bb4ee6a4SAndroid Build Coastguard Worker }
232*bb4ee6a4SAndroid Build Coastguard Worker }
233*bb4ee6a4SAndroid Build Coastguard Worker
read(&mut self, info: BusAccessInfo, data: &mut [u8])234*bb4ee6a4SAndroid Build Coastguard Worker fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
235*bb4ee6a4SAndroid Build Coastguard Worker self.ensure_started();
236*bb4ee6a4SAndroid Build Coastguard Worker
237*bb4ee6a4SAndroid Build Coastguard Worker if data.len() != 1 {
238*bb4ee6a4SAndroid Build Coastguard Worker warn!("Bad read size for Pit: {}", data.len());
239*bb4ee6a4SAndroid Build Coastguard Worker return;
240*bb4ee6a4SAndroid Build Coastguard Worker }
241*bb4ee6a4SAndroid Build Coastguard Worker data[0] = match PortIOSpace::n(info.address as i64) {
242*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().read_counter(),
243*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().read_counter(),
244*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().read_counter(),
245*bb4ee6a4SAndroid Build Coastguard Worker // This should function as a no-op, since the specification doesn't allow the
246*bb4ee6a4SAndroid Build Coastguard Worker // command register to be read. However, software is free to ask for it to
247*bb4ee6a4SAndroid Build Coastguard Worker // to be read.
248*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortCommand) => {
249*bb4ee6a4SAndroid Build Coastguard Worker warn!("Ignoring read to command reg");
250*bb4ee6a4SAndroid Build Coastguard Worker 0
251*bb4ee6a4SAndroid Build Coastguard Worker }
252*bb4ee6a4SAndroid Build Coastguard Worker Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().read_speaker(),
253*bb4ee6a4SAndroid Build Coastguard Worker None => {
254*bb4ee6a4SAndroid Build Coastguard Worker warn!("PIT: bad read from {}", info);
255*bb4ee6a4SAndroid Build Coastguard Worker return;
256*bb4ee6a4SAndroid Build Coastguard Worker }
257*bb4ee6a4SAndroid Build Coastguard Worker };
258*bb4ee6a4SAndroid Build Coastguard Worker }
259*bb4ee6a4SAndroid Build Coastguard Worker }
260*bb4ee6a4SAndroid Build Coastguard Worker
261*bb4ee6a4SAndroid Build Coastguard Worker impl Pit {
new(interrupt_evt: IrqEdgeEvent, clock: Arc<Mutex<Clock>>) -> PitResult<Pit>262*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(interrupt_evt: IrqEdgeEvent, clock: Arc<Mutex<Clock>>) -> PitResult<Pit> {
263*bb4ee6a4SAndroid Build Coastguard Worker let mut counters = Vec::new();
264*bb4ee6a4SAndroid Build Coastguard Worker let mut interrupt = Some(interrupt_evt);
265*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..NUM_OF_COUNTERS {
266*bb4ee6a4SAndroid Build Coastguard Worker let pit_counter = PitCounter::new(i, interrupt, clock.clone())?;
267*bb4ee6a4SAndroid Build Coastguard Worker counters.push(Arc::new(Mutex::new(pit_counter)));
268*bb4ee6a4SAndroid Build Coastguard Worker // pass interrupt IrqFd ONLY to counter 0; the rest do not deliver interrupts.
269*bb4ee6a4SAndroid Build Coastguard Worker interrupt = None;
270*bb4ee6a4SAndroid Build Coastguard Worker }
271*bb4ee6a4SAndroid Build Coastguard Worker // We asssert here because:
272*bb4ee6a4SAndroid Build Coastguard Worker // (a) this code only gets invoked at VM startup
273*bb4ee6a4SAndroid Build Coastguard Worker // (b) the assert is very loud and would be easy to notice in tests
274*bb4ee6a4SAndroid Build Coastguard Worker // (c) if we have the wrong number of counters, something is very wrong with the PIT and it
275*bb4ee6a4SAndroid Build Coastguard Worker // may not make sense to continue operation.
276*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(counters.len(), NUM_OF_COUNTERS);
277*bb4ee6a4SAndroid Build Coastguard Worker
278*bb4ee6a4SAndroid Build Coastguard Worker Ok(Pit {
279*bb4ee6a4SAndroid Build Coastguard Worker counters,
280*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: None,
281*bb4ee6a4SAndroid Build Coastguard Worker activated: false,
282*bb4ee6a4SAndroid Build Coastguard Worker })
283*bb4ee6a4SAndroid Build Coastguard Worker }
284*bb4ee6a4SAndroid Build Coastguard Worker
ensure_started(&mut self)285*bb4ee6a4SAndroid Build Coastguard Worker fn ensure_started(&mut self) {
286*bb4ee6a4SAndroid Build Coastguard Worker if self.worker_thread.is_some() {
287*bb4ee6a4SAndroid Build Coastguard Worker return;
288*bb4ee6a4SAndroid Build Coastguard Worker }
289*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.start() {
290*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to start PIT: {}", e);
291*bb4ee6a4SAndroid Build Coastguard Worker }
292*bb4ee6a4SAndroid Build Coastguard Worker }
293*bb4ee6a4SAndroid Build Coastguard Worker
start(&mut self) -> PitResult<()>294*bb4ee6a4SAndroid Build Coastguard Worker fn start(&mut self) -> PitResult<()> {
295*bb4ee6a4SAndroid Build Coastguard Worker let pit_counter = self.counters[0].clone();
296*bb4ee6a4SAndroid Build Coastguard Worker self.worker_thread = Some(WorkerThread::start("pit counter worker", move |kill_evt| {
297*bb4ee6a4SAndroid Build Coastguard Worker let timer_descriptor = Descriptor(pit_counter.lock().timer.as_raw_descriptor());
298*bb4ee6a4SAndroid Build Coastguard Worker let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
299*bb4ee6a4SAndroid Build Coastguard Worker (&timer_descriptor, Token::TimerExpire),
300*bb4ee6a4SAndroid Build Coastguard Worker (&kill_evt, Token::Kill),
301*bb4ee6a4SAndroid Build Coastguard Worker ])
302*bb4ee6a4SAndroid Build Coastguard Worker .map_err(PitError::CreateWaitContext)?;
303*bb4ee6a4SAndroid Build Coastguard Worker
304*bb4ee6a4SAndroid Build Coastguard Worker let mut worker = Worker {
305*bb4ee6a4SAndroid Build Coastguard Worker pit_counter,
306*bb4ee6a4SAndroid Build Coastguard Worker wait_ctx,
307*bb4ee6a4SAndroid Build Coastguard Worker };
308*bb4ee6a4SAndroid Build Coastguard Worker
309*bb4ee6a4SAndroid Build Coastguard Worker worker.run()
310*bb4ee6a4SAndroid Build Coastguard Worker }));
311*bb4ee6a4SAndroid Build Coastguard Worker self.activated = true;
312*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
313*bb4ee6a4SAndroid Build Coastguard Worker }
314*bb4ee6a4SAndroid Build Coastguard Worker
command_write(&mut self, control_word: u8)315*bb4ee6a4SAndroid Build Coastguard Worker fn command_write(&mut self, control_word: u8) {
316*bb4ee6a4SAndroid Build Coastguard Worker let command: u16 = (control_word & CommandBit::CommandSC as u8).into();
317*bb4ee6a4SAndroid Build Coastguard Worker let counter_index: usize = (command >> 6).into();
318*bb4ee6a4SAndroid Build Coastguard Worker if command == (CommandCounter::CommandReadBack as u16) {
319*bb4ee6a4SAndroid Build Coastguard Worker // ReadBack commands can apply to multiple counters.
320*bb4ee6a4SAndroid Build Coastguard Worker if (control_word & (CommandReadBackCounters::CommandRBCounter0 as u8)) != 0 {
321*bb4ee6a4SAndroid Build Coastguard Worker self.counters[0].lock().read_back_command(control_word);
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker if (control_word & (CommandReadBackCounters::CommandRBCounter1 as u8)) != 0 {
324*bb4ee6a4SAndroid Build Coastguard Worker self.counters[1].lock().read_back_command(control_word);
325*bb4ee6a4SAndroid Build Coastguard Worker }
326*bb4ee6a4SAndroid Build Coastguard Worker if (control_word & (CommandReadBackCounters::CommandRBCounter2 as u8)) != 0 {
327*bb4ee6a4SAndroid Build Coastguard Worker self.counters[2].lock().read_back_command(control_word);
328*bb4ee6a4SAndroid Build Coastguard Worker }
329*bb4ee6a4SAndroid Build Coastguard Worker } else if (control_word & (CommandBit::CommandRW as u8))
330*bb4ee6a4SAndroid Build Coastguard Worker == (CommandAccess::CommandLatch as u8)
331*bb4ee6a4SAndroid Build Coastguard Worker {
332*bb4ee6a4SAndroid Build Coastguard Worker self.counters[counter_index].lock().latch_counter();
333*bb4ee6a4SAndroid Build Coastguard Worker } else {
334*bb4ee6a4SAndroid Build Coastguard Worker self.counters[counter_index]
335*bb4ee6a4SAndroid Build Coastguard Worker .lock()
336*bb4ee6a4SAndroid Build Coastguard Worker .store_command(control_word);
337*bb4ee6a4SAndroid Build Coastguard Worker }
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker
get_pit_state(&self) -> PitState340*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_pit_state(&self) -> PitState {
341*bb4ee6a4SAndroid Build Coastguard Worker PitState {
342*bb4ee6a4SAndroid Build Coastguard Worker channels: [
343*bb4ee6a4SAndroid Build Coastguard Worker self.counters[0].lock().get_channel_state(),
344*bb4ee6a4SAndroid Build Coastguard Worker self.counters[1].lock().get_channel_state(),
345*bb4ee6a4SAndroid Build Coastguard Worker self.counters[2].lock().get_channel_state(),
346*bb4ee6a4SAndroid Build Coastguard Worker ],
347*bb4ee6a4SAndroid Build Coastguard Worker flags: 0,
348*bb4ee6a4SAndroid Build Coastguard Worker }
349*bb4ee6a4SAndroid Build Coastguard Worker }
350*bb4ee6a4SAndroid Build Coastguard Worker
set_pit_state(&mut self, state: &PitState)351*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_pit_state(&mut self, state: &PitState) {
352*bb4ee6a4SAndroid Build Coastguard Worker self.counters[0]
353*bb4ee6a4SAndroid Build Coastguard Worker .lock()
354*bb4ee6a4SAndroid Build Coastguard Worker .set_channel_state(&state.channels[0]);
355*bb4ee6a4SAndroid Build Coastguard Worker self.counters[1]
356*bb4ee6a4SAndroid Build Coastguard Worker .lock()
357*bb4ee6a4SAndroid Build Coastguard Worker .set_channel_state(&state.channels[1]);
358*bb4ee6a4SAndroid Build Coastguard Worker self.counters[2]
359*bb4ee6a4SAndroid Build Coastguard Worker .lock()
360*bb4ee6a4SAndroid Build Coastguard Worker .set_channel_state(&state.channels[2]);
361*bb4ee6a4SAndroid Build Coastguard Worker }
362*bb4ee6a4SAndroid Build Coastguard Worker }
363*bb4ee6a4SAndroid Build Coastguard Worker
364*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for Pit {
sleep(&mut self) -> anyhow::Result<()>365*bb4ee6a4SAndroid Build Coastguard Worker fn sleep(&mut self) -> anyhow::Result<()> {
366*bb4ee6a4SAndroid Build Coastguard Worker if let Some(thread) = self.worker_thread.take() {
367*bb4ee6a4SAndroid Build Coastguard Worker thread
368*bb4ee6a4SAndroid Build Coastguard Worker .stop()
369*bb4ee6a4SAndroid Build Coastguard Worker .context("pit worker thread exited with error")?;
370*bb4ee6a4SAndroid Build Coastguard Worker }
371*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
372*bb4ee6a4SAndroid Build Coastguard Worker }
373*bb4ee6a4SAndroid Build Coastguard Worker
wake(&mut self) -> anyhow::Result<()>374*bb4ee6a4SAndroid Build Coastguard Worker fn wake(&mut self) -> anyhow::Result<()> {
375*bb4ee6a4SAndroid Build Coastguard Worker if self.activated {
376*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.start() {
377*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to start PIT: {}", e);
378*bb4ee6a4SAndroid Build Coastguard Worker }
379*bb4ee6a4SAndroid Build Coastguard Worker }
380*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
381*bb4ee6a4SAndroid Build Coastguard Worker }
382*bb4ee6a4SAndroid Build Coastguard Worker
383*bb4ee6a4SAndroid Build Coastguard Worker /// The PIT is only used in very early boot on x86_64, and snapshots are not
384*bb4ee6a4SAndroid Build Coastguard Worker /// generally taken during that time, so we can safely skip the PIT for now.
snapshot(&mut self) -> anyhow::Result<serde_json::Value>385*bb4ee6a4SAndroid Build Coastguard Worker fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
386*bb4ee6a4SAndroid Build Coastguard Worker Ok(serde_json::Value::Null)
387*bb4ee6a4SAndroid Build Coastguard Worker }
388*bb4ee6a4SAndroid Build Coastguard Worker
389*bb4ee6a4SAndroid Build Coastguard Worker /// The PIT is only used in very early boot on x86_64, and snapshots are not
390*bb4ee6a4SAndroid Build Coastguard Worker /// generally taken during that time, so we can safely skip the PIT for now.
restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()>391*bb4ee6a4SAndroid Build Coastguard Worker fn restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()> {
392*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
393*bb4ee6a4SAndroid Build Coastguard Worker }
394*bb4ee6a4SAndroid Build Coastguard Worker }
395*bb4ee6a4SAndroid Build Coastguard Worker
396*bb4ee6a4SAndroid Build Coastguard Worker // Each instance of this represents one of the PIT counters. They are used to
397*bb4ee6a4SAndroid Build Coastguard Worker // implement one-shot and repeating timer alarms. An 8254 has three counters.
398*bb4ee6a4SAndroid Build Coastguard Worker struct PitCounter {
399*bb4ee6a4SAndroid Build Coastguard Worker // Event to write when asserting an interrupt.
400*bb4ee6a4SAndroid Build Coastguard Worker interrupt_evt: Option<IrqEdgeEvent>,
401*bb4ee6a4SAndroid Build Coastguard Worker // Stores the value with which the counter was initialized. Counters are 16-
402*bb4ee6a4SAndroid Build Coastguard Worker // bit values with an effective range of 1-65536 (65536 represented by 0).
403*bb4ee6a4SAndroid Build Coastguard Worker reload_value: u16,
404*bb4ee6a4SAndroid Build Coastguard Worker // Stores value when latch was called.
405*bb4ee6a4SAndroid Build Coastguard Worker latched_value: u16,
406*bb4ee6a4SAndroid Build Coastguard Worker // Stores last command from command register.
407*bb4ee6a4SAndroid Build Coastguard Worker command: u8,
408*bb4ee6a4SAndroid Build Coastguard Worker // Stores status from readback command
409*bb4ee6a4SAndroid Build Coastguard Worker status: u8,
410*bb4ee6a4SAndroid Build Coastguard Worker // Stores time of starting timer. Used for calculating remaining count, if an alarm is
411*bb4ee6a4SAndroid Build Coastguard Worker // scheduled.
412*bb4ee6a4SAndroid Build Coastguard Worker start: Option<Instant>,
413*bb4ee6a4SAndroid Build Coastguard Worker // Current time.
414*bb4ee6a4SAndroid Build Coastguard Worker clock: Arc<Mutex<Clock>>,
415*bb4ee6a4SAndroid Build Coastguard Worker // Time when object was created. Used for a 15us counter.
416*bb4ee6a4SAndroid Build Coastguard Worker creation_time: Instant,
417*bb4ee6a4SAndroid Build Coastguard Worker // The number of the counter. The behavior for each counter is slightly different.
418*bb4ee6a4SAndroid Build Coastguard Worker // Note that once a PitCounter is created, this value should never change.
419*bb4ee6a4SAndroid Build Coastguard Worker counter_id: usize,
420*bb4ee6a4SAndroid Build Coastguard Worker // Indicates if the low byte has been written in RWBoth.
421*bb4ee6a4SAndroid Build Coastguard Worker wrote_low_byte: bool,
422*bb4ee6a4SAndroid Build Coastguard Worker // Indicates if the low byte has been read in RWBoth.
423*bb4ee6a4SAndroid Build Coastguard Worker read_low_byte: bool,
424*bb4ee6a4SAndroid Build Coastguard Worker // Indicates whether counter has been latched.
425*bb4ee6a4SAndroid Build Coastguard Worker latched: bool,
426*bb4ee6a4SAndroid Build Coastguard Worker // Indicates whether ReadBack status has been latched.
427*bb4ee6a4SAndroid Build Coastguard Worker status_latched: bool,
428*bb4ee6a4SAndroid Build Coastguard Worker // Only should be used for counter 2. See http://wiki.osdev.org/PIT.
429*bb4ee6a4SAndroid Build Coastguard Worker gate: bool,
430*bb4ee6a4SAndroid Build Coastguard Worker speaker_on: bool,
431*bb4ee6a4SAndroid Build Coastguard Worker // The starting value for the counter.
432*bb4ee6a4SAndroid Build Coastguard Worker count: u32,
433*bb4ee6a4SAndroid Build Coastguard Worker // Indicates whether the current timer is valid.
434*bb4ee6a4SAndroid Build Coastguard Worker timer_valid: bool,
435*bb4ee6a4SAndroid Build Coastguard Worker // Timer to set and receive periodic notifications.
436*bb4ee6a4SAndroid Build Coastguard Worker timer: Box<dyn TimerTrait>,
437*bb4ee6a4SAndroid Build Coastguard Worker }
438*bb4ee6a4SAndroid Build Coastguard Worker
439*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for PitCounter {
drop(&mut self)440*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
441*bb4ee6a4SAndroid Build Coastguard Worker if self.timer_valid {
442*bb4ee6a4SAndroid Build Coastguard Worker // This should not fail - timer.clear() only fails if timerfd_settime fails, which
443*bb4ee6a4SAndroid Build Coastguard Worker // only happens due to invalid arguments or bad file descriptors. The arguments to
444*bb4ee6a4SAndroid Build Coastguard Worker // timerfd_settime are constant, so its arguments won't be invalid, and it manages
445*bb4ee6a4SAndroid Build Coastguard Worker // the file descriptor safely (we don't use the unsafe FromRawDescriptor) so its file
446*bb4ee6a4SAndroid Build Coastguard Worker // descriptor will be valid.
447*bb4ee6a4SAndroid Build Coastguard Worker self.timer.clear().unwrap();
448*bb4ee6a4SAndroid Build Coastguard Worker }
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker }
451*bb4ee6a4SAndroid Build Coastguard Worker
adjust_count(count: u32) -> u32452*bb4ee6a4SAndroid Build Coastguard Worker fn adjust_count(count: u32) -> u32 {
453*bb4ee6a4SAndroid Build Coastguard Worker // As per spec 0 means max.
454*bb4ee6a4SAndroid Build Coastguard Worker if count == 0 {
455*bb4ee6a4SAndroid Build Coastguard Worker MAX_TIMER_FREQ
456*bb4ee6a4SAndroid Build Coastguard Worker } else {
457*bb4ee6a4SAndroid Build Coastguard Worker count
458*bb4ee6a4SAndroid Build Coastguard Worker }
459*bb4ee6a4SAndroid Build Coastguard Worker }
460*bb4ee6a4SAndroid Build Coastguard Worker
461*bb4ee6a4SAndroid Build Coastguard Worker impl PitCounter {
new( counter_id: usize, interrupt_evt: Option<IrqEdgeEvent>, clock: Arc<Mutex<Clock>>, ) -> PitResult<PitCounter>462*bb4ee6a4SAndroid Build Coastguard Worker fn new(
463*bb4ee6a4SAndroid Build Coastguard Worker counter_id: usize,
464*bb4ee6a4SAndroid Build Coastguard Worker interrupt_evt: Option<IrqEdgeEvent>,
465*bb4ee6a4SAndroid Build Coastguard Worker clock: Arc<Mutex<Clock>>,
466*bb4ee6a4SAndroid Build Coastguard Worker ) -> PitResult<PitCounter> {
467*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(test))]
468*bb4ee6a4SAndroid Build Coastguard Worker let timer = Timer::new().map_err(PitError::TimerCreateError)?;
469*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
470*bb4ee6a4SAndroid Build Coastguard Worker let timer = Timer::new(clock.clone());
471*bb4ee6a4SAndroid Build Coastguard Worker Ok(PitCounter {
472*bb4ee6a4SAndroid Build Coastguard Worker interrupt_evt,
473*bb4ee6a4SAndroid Build Coastguard Worker reload_value: 0,
474*bb4ee6a4SAndroid Build Coastguard Worker latched_value: 0,
475*bb4ee6a4SAndroid Build Coastguard Worker command: 0,
476*bb4ee6a4SAndroid Build Coastguard Worker status: 0,
477*bb4ee6a4SAndroid Build Coastguard Worker start: None,
478*bb4ee6a4SAndroid Build Coastguard Worker clock: clock.clone(),
479*bb4ee6a4SAndroid Build Coastguard Worker creation_time: clock.lock().now(),
480*bb4ee6a4SAndroid Build Coastguard Worker counter_id,
481*bb4ee6a4SAndroid Build Coastguard Worker wrote_low_byte: false,
482*bb4ee6a4SAndroid Build Coastguard Worker read_low_byte: false,
483*bb4ee6a4SAndroid Build Coastguard Worker latched: false,
484*bb4ee6a4SAndroid Build Coastguard Worker status_latched: false,
485*bb4ee6a4SAndroid Build Coastguard Worker gate: false,
486*bb4ee6a4SAndroid Build Coastguard Worker speaker_on: false,
487*bb4ee6a4SAndroid Build Coastguard Worker // `count` is undefined in real hardware and can't ever be programmed to 0, so we
488*bb4ee6a4SAndroid Build Coastguard Worker // initialize it to max to prevent a misbehaving guest from triggering a divide by 0.
489*bb4ee6a4SAndroid Build Coastguard Worker count: MAX_TIMER_FREQ,
490*bb4ee6a4SAndroid Build Coastguard Worker timer_valid: false,
491*bb4ee6a4SAndroid Build Coastguard Worker timer: Box::new(timer),
492*bb4ee6a4SAndroid Build Coastguard Worker })
493*bb4ee6a4SAndroid Build Coastguard Worker }
494*bb4ee6a4SAndroid Build Coastguard Worker
get_channel_state(&self) -> PitChannelState495*bb4ee6a4SAndroid Build Coastguard Worker fn get_channel_state(&self) -> PitChannelState {
496*bb4ee6a4SAndroid Build Coastguard Worker let load_time = match &self.start {
497*bb4ee6a4SAndroid Build Coastguard Worker Some(t) => t.saturating_duration_since(self.creation_time).as_nanos() as u64,
498*bb4ee6a4SAndroid Build Coastguard Worker None => 0,
499*bb4ee6a4SAndroid Build Coastguard Worker };
500*bb4ee6a4SAndroid Build Coastguard Worker
501*bb4ee6a4SAndroid Build Coastguard Worker let mut state = PitChannelState {
502*bb4ee6a4SAndroid Build Coastguard Worker count: self.count,
503*bb4ee6a4SAndroid Build Coastguard Worker latched_count: self.latched_value,
504*bb4ee6a4SAndroid Build Coastguard Worker status_latched: self.status_latched,
505*bb4ee6a4SAndroid Build Coastguard Worker status: self.status,
506*bb4ee6a4SAndroid Build Coastguard Worker reload_value: self.reload_value,
507*bb4ee6a4SAndroid Build Coastguard Worker mode: (self.command & CommandBit::CommandMode as u8) >> 1,
508*bb4ee6a4SAndroid Build Coastguard Worker bcd: false,
509*bb4ee6a4SAndroid Build Coastguard Worker gate: self.gate,
510*bb4ee6a4SAndroid Build Coastguard Worker count_load_time: load_time,
511*bb4ee6a4SAndroid Build Coastguard Worker rw_mode: PitRWMode::None,
512*bb4ee6a4SAndroid Build Coastguard Worker read_state: PitRWState::None,
513*bb4ee6a4SAndroid Build Coastguard Worker write_state: PitRWState::None,
514*bb4ee6a4SAndroid Build Coastguard Worker count_latched: PitRWState::None,
515*bb4ee6a4SAndroid Build Coastguard Worker };
516*bb4ee6a4SAndroid Build Coastguard Worker
517*bb4ee6a4SAndroid Build Coastguard Worker match self.get_access_mode() {
518*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWLeast) => {
519*bb4ee6a4SAndroid Build Coastguard Worker // If access mode is least, RWStates are always LSB
520*bb4ee6a4SAndroid Build Coastguard Worker state.rw_mode = PitRWMode::Least;
521*bb4ee6a4SAndroid Build Coastguard Worker state.read_state = PitRWState::LSB;
522*bb4ee6a4SAndroid Build Coastguard Worker state.write_state = PitRWState::LSB;
523*bb4ee6a4SAndroid Build Coastguard Worker }
524*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWMost) => {
525*bb4ee6a4SAndroid Build Coastguard Worker // If access mode is most, RWStates are always MSB
526*bb4ee6a4SAndroid Build Coastguard Worker state.rw_mode = PitRWMode::Most;
527*bb4ee6a4SAndroid Build Coastguard Worker state.read_state = PitRWState::MSB;
528*bb4ee6a4SAndroid Build Coastguard Worker state.write_state = PitRWState::MSB;
529*bb4ee6a4SAndroid Build Coastguard Worker }
530*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWBoth) => {
531*bb4ee6a4SAndroid Build Coastguard Worker state.rw_mode = PitRWMode::Both;
532*bb4ee6a4SAndroid Build Coastguard Worker // read_state depends on whether or not we've read the low byte already
533*bb4ee6a4SAndroid Build Coastguard Worker state.read_state = if self.read_low_byte {
534*bb4ee6a4SAndroid Build Coastguard Worker PitRWState::Word1
535*bb4ee6a4SAndroid Build Coastguard Worker } else {
536*bb4ee6a4SAndroid Build Coastguard Worker PitRWState::Word0
537*bb4ee6a4SAndroid Build Coastguard Worker };
538*bb4ee6a4SAndroid Build Coastguard Worker // write_state depends on whether or not we've written the low byte already
539*bb4ee6a4SAndroid Build Coastguard Worker state.write_state = if self.wrote_low_byte {
540*bb4ee6a4SAndroid Build Coastguard Worker PitRWState::Word1
541*bb4ee6a4SAndroid Build Coastguard Worker } else {
542*bb4ee6a4SAndroid Build Coastguard Worker PitRWState::Word0
543*bb4ee6a4SAndroid Build Coastguard Worker };
544*bb4ee6a4SAndroid Build Coastguard Worker }
545*bb4ee6a4SAndroid Build Coastguard Worker _ => {}
546*bb4ee6a4SAndroid Build Coastguard Worker };
547*bb4ee6a4SAndroid Build Coastguard Worker
548*bb4ee6a4SAndroid Build Coastguard Worker // Count_latched should be PitRWSTate::None unless we're latched
549*bb4ee6a4SAndroid Build Coastguard Worker if self.latched {
550*bb4ee6a4SAndroid Build Coastguard Worker state.count_latched = state.read_state;
551*bb4ee6a4SAndroid Build Coastguard Worker }
552*bb4ee6a4SAndroid Build Coastguard Worker
553*bb4ee6a4SAndroid Build Coastguard Worker state
554*bb4ee6a4SAndroid Build Coastguard Worker }
555*bb4ee6a4SAndroid Build Coastguard Worker
set_channel_state(&mut self, state: &PitChannelState)556*bb4ee6a4SAndroid Build Coastguard Worker fn set_channel_state(&mut self, state: &PitChannelState) {
557*bb4ee6a4SAndroid Build Coastguard Worker self.count = state.count;
558*bb4ee6a4SAndroid Build Coastguard Worker self.latched_value = state.latched_count;
559*bb4ee6a4SAndroid Build Coastguard Worker self.status_latched = state.status_latched;
560*bb4ee6a4SAndroid Build Coastguard Worker self.status = state.status;
561*bb4ee6a4SAndroid Build Coastguard Worker self.reload_value = state.reload_value;
562*bb4ee6a4SAndroid Build Coastguard Worker
563*bb4ee6a4SAndroid Build Coastguard Worker // the command consists of:
564*bb4ee6a4SAndroid Build Coastguard Worker // - 1 bcd bit, which we don't care about because we don't support non-binary mode
565*bb4ee6a4SAndroid Build Coastguard Worker // - 3 mode bits
566*bb4ee6a4SAndroid Build Coastguard Worker // - 2 access mode bits
567*bb4ee6a4SAndroid Build Coastguard Worker // - 2 counter select bits, which aren't used by the counter/channel itself
568*bb4ee6a4SAndroid Build Coastguard Worker self.command = (state.mode << 1) | ((state.rw_mode as u8) << 4);
569*bb4ee6a4SAndroid Build Coastguard Worker self.gate = state.gate;
570*bb4ee6a4SAndroid Build Coastguard Worker self.latched = state.count_latched != PitRWState::None;
571*bb4ee6a4SAndroid Build Coastguard Worker self.read_low_byte = state.read_state == PitRWState::Word1;
572*bb4ee6a4SAndroid Build Coastguard Worker self.wrote_low_byte = state.write_state == PitRWState::Word1;
573*bb4ee6a4SAndroid Build Coastguard Worker
574*bb4ee6a4SAndroid Build Coastguard Worker self.start = self
575*bb4ee6a4SAndroid Build Coastguard Worker .creation_time
576*bb4ee6a4SAndroid Build Coastguard Worker .checked_add(Duration::from_nanos(state.count_load_time));
577*bb4ee6a4SAndroid Build Coastguard Worker }
578*bb4ee6a4SAndroid Build Coastguard Worker
get_access_mode(&self) -> Option<CommandAccess>579*bb4ee6a4SAndroid Build Coastguard Worker fn get_access_mode(&self) -> Option<CommandAccess> {
580*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::n(self.command & (CommandBit::CommandRW as u8))
581*bb4ee6a4SAndroid Build Coastguard Worker }
582*bb4ee6a4SAndroid Build Coastguard Worker
get_command_mode(&self) -> Option<CommandMode>583*bb4ee6a4SAndroid Build Coastguard Worker fn get_command_mode(&self) -> Option<CommandMode> {
584*bb4ee6a4SAndroid Build Coastguard Worker CommandMode::n(self.command & CommandBit::CommandMode as u8)
585*bb4ee6a4SAndroid Build Coastguard Worker }
586*bb4ee6a4SAndroid Build Coastguard Worker
read_counter(&mut self) -> u8587*bb4ee6a4SAndroid Build Coastguard Worker fn read_counter(&mut self) -> u8 {
588*bb4ee6a4SAndroid Build Coastguard Worker if self.status_latched {
589*bb4ee6a4SAndroid Build Coastguard Worker self.status_latched = false;
590*bb4ee6a4SAndroid Build Coastguard Worker return self.status;
591*bb4ee6a4SAndroid Build Coastguard Worker };
592*bb4ee6a4SAndroid Build Coastguard Worker let data_value: u16 = if self.latched {
593*bb4ee6a4SAndroid Build Coastguard Worker self.latched_value
594*bb4ee6a4SAndroid Build Coastguard Worker } else {
595*bb4ee6a4SAndroid Build Coastguard Worker self.get_read_value()
596*bb4ee6a4SAndroid Build Coastguard Worker };
597*bb4ee6a4SAndroid Build Coastguard Worker
598*bb4ee6a4SAndroid Build Coastguard Worker let access_mode = self.get_access_mode();
599*bb4ee6a4SAndroid Build Coastguard Worker // Latch may be true without being indicated by the access mode if
600*bb4ee6a4SAndroid Build Coastguard Worker // a ReadBack was issued.
601*bb4ee6a4SAndroid Build Coastguard Worker match (access_mode, self.read_low_byte) {
602*bb4ee6a4SAndroid Build Coastguard Worker (Some(CommandAccess::CommandRWLeast), _) => {
603*bb4ee6a4SAndroid Build Coastguard Worker self.latched = false; // Unlatch if only reading the low byte.
604*bb4ee6a4SAndroid Build Coastguard Worker (data_value & 0xff) as u8
605*bb4ee6a4SAndroid Build Coastguard Worker }
606*bb4ee6a4SAndroid Build Coastguard Worker (Some(CommandAccess::CommandRWBoth), false) => {
607*bb4ee6a4SAndroid Build Coastguard Worker self.read_low_byte = true;
608*bb4ee6a4SAndroid Build Coastguard Worker (data_value & 0xff) as u8
609*bb4ee6a4SAndroid Build Coastguard Worker }
610*bb4ee6a4SAndroid Build Coastguard Worker (Some(CommandAccess::CommandRWBoth), true)
611*bb4ee6a4SAndroid Build Coastguard Worker | (Some(CommandAccess::CommandRWMost), _) => {
612*bb4ee6a4SAndroid Build Coastguard Worker self.read_low_byte = false; // Allow for future reads for RWBoth.
613*bb4ee6a4SAndroid Build Coastguard Worker self.latched = false;
614*bb4ee6a4SAndroid Build Coastguard Worker (data_value >> 8) as u8
615*bb4ee6a4SAndroid Build Coastguard Worker }
616*bb4ee6a4SAndroid Build Coastguard Worker (_, _) => 0, // Default for erroneous call
617*bb4ee6a4SAndroid Build Coastguard Worker }
618*bb4ee6a4SAndroid Build Coastguard Worker }
619*bb4ee6a4SAndroid Build Coastguard Worker
write_counter(&mut self, written_datum: u8)620*bb4ee6a4SAndroid Build Coastguard Worker fn write_counter(&mut self, written_datum: u8) {
621*bb4ee6a4SAndroid Build Coastguard Worker let access_mode = self.get_access_mode();
622*bb4ee6a4SAndroid Build Coastguard Worker let datum: u16 = written_datum.into();
623*bb4ee6a4SAndroid Build Coastguard Worker let mut should_start_timer = true;
624*bb4ee6a4SAndroid Build Coastguard Worker self.reload_value = match access_mode {
625*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWLeast) => datum,
626*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWMost) => datum << 8,
627*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandAccess::CommandRWBoth) => {
628*bb4ee6a4SAndroid Build Coastguard Worker // In kCommandRWBoth mode, the first guest write is the low byte and the
629*bb4ee6a4SAndroid Build Coastguard Worker // the second guest write is the high byte. The timer isn't started
630*bb4ee6a4SAndroid Build Coastguard Worker // until after the second byte is written.
631*bb4ee6a4SAndroid Build Coastguard Worker if self.wrote_low_byte {
632*bb4ee6a4SAndroid Build Coastguard Worker self.wrote_low_byte = false;
633*bb4ee6a4SAndroid Build Coastguard Worker self.reload_value | (datum << 8)
634*bb4ee6a4SAndroid Build Coastguard Worker } else {
635*bb4ee6a4SAndroid Build Coastguard Worker self.wrote_low_byte = true;
636*bb4ee6a4SAndroid Build Coastguard Worker should_start_timer = false; // Don't start until high byte written.
637*bb4ee6a4SAndroid Build Coastguard Worker datum
638*bb4ee6a4SAndroid Build Coastguard Worker }
639*bb4ee6a4SAndroid Build Coastguard Worker }
640*bb4ee6a4SAndroid Build Coastguard Worker _ => {
641*bb4ee6a4SAndroid Build Coastguard Worker should_start_timer = false;
642*bb4ee6a4SAndroid Build Coastguard Worker self.reload_value
643*bb4ee6a4SAndroid Build Coastguard Worker }
644*bb4ee6a4SAndroid Build Coastguard Worker };
645*bb4ee6a4SAndroid Build Coastguard Worker if should_start_timer {
646*bb4ee6a4SAndroid Build Coastguard Worker let reload: u32 = self.reload_value.into();
647*bb4ee6a4SAndroid Build Coastguard Worker self.load_and_start_timer(reload);
648*bb4ee6a4SAndroid Build Coastguard Worker }
649*bb4ee6a4SAndroid Build Coastguard Worker }
650*bb4ee6a4SAndroid Build Coastguard Worker
get_output(&self) -> bool651*bb4ee6a4SAndroid Build Coastguard Worker fn get_output(&self) -> bool {
652*bb4ee6a4SAndroid Build Coastguard Worker let ticks_passed = self.get_ticks_passed();
653*bb4ee6a4SAndroid Build Coastguard Worker let count: u64 = self.count.into();
654*bb4ee6a4SAndroid Build Coastguard Worker match self.get_command_mode() {
655*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandInterrupt) => ticks_passed >= count,
656*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandHWOneShot) => ticks_passed < count,
657*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandRateGen) => ticks_passed != 0 && ticks_passed % count == 0,
658*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandSquareWaveGen) => ticks_passed < (count + 1) / 2,
659*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandSWStrobe) | Some(CommandMode::CommandHWStrobe) => {
660*bb4ee6a4SAndroid Build Coastguard Worker ticks_passed == count
661*bb4ee6a4SAndroid Build Coastguard Worker }
662*bb4ee6a4SAndroid Build Coastguard Worker None => {
663*bb4ee6a4SAndroid Build Coastguard Worker warn!("Invalid command mode based on command: {:#x}", self.command);
664*bb4ee6a4SAndroid Build Coastguard Worker false
665*bb4ee6a4SAndroid Build Coastguard Worker }
666*bb4ee6a4SAndroid Build Coastguard Worker }
667*bb4ee6a4SAndroid Build Coastguard Worker }
668*bb4ee6a4SAndroid Build Coastguard Worker
read_speaker(&self) -> u8669*bb4ee6a4SAndroid Build Coastguard Worker fn read_speaker(&self) -> u8 {
670*bb4ee6a4SAndroid Build Coastguard Worker // Refresh clock is a value independent of the actual
671*bb4ee6a4SAndroid Build Coastguard Worker // counter that goes up and down approx every 15 us (~66000/s).
672*bb4ee6a4SAndroid Build Coastguard Worker let us = self
673*bb4ee6a4SAndroid Build Coastguard Worker .clock
674*bb4ee6a4SAndroid Build Coastguard Worker .lock()
675*bb4ee6a4SAndroid Build Coastguard Worker .now()
676*bb4ee6a4SAndroid Build Coastguard Worker .duration_since(self.creation_time)
677*bb4ee6a4SAndroid Build Coastguard Worker .subsec_micros();
678*bb4ee6a4SAndroid Build Coastguard Worker let refresh_clock = us % 15 == 0;
679*bb4ee6a4SAndroid Build Coastguard Worker let mut speaker = SpeakerPortFields::new();
680*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_gate(self.gate.into());
681*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_speaker_on(self.speaker_on.into());
682*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_iochk_enable(0);
683*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_refresh_clock(refresh_clock.into());
684*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_output(self.get_output().into());
685*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_iochk_nmi(0);
686*bb4ee6a4SAndroid Build Coastguard Worker speaker.set_serr_nmi(0);
687*bb4ee6a4SAndroid Build Coastguard Worker speaker.get(/* offset= */ 0, /* width= */ 8) as u8
688*bb4ee6a4SAndroid Build Coastguard Worker }
689*bb4ee6a4SAndroid Build Coastguard Worker
write_speaker(&mut self, datum: u8)690*bb4ee6a4SAndroid Build Coastguard Worker fn write_speaker(&mut self, datum: u8) {
691*bb4ee6a4SAndroid Build Coastguard Worker let mut speaker = SpeakerPortFields::new();
692*bb4ee6a4SAndroid Build Coastguard Worker speaker.set(/* offset= */ 0, /* width= */ 8, datum.into());
693*bb4ee6a4SAndroid Build Coastguard Worker let new_gate = speaker.get_gate() != 0;
694*bb4ee6a4SAndroid Build Coastguard Worker match self.get_command_mode() {
695*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (),
696*bb4ee6a4SAndroid Build Coastguard Worker Some(_) => {
697*bb4ee6a4SAndroid Build Coastguard Worker if new_gate && !self.gate {
698*bb4ee6a4SAndroid Build Coastguard Worker self.start = Some(self.clock.lock().now());
699*bb4ee6a4SAndroid Build Coastguard Worker }
700*bb4ee6a4SAndroid Build Coastguard Worker }
701*bb4ee6a4SAndroid Build Coastguard Worker None => {
702*bb4ee6a4SAndroid Build Coastguard Worker warn!("Invalid command mode based on command {:#x}", self.command);
703*bb4ee6a4SAndroid Build Coastguard Worker return;
704*bb4ee6a4SAndroid Build Coastguard Worker }
705*bb4ee6a4SAndroid Build Coastguard Worker }
706*bb4ee6a4SAndroid Build Coastguard Worker self.speaker_on = speaker.get_speaker_on() != 0;
707*bb4ee6a4SAndroid Build Coastguard Worker self.gate = new_gate;
708*bb4ee6a4SAndroid Build Coastguard Worker }
709*bb4ee6a4SAndroid Build Coastguard Worker
load_and_start_timer(&mut self, initial_count: u32)710*bb4ee6a4SAndroid Build Coastguard Worker fn load_and_start_timer(&mut self, initial_count: u32) {
711*bb4ee6a4SAndroid Build Coastguard Worker self.count = adjust_count(initial_count);
712*bb4ee6a4SAndroid Build Coastguard Worker self.start_timer();
713*bb4ee6a4SAndroid Build Coastguard Worker }
714*bb4ee6a4SAndroid Build Coastguard Worker
start_timer(&mut self)715*bb4ee6a4SAndroid Build Coastguard Worker fn start_timer(&mut self) {
716*bb4ee6a4SAndroid Build Coastguard Worker self.start = Some(self.clock.lock().now());
717*bb4ee6a4SAndroid Build Coastguard Worker
718*bb4ee6a4SAndroid Build Coastguard Worker // Counter 0 is the only counter that generates interrupts, so we
719*bb4ee6a4SAndroid Build Coastguard Worker // don't need to set a timer for the other two counters.
720*bb4ee6a4SAndroid Build Coastguard Worker if self.counter_id != 0 {
721*bb4ee6a4SAndroid Build Coastguard Worker return;
722*bb4ee6a4SAndroid Build Coastguard Worker }
723*bb4ee6a4SAndroid Build Coastguard Worker
724*bb4ee6a4SAndroid Build Coastguard Worker let timer_len = Duration::from_nanos(u64::from(self.count) * NANOS_PER_SEC / FREQUENCY_HZ);
725*bb4ee6a4SAndroid Build Coastguard Worker let safe_timer_len = if timer_len == Duration::new(0, 0) {
726*bb4ee6a4SAndroid Build Coastguard Worker Duration::from_nanos(1)
727*bb4ee6a4SAndroid Build Coastguard Worker } else {
728*bb4ee6a4SAndroid Build Coastguard Worker timer_len
729*bb4ee6a4SAndroid Build Coastguard Worker };
730*bb4ee6a4SAndroid Build Coastguard Worker
731*bb4ee6a4SAndroid Build Coastguard Worker match self.get_command_mode() {
732*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandInterrupt)
733*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandHWOneShot)
734*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandSWStrobe)
735*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandHWStrobe) => {
736*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.reset_oneshot(safe_timer_len) {
737*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to reset oneshot timer: {}", e);
738*bb4ee6a4SAndroid Build Coastguard Worker }
739*bb4ee6a4SAndroid Build Coastguard Worker }
740*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandRateGen) | Some(CommandMode::CommandSquareWaveGen) => {
741*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.reset_repeating(safe_timer_len) {
742*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to reset repeating timer: {}", e);
743*bb4ee6a4SAndroid Build Coastguard Worker }
744*bb4ee6a4SAndroid Build Coastguard Worker }
745*bb4ee6a4SAndroid Build Coastguard Worker // Don't arm timer if invalid mode.
746*bb4ee6a4SAndroid Build Coastguard Worker None => {
747*bb4ee6a4SAndroid Build Coastguard Worker // This will still result in start being set to the current time.
748*bb4ee6a4SAndroid Build Coastguard Worker // Per spec:
749*bb4ee6a4SAndroid Build Coastguard Worker // A new initial count may be written to a Counter at any time without affecting
750*bb4ee6a4SAndroid Build Coastguard Worker // the Counter’s programmed Mode in any way. Counting will be affected as
751*bb4ee6a4SAndroid Build Coastguard Worker // described in the Mode definitions. The new count must follow the programmed
752*bb4ee6a4SAndroid Build Coastguard Worker // count format
753*bb4ee6a4SAndroid Build Coastguard Worker // It's unclear whether setting `self.start` in this case is entirely compliant,
754*bb4ee6a4SAndroid Build Coastguard Worker // but the spec is fairly quiet on expected behavior in error cases, so OSs
755*bb4ee6a4SAndroid Build Coastguard Worker // shouldn't enter invalid modes in the first place. If they do, and then try to
756*bb4ee6a4SAndroid Build Coastguard Worker // get out of it by first setting the counter then the command, this behavior will
757*bb4ee6a4SAndroid Build Coastguard Worker // (perhaps) be minimally surprising, but arguments can be made for other behavior.
758*bb4ee6a4SAndroid Build Coastguard Worker // It's uncertain if this behavior matches real PIT hardware.
759*bb4ee6a4SAndroid Build Coastguard Worker warn!("Invalid command mode based on command {:#x}", self.command);
760*bb4ee6a4SAndroid Build Coastguard Worker return;
761*bb4ee6a4SAndroid Build Coastguard Worker }
762*bb4ee6a4SAndroid Build Coastguard Worker }
763*bb4ee6a4SAndroid Build Coastguard Worker
764*bb4ee6a4SAndroid Build Coastguard Worker self.timer_valid = true;
765*bb4ee6a4SAndroid Build Coastguard Worker }
766*bb4ee6a4SAndroid Build Coastguard Worker
read_back_command(&mut self, control_word: u8)767*bb4ee6a4SAndroid Build Coastguard Worker fn read_back_command(&mut self, control_word: u8) {
768*bb4ee6a4SAndroid Build Coastguard Worker let latch_cmd =
769*bb4ee6a4SAndroid Build Coastguard Worker CommandReadBackLatch::n(control_word & CommandReadBackLatch::CommandRBLatchBits as u8);
770*bb4ee6a4SAndroid Build Coastguard Worker match latch_cmd {
771*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandReadBackLatch::CommandRBLatchCount) => {
772*bb4ee6a4SAndroid Build Coastguard Worker self.latch_counter();
773*bb4ee6a4SAndroid Build Coastguard Worker }
774*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandReadBackLatch::CommandRBLatchStatus) => {
775*bb4ee6a4SAndroid Build Coastguard Worker self.latch_status();
776*bb4ee6a4SAndroid Build Coastguard Worker }
777*bb4ee6a4SAndroid Build Coastguard Worker _ => warn!(
778*bb4ee6a4SAndroid Build Coastguard Worker "Unexpected ReadBackLatch. control_word: {:#x}",
779*bb4ee6a4SAndroid Build Coastguard Worker control_word
780*bb4ee6a4SAndroid Build Coastguard Worker ),
781*bb4ee6a4SAndroid Build Coastguard Worker };
782*bb4ee6a4SAndroid Build Coastguard Worker }
783*bb4ee6a4SAndroid Build Coastguard Worker
latch_counter(&mut self)784*bb4ee6a4SAndroid Build Coastguard Worker fn latch_counter(&mut self) {
785*bb4ee6a4SAndroid Build Coastguard Worker if self.latched {
786*bb4ee6a4SAndroid Build Coastguard Worker return;
787*bb4ee6a4SAndroid Build Coastguard Worker }
788*bb4ee6a4SAndroid Build Coastguard Worker
789*bb4ee6a4SAndroid Build Coastguard Worker self.latched_value = self.get_read_value();
790*bb4ee6a4SAndroid Build Coastguard Worker self.latched = true;
791*bb4ee6a4SAndroid Build Coastguard Worker self.read_low_byte = false;
792*bb4ee6a4SAndroid Build Coastguard Worker }
793*bb4ee6a4SAndroid Build Coastguard Worker
latch_status(&mut self)794*bb4ee6a4SAndroid Build Coastguard Worker fn latch_status(&mut self) {
795*bb4ee6a4SAndroid Build Coastguard Worker // Including BCD here, even though it currently never gets used.
796*bb4ee6a4SAndroid Build Coastguard Worker self.status = self.command
797*bb4ee6a4SAndroid Build Coastguard Worker & (CommandBit::CommandRW as u8
798*bb4ee6a4SAndroid Build Coastguard Worker | CommandBit::CommandMode as u8
799*bb4ee6a4SAndroid Build Coastguard Worker | CommandBit::CommandBCD as u8);
800*bb4ee6a4SAndroid Build Coastguard Worker if self.start.is_none() {
801*bb4ee6a4SAndroid Build Coastguard Worker self.status |= ReadBackData::ReadBackNullCount as u8;
802*bb4ee6a4SAndroid Build Coastguard Worker }
803*bb4ee6a4SAndroid Build Coastguard Worker if self.get_output() {
804*bb4ee6a4SAndroid Build Coastguard Worker self.status |= ReadBackData::ReadBackOutput as u8;
805*bb4ee6a4SAndroid Build Coastguard Worker }
806*bb4ee6a4SAndroid Build Coastguard Worker self.status_latched = true;
807*bb4ee6a4SAndroid Build Coastguard Worker }
808*bb4ee6a4SAndroid Build Coastguard Worker
store_command(&mut self, datum: u8)809*bb4ee6a4SAndroid Build Coastguard Worker fn store_command(&mut self, datum: u8) {
810*bb4ee6a4SAndroid Build Coastguard Worker self.command = datum;
811*bb4ee6a4SAndroid Build Coastguard Worker self.latched = false;
812*bb4ee6a4SAndroid Build Coastguard Worker
813*bb4ee6a4SAndroid Build Coastguard Worker // If a new RW command is written, cancel the current timer.
814*bb4ee6a4SAndroid Build Coastguard Worker if self.timer_valid {
815*bb4ee6a4SAndroid Build Coastguard Worker self.start = None;
816*bb4ee6a4SAndroid Build Coastguard Worker self.timer_valid = false;
817*bb4ee6a4SAndroid Build Coastguard Worker // See the comment in the impl of Drop for PitCounter for justification of the unwrap()
818*bb4ee6a4SAndroid Build Coastguard Worker self.timer.clear().unwrap();
819*bb4ee6a4SAndroid Build Coastguard Worker }
820*bb4ee6a4SAndroid Build Coastguard Worker
821*bb4ee6a4SAndroid Build Coastguard Worker self.wrote_low_byte = false;
822*bb4ee6a4SAndroid Build Coastguard Worker self.read_low_byte = false;
823*bb4ee6a4SAndroid Build Coastguard Worker }
824*bb4ee6a4SAndroid Build Coastguard Worker
timer_handler(&mut self)825*bb4ee6a4SAndroid Build Coastguard Worker fn timer_handler(&mut self) {
826*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.mark_waited() {
827*bb4ee6a4SAndroid Build Coastguard Worker // Under the current Timer implementation (as of Jan 2019), this failure shouldn't
828*bb4ee6a4SAndroid Build Coastguard Worker // happen but implementation details may change in the future, and the failure
829*bb4ee6a4SAndroid Build Coastguard Worker // cases are complex to reason about. Because of this, avoid unwrap().
830*bb4ee6a4SAndroid Build Coastguard Worker error!("pit: timer wait unexpectedly failed: {}", e);
831*bb4ee6a4SAndroid Build Coastguard Worker return;
832*bb4ee6a4SAndroid Build Coastguard Worker }
833*bb4ee6a4SAndroid Build Coastguard Worker let mode = self.get_command_mode();
834*bb4ee6a4SAndroid Build Coastguard Worker if mode == Some(CommandMode::CommandRateGen)
835*bb4ee6a4SAndroid Build Coastguard Worker || mode == Some(CommandMode::CommandSquareWaveGen)
836*bb4ee6a4SAndroid Build Coastguard Worker {
837*bb4ee6a4SAndroid Build Coastguard Worker // Reset the start time for timer modes that repeat.
838*bb4ee6a4SAndroid Build Coastguard Worker self.start = Some(self.clock.lock().now());
839*bb4ee6a4SAndroid Build Coastguard Worker }
840*bb4ee6a4SAndroid Build Coastguard Worker
841*bb4ee6a4SAndroid Build Coastguard Worker // For square wave mode, this isn't quite accurate to the spec, but the
842*bb4ee6a4SAndroid Build Coastguard Worker // difference isn't meaningfully visible to the guest in any important way,
843*bb4ee6a4SAndroid Build Coastguard Worker // and the code is simpler without the special case.
844*bb4ee6a4SAndroid Build Coastguard Worker if let Some(interrupt) = &mut self.interrupt_evt {
845*bb4ee6a4SAndroid Build Coastguard Worker // This is safe because the file descriptor is nonblocking and we're writing 1.
846*bb4ee6a4SAndroid Build Coastguard Worker interrupt.trigger().unwrap();
847*bb4ee6a4SAndroid Build Coastguard Worker }
848*bb4ee6a4SAndroid Build Coastguard Worker }
849*bb4ee6a4SAndroid Build Coastguard Worker
get_ticks_passed(&self) -> u64850*bb4ee6a4SAndroid Build Coastguard Worker fn get_ticks_passed(&self) -> u64 {
851*bb4ee6a4SAndroid Build Coastguard Worker match self.start {
852*bb4ee6a4SAndroid Build Coastguard Worker None => 0,
853*bb4ee6a4SAndroid Build Coastguard Worker Some(t) => {
854*bb4ee6a4SAndroid Build Coastguard Worker let dur = self.clock.lock().now().duration_since(t);
855*bb4ee6a4SAndroid Build Coastguard Worker let dur_ns: u64 = dur.as_secs() * NANOS_PER_SEC + u64::from(dur.subsec_nanos());
856*bb4ee6a4SAndroid Build Coastguard Worker dur_ns * FREQUENCY_HZ / NANOS_PER_SEC
857*bb4ee6a4SAndroid Build Coastguard Worker }
858*bb4ee6a4SAndroid Build Coastguard Worker }
859*bb4ee6a4SAndroid Build Coastguard Worker }
860*bb4ee6a4SAndroid Build Coastguard Worker
get_read_value(&self) -> u16861*bb4ee6a4SAndroid Build Coastguard Worker fn get_read_value(&self) -> u16 {
862*bb4ee6a4SAndroid Build Coastguard Worker match self.start {
863*bb4ee6a4SAndroid Build Coastguard Worker None => 0,
864*bb4ee6a4SAndroid Build Coastguard Worker Some(_) => {
865*bb4ee6a4SAndroid Build Coastguard Worker let count: u64 = adjust_count(self.reload_value.into()).into();
866*bb4ee6a4SAndroid Build Coastguard Worker let ticks_passed = self.get_ticks_passed();
867*bb4ee6a4SAndroid Build Coastguard Worker match self.get_command_mode() {
868*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandInterrupt)
869*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandHWOneShot)
870*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandSWStrobe)
871*bb4ee6a4SAndroid Build Coastguard Worker | Some(CommandMode::CommandHWStrobe) => {
872*bb4ee6a4SAndroid Build Coastguard Worker if ticks_passed > count {
873*bb4ee6a4SAndroid Build Coastguard Worker // Some risk of raciness here in that the count may return a value
874*bb4ee6a4SAndroid Build Coastguard Worker // indicating that the count has expired when the interrupt hasn't
875*bb4ee6a4SAndroid Build Coastguard Worker // yet been injected.
876*bb4ee6a4SAndroid Build Coastguard Worker 0
877*bb4ee6a4SAndroid Build Coastguard Worker } else {
878*bb4ee6a4SAndroid Build Coastguard Worker ((count - ticks_passed) & 0xFFFF) as u16
879*bb4ee6a4SAndroid Build Coastguard Worker }
880*bb4ee6a4SAndroid Build Coastguard Worker }
881*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandRateGen) => (count - (ticks_passed % count)) as u16,
882*bb4ee6a4SAndroid Build Coastguard Worker Some(CommandMode::CommandSquareWaveGen) => {
883*bb4ee6a4SAndroid Build Coastguard Worker (count - ((ticks_passed * 2) % count)) as u16
884*bb4ee6a4SAndroid Build Coastguard Worker }
885*bb4ee6a4SAndroid Build Coastguard Worker None => {
886*bb4ee6a4SAndroid Build Coastguard Worker warn!("Invalid command mode: command = {:#x}", self.command);
887*bb4ee6a4SAndroid Build Coastguard Worker 0
888*bb4ee6a4SAndroid Build Coastguard Worker }
889*bb4ee6a4SAndroid Build Coastguard Worker }
890*bb4ee6a4SAndroid Build Coastguard Worker }
891*bb4ee6a4SAndroid Build Coastguard Worker }
892*bb4ee6a4SAndroid Build Coastguard Worker }
893*bb4ee6a4SAndroid Build Coastguard Worker }
894*bb4ee6a4SAndroid Build Coastguard Worker
895*bb4ee6a4SAndroid Build Coastguard Worker struct Worker {
896*bb4ee6a4SAndroid Build Coastguard Worker pit_counter: Arc<Mutex<PitCounter>>,
897*bb4ee6a4SAndroid Build Coastguard Worker wait_ctx: WaitContext<Token>,
898*bb4ee6a4SAndroid Build Coastguard Worker }
899*bb4ee6a4SAndroid Build Coastguard Worker
900*bb4ee6a4SAndroid Build Coastguard Worker impl Worker {
run(&mut self) -> PitResult<()>901*bb4ee6a4SAndroid Build Coastguard Worker fn run(&mut self) -> PitResult<()> {
902*bb4ee6a4SAndroid Build Coastguard Worker loop {
903*bb4ee6a4SAndroid Build Coastguard Worker let events = self.wait_ctx.wait().map_err(PitError::WaitError)?;
904*bb4ee6a4SAndroid Build Coastguard Worker for event in events.iter().filter(|e| e.is_readable) {
905*bb4ee6a4SAndroid Build Coastguard Worker match event.token {
906*bb4ee6a4SAndroid Build Coastguard Worker Token::TimerExpire => {
907*bb4ee6a4SAndroid Build Coastguard Worker let mut pit = self.pit_counter.lock();
908*bb4ee6a4SAndroid Build Coastguard Worker pit.timer_handler();
909*bb4ee6a4SAndroid Build Coastguard Worker }
910*bb4ee6a4SAndroid Build Coastguard Worker Token::Kill => return Ok(()),
911*bb4ee6a4SAndroid Build Coastguard Worker }
912*bb4ee6a4SAndroid Build Coastguard Worker }
913*bb4ee6a4SAndroid Build Coastguard Worker }
914*bb4ee6a4SAndroid Build Coastguard Worker }
915*bb4ee6a4SAndroid Build Coastguard Worker }
916*bb4ee6a4SAndroid Build Coastguard Worker
917*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
918*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
919*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
920*bb4ee6a4SAndroid Build Coastguard Worker
921*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
922*bb4ee6a4SAndroid Build Coastguard Worker
923*bb4ee6a4SAndroid Build Coastguard Worker struct TestData {
924*bb4ee6a4SAndroid Build Coastguard Worker pit: Pit,
925*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event,
926*bb4ee6a4SAndroid Build Coastguard Worker clock: Arc<Mutex<Clock>>,
927*bb4ee6a4SAndroid Build Coastguard Worker }
928*bb4ee6a4SAndroid Build Coastguard Worker
pit_bus_address(address: PortIOSpace) -> BusAccessInfo929*bb4ee6a4SAndroid Build Coastguard Worker fn pit_bus_address(address: PortIOSpace) -> BusAccessInfo {
930*bb4ee6a4SAndroid Build Coastguard Worker // The PIT is added to the io_bus in two locations, so the offset depends on which
931*bb4ee6a4SAndroid Build Coastguard Worker // address range the address is in. The PIT implementation currently does not use the
932*bb4ee6a4SAndroid Build Coastguard Worker // offset, but we're setting it accurately here in case it does in the future.
933*bb4ee6a4SAndroid Build Coastguard Worker let offset = match address as u64 {
934*bb4ee6a4SAndroid Build Coastguard Worker x if x >= PortIOSpace::PortCounter0Data as u64
935*bb4ee6a4SAndroid Build Coastguard Worker && x < PortIOSpace::PortCounter0Data as u64 + 0x8 =>
936*bb4ee6a4SAndroid Build Coastguard Worker {
937*bb4ee6a4SAndroid Build Coastguard Worker address as u64 - PortIOSpace::PortCounter0Data as u64
938*bb4ee6a4SAndroid Build Coastguard Worker }
939*bb4ee6a4SAndroid Build Coastguard Worker x if x == PortIOSpace::PortSpeaker as u64 => 0,
940*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("invalid PIT address: {:#x}", address as u64),
941*bb4ee6a4SAndroid Build Coastguard Worker };
942*bb4ee6a4SAndroid Build Coastguard Worker
943*bb4ee6a4SAndroid Build Coastguard Worker BusAccessInfo {
944*bb4ee6a4SAndroid Build Coastguard Worker offset,
945*bb4ee6a4SAndroid Build Coastguard Worker address: address as u64,
946*bb4ee6a4SAndroid Build Coastguard Worker id: 0,
947*bb4ee6a4SAndroid Build Coastguard Worker }
948*bb4ee6a4SAndroid Build Coastguard Worker }
949*bb4ee6a4SAndroid Build Coastguard Worker
950*bb4ee6a4SAndroid Build Coastguard Worker /// Utility method for writing a command word to a command register.
write_command(pit: &mut Pit, command: u8)951*bb4ee6a4SAndroid Build Coastguard Worker fn write_command(pit: &mut Pit, command: u8) {
952*bb4ee6a4SAndroid Build Coastguard Worker pit.write(pit_bus_address(PortIOSpace::PortCommand), &[command])
953*bb4ee6a4SAndroid Build Coastguard Worker }
954*bb4ee6a4SAndroid Build Coastguard Worker
955*bb4ee6a4SAndroid Build Coastguard Worker /// Utility method for writing a command word to the speaker register.
write_speaker(pit: &mut Pit, command: u8)956*bb4ee6a4SAndroid Build Coastguard Worker fn write_speaker(pit: &mut Pit, command: u8) {
957*bb4ee6a4SAndroid Build Coastguard Worker pit.write(pit_bus_address(PortIOSpace::PortSpeaker), &[command])
958*bb4ee6a4SAndroid Build Coastguard Worker }
959*bb4ee6a4SAndroid Build Coastguard Worker
960*bb4ee6a4SAndroid Build Coastguard Worker /// Utility method for writing to a counter.
write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess)961*bb4ee6a4SAndroid Build Coastguard Worker fn write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess) {
962*bb4ee6a4SAndroid Build Coastguard Worker let port = match counter_idx {
963*bb4ee6a4SAndroid Build Coastguard Worker 0 => PortIOSpace::PortCounter0Data,
964*bb4ee6a4SAndroid Build Coastguard Worker 1 => PortIOSpace::PortCounter1Data,
965*bb4ee6a4SAndroid Build Coastguard Worker 2 => PortIOSpace::PortCounter2Data,
966*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Invalid counter_idx: {}", counter_idx),
967*bb4ee6a4SAndroid Build Coastguard Worker };
968*bb4ee6a4SAndroid Build Coastguard Worker // Write the least, then the most, significant byte.
969*bb4ee6a4SAndroid Build Coastguard Worker if access_mode == CommandAccess::CommandRWLeast
970*bb4ee6a4SAndroid Build Coastguard Worker || access_mode == CommandAccess::CommandRWBoth
971*bb4ee6a4SAndroid Build Coastguard Worker {
972*bb4ee6a4SAndroid Build Coastguard Worker pit.write(pit_bus_address(port), &[(data & 0xff) as u8]);
973*bb4ee6a4SAndroid Build Coastguard Worker }
974*bb4ee6a4SAndroid Build Coastguard Worker if access_mode == CommandAccess::CommandRWMost
975*bb4ee6a4SAndroid Build Coastguard Worker || access_mode == CommandAccess::CommandRWBoth
976*bb4ee6a4SAndroid Build Coastguard Worker {
977*bb4ee6a4SAndroid Build Coastguard Worker pit.write(pit_bus_address(port), &[(data >> 8) as u8]);
978*bb4ee6a4SAndroid Build Coastguard Worker }
979*bb4ee6a4SAndroid Build Coastguard Worker }
980*bb4ee6a4SAndroid Build Coastguard Worker
981*bb4ee6a4SAndroid Build Coastguard Worker /// Utility method for reading a counter. Check if the read value matches expected_value.
read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess)982*bb4ee6a4SAndroid Build Coastguard Worker fn read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess) {
983*bb4ee6a4SAndroid Build Coastguard Worker let port = match counter_idx {
984*bb4ee6a4SAndroid Build Coastguard Worker 0 => PortIOSpace::PortCounter0Data,
985*bb4ee6a4SAndroid Build Coastguard Worker 1 => PortIOSpace::PortCounter1Data,
986*bb4ee6a4SAndroid Build Coastguard Worker 2 => PortIOSpace::PortCounter2Data,
987*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Invalid counter_idx: {}", counter_idx),
988*bb4ee6a4SAndroid Build Coastguard Worker };
989*bb4ee6a4SAndroid Build Coastguard Worker let mut result: u16 = 0;
990*bb4ee6a4SAndroid Build Coastguard Worker if access_mode == CommandAccess::CommandRWLeast
991*bb4ee6a4SAndroid Build Coastguard Worker || access_mode == CommandAccess::CommandRWBoth
992*bb4ee6a4SAndroid Build Coastguard Worker {
993*bb4ee6a4SAndroid Build Coastguard Worker let mut buffer = [0];
994*bb4ee6a4SAndroid Build Coastguard Worker pit.read(pit_bus_address(port), &mut buffer);
995*bb4ee6a4SAndroid Build Coastguard Worker result = buffer[0].into();
996*bb4ee6a4SAndroid Build Coastguard Worker }
997*bb4ee6a4SAndroid Build Coastguard Worker if access_mode == CommandAccess::CommandRWMost
998*bb4ee6a4SAndroid Build Coastguard Worker || access_mode == CommandAccess::CommandRWBoth
999*bb4ee6a4SAndroid Build Coastguard Worker {
1000*bb4ee6a4SAndroid Build Coastguard Worker let mut buffer = [0];
1001*bb4ee6a4SAndroid Build Coastguard Worker pit.read(pit_bus_address(port), &mut buffer);
1002*bb4ee6a4SAndroid Build Coastguard Worker result |= u16::from(buffer[0]) << 8;
1003*bb4ee6a4SAndroid Build Coastguard Worker }
1004*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(result, expected);
1005*bb4ee6a4SAndroid Build Coastguard Worker }
1006*bb4ee6a4SAndroid Build Coastguard Worker
set_up() -> TestData1007*bb4ee6a4SAndroid Build Coastguard Worker fn set_up() -> TestData {
1008*bb4ee6a4SAndroid Build Coastguard Worker let evt = IrqEdgeEvent::new().unwrap();
1009*bb4ee6a4SAndroid Build Coastguard Worker let clock = Arc::new(Mutex::new(Clock::new()));
1010*bb4ee6a4SAndroid Build Coastguard Worker TestData {
1011*bb4ee6a4SAndroid Build Coastguard Worker irqfd: evt.get_trigger().try_clone().unwrap(),
1012*bb4ee6a4SAndroid Build Coastguard Worker pit: Pit::new(evt, clock.clone()).unwrap(),
1013*bb4ee6a4SAndroid Build Coastguard Worker clock,
1014*bb4ee6a4SAndroid Build Coastguard Worker }
1015*bb4ee6a4SAndroid Build Coastguard Worker }
1016*bb4ee6a4SAndroid Build Coastguard Worker
advance_by_tick(data: &mut TestData)1017*bb4ee6a4SAndroid Build Coastguard Worker fn advance_by_tick(data: &mut TestData) {
1018*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(data, 1);
1019*bb4ee6a4SAndroid Build Coastguard Worker }
1020*bb4ee6a4SAndroid Build Coastguard Worker
advance_by_ticks(data: &mut TestData, ticks: u64)1021*bb4ee6a4SAndroid Build Coastguard Worker fn advance_by_ticks(data: &mut TestData, ticks: u64) {
1022*bb4ee6a4SAndroid Build Coastguard Worker println!(
1023*bb4ee6a4SAndroid Build Coastguard Worker "Advancing by {:#x} ticks ({} ns)",
1024*bb4ee6a4SAndroid Build Coastguard Worker ticks,
1025*bb4ee6a4SAndroid Build Coastguard Worker (NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1
1026*bb4ee6a4SAndroid Build Coastguard Worker );
1027*bb4ee6a4SAndroid Build Coastguard Worker let mut lock = data.clock.lock();
1028*bb4ee6a4SAndroid Build Coastguard Worker lock.add_ns((NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1);
1029*bb4ee6a4SAndroid Build Coastguard Worker }
1030*bb4ee6a4SAndroid Build Coastguard Worker
1031*bb4ee6a4SAndroid Build Coastguard Worker /// Tests the ability to write a command and data and read the data back using latch.
1032*bb4ee6a4SAndroid Build Coastguard Worker #[test]
write_and_latch()1033*bb4ee6a4SAndroid Build Coastguard Worker fn write_and_latch() {
1034*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1035*bb4ee6a4SAndroid Build Coastguard Worker let both_interrupt =
1036*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth as u8 | CommandMode::CommandInterrupt as u8;
1037*bb4ee6a4SAndroid Build Coastguard Worker // Issue a command to write both digits of counter 0 in interrupt mode.
1038*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1039*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1040*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | both_interrupt,
1041*bb4ee6a4SAndroid Build Coastguard Worker );
1042*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 24, CommandAccess::CommandRWBoth);
1043*bb4ee6a4SAndroid Build Coastguard Worker // Advance time by one tick -- value read back should decrease.
1044*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1045*bb4ee6a4SAndroid Build Coastguard Worker
1046*bb4ee6a4SAndroid Build Coastguard Worker // Latch and read back the value written.
1047*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1048*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1049*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1050*bb4ee6a4SAndroid Build Coastguard Worker );
1051*bb4ee6a4SAndroid Build Coastguard Worker // Advance again after latching to verify that value read back doesn't change.
1052*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1053*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 23, CommandAccess::CommandRWBoth);
1054*bb4ee6a4SAndroid Build Coastguard Worker
1055*bb4ee6a4SAndroid Build Coastguard Worker // Repeat with counter 1.
1056*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1057*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1058*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter1 as u8 | both_interrupt,
1059*bb4ee6a4SAndroid Build Coastguard Worker );
1060*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 1, 314, CommandAccess::CommandRWBoth);
1061*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1062*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1063*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1064*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter1 as u8 | CommandAccess::CommandLatch as u8,
1065*bb4ee6a4SAndroid Build Coastguard Worker );
1066*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1067*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 1, 313, CommandAccess::CommandRWBoth);
1068*bb4ee6a4SAndroid Build Coastguard Worker
1069*bb4ee6a4SAndroid Build Coastguard Worker // Repeat with counter 2.
1070*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1071*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1072*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter2 as u8 | both_interrupt,
1073*bb4ee6a4SAndroid Build Coastguard Worker );
1074*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1075*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1076*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1077*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1078*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter2 as u8 | CommandAccess::CommandLatch as u8,
1079*bb4ee6a4SAndroid Build Coastguard Worker );
1080*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1081*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 2, 0xfffe, CommandAccess::CommandRWBoth);
1082*bb4ee6a4SAndroid Build Coastguard Worker }
1083*bb4ee6a4SAndroid Build Coastguard Worker
1084*bb4ee6a4SAndroid Build Coastguard Worker /// Tests the ability to read only the least significant byte.
1085*bb4ee6a4SAndroid Build Coastguard Worker #[test]
write_and_read_least()1086*bb4ee6a4SAndroid Build Coastguard Worker fn write_and_read_least() {
1087*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1088*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1089*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1090*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1091*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWLeast as u8
1092*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1093*bb4ee6a4SAndroid Build Coastguard Worker );
1094*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWLeast);
1095*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1096*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1097*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1098*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1099*bb4ee6a4SAndroid Build Coastguard Worker );
1100*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1101*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1102*bb4ee6a4SAndroid Build Coastguard Worker }
1103*bb4ee6a4SAndroid Build Coastguard Worker
1104*bb4ee6a4SAndroid Build Coastguard Worker /// Tests the ability to read only the most significant byte.
1105*bb4ee6a4SAndroid Build Coastguard Worker #[test]
write_and_read_most()1106*bb4ee6a4SAndroid Build Coastguard Worker fn write_and_read_most() {
1107*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1108*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1109*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1110*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1111*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWMost as u8
1112*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1113*bb4ee6a4SAndroid Build Coastguard Worker );
1114*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWMost);
1115*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1116*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1117*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1118*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1119*bb4ee6a4SAndroid Build Coastguard Worker );
1120*bb4ee6a4SAndroid Build Coastguard Worker advance_by_tick(&mut data);
1121*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1122*bb4ee6a4SAndroid Build Coastguard Worker }
1123*bb4ee6a4SAndroid Build Coastguard Worker
1124*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that reading the command register does nothing.
1125*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_command()1126*bb4ee6a4SAndroid Build Coastguard Worker fn read_command() {
1127*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1128*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0];
1129*bb4ee6a4SAndroid Build Coastguard Worker data.pit
1130*bb4ee6a4SAndroid Build Coastguard Worker .read(pit_bus_address(PortIOSpace::PortCommand), &mut buf);
1131*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(buf, [0]);
1132*bb4ee6a4SAndroid Build Coastguard Worker }
1133*bb4ee6a4SAndroid Build Coastguard Worker
1134*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that latching prevents the read time from actually advancing.
1135*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_timed_latch()1136*bb4ee6a4SAndroid Build Coastguard Worker fn test_timed_latch() {
1137*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1138*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1139*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1140*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1141*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1142*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1143*bb4ee6a4SAndroid Build Coastguard Worker );
1144*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1145*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1146*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1147*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1148*bb4ee6a4SAndroid Build Coastguard Worker );
1149*bb4ee6a4SAndroid Build Coastguard Worker data.clock.lock().add_ns(25_000_000);
1150*bb4ee6a4SAndroid Build Coastguard Worker // The counter should ignore this second latch.
1151*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1152*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1153*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1154*bb4ee6a4SAndroid Build Coastguard Worker );
1155*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1156*bb4ee6a4SAndroid Build Coastguard Worker // It should, however, store the count for this latch.
1157*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1158*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1159*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1160*bb4ee6a4SAndroid Build Coastguard Worker );
1161*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1162*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1163*bb4ee6a4SAndroid Build Coastguard Worker 0,
1164*bb4ee6a4SAndroid Build Coastguard Worker 0xffff - ((25_000_000 * FREQUENCY_HZ) / NANOS_PER_SEC) as u16,
1165*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth,
1166*bb4ee6a4SAndroid Build Coastguard Worker );
1167*bb4ee6a4SAndroid Build Coastguard Worker }
1168*bb4ee6a4SAndroid Build Coastguard Worker
1169*bb4ee6a4SAndroid Build Coastguard Worker /// Tests Mode 0 (Interrupt on terminal count); checks whether IRQ has been asserted.
1170*bb4ee6a4SAndroid Build Coastguard Worker #[test]
interrupt_mode()1171*bb4ee6a4SAndroid Build Coastguard Worker fn interrupt_mode() {
1172*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1173*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1174*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1175*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1176*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1177*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1178*bb4ee6a4SAndroid Build Coastguard Worker );
1179*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1180*bb4ee6a4SAndroid Build Coastguard Worker // Advance clock enough to trigger interrupt.
1181*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 0xffff);
1182*bb4ee6a4SAndroid Build Coastguard Worker data.irqfd.wait().unwrap();
1183*bb4ee6a4SAndroid Build Coastguard Worker }
1184*bb4ee6a4SAndroid Build Coastguard Worker
1185*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that Rate Generator mode (mode 2) handls the interrupt properly when the timer
1186*bb4ee6a4SAndroid Build Coastguard Worker /// expires and that it resets the timer properly.
1187*bb4ee6a4SAndroid Build Coastguard Worker #[test]
rate_gen_mode()1188*bb4ee6a4SAndroid Build Coastguard Worker fn rate_gen_mode() {
1189*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1190*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1191*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1192*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1193*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1194*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandRateGen as u8,
1195*bb4ee6a4SAndroid Build Coastguard Worker );
1196*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1197*bb4ee6a4SAndroid Build Coastguard Worker // Repatedly advance clock and expect interrupt.
1198*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 0xffff);
1199*bb4ee6a4SAndroid Build Coastguard Worker data.irqfd.wait().unwrap();
1200*bb4ee6a4SAndroid Build Coastguard Worker
1201*bb4ee6a4SAndroid Build Coastguard Worker // Repatedly advance clock and expect interrupt.
1202*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 0xffff);
1203*bb4ee6a4SAndroid Build Coastguard Worker data.irqfd.wait().unwrap();
1204*bb4ee6a4SAndroid Build Coastguard Worker
1205*bb4ee6a4SAndroid Build Coastguard Worker // Repatedly advance clock and expect interrupt.
1206*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 0xffff);
1207*bb4ee6a4SAndroid Build Coastguard Worker data.irqfd.wait().unwrap();
1208*bb4ee6a4SAndroid Build Coastguard Worker }
1209*bb4ee6a4SAndroid Build Coastguard Worker
1210*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that square wave mode advances the counter correctly.
1211*bb4ee6a4SAndroid Build Coastguard Worker #[test]
square_wave_counter_read()1212*bb4ee6a4SAndroid Build Coastguard Worker fn square_wave_counter_read() {
1213*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1214*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1215*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1216*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1217*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1218*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandSquareWaveGen as u8,
1219*bb4ee6a4SAndroid Build Coastguard Worker );
1220*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1221*bb4ee6a4SAndroid Build Coastguard Worker
1222*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 10_000);
1223*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1224*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1225*bb4ee6a4SAndroid Build Coastguard Worker 0,
1226*bb4ee6a4SAndroid Build Coastguard Worker 0xffff - 10_000 * 2,
1227*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth,
1228*bb4ee6a4SAndroid Build Coastguard Worker );
1229*bb4ee6a4SAndroid Build Coastguard Worker }
1230*bb4ee6a4SAndroid Build Coastguard Worker
1231*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that rategen mode updates the counter correctly.
1232*bb4ee6a4SAndroid Build Coastguard Worker #[test]
rate_gen_counter_read()1233*bb4ee6a4SAndroid Build Coastguard Worker fn rate_gen_counter_read() {
1234*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1235*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1236*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1237*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1238*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1239*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandRateGen as u8,
1240*bb4ee6a4SAndroid Build Coastguard Worker );
1241*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1242*bb4ee6a4SAndroid Build Coastguard Worker
1243*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 10_000);
1244*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1245*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1246*bb4ee6a4SAndroid Build Coastguard Worker 0,
1247*bb4ee6a4SAndroid Build Coastguard Worker 0xffff - 10_000,
1248*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth,
1249*bb4ee6a4SAndroid Build Coastguard Worker );
1250*bb4ee6a4SAndroid Build Coastguard Worker }
1251*bb4ee6a4SAndroid Build Coastguard Worker
1252*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that interrupt counter mode updates the counter correctly.
1253*bb4ee6a4SAndroid Build Coastguard Worker #[test]
interrupt_counter_read()1254*bb4ee6a4SAndroid Build Coastguard Worker fn interrupt_counter_read() {
1255*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1256*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1257*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1258*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1259*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1260*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1261*bb4ee6a4SAndroid Build Coastguard Worker );
1262*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1263*bb4ee6a4SAndroid Build Coastguard Worker
1264*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 10_000);
1265*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1266*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1267*bb4ee6a4SAndroid Build Coastguard Worker 0,
1268*bb4ee6a4SAndroid Build Coastguard Worker 0xffff - 10_000,
1269*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth,
1270*bb4ee6a4SAndroid Build Coastguard Worker );
1271*bb4ee6a4SAndroid Build Coastguard Worker
1272*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 3 * FREQUENCY_HZ);
1273*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0, CommandAccess::CommandRWBoth);
1274*bb4ee6a4SAndroid Build Coastguard Worker }
1275*bb4ee6a4SAndroid Build Coastguard Worker
1276*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that ReadBack count works properly for `low` access mode.
1277*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_back_count_access_low()1278*bb4ee6a4SAndroid Build Coastguard Worker fn read_back_count_access_low() {
1279*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1280*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1281*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1282*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1283*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWLeast as u8
1284*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1285*bb4ee6a4SAndroid Build Coastguard Worker );
1286*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1287*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1288*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1289*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1290*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1291*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1292*bb4ee6a4SAndroid Build Coastguard Worker );
1293*bb4ee6a4SAndroid Build Coastguard Worker
1294*bb4ee6a4SAndroid Build Coastguard Worker // Advance 100 ticks and verify that low byte of counter is appropriately updated.
1295*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 100);
1296*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1297*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1298*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1299*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1300*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1301*bb4ee6a4SAndroid Build Coastguard Worker );
1302*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0x00ff, CommandAccess::CommandRWLeast);
1303*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1304*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1305*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1306*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1307*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1308*bb4ee6a4SAndroid Build Coastguard Worker );
1309*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1310*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1311*bb4ee6a4SAndroid Build Coastguard Worker 0,
1312*bb4ee6a4SAndroid Build Coastguard Worker (0xffff - 100) & 0x00ff,
1313*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWLeast,
1314*bb4ee6a4SAndroid Build Coastguard Worker );
1315*bb4ee6a4SAndroid Build Coastguard Worker }
1316*bb4ee6a4SAndroid Build Coastguard Worker
1317*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that ReadBack count works properly for `high` access mode.
1318*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_back_count_access_high()1319*bb4ee6a4SAndroid Build Coastguard Worker fn read_back_count_access_high() {
1320*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1321*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1322*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1323*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1324*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWMost as u8
1325*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1326*bb4ee6a4SAndroid Build Coastguard Worker );
1327*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1328*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1329*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1330*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1331*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1332*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1333*bb4ee6a4SAndroid Build Coastguard Worker );
1334*bb4ee6a4SAndroid Build Coastguard Worker
1335*bb4ee6a4SAndroid Build Coastguard Worker // Advance 100 ticks and verify that low byte of counter is appropriately updated.
1336*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 512);
1337*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1338*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1339*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1340*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1341*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1342*bb4ee6a4SAndroid Build Coastguard Worker );
1343*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 0, 0xff00, CommandAccess::CommandRWMost);
1344*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1345*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1346*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1347*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchCount as u8
1348*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1349*bb4ee6a4SAndroid Build Coastguard Worker );
1350*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1351*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1352*bb4ee6a4SAndroid Build Coastguard Worker 0,
1353*bb4ee6a4SAndroid Build Coastguard Worker (0xffff - 512) & 0xff00,
1354*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWMost,
1355*bb4ee6a4SAndroid Build Coastguard Worker );
1356*bb4ee6a4SAndroid Build Coastguard Worker }
1357*bb4ee6a4SAndroid Build Coastguard Worker
1358*bb4ee6a4SAndroid Build Coastguard Worker /// Tests that ReadBack status returns the expected values.
1359*bb4ee6a4SAndroid Build Coastguard Worker #[test]
read_back_status()1360*bb4ee6a4SAndroid Build Coastguard Worker fn read_back_status() {
1361*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1362*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1363*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1364*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter0 as u8
1365*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1366*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandSWStrobe as u8,
1367*bb4ee6a4SAndroid Build Coastguard Worker );
1368*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1369*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1370*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1371*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandReadBack as u8
1372*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackLatch::CommandRBLatchStatus as u8
1373*bb4ee6a4SAndroid Build Coastguard Worker | CommandReadBackCounters::CommandRBCounter0 as u8,
1374*bb4ee6a4SAndroid Build Coastguard Worker );
1375*bb4ee6a4SAndroid Build Coastguard Worker
1376*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1377*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1378*bb4ee6a4SAndroid Build Coastguard Worker 0,
1379*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth as u16 | CommandMode::CommandSWStrobe as u16,
1380*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWLeast,
1381*bb4ee6a4SAndroid Build Coastguard Worker );
1382*bb4ee6a4SAndroid Build Coastguard Worker }
1383*bb4ee6a4SAndroid Build Coastguard Worker
1384*bb4ee6a4SAndroid Build Coastguard Worker #[test]
speaker_square_wave()1385*bb4ee6a4SAndroid Build Coastguard Worker fn speaker_square_wave() {
1386*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1387*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1388*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1389*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter2 as u8
1390*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1391*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandSquareWaveGen as u8,
1392*bb4ee6a4SAndroid Build Coastguard Worker );
1393*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1394*bb4ee6a4SAndroid Build Coastguard Worker
1395*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 128);
1396*bb4ee6a4SAndroid Build Coastguard Worker read_counter(
1397*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1398*bb4ee6a4SAndroid Build Coastguard Worker 2,
1399*bb4ee6a4SAndroid Build Coastguard Worker 0xffff - 128 * 2,
1400*bb4ee6a4SAndroid Build Coastguard Worker CommandAccess::CommandRWBoth,
1401*bb4ee6a4SAndroid Build Coastguard Worker );
1402*bb4ee6a4SAndroid Build Coastguard Worker }
1403*bb4ee6a4SAndroid Build Coastguard Worker
1404*bb4ee6a4SAndroid Build Coastguard Worker #[test]
speaker_rate_gen()1405*bb4ee6a4SAndroid Build Coastguard Worker fn speaker_rate_gen() {
1406*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1407*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1408*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1409*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter2 as u8
1410*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1411*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandRateGen as u8,
1412*bb4ee6a4SAndroid Build Coastguard Worker );
1413*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1414*bb4ee6a4SAndroid Build Coastguard Worker
1415*bb4ee6a4SAndroid Build Coastguard Worker // In Rate Gen mode, the counter should start over when the gate is
1416*bb4ee6a4SAndroid Build Coastguard Worker // set to high using SpeakerWrite.
1417*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 128);
1418*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1419*bb4ee6a4SAndroid Build Coastguard Worker
1420*bb4ee6a4SAndroid Build Coastguard Worker write_speaker(&mut data.pit, 0x1);
1421*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 128);
1422*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1423*bb4ee6a4SAndroid Build Coastguard Worker }
1424*bb4ee6a4SAndroid Build Coastguard Worker
1425*bb4ee6a4SAndroid Build Coastguard Worker #[test]
speaker_interrupt()1426*bb4ee6a4SAndroid Build Coastguard Worker fn speaker_interrupt() {
1427*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1428*bb4ee6a4SAndroid Build Coastguard Worker
1429*bb4ee6a4SAndroid Build Coastguard Worker write_command(
1430*bb4ee6a4SAndroid Build Coastguard Worker &mut data.pit,
1431*bb4ee6a4SAndroid Build Coastguard Worker CommandCounter::CommandCounter2 as u8
1432*bb4ee6a4SAndroid Build Coastguard Worker | CommandAccess::CommandRWBoth as u8
1433*bb4ee6a4SAndroid Build Coastguard Worker | CommandMode::CommandInterrupt as u8,
1434*bb4ee6a4SAndroid Build Coastguard Worker );
1435*bb4ee6a4SAndroid Build Coastguard Worker write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1436*bb4ee6a4SAndroid Build Coastguard Worker
1437*bb4ee6a4SAndroid Build Coastguard Worker // In Interrupt mode, the counter should NOT start over when the gate is
1438*bb4ee6a4SAndroid Build Coastguard Worker // set to high using SpeakerWrite.
1439*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 128);
1440*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1441*bb4ee6a4SAndroid Build Coastguard Worker
1442*bb4ee6a4SAndroid Build Coastguard Worker write_speaker(&mut data.pit, 0x1);
1443*bb4ee6a4SAndroid Build Coastguard Worker advance_by_ticks(&mut data, 128);
1444*bb4ee6a4SAndroid Build Coastguard Worker read_counter(&mut data.pit, 2, 0xffff - 256, CommandAccess::CommandRWBoth);
1445*bb4ee6a4SAndroid Build Coastguard Worker }
1446*bb4ee6a4SAndroid Build Coastguard Worker
1447*bb4ee6a4SAndroid Build Coastguard Worker /// Verify that invalid reads and writes do not cause crashes.
1448*bb4ee6a4SAndroid Build Coastguard Worker #[test]
invalid_write_and_read()1449*bb4ee6a4SAndroid Build Coastguard Worker fn invalid_write_and_read() {
1450*bb4ee6a4SAndroid Build Coastguard Worker let mut data = set_up();
1451*bb4ee6a4SAndroid Build Coastguard Worker data.pit.write(
1452*bb4ee6a4SAndroid Build Coastguard Worker BusAccessInfo {
1453*bb4ee6a4SAndroid Build Coastguard Worker address: 0x44,
1454*bb4ee6a4SAndroid Build Coastguard Worker offset: 0x4,
1455*bb4ee6a4SAndroid Build Coastguard Worker id: 0,
1456*bb4ee6a4SAndroid Build Coastguard Worker },
1457*bb4ee6a4SAndroid Build Coastguard Worker &[0],
1458*bb4ee6a4SAndroid Build Coastguard Worker );
1459*bb4ee6a4SAndroid Build Coastguard Worker data.pit.read(
1460*bb4ee6a4SAndroid Build Coastguard Worker BusAccessInfo {
1461*bb4ee6a4SAndroid Build Coastguard Worker address: 0x55,
1462*bb4ee6a4SAndroid Build Coastguard Worker offset: 0x15,
1463*bb4ee6a4SAndroid Build Coastguard Worker id: 0,
1464*bb4ee6a4SAndroid Build Coastguard Worker },
1465*bb4ee6a4SAndroid Build Coastguard Worker &mut [0],
1466*bb4ee6a4SAndroid Build Coastguard Worker );
1467*bb4ee6a4SAndroid Build Coastguard Worker }
1468*bb4ee6a4SAndroid Build Coastguard Worker }
1469