mirror of https://github.com/m-labs/artiq.git
parent
674bf82f3a
commit
14ae1cc100
|
@ -16,7 +16,7 @@ def dma_record_start() -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall
|
||||||
def dma_record_stop(name: TStr) -> TNone:
|
def dma_record_stop(name: TStr, duration: TInt64) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall
|
||||||
|
@ -51,7 +51,7 @@ class DMARecordContextManager:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
dma_record_stop(self.name) # see above
|
dma_record_stop(self.name, now_mu()) # see above
|
||||||
at_mu(self.saved_now_mu)
|
at_mu(self.saved_now_mu)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ extern fn dma_record_start() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn dma_record_stop(name: CSlice<u8>) {
|
extern fn dma_record_stop(name: CSlice<u8>, duration: i64) {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -272,7 +272,10 @@ extern fn dma_record_stop(name: CSlice<u8>) {
|
||||||
rtio::output_wide as *const () as u32).unwrap();
|
rtio::output_wide as *const () as u32).unwrap();
|
||||||
|
|
||||||
DMA_RECORDING = false;
|
DMA_RECORDING = false;
|
||||||
send(&DmaRecordStop(name));
|
send(&DmaRecordStop {
|
||||||
|
name: name,
|
||||||
|
duration: duration as u64
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,15 +301,16 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, dat
|
||||||
extern fn dma_erase(name: CSlice<u8>) {
|
extern fn dma_erase(name: CSlice<u8>) {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
send(&DmaEraseRequest(name));
|
send(&DmaEraseRequest { name: name });
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn dma_playback(timestamp: i64, name: CSlice<u8>) {
|
extern fn dma_playback(timestamp: i64, name: CSlice<u8>) {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
send(&DmaPlaybackRequest(name));
|
send(&DmaPlaybackRequest { name: name });
|
||||||
let succeeded = recv!(&DmaPlaybackReply(data) => unsafe {
|
let (succeeded, now_advance) =
|
||||||
match data {
|
recv!(&DmaPlaybackReply { trace, duration } => unsafe {
|
||||||
|
match trace {
|
||||||
Some(bytes) => {
|
Some(bytes) => {
|
||||||
let ptr = bytes.as_ptr() as usize;
|
let ptr = bytes.as_ptr() as usize;
|
||||||
assert!(ptr % 64 == 0);
|
assert!(ptr % 64 == 0);
|
||||||
|
@ -319,9 +323,10 @@ extern fn dma_playback(timestamp: i64, name: CSlice<u8>) {
|
||||||
while csr::rtio_dma::enable_read() != 0 {}
|
while csr::rtio_dma::enable_read() != 0 {}
|
||||||
csr::cri_con::selected_write(0);
|
csr::cri_con::selected_write(0);
|
||||||
|
|
||||||
true
|
(true, duration)
|
||||||
}
|
}
|
||||||
None => false
|
None =>
|
||||||
|
(false, 0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -347,6 +352,8 @@ extern fn dma_playback(timestamp: i64, name: CSlice<u8>) {
|
||||||
"RTIO sequence error at {0} mu, channel {1}",
|
"RTIO sequence error at {0} mu, channel {1}",
|
||||||
timestamp as i64, channel as i64, 0)
|
timestamp as i64, channel as i64, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NOW += now_advance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,22 @@ pub enum Message<'a> {
|
||||||
address: u32,
|
address: u32,
|
||||||
data: &'a [u32]
|
data: &'a [u32]
|
||||||
},
|
},
|
||||||
DmaRecordStop(&'a str),
|
DmaRecordStop {
|
||||||
|
name: &'a str,
|
||||||
|
duration: u64
|
||||||
|
},
|
||||||
|
|
||||||
DmaEraseRequest(&'a str),
|
DmaEraseRequest {
|
||||||
|
name: &'a str
|
||||||
|
},
|
||||||
|
|
||||||
DmaPlaybackRequest(&'a str),
|
DmaPlaybackRequest {
|
||||||
DmaPlaybackReply(Option<&'a [u8]>),
|
name: &'a str
|
||||||
|
},
|
||||||
|
DmaPlaybackReply {
|
||||||
|
trace: Option<&'a [u8]>,
|
||||||
|
duration: u64
|
||||||
|
},
|
||||||
|
|
||||||
DrtioChannelStateRequest { channel: u32 },
|
DrtioChannelStateRequest { channel: u32 },
|
||||||
DrtioChannelStateReply { fifo_space: u16, last_timestamp: u64 },
|
DrtioChannelStateReply { fifo_space: u16, last_timestamp: u64 },
|
||||||
|
|
|
@ -9,7 +9,8 @@ const ALIGNMENT: usize = 64;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Entry {
|
struct Entry {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
padding: usize
|
padding: usize,
|
||||||
|
duration: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -62,7 +63,7 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_stop(&mut self, name: &str) {
|
pub fn record_stop(&mut self, name: &str, duration: u64) {
|
||||||
let mut recorded = Vec::new();
|
let mut recorded = Vec::new();
|
||||||
mem::swap(&mut self.recording, &mut recorded);
|
mem::swap(&mut self.recording, &mut recorded);
|
||||||
recorded.push(0);
|
recorded.push(0);
|
||||||
|
@ -83,6 +84,7 @@ impl Manager {
|
||||||
self.entries.insert(String::from(name), Entry {
|
self.entries.insert(String::from(name), Entry {
|
||||||
data: recorded,
|
data: recorded,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
|
duration: duration
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +92,11 @@ impl Manager {
|
||||||
self.entries.remove(name);
|
self.entries.remove(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_trace<F: FnOnce(Option<&[u8]>) -> R, R>(&self, name: &str, f: F) -> R {
|
pub fn with_trace<F, R>(&self, name: &str, f: F) -> R
|
||||||
f(self.entries
|
where F: FnOnce(Option<&[u8]>, u64) -> R {
|
||||||
.get(name)
|
match self.entries.get(name) {
|
||||||
.map(|entry| &entry.data[entry.padding..]))
|
Some(entry) => f(Some(&entry.data[entry.padding..]), entry.duration),
|
||||||
|
None => f(None, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,18 +388,21 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
|
||||||
session.congress.dma_manager.record_append(timestamp, channel, address, data);
|
session.congress.dma_manager.record_append(timestamp, channel, address, data);
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
}
|
}
|
||||||
&kern::DmaRecordStop(name) => {
|
&kern::DmaRecordStop { name, duration } => {
|
||||||
session.congress.dma_manager.record_stop(name);
|
session.congress.dma_manager.record_stop(name, duration);
|
||||||
board::cache::flush_l2_cache();
|
board::cache::flush_l2_cache();
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
}
|
}
|
||||||
&kern::DmaEraseRequest(name) => {
|
&kern::DmaEraseRequest { name } => {
|
||||||
session.congress.dma_manager.erase(name);
|
session.congress.dma_manager.erase(name);
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
}
|
}
|
||||||
&kern::DmaPlaybackRequest(name) => {
|
&kern::DmaPlaybackRequest { name } => {
|
||||||
session.congress.dma_manager.with_trace(name, |trace| {
|
session.congress.dma_manager.with_trace(name, |trace, duration| {
|
||||||
kern_send(io, &kern::DmaPlaybackReply(trace))
|
kern_send(io, &kern::DmaPlaybackReply {
|
||||||
|
trace: trace,
|
||||||
|
duration: duration
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# Copyright (C) 2014, 2015 Robert Jordens <jordens@gmail.com>
|
# Copyright (C) 2014, 2015 Robert Jordens <jordens@gmail.com>
|
||||||
|
|
||||||
import os, unittest
|
import os, unittest
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
|
|
||||||
|
@ -477,6 +478,7 @@ class _DMA(EnvExperiment):
|
||||||
self.setattr_device("core_dma")
|
self.setattr_device("core_dma")
|
||||||
self.setattr_device("ttl1")
|
self.setattr_device("ttl1")
|
||||||
self.trace_name = trace_name
|
self.trace_name = trace_name
|
||||||
|
self.delta = np.int64(0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def record(self):
|
def record(self):
|
||||||
|
@ -492,6 +494,14 @@ class _DMA(EnvExperiment):
|
||||||
delay(100*ms)
|
delay(100*ms)
|
||||||
self.core_dma.replay(self.trace_name)
|
self.core_dma.replay(self.trace_name)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def replay_delta(self):
|
||||||
|
self.core.break_realtime()
|
||||||
|
delay(100*ms)
|
||||||
|
start = now_mu()
|
||||||
|
self.core_dma.replay(self.trace_name)
|
||||||
|
self.delta = now_mu() - start
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def erase(self):
|
def erase(self):
|
||||||
self.core_dma.erase(self.trace_name)
|
self.core_dma.erase(self.trace_name)
|
||||||
|
@ -539,3 +549,9 @@ class DMATest(ExperimentCase):
|
||||||
self.assertEqual(dump.messages[1].data, 0)
|
self.assertEqual(dump.messages[1].data, 0)
|
||||||
self.assertEqual(dump.messages[1].timestamp -
|
self.assertEqual(dump.messages[1].timestamp -
|
||||||
dump.messages[0].timestamp, 100)
|
dump.messages[0].timestamp, 100)
|
||||||
|
|
||||||
|
def test_dma_delta(self):
|
||||||
|
exp = self.create(_DMA)
|
||||||
|
exp.record()
|
||||||
|
exp.replay_delta()
|
||||||
|
self.assertEqual(exp.delta, 200)
|
||||||
|
|
Loading…
Reference in New Issue