2014-08-28 16:56:48 +08:00
|
|
|
#include <generated/csr.h>
|
|
|
|
|
2016-03-03 19:48:06 +08:00
|
|
|
#include "artiq_personality.h"
|
2014-08-28 16:56:48 +08:00
|
|
|
#include "rtio.h"
|
|
|
|
|
|
|
|
void rtio_init(void)
|
|
|
|
{
|
2014-11-30 00:13:54 +08:00
|
|
|
rtio_reset_write(1);
|
|
|
|
rtio_reset_write(0);
|
2015-05-02 11:47:11 +08:00
|
|
|
rtio_reset_phy_write(0);
|
2014-08-28 16:56:48 +08:00
|
|
|
}
|
|
|
|
|
2015-05-08 14:44:39 +08:00
|
|
|
long long int rtio_get_counter(void)
|
2014-08-28 16:56:48 +08:00
|
|
|
{
|
2015-05-08 14:44:39 +08:00
|
|
|
rtio_counter_update_write(1);
|
|
|
|
return rtio_counter_read();
|
2014-09-11 23:14:45 +08:00
|
|
|
}
|
2015-07-29 19:43:35 +08:00
|
|
|
|
2016-03-02 04:38:51 +08:00
|
|
|
static void rtio_process_exceptional_status(
|
|
|
|
long long int timestamp, int channel, int status)
|
2015-07-29 19:43:35 +08:00
|
|
|
{
|
|
|
|
if(status & RTIO_O_STATUS_FULL)
|
|
|
|
while(rtio_o_status_read() & RTIO_O_STATUS_FULL);
|
|
|
|
if(status & RTIO_O_STATUS_UNDERFLOW) {
|
|
|
|
rtio_o_underflow_reset_write(1);
|
2015-11-07 14:44:20 +08:00
|
|
|
artiq_raise_from_c("RTIOUnderflow",
|
2016-01-19 08:28:37 +08:00
|
|
|
"RTIO underflow at {0} mu, channel {1}, slack {2} mu",
|
|
|
|
timestamp, channel, timestamp - rtio_get_counter());
|
2015-07-29 19:43:35 +08:00
|
|
|
}
|
|
|
|
if(status & RTIO_O_STATUS_SEQUENCE_ERROR) {
|
|
|
|
rtio_o_sequence_error_reset_write(1);
|
2015-11-07 14:44:20 +08:00
|
|
|
artiq_raise_from_c("RTIOSequenceError",
|
|
|
|
"RTIO sequence error at {0} mu, channel {1}",
|
2015-07-29 19:43:35 +08:00
|
|
|
timestamp, channel, 0);
|
|
|
|
}
|
2016-03-08 15:38:08 +08:00
|
|
|
if(status & RTIO_O_STATUS_COLLISION) {
|
|
|
|
rtio_o_collision_reset_write(1);
|
|
|
|
artiq_raise_from_c("RTIOCollision",
|
|
|
|
"RTIO collision at {0} mu, channel {1}",
|
2015-07-29 19:43:35 +08:00
|
|
|
timestamp, channel, 0);
|
|
|
|
}
|
2016-03-09 01:04:34 +08:00
|
|
|
if(status & RTIO_O_STATUS_BUSY) {
|
|
|
|
rtio_o_busy_reset_write(1);
|
|
|
|
artiq_raise_from_c("RTIOBusy",
|
2016-03-09 20:42:32 +08:00
|
|
|
"RTIO busy on channel {0}",
|
|
|
|
channel, 0, 0);
|
2016-03-09 01:04:34 +08:00
|
|
|
}
|
2015-07-29 19:43:35 +08:00
|
|
|
}
|
2015-12-26 22:44:50 +08:00
|
|
|
|
2016-03-01 02:16:29 +08:00
|
|
|
|
|
|
|
void rtio_output(long long int timestamp, int channel, unsigned int addr,
|
|
|
|
unsigned int data)
|
|
|
|
{
|
2016-03-01 22:40:35 +08:00
|
|
|
int status;
|
|
|
|
|
2016-03-01 02:16:29 +08:00
|
|
|
rtio_chan_sel_write(channel);
|
|
|
|
rtio_o_timestamp_write(timestamp);
|
2016-07-27 19:19:44 +08:00
|
|
|
#ifdef CSR_RTIO_O_ADDRESS_ADDR
|
2016-03-01 02:16:29 +08:00
|
|
|
rtio_o_address_write(addr);
|
2016-07-27 19:19:44 +08:00
|
|
|
#endif
|
2016-03-01 02:16:29 +08:00
|
|
|
rtio_o_data_write(data);
|
2016-03-01 22:40:35 +08:00
|
|
|
rtio_o_we_write(1);
|
|
|
|
status = rtio_o_status_read();
|
|
|
|
if(status)
|
2016-03-02 04:38:51 +08:00
|
|
|
rtio_process_exceptional_status(timestamp, channel, status);
|
2016-03-01 02:16:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-01 23:34:05 +08:00
|
|
|
long long int rtio_input_timestamp(long long int timeout, int channel)
|
2016-03-01 02:16:29 +08:00
|
|
|
{
|
2016-03-01 23:34:05 +08:00
|
|
|
long long int r;
|
2016-03-01 02:16:29 +08:00
|
|
|
int status;
|
|
|
|
|
|
|
|
rtio_chan_sel_write(channel);
|
|
|
|
while((status = rtio_i_status_read())) {
|
|
|
|
if(status & RTIO_I_STATUS_OVERFLOW) {
|
|
|
|
rtio_i_overflow_reset_write(1);
|
2016-03-01 02:49:15 +08:00
|
|
|
break;
|
2016-03-01 02:16:29 +08:00
|
|
|
}
|
|
|
|
if(rtio_get_counter() >= timeout) {
|
|
|
|
/* check empty flag again to prevent race condition.
|
|
|
|
* now we are sure that the time limit has been exceeded.
|
|
|
|
*/
|
2016-03-01 02:49:15 +08:00
|
|
|
status = rtio_i_status_read();
|
|
|
|
if(status & RTIO_I_STATUS_EMPTY)
|
|
|
|
break;
|
2016-03-01 02:16:29 +08:00
|
|
|
}
|
|
|
|
/* input FIFO is empty - keep waiting */
|
|
|
|
}
|
2016-03-01 23:34:05 +08:00
|
|
|
|
|
|
|
if (status & RTIO_I_STATUS_OVERFLOW)
|
|
|
|
artiq_raise_from_c("RTIOOverflow",
|
|
|
|
"RTIO input overflow on channel {0}",
|
|
|
|
channel, 0, 0);
|
|
|
|
if (status & RTIO_I_STATUS_EMPTY)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
r = rtio_i_timestamp_read();
|
|
|
|
rtio_i_re_write(1);
|
|
|
|
return r;
|
2016-03-01 02:16:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-02 02:21:50 +08:00
|
|
|
unsigned int rtio_input_data(int channel)
|
|
|
|
{
|
|
|
|
unsigned int data;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
rtio_chan_sel_write(channel);
|
|
|
|
while((status = rtio_i_status_read())) {
|
|
|
|
if(status & RTIO_I_STATUS_OVERFLOW) {
|
|
|
|
rtio_i_overflow_reset_write(1);
|
|
|
|
artiq_raise_from_c("RTIOOverflow",
|
|
|
|
"RTIO input overflow on channel {0}",
|
|
|
|
channel, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data = rtio_i_data_read();
|
|
|
|
rtio_i_re_write(1);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-15 07:12:39 +08:00
|
|
|
void rtio_log_va(long long int timestamp, const char *fmt, va_list args)
|
2015-12-26 22:44:50 +08:00
|
|
|
{
|
2016-02-15 07:12:39 +08:00
|
|
|
// This executes on the kernel CPU's stack, which is specifically designed
|
|
|
|
// for allocation of this kind of massive buffers.
|
|
|
|
int len = vsnprintf(NULL, 0, fmt, args);
|
|
|
|
char *buf = __builtin_alloca(len + 1);
|
|
|
|
vsnprintf(buf, len + 1, fmt, args);
|
2015-12-26 22:44:50 +08:00
|
|
|
|
|
|
|
rtio_chan_sel_write(CONFIG_RTIO_LOG_CHANNEL);
|
|
|
|
rtio_o_timestamp_write(timestamp);
|
|
|
|
|
2016-02-15 16:57:23 +08:00
|
|
|
int i = 0;
|
2016-02-15 07:12:39 +08:00
|
|
|
unsigned int word = 0;
|
2015-12-26 22:44:50 +08:00
|
|
|
while(1) {
|
2015-12-27 01:07:18 +08:00
|
|
|
word <<= 8;
|
2016-02-15 07:12:39 +08:00
|
|
|
word |= *buf & 0xff;
|
|
|
|
if(*buf == 0) {
|
2015-12-26 22:44:50 +08:00
|
|
|
rtio_o_data_write(word);
|
|
|
|
rtio_o_we_write(1);
|
|
|
|
break;
|
|
|
|
}
|
2016-02-15 07:12:39 +08:00
|
|
|
buf++;
|
2015-12-26 22:44:50 +08:00
|
|
|
i++;
|
|
|
|
if(i == 4) {
|
|
|
|
rtio_o_data_write(word);
|
|
|
|
rtio_o_we_write(1);
|
|
|
|
word = 0;
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-15 07:12:39 +08:00
|
|
|
|
|
|
|
void rtio_log(long long int timestamp, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
rtio_log_va(timestamp, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|