gateware,runtime: optimize RTIO kernel interface further

* now pinning (TODO: atomicity)
* for inputs, merge request and timeout registers
This commit is contained in:
Sebastien Bourdeauducq 2018-11-08 18:29:24 +08:00
parent aadf5112b7
commit 8caea0e6d3
26 changed files with 99 additions and 100 deletions

View File

@ -1946,8 +1946,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
def printf(format_string, *args): def printf(format_string, *args):
format = ir.Constant(format_string, builtins.TStr()) format = ir.Constant(format_string, builtins.TStr())
if as_rtio: if as_rtio:
now_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt64())) self.append(ir.Builtin("rtio_log", [format, *args], builtins.TNone()))
self.append(ir.Builtin("rtio_log", [now_mu, format, *args], builtins.TNone()))
else: else:
self.append(ir.Builtin("printf", [format, *args], builtins.TNone())) self.append(ir.Builtin("printf", [format, *args], builtins.TNone()))

View File

@ -336,7 +336,7 @@ class LLVMIRGenerator:
elif name == self.target.print_function: elif name == self.target.print_function:
llty = ll.FunctionType(llvoid, [llptr], var_arg=True) llty = ll.FunctionType(llvoid, [llptr], var_arg=True)
elif name == "rtio_log": elif name == "rtio_log":
llty = ll.FunctionType(llvoid, [lli64, llptr], var_arg=True) llty = ll.FunctionType(llvoid, [llptr], var_arg=True)
elif name == "__artiq_personality": elif name == "__artiq_personality":
llty = ll.FunctionType(lli32, [], var_arg=True) llty = ll.FunctionType(lli32, [], var_arg=True)
elif name == "__artiq_raise": elif name == "__artiq_raise":
@ -1137,7 +1137,7 @@ class LLVMIRGenerator:
lloperands = [] lloperands = []
for i, operand in enumerate(insn.operands): for i, operand in enumerate(insn.operands):
lloperand = self.map(operand) lloperand = self.map(operand)
if i == 0 and insn.op == "printf" or i == 1 and insn.op == "rtio_log": if i == 0 and (insn.op == "printf" or insn.op == "rtio_log"):
lloperands.append(self.llbuilder.extract_value(lloperand, 0)) lloperands.append(self.llbuilder.extract_value(lloperand, 0))
elif builtins.is_str(operand.type) or builtins.is_bytes(operand.type): elif builtins.is_str(operand.type) or builtins.is_bytes(operand.type):
lloperands.append(self.llbuilder.extract_value(lloperand, 1)) lloperands.append(self.llbuilder.extract_value(lloperand, 1))

View File

@ -3,13 +3,12 @@ from artiq.language.types import TInt64, TInt32, TNone, TList
@syscall(flags={"nowrite"}) @syscall(flags={"nowrite"})
def rtio_output(time_mu: TInt64, target: TInt32, data: TInt32) -> TNone: def rtio_output(target: TInt32, data: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")
@syscall(flags={"nowrite"}) @syscall(flags={"nowrite"})
def rtio_output_wide(time_mu: TInt64, target: TInt32, def rtio_output_wide(target: TInt32, data: TList(TInt32)) -> TNone:
data: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")

View File

@ -42,7 +42,7 @@ class TTLOut:
@kernel @kernel
def set_o(self, o): def set_o(self, o):
rtio_output(now_mu(), self.target_o, 1 if o else 0) rtio_output(self.target_o, 1 if o else 0)
@kernel @kernel
def on(self): def on(self):
@ -120,7 +120,7 @@ class TTLInOut:
@kernel @kernel
def set_oe(self, oe): def set_oe(self, oe):
rtio_output(now_mu(), self.target_oe, 1 if oe else 0) rtio_output(self.target_oe, 1 if oe else 0)
@kernel @kernel
def output(self): def output(self):
@ -142,7 +142,7 @@ class TTLInOut:
@kernel @kernel
def set_o(self, o): def set_o(self, o):
rtio_output(now_mu(), self.target_o, 1 if o else 0) rtio_output(self.target_o, 1 if o else 0)
@kernel @kernel
def on(self): def on(self):
@ -187,7 +187,7 @@ class TTLInOut:
# Input API: gating # Input API: gating
@kernel @kernel
def _set_sensitivity(self, value): def _set_sensitivity(self, value):
rtio_output(now_mu(), self.target_sens, value) rtio_output(self.target_sens, value)
@kernel @kernel
def gate_rising_mu(self, duration): def gate_rising_mu(self, duration):
@ -361,7 +361,7 @@ class TTLInOut:
position of the time cursor. position of the time cursor.
The time cursor is not modified by this function.""" The time cursor is not modified by this function."""
rtio_output(now_mu(), self.target_sample, 0) rtio_output(self.target_sample, 0)
@kernel @kernel
def sample_get(self): def sample_get(self):
@ -398,13 +398,13 @@ class TTLInOut:
The time cursor is not modified by this function. The time cursor is not modified by this function.
""" """
rtio_output(now_mu(), self.target_sample, 2) # gate falling rtio_output(self.target_sample, 2) # gate falling
return rtio_input_data(self.channel) == 1 return rtio_input_data(self.channel) == 1
@kernel @kernel
def watch_stay_off(self): def watch_stay_off(self):
"""Like :meth:`watch_stay_on`, but for low levels.""" """Like :meth:`watch_stay_on`, but for low levels."""
rtio_output(now_mu(), self.target_sample, 1) # gate rising rtio_output(self.target_sample, 1) # gate rising
return rtio_input_data(self.channel) == 0 return rtio_input_data(self.channel) == 0
@kernel @kernel
@ -417,7 +417,7 @@ class TTLInOut:
The time cursor is not modified by this function. This function The time cursor is not modified by this function. This function
always makes the slack negative. always makes the slack negative.
""" """
rtio_output(now_mu(), self.target_sens, 0) rtio_output(self.target_sens, 0)
success = True success = True
try: try:
while rtio_input_timestamp(now_mu(), self.channel) != -1: while rtio_input_timestamp(now_mu(), self.channel) != -1:
@ -479,7 +479,7 @@ class TTLClockGen:
Due to the way the clock generator operates, frequency tuning words Due to the way the clock generator operates, frequency tuning words
that are not powers of two cause jitter of one RTIO clock cycle at the that are not powers of two cause jitter of one RTIO clock cycle at the
output.""" output."""
rtio_output(now_mu(), self.target, frequency) rtio_output(self.target, frequency)
@kernel @kernel
def set(self, frequency): def set(self, frequency):

View File

@ -1,3 +1,5 @@
use board_misoc::csr;
macro_rules! api { macro_rules! api {
($i:ident) => ({ ($i:ident) => ({
extern { static $i: u8; } extern { static $i: u8; }
@ -78,7 +80,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
/* proxified syscalls */ /* proxified syscalls */
api!(core_log), api!(core_log),
api!(now = &::NOW as *const _), api!(now = csr::rtio::NOW_HI_ADDR as *const _),
api!(watchdog_set = ::watchdog_set), api!(watchdog_set = ::watchdog_set),
api!(watchdog_clear = ::watchdog_clear), api!(watchdog_clear = ::watchdog_clear),

View File

@ -12,7 +12,7 @@ struct slice {
}; };
void send_to_core_log(struct slice str); void send_to_core_log(struct slice str);
void send_to_rtio_log(long long int timestamp, struct slice data); void send_to_rtio_log(struct slice data);
#define KERNELCPU_EXEC_ADDRESS 0x40800000 #define KERNELCPU_EXEC_ADDRESS 0x40800000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000 #define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
@ -139,8 +139,8 @@ int core_log(const char *fmt, ...)
} }
/* called by kernel */ /* called by kernel */
void rtio_log(long long int timestamp, const char *fmt, ...); void rtio_log(const char *fmt, ...);
void rtio_log(long long int timestamp, const char *fmt, ...) void rtio_log(const char *fmt, ...)
{ {
va_list args; va_list args;
@ -154,5 +154,5 @@ void rtio_log(long long int timestamp, const char *fmt, ...)
va_end(args); va_end(args);
struct slice str = { buf, size }; struct slice str = { buf, size };
send_to_rtio_log(timestamp, str); send_to_rtio_log(str);
} }

View File

@ -99,7 +99,6 @@ mod api;
mod rtio; mod rtio;
mod nrt_bus; mod nrt_bus;
static mut NOW: u64 = 0;
static mut LIBRARY: Option<Library<'static>> = None; static mut LIBRARY: Option<Library<'static>> = None;
#[no_mangle] #[no_mangle]
@ -114,8 +113,8 @@ pub extern fn send_to_core_log(text: CSlice<u8>) {
} }
#[no_mangle] #[no_mangle]
pub extern fn send_to_rtio_log(timestamp: i64, text: CSlice<u8>) { pub extern fn send_to_rtio_log(text: CSlice<u8>) {
rtio::log(timestamp, text.as_ref()) rtio::log(text.as_ref())
} }
#[unwind(aborts)] #[unwind(aborts)]
@ -184,7 +183,6 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! {
} }
let backtrace = &mut backtrace.as_mut()[0..cursor]; let backtrace = &mut backtrace.as_mut()[0..cursor];
send(&NowSave(unsafe { NOW }));
send(&RunException { send(&RunException {
exception: kernel_proto::Exception { exception: kernel_proto::Exception {
name: str::from_utf8(exception.name.as_ref()).unwrap(), name: str::from_utf8(exception.name.as_ref()).unwrap(),
@ -508,10 +506,7 @@ pub unsafe fn main() {
ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize);
send(&NowInitRequest);
recv!(&NowInitReply(now) => NOW = now);
(mem::transmute::<u32, fn()>(__modinit__))(); (mem::transmute::<u32, fn()>(__modinit__))();
send(&NowSave(NOW));
if let Some(typeinfo) = typeinfo { if let Some(typeinfo) = typeinfo {
attribute_writeback(typeinfo as *const ()); attribute_writeback(typeinfo as *const ());

View File

@ -51,7 +51,8 @@ mod imp {
} }
#[inline(never)] #[inline(never)]
unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) { unsafe fn process_exceptional_status(channel: i32, status: u8) {
let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64);
if status & RTIO_O_STATUS_WAIT != 0 { if status & RTIO_O_STATUS_WAIT != 0 {
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {} while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
} }
@ -67,30 +68,28 @@ mod imp {
} }
} }
pub extern fn output(timestamp: i64, target: i32, data: i32) { pub extern fn output(target: i32, data: i32) {
unsafe { unsafe {
csr::rtio::target_write(target as u32); csr::rtio::target_write(target as u32);
// writing timestamp clears o_data // writing target clears o_data
csr::rtio::timestamp_write(timestamp as u64);
rtio_o_data_write(0, data as _); rtio_o_data_write(0, data as _);
let status = csr::rtio::o_status_read(); let status = csr::rtio::o_status_read();
if status != 0 { if status != 0 {
process_exceptional_status(timestamp, target >> 8, status); process_exceptional_status(target >> 8, status);
} }
} }
} }
pub extern fn output_wide(timestamp: i64, target: i32, data: CSlice<i32>) { pub extern fn output_wide(target: i32, data: CSlice<i32>) {
unsafe { unsafe {
csr::rtio::target_write(target as u32); csr::rtio::target_write(target as u32);
// writing timestamp clears o_data // writing target clears o_data
csr::rtio::timestamp_write(timestamp as u64);
for i in 0..data.len() { for i in 0..data.len() {
rtio_o_data_write(i, data[i] as _) rtio_o_data_write(i, data[i] as _)
} }
let status = csr::rtio::o_status_read(); let status = csr::rtio::o_status_read();
if status != 0 { if status != 0 {
process_exceptional_status(timestamp, target >> 8, status); process_exceptional_status(target >> 8, status);
} }
} }
} }
@ -98,8 +97,7 @@ mod imp {
pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 { pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 {
unsafe { unsafe {
csr::rtio::target_write((channel as u32) << 8); csr::rtio::target_write((channel as u32) << 8);
csr::rtio::timestamp_write(timeout as u64); csr::rtio::i_timeout_write(timeout as u64);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS; let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 { while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
@ -128,8 +126,7 @@ mod imp {
pub extern fn input_data(channel: i32) -> i32 { pub extern fn input_data(channel: i32) -> i32 {
unsafe { unsafe {
csr::rtio::target_write((channel as u32) << 8); csr::rtio::target_write((channel as u32) << 8);
csr::rtio::timestamp_write(0xffffffff_ffffffff); csr::rtio::i_timeout_write(0xffffffff_ffffffff);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS; let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 { while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
@ -153,10 +150,9 @@ mod imp {
} }
#[cfg(has_rtio_log)] #[cfg(has_rtio_log)]
pub fn log(timestamp: i64, data: &[u8]) { pub fn log(data: &[u8]) {
unsafe { unsafe {
csr::rtio::target_write(csr::CONFIG_RTIO_LOG_CHANNEL << 8); csr::rtio::target_write(csr::CONFIG_RTIO_LOG_CHANNEL << 8);
csr::rtio::timestamp_write(timestamp as u64);
let mut word: u32 = 0; let mut word: u32 = 0;
for i in 0..data.len() { for i in 0..data.len() {
@ -175,7 +171,7 @@ mod imp {
} }
#[cfg(not(has_rtio_log))] #[cfg(not(has_rtio_log))]
pub fn log(_timestamp: i64, _data: &[u8]) { pub fn log(_data: &[u8]) {
unimplemented!("not(has_rtio_log)") unimplemented!("not(has_rtio_log)")
} }
} }

View File

@ -22,10 +22,6 @@ pub enum Message<'a> {
LoadRequest(&'a [u8]), LoadRequest(&'a [u8]),
LoadReply(Result<(), dyld::Error<'a>>), LoadReply(Result<(), dyld::Error<'a>>),
NowInitRequest,
NowInitReply(u64),
NowSave(u64),
RtioInitRequest, RtioInitRequest,
RtioDestinationStatusRequest { destination: u8 }, RtioDestinationStatusRequest { destination: u8 },

View File

@ -63,7 +63,6 @@ macro_rules! unexpected {
// Persistent state // Persistent state
#[derive(Debug)] #[derive(Debug)]
struct Congress { struct Congress {
now: u64,
cache: Cache, cache: Cache,
dma_manager: DmaManager, dma_manager: DmaManager,
finished_cleanly: Cell<bool> finished_cleanly: Cell<bool>
@ -72,7 +71,6 @@ struct Congress {
impl Congress { impl Congress {
fn new() -> Congress { fn new() -> Congress {
Congress { Congress {
now: 0,
cache: Cache::new(), cache: Cache::new(),
dma_manager: DmaManager::new(), dma_manager: DmaManager::new(),
finished_cleanly: Cell::new(true) finished_cleanly: Cell::new(true)
@ -365,14 +363,6 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
kern_acknowledge() kern_acknowledge()
} }
&kern::NowInitRequest =>
kern_send(io, &kern::NowInitReply(session.congress.now)),
&kern::NowSave(now) => {
session.congress.now = now;
kern_acknowledge()
}
&kern::DmaRecordStart(name) => { &kern::DmaRecordStart(name) => {
session.congress.dma_manager.record_start(name); session.congress.dma_manager.record_start(name);
kern_acknowledge() kern_acknowledge()

View File

@ -73,7 +73,11 @@ class RTController(Module):
rt_packet.sr_chan_sel.eq(chan_sel), rt_packet.sr_chan_sel.eq(chan_sel),
rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_address.eq(self.cri.o_address),
rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_data.eq(self.cri.o_data),
rt_packet.sr_timestamp.eq(self.cri.timestamp), If(rt_packet_read_request,
rt_packet.sr_timestamp.eq(self.cri.i_timeout)
).Else(
rt_packet.sr_timestamp.eq(self.cri.o_timestamp)
),
If(rt_packet_buffer_request, If(rt_packet_buffer_request,
rt_packet.sr_notwrite.eq(1), rt_packet.sr_notwrite.eq(1),
rt_packet.sr_address.eq(0) rt_packet.sr_address.eq(0)
@ -103,7 +107,7 @@ class RTController(Module):
self.submodules += timeout_counter self.submodules += timeout_counter
cond_underflow = Signal() cond_underflow = Signal()
self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] self.comb += cond_underflow.eq((self.cri.o_timestamp[tsc.glbl_fine_ts_width:]
- self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys)
# buffer space # buffer space

View File

@ -61,7 +61,7 @@ class RTErrorsSatellite(Module, AutoCSR):
underflow.eq(cri.o_status[1]), underflow.eq(cri.o_status[1]),
overflow.eq(cri.o_status[0]), overflow.eq(cri.o_status[0]),
underflow_error_cri.eq(Cat(cri.chan_sel[:16], underflow_error_cri.eq(Cat(cri.chan_sel[:16],
cri.timestamp, cri.o_timestamp,
tsc.full_ts_cri)), tsc.full_ts_cri)),
Cat(self.underflow_channel.status, Cat(self.underflow_channel.status,
self.underflow_timestamp_event.status, self.underflow_timestamp_event.status,

View File

@ -68,7 +68,11 @@ class RTPacketRepeater(Module):
If(~self.reset & ~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), If(~self.reset & ~cb0_loaded & (self.cri.cmd != cri.commands["nop"]),
cb0_loaded.eq(1), cb0_loaded.eq(1),
cb0_cmd.eq(self.cri.cmd), cb0_cmd.eq(self.cri.cmd),
cb0_timestamp.eq(self.cri.timestamp), If(self.cri.cmd == cri.commands["read"],
cb0_timestamp.eq(self.cri.i_timeout)
).Else(
cb0_timestamp.eq(self.cri.o_timestamp)
),
cb0_chan_sel.eq(self.cri.chan_sel), cb0_chan_sel.eq(self.cri.chan_sel),
cb0_o_address.eq(self.cri.o_address), cb0_o_address.eq(self.cri.o_address),
cb0_o_data.eq(self.cri.o_data) cb0_o_data.eq(self.cri.o_data)

View File

@ -94,13 +94,10 @@ class RTPacketSatellite(Module):
self.cri.chan_sel.eq( self.cri.chan_sel.eq(
rx_dp.packet_as["write"].chan_sel), rx_dp.packet_as["write"].chan_sel),
), ),
If(cri_read | read_request_pending, self.cri.i_timeout.eq(
self.cri.timestamp.eq( rx_dp.packet_as["read_request"].timeout),
rx_dp.packet_as["read_request"].timeout) self.cri.o_timestamp.eq(
).Else( rx_dp.packet_as["write"].timestamp),
self.cri.timestamp.eq(
rx_dp.packet_as["write"].timestamp)
),
self.cri.o_address.eq( self.cri.o_address.eq(
rx_dp.packet_as["write"].address), rx_dp.packet_as["write"].address),
self.cri.o_data.eq( self.cri.o_data.eq(

View File

@ -70,7 +70,7 @@ class MessageEncoder(Module, AutoCSR):
input_output.rtio_counter.eq(tsc.full_ts_cri), input_output.rtio_counter.eq(tsc.full_ts_cri),
If(cri.cmd == cri_commands["write"], If(cri.cmd == cri_commands["write"],
input_output.message_type.eq(MessageType.output.value), input_output.message_type.eq(MessageType.output.value),
input_output.timestamp.eq(cri.timestamp), input_output.timestamp.eq(cri.o_timestamp),
input_output.data.eq(cri.o_data) input_output.data.eq(cri.o_data)
).Else( ).Else(
input_output.message_type.eq(MessageType.input.value), input_output.message_type.eq(MessageType.input.value),

View File

@ -29,8 +29,8 @@ layout = [
# 8 MSBs of chan_sel = routing destination # 8 MSBs of chan_sel = routing destination
# 16 LSBs of chan_sel = channel within the destination # 16 LSBs of chan_sel = channel within the destination
("chan_sel", 24, DIR_M_TO_S), ("chan_sel", 24, DIR_M_TO_S),
("timestamp", 64, DIR_M_TO_S),
("o_timestamp", 64, DIR_M_TO_S),
("o_data", 512, DIR_M_TO_S), ("o_data", 512, DIR_M_TO_S),
("o_address", 8, DIR_M_TO_S), ("o_address", 8, DIR_M_TO_S),
# o_status bits: # o_status bits:
@ -43,6 +43,7 @@ layout = [
("o_buffer_space_valid", 1, DIR_S_TO_M), ("o_buffer_space_valid", 1, DIR_S_TO_M),
("o_buffer_space", 16, DIR_S_TO_M), ("o_buffer_space", 16, DIR_S_TO_M),
("i_timeout", 64, DIR_M_TO_S),
("i_data", 32, DIR_S_TO_M), ("i_data", 32, DIR_S_TO_M),
("i_timestamp", 64, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M),
# i_status bits: # i_status bits:
@ -61,17 +62,19 @@ class Interface(Record):
class KernelInitiator(Module, AutoCSR): class KernelInitiator(Module, AutoCSR):
def __init__(self, tsc, cri=None): def __init__(self, tsc, cri=None):
self.target = CSRStorage(32) self.target = CSRStorage(32)
self.timestamp = CSRStorage(64) # not using CSRStorage atomic_write feature here to make storage reset_less
self.now_hi = CSR(32)
self.now_lo = CSR(32)
# Writing timestamp clears o_data. This implements automatic # Writing target clears o_data. This implements automatic
# zero-extension of output event data by the gateware. When staging an # zero-extension of output event data by the gateware. When staging an
# output event, always write timestamp before o_data. # output event, always write target before o_data.
self.o_data = CSRStorage(512, write_from_dev=True) self.o_data = CSRStorage(512, write_from_dev=True)
self.o_status = CSRStatus(3) self.o_status = CSRStatus(3)
self.i_timeout = CSRStorage(64)
self.i_data = CSRStatus(32) self.i_data = CSRStatus(32)
self.i_timestamp = CSRStatus(64) self.i_timestamp = CSRStatus(64)
self.i_request = CSR()
self.i_status = CSRStatus(4) self.i_status = CSRStatus(4)
self.i_overflow_reset = CSR() self.i_overflow_reset = CSR()
@ -84,24 +87,39 @@ class KernelInitiator(Module, AutoCSR):
# # # # # #
now_lo_backing = Signal(32)
now = Signal(64, reset_less=True)
self.sync += [
# TODO: fix compiler and make atomic
#If(self.now_lo.re, now_lo_backing.eq(self.now_lo.r)),
#If(self.now_hi.re, now.eq(Cat(now_lo_backing, self.now_hi.r)))
If(self.now_lo.re, now[:32].eq(self.now_lo.r)),
If(self.now_hi.re, now[32:].eq(self.now_hi.r))
]
self.comb += [
self.now_lo.w.eq(now[:32]),
self.now_hi.w.eq(now[32:])
]
self.comb += [ self.comb += [
self.cri.cmd.eq(commands["nop"]), self.cri.cmd.eq(commands["nop"]),
If(self.o_data.re, self.cri.cmd.eq(commands["write"])), If(self.o_data.re, self.cri.cmd.eq(commands["write"])),
If(self.i_request.re, self.cri.cmd.eq(commands["read"])), If(self.i_timeout.re, self.cri.cmd.eq(commands["read"])),
self.cri.chan_sel.eq(self.target.storage[8:]), self.cri.chan_sel.eq(self.target.storage[8:]),
self.cri.timestamp.eq(self.timestamp.storage),
self.cri.o_timestamp.eq(now),
self.cri.o_data.eq(self.o_data.storage), self.cri.o_data.eq(self.o_data.storage),
self.cri.o_address.eq(self.target.storage[:8]), self.cri.o_address.eq(self.target.storage[:8]),
self.o_status.status.eq(self.cri.o_status), self.o_status.status.eq(self.cri.o_status),
self.cri.i_timeout.eq(self.i_timeout.storage),
self.i_data.status.eq(self.cri.i_data), self.i_data.status.eq(self.cri.i_data),
self.i_timestamp.status.eq(self.cri.i_timestamp), self.i_timestamp.status.eq(self.cri.i_timestamp),
self.i_status.status.eq(self.cri.i_status), self.i_status.status.eq(self.cri.i_status),
self.o_data.dat_w.eq(0), self.o_data.dat_w.eq(0),
self.o_data.we.eq(self.timestamp.re), self.o_data.we.eq(self.target.re),
] ]
self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri))

View File

@ -274,7 +274,7 @@ class CRIMaster(Module, AutoCSR):
self.comb += [ self.comb += [
self.cri.chan_sel.eq(self.sink.channel), self.cri.chan_sel.eq(self.sink.channel),
self.cri.timestamp.eq(self.sink.timestamp), self.cri.o_timestamp.eq(self.sink.timestamp),
self.cri.o_address.eq(self.sink.address), self.cri.o_address.eq(self.sink.address),
self.cri.o_data.eq(self.sink.data) self.cri.o_data.eq(self.sink.data)
] ]

View File

@ -118,7 +118,7 @@ class InputCollector(Module):
i_status_raw = Signal(2) i_status_raw = Signal(2)
self.comb += i_status_raw.eq(Array(i_statuses)[sel]) self.comb += i_status_raw.eq(Array(i_statuses)[sel])
input_timeout = Signal.like(self.cri.timestamp, reset_less=True) input_timeout = Signal.like(self.cri.i_timeout, reset_less=True)
input_pending = Signal() input_pending = Signal()
self.cri.i_data.reset_less = True self.cri.i_data.reset_less = True
self.cri.i_timestamp.reset_less = True self.cri.i_timestamp.reset_less = True
@ -134,7 +134,7 @@ class InputCollector(Module):
input_pending.eq(0) input_pending.eq(0)
), ),
If(self.cri.cmd == cri.commands["read"], If(self.cri.cmd == cri.commands["read"],
input_timeout.eq(self.cri.timestamp), input_timeout.eq(self.cri.i_timeout),
input_pending.eq(1), input_pending.eq(1),
self.cri.i_status.eq(0b100) self.cri.i_status.eq(0b100)
) )

View File

@ -60,7 +60,7 @@ class LaneDistributor(Module):
self.comb += [ self.comb += [
lio.seqn.eq(seqn), lio.seqn.eq(seqn),
lio.payload.channel.eq(self.cri.chan_sel[:16]), lio.payload.channel.eq(self.cri.chan_sel[:16]),
lio.payload.timestamp.eq(self.cri.timestamp), lio.payload.timestamp.eq(self.cri.o_timestamp),
] ]
if hasattr(lio.payload, "address"): if hasattr(lio.payload, "address"):
self.comb += lio.payload.address.eq(self.cri.o_address) self.comb += lio.payload.address.eq(self.cri.o_address)
@ -69,7 +69,7 @@ class LaneDistributor(Module):
# when timestamp and channel arrive in cycle #1, prepare computations # when timestamp and channel arrive in cycle #1, prepare computations
coarse_timestamp = Signal(us_timestamp_width) coarse_timestamp = Signal(us_timestamp_width)
self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) self.comb += coarse_timestamp.eq(self.cri.o_timestamp[glbl_fine_ts_width:])
min_minus_timestamp = Signal((us_timestamp_width + 1, True), min_minus_timestamp = Signal((us_timestamp_width + 1, True),
reset_less=True) reset_less=True)
laneAmin_minus_timestamp = Signal.like(min_minus_timestamp) laneAmin_minus_timestamp = Signal.like(min_minus_timestamp)
@ -141,7 +141,7 @@ class LaneDistributor(Module):
Array(lio.we for lio in self.output)[use_lanen].eq(do_write) Array(lio.we for lio in self.output)[use_lanen].eq(do_write)
] ]
compensated_timestamp = Signal(64) compensated_timestamp = Signal(64)
self.comb += compensated_timestamp.eq(self.cri.timestamp + (compensation << glbl_fine_ts_width)) self.comb += compensated_timestamp.eq(self.cri.o_timestamp + (compensation << glbl_fine_ts_width))
self.sync += [ self.sync += [
If(do_write, If(do_write,
current_lane.eq(use_lanen), current_lane.eq(use_lanen),

View File

@ -112,10 +112,10 @@ class OutputsTestbench:
def write(self, channel, data): def write(self, channel, data):
kcsrs = self.dut.master_ki kcsrs = self.dut.master_ki
yield from kcsrs.chan_sel.write(channel) yield from kcsrs.target.write(channel << 8)
yield from kcsrs.timestamp.write(self.now) yield from kcsrs.now_hi.write(self.now >> 32)
yield from kcsrs.now_lo.write(self.now & 0xffffffff)
yield from kcsrs.o_data.write(data) yield from kcsrs.o_data.write(data)
yield from kcsrs.o_we.write(1)
yield yield
status = 1 status = 1
wlen = 0 wlen = 0
@ -249,9 +249,8 @@ class TestFullStack(unittest.TestCase):
kcsrs = dut.master_ki kcsrs = dut.master_ki
def get_input(timeout): def get_input(timeout):
yield from kcsrs.chan_sel.write(2) yield from kcsrs.target.write(2 << 8)
yield from kcsrs.timestamp.write(10) yield from kcsrs.i_timeout.write(10)
yield from kcsrs.i_request.write(1)
yield yield
status = yield from kcsrs.i_status.read() status = yield from kcsrs.i_status.read()
while status & 0x4: while status & 0x4:

View File

@ -65,7 +65,7 @@ class TestRepeater(unittest.TestCase):
yield yield
for channel, timestamp, address, data in test_writes: for channel, timestamp, address, data in test_writes:
yield dut.cri.chan_sel.eq(channel) yield dut.cri.chan_sel.eq(channel)
yield dut.cri.timestamp.eq(timestamp) yield dut.cri.o_timestamp.eq(timestamp)
yield dut.cri.o_address.eq(address) yield dut.cri.o_address.eq(address)
yield dut.cri.o_data.eq(data) yield dut.cri.o_data.eq(data)
yield dut.cri.cmd.eq(cri.commands["write"]) yield dut.cri.cmd.eq(cri.commands["write"])
@ -135,7 +135,7 @@ class TestRepeater(unittest.TestCase):
def read(chan_sel, timeout): def read(chan_sel, timeout):
yield dut.cri.chan_sel.eq(chan_sel) yield dut.cri.chan_sel.eq(chan_sel)
yield dut.cri.timestamp.eq(timeout) yield dut.cri.i_timeout.eq(timeout)
yield dut.cri.cmd.eq(cri.commands["read"]) yield dut.cri.cmd.eq(cri.commands["read"])
yield yield
yield dut.cri.cmd.eq(cri.commands["nop"]) yield dut.cri.cmd.eq(cri.commands["nop"])

View File

@ -90,7 +90,7 @@ class Testbench:
def write(self, channel, data): def write(self, channel, data):
mcri = self.dut.master.cri mcri = self.dut.master.cri
yield mcri.chan_sel.eq(channel) yield mcri.chan_sel.eq(channel)
yield mcri.timestamp.eq(self.now) yield mcri.o_timestamp.eq(self.now)
yield mcri.o_data.eq(data) yield mcri.o_data.eq(data)
yield yield
yield mcri.cmd.eq(cri.commands["write"]) yield mcri.cmd.eq(cri.commands["write"])
@ -109,7 +109,7 @@ class Testbench:
def read(self, channel, timeout): def read(self, channel, timeout):
mcri = self.dut.master.cri mcri = self.dut.master.cri
yield mcri.chan_sel.eq(channel) yield mcri.chan_sel.eq(channel)
yield mcri.timestamp.eq(timeout) yield mcri.i_timeout.eq(timeout)
yield yield
yield mcri.cmd.eq(cri.commands["read"]) yield mcri.cmd.eq(cri.commands["read"])
yield yield

View File

@ -26,7 +26,7 @@ def encode_record(channel, timestamp, address, data):
r = [] r = []
r += encode_n(channel, 3, 3) r += encode_n(channel, 3, 3)
r += encode_n(timestamp, 8, 8) r += encode_n(timestamp, 8, 8)
r += encode_n(address, 2, 2) r += encode_n(address, 1, 1)
r += encode_n(data, 1, 64) r += encode_n(data, 1, 64)
return encode_n(len(r)+1, 1, 1) + r return encode_n(len(r)+1, 1, 1) + r
@ -66,7 +66,7 @@ def do_dma(dut, address):
test_writes1 = [ test_writes1 = [
(0x01, 0x23, 0x12, 0x33), (0x01, 0x23, 0x12, 0x33),
(0x901, 0x902, 0x911, 0xeeeeeeeeeeeeeefffffffffffffffffffffffffffffff28888177772736646717738388488), (0x901, 0x902, 0x11, 0xeeeeeeeeeeeeeefffffffffffffffffffffffffffffff28888177772736646717738388488),
(0x81, 0x288, 0x88, 0x8888) (0x81, 0x288, 0x88, 0x8888)
] ]
@ -150,7 +150,7 @@ class TestDMA(unittest.TestCase):
pass pass
elif cmd == cri.commands["write"]: elif cmd == cri.commands["write"]:
channel = yield dut_cri.chan_sel channel = yield dut_cri.chan_sel
timestamp = yield dut_cri.timestamp timestamp = yield dut_cri.o_timestamp
address = yield dut_cri.o_address address = yield dut_cri.o_address
data = yield dut_cri.o_data data = yield dut_cri.o_data
received.append((channel, timestamp, address, data)) received.append((channel, timestamp, address, data))

View File

@ -54,7 +54,7 @@ def simulate(wait_cycles, ts_timeouts):
yield yield
for ts_timeout in ts_timeouts: for ts_timeout in ts_timeouts:
yield dut.cri.timestamp.eq(ts_timeout) yield dut.cri.i_timeout.eq(ts_timeout)
yield dut.cri.cmd.eq(cri.commands["read"]) yield dut.cri.cmd.eq(cri.commands["read"])
yield yield
yield dut.cri.cmd.eq(cri.commands["nop"]) yield dut.cri.cmd.eq(cri.commands["nop"])

View File

@ -21,7 +21,7 @@ def simulate(input_events, compensation=None, wait=True):
def gen(): def gen():
for channel, timestamp in input_events: for channel, timestamp in input_events:
yield dut.cri.chan_sel.eq(channel) yield dut.cri.chan_sel.eq(channel)
yield dut.cri.timestamp.eq(timestamp) yield dut.cri.o_timestamp.eq(timestamp)
yield yield
yield dut.cri.cmd.eq(cri.commands["write"]) yield dut.cri.cmd.eq(cri.commands["write"])

View File

@ -38,7 +38,7 @@ def simulate(input_events, **kwargs):
def gen(): def gen():
yield dut.sed.cri.chan_sel.eq(0) yield dut.sed.cri.chan_sel.eq(0)
for timestamp, data in input_events: for timestamp, data in input_events:
yield dut.sed.cri.timestamp.eq(timestamp) yield dut.sed.cri.o_timestamp.eq(timestamp)
yield dut.sed.cri.o_data.eq(data) yield dut.sed.cri.o_data.eq(data)
yield yield