diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 45b6f6ea3..3b81d5af8 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := isr.o clock.o rtiocrg.o flash_storage.o mailbox.o \ - session.o log.o moninj.o net_server.o bridge_ctl.o \ + session.o log.o analyzer.o moninj.o net_server.o bridge_ctl.o \ ksupport_data.o kloader.o test_mode.o main.o OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \ bridge.o rtio.o ttl.o dds.o diff --git a/artiq/runtime/analyzer.c b/artiq/runtime/analyzer.c new file mode 100644 index 000000000..4a127ffdc --- /dev/null +++ b/artiq/runtime/analyzer.c @@ -0,0 +1,138 @@ +#include + +#include "analyzer.h" + + +#ifdef CSR_RTIO_ANALYZER_BASE + +struct analyzer_header { + unsigned int sent_bytes; + unsigned long long int total_byte_count; + unsigned int overflow_occured; +} __attribute__((packed)); + + +#define ANALYZER_BUFFER_SIZE (512*1024) + +static struct analyzer_header analyzer_header; +static char analyzer_buffer[ANALYZER_BUFFER_SIZE] __attribute__((aligned(64))); + +static void arm(void) +{ + rtio_analyzer_message_encoder_overflow_reset_write(1); + rtio_analyzer_dma_base_address_write((unsigned int)analyzer_buffer); + rtio_analyzer_dma_last_address_write((unsigned int)analyzer_buffer + ANALYZER_BUFFER_SIZE - 1); + rtio_analyzer_dma_reset_write(1); + rtio_analyzer_dma_enable_write(1); +} + +static void disarm(void) +{ + rtio_analyzer_dma_enable_write(0); + while(rtio_analyzer_dma_busy_read()); +} + +void analyzer_init(void) +{ + arm(); +} + +enum { + SEND_STATE_HEADER, + SEND_STATE_POST_POINTER, /* send from pointer to end of buffer */ + SEND_STATE_PRE_POINTER, /* send from start of buffer to pointer-1 */ + SEND_STATE_TERMINATE +}; + +static int send_state; +static int pointer; +static int wraparound; +static int offset_consumed; +static int offset_sent; + +void analyzer_start(void) +{ + disarm(); + + analyzer_header.total_byte_count = rtio_analyzer_dma_byte_count_read(); + pointer = analyzer_header.total_byte_count % ANALYZER_BUFFER_SIZE; + wraparound = analyzer_header.total_byte_count >= ANALYZER_BUFFER_SIZE; + + if(wraparound) + analyzer_header.sent_bytes = ANALYZER_BUFFER_SIZE; + else + analyzer_header.sent_bytes = analyzer_header.total_byte_count; + + analyzer_header.overflow_occured = rtio_analyzer_message_encoder_overflow_read(); + + offset_consumed = 0; + offset_sent = 0; + send_state = SEND_STATE_HEADER; +} + +void analyzer_end(void) +{ + arm(); +} + +int analyzer_input(void *data, int length) +{ + /* The analyzer never accepts input. */ + return -1; +} + +void analyzer_poll(void **data, int *length) +{ + switch(send_state) { + case SEND_STATE_HEADER: + *length = sizeof(struct analyzer_header) - offset_consumed; + *data = (char *)&analyzer_header + offset_consumed; + break; + case SEND_STATE_POST_POINTER: + *length = ANALYZER_BUFFER_SIZE - pointer - offset_consumed; + *data = analyzer_buffer + pointer + offset_consumed; + break; + case SEND_STATE_PRE_POINTER: + *length = pointer - offset_consumed; + *data = analyzer_buffer + offset_consumed; + break; + case SEND_STATE_TERMINATE: + *length = -1; + break; + } +} + +void analyzer_ack_consumed(int length) +{ + offset_consumed += length; +} + +void analyzer_ack_sent(int length) +{ + offset_sent += length; + switch(send_state) { + case SEND_STATE_HEADER: + if(offset_sent >= sizeof(struct analyzer_header)) { + offset_consumed = 0; + offset_sent = 0; + if(wraparound) + send_state = SEND_STATE_POST_POINTER; + else + send_state = SEND_STATE_PRE_POINTER; + } + break; + case SEND_STATE_POST_POINTER: + if(pointer + offset_consumed >= ANALYZER_BUFFER_SIZE) { + offset_consumed = 0; + offset_sent = 0; + send_state = SEND_STATE_PRE_POINTER; + } + break; + case SEND_STATE_PRE_POINTER: + if(offset_sent >= pointer) + send_state = SEND_STATE_TERMINATE; + break; + } +} + +#endif diff --git a/artiq/runtime/analyzer.h b/artiq/runtime/analyzer.h new file mode 100644 index 000000000..f1800c643 --- /dev/null +++ b/artiq/runtime/analyzer.h @@ -0,0 +1,14 @@ +#ifndef __ANALYZER_H +#define __ANALYZER_H + +void analyzer_init(void); + +void analyzer_start(void); +void analyzer_end(void); + +int analyzer_input(void *data, int length); +void analyzer_poll(void **data, int *length); +void analyzer_ack_consumed(int length); +void analyzer_ack_sent(int length); + +#endif /* __ANALYZER_H */ diff --git a/artiq/runtime/main.c b/artiq/runtime/main.c index d9811642a..2e8f7f15e 100644 --- a/artiq/runtime/main.c +++ b/artiq/runtime/main.c @@ -28,6 +28,7 @@ #include "test_mode.h" #include "net_server.h" #include "session.h" +#include "analyzer.h" #include "moninj.h" #ifdef CSR_ETHMAC_BASE @@ -137,11 +138,27 @@ static struct net_server_instance session_inst = { .ack_sent = session_ack_sent }; +#ifdef CSR_RTIO_ANALYZER_BASE +static struct net_server_instance analyzer_inst = { + .port = 1382, + .start = analyzer_start, + .end = analyzer_end, + .input = analyzer_input, + .poll = analyzer_poll, + .ack_consumed = analyzer_ack_consumed, + .ack_sent = analyzer_ack_sent +}; +#endif + static void regular_main(void) { puts("Accepting sessions on Ethernet."); network_init(); net_server_init(&session_inst); +#ifdef CSR_RTIO_ANALYZER_BASE + analyzer_init(); + net_server_init(&analyzer_inst); +#endif moninj_init(); session_end(); diff --git a/artiq/runtime/session.c b/artiq/runtime/session.c index 0870f34df..521f7d353 100644 --- a/artiq/runtime/session.c +++ b/artiq/runtime/session.c @@ -203,7 +203,8 @@ static void out_packet_advance_consumed(int length) buffer_out_read_cursor += length; } -static void out_packet_advance_sent(int length) { +static void out_packet_advance_sent(int length) +{ if(buffer_out_sent_cursor + length > buffer_out_write_cursor) { log("session.c: write underrun (send) while trying to" " acknowledge %d bytes (%d remaining)",