summaryrefslogtreecommitdiff
path: root/code/fe310/eos
diff options
context:
space:
mode:
Diffstat (limited to 'code/fe310/eos')
-rw-r--r--code/fe310/eos/Makefile18
-rw-r--r--code/fe310/eos/ecp.c66
-rw-r--r--code/fe310/eos/ecp.h3
-rw-r--r--code/fe310/eos/eos.c17
-rw-r--r--code/fe310/eos/eos.h6
-rw-r--r--code/fe310/eos/event.c85
-rw-r--r--code/fe310/eos/event.h16
-rw-r--r--code/fe310/eos/interrupt.c53
-rw-r--r--code/fe310/eos/interrupt.h8
-rw-r--r--code/fe310/eos/msgq.c66
-rw-r--r--code/fe310/eos/msgq.h19
-rw-r--r--code/fe310/eos/net.c365
-rw-r--r--code/fe310/eos/net.h20
-rw-r--r--code/fe310/eos/spi.h32
-rw-r--r--code/fe310/eos/timer.c86
-rw-r--r--code/fe310/eos/timer.h7
16 files changed, 867 insertions, 0 deletions
diff --git a/code/fe310/eos/Makefile b/code/fe310/eos/Makefile
new file mode 100644
index 0000000..573bca7
--- /dev/null
+++ b/code/fe310/eos/Makefile
@@ -0,0 +1,18 @@
+FE310_HOME=/opt/my/freedom-e-sdk
+
+CC=$(FE310_HOME)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-gcc
+AR=$(FE310_HOME)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin/riscv64-unknown-elf-ar
+
+CFLAGS=-O3 -fno-builtin-printf -march=rv32imac -mabi=ilp32 -mcmodel=medany -I$(FE310_HOME)/bsp/include -I$(FE310_HOME)/bsp/drivers -I$(FE310_HOME)/bsp/env -I$(FE310_HOME)/bsp/env/freedom-e300-hifive1 -I../..
+
+obj = msgq.o event.o interrupt.o timer.o net.o eos.o ecp.o
+
+
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $<
+
+all: $(obj)
+ $(AR) rcs libeos.a $(obj)
+
+clean:
+ rm -f *.o *.a \ No newline at end of file
diff --git a/code/fe310/eos/ecp.c b/code/fe310/eos/ecp.c
new file mode 100644
index 0000000..433e693
--- /dev/null
+++ b/code/fe310/eos/ecp.c
@@ -0,0 +1,66 @@
+#include <stddef.h>
+#include <string.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "event.h"
+#include "timer.h"
+#include "net.h"
+
+#include "ecp.h"
+
+static ECPSocket *_sock = NULL;
+
+static unsigned char net_buf_reserved = 0;
+static void timer_handler(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ int ok = eos_net_acquire(net_buf_reserved);
+ if (ok) {
+ ecp_cts_t next = ecp_timer_exe(_sock);
+ if (next) {
+ uint32_t tick = next * (uint64_t)RTC_FREQ / 1000;
+ eos_timer_set(tick, 1);
+ }
+ eos_net_release(1);
+ net_buf_reserved = 0;
+ } else {
+ net_buf_reserved = 1;
+ eos_evtq_push(EOS_EVT_TIMER, NULL, 0);
+ }
+}
+
+static void packet_handler(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ ECPNetAddr addr;
+ size_t addr_len = sizeof(addr.host) + sizeof(addr.port);
+
+ ECP2Buffer bufs;
+ ECPBuffer packet;
+ ECPBuffer payload;
+ unsigned char pld_buf[ECP_MAX_PLD];
+
+ bufs.packet = &packet;
+ bufs.payload = &payload;
+
+ packet.buffer = buffer+addr_len;
+ packet.size = ECP_MAX_PKT;
+ payload.buffer = pld_buf;
+ payload.size = ECP_MAX_PLD;
+
+ memcpy(addr.host, buffer, sizeof(addr.host));
+ memcpy(&addr.port, buffer+sizeof(addr.host), sizeof(addr.port));
+ ssize_t rv = ecp_pkt_handle(_sock, &addr, NULL, &bufs, len-addr_len);
+ if (bufs.packet->buffer) eos_net_free(buffer, 0);
+ eos_net_release(0);
+}
+
+int ecp_init(ECPContext *ctx) {
+ int rv;
+
+ rv = ecp_ctx_create(ctx);
+ if (rv) return rv;
+
+ eos_evtq_set_handler(EOS_EVT_TIMER, timer_handler);
+ eos_evtq_set_handler(EOS_EVT_MASK_NET | EOS_NET_CMD_PKT, packet_handler);
+
+ return ECP_OK;
+} \ No newline at end of file
diff --git a/code/fe310/eos/ecp.h b/code/fe310/eos/ecp.h
new file mode 100644
index 0000000..95aed31
--- /dev/null
+++ b/code/fe310/eos/ecp.h
@@ -0,0 +1,3 @@
+#include <ecp/core.h>
+
+int ecp_init(ECPContext *ctx); \ No newline at end of file
diff --git a/code/fe310/eos/eos.c b/code/fe310/eos/eos.c
new file mode 100644
index 0000000..3ad3b68
--- /dev/null
+++ b/code/fe310/eos/eos.c
@@ -0,0 +1,17 @@
+#include "event.h"
+#include "interrupt.h"
+#include "timer.h"
+#include "net.h"
+
+#include "eos.h"
+
+void eos_init(void) {
+ eos_evtq_init();
+ eos_intr_init();
+ eos_timer_init();
+ eos_net_init();
+}
+
+void eos_start(void) {
+ eos_net_start(15);
+} \ No newline at end of file
diff --git a/code/fe310/eos/eos.h b/code/fe310/eos/eos.h
new file mode 100644
index 0000000..938030e
--- /dev/null
+++ b/code/fe310/eos/eos.h
@@ -0,0 +1,6 @@
+#define EOS_OK 0
+#define EOS_ERR_Q_FULL -10
+
+void eos_init(void);
+void eos_start(void);
+
diff --git a/code/fe310/eos/event.c b/code/fe310/eos/event.c
new file mode 100644
index 0000000..25f1fa1
--- /dev/null
+++ b/code/fe310/eos/event.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "net.h"
+#include "timer.h"
+#include "event.h"
+
+static EOSMsgQ event_q;
+static EOSMsgItem event_q_array[EOS_EVT_SIZE_Q];
+
+static eos_evt_fptr_t evt_net_handler[EOS_NET_MAX_CMD];
+static eos_evt_fptr_t evt_timer_handler = NULL;
+static eos_evt_fptr_t evt_ui_handler = NULL;
+
+static void bad_handler(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ printf("bad handler: %d\n", cmd);
+}
+
+void eos_evtq_init(void) {
+ int i;
+
+ for (i=0; i<EOS_NET_MAX_CMD; i++) {
+ evt_net_handler[i] = bad_handler;
+ }
+ evt_timer_handler = bad_handler;
+ evt_ui_handler = bad_handler;
+ eos_msgq_init(&event_q, event_q_array, EOS_EVT_SIZE_Q);
+}
+
+int eos_evtq_push(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ return eos_msgq_push(&event_q, cmd, buffer, len);
+}
+
+void eos_evtq_pop(unsigned char *cmd, unsigned char **buffer, uint16_t *len) {
+ eos_msgq_pop(&event_q, cmd, buffer, len);
+}
+
+void eos_evtq_handle(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ if (cmd & EOS_EVT_MASK_NET) {
+ cmd &= ~EOS_EVT_MASK_NET;
+ if (cmd < EOS_NET_MAX_CMD) {
+ evt_net_handler[cmd](cmd, buffer, len);
+ } else {
+ bad_handler(cmd, buffer, len);
+ }
+ } else if (cmd == EOS_EVT_TIMER) {
+ evt_timer_handler(cmd, buffer, len);
+ } else if (cmd == EOS_EVT_UI) {
+ evt_ui_handler(cmd, buffer, len);
+ }
+}
+
+void eos_evtq_loop(void) {
+ unsigned char cmd;
+ unsigned char *buffer;
+ uint16_t len;
+ volatile int foo = 1;
+
+ while(foo) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ eos_evtq_pop(&cmd, &buffer, &len);
+ if (cmd) {
+ set_csr(mstatus, MSTATUS_MIE);
+ eos_evtq_handle(cmd, buffer, len);
+ clear_csr(mstatus, MSTATUS_MIE);
+ } else {
+ // asm volatile ("wfi");
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+}
+
+void eos_evtq_set_handler(unsigned char cmd, eos_evt_fptr_t handler) {
+ if (cmd & EOS_EVT_MASK_NET) {
+ evt_net_handler[cmd & ~EOS_EVT_MASK_NET] = handler;
+ } else if (cmd == EOS_EVT_TIMER) {
+ evt_timer_handler = handler;
+ } else if (cmd == EOS_EVT_UI) {
+ evt_ui_handler = handler;
+ }
+} \ No newline at end of file
diff --git a/code/fe310/eos/event.h b/code/fe310/eos/event.h
new file mode 100644
index 0000000..21079b4
--- /dev/null
+++ b/code/fe310/eos/event.h
@@ -0,0 +1,16 @@
+#include <stdint.h>
+
+#define EOS_EVT_MASK_NET 0x80
+#define EOS_EVT_TIMER 0x01
+#define EOS_EVT_UI 0x02
+
+#define EOS_EVT_SIZE_Q 4
+
+typedef void (*eos_evt_fptr_t) (unsigned char, unsigned char *, uint16_t);
+
+void eos_evtq_init(void);
+int eos_evtq_push(unsigned char cmd, unsigned char *buffer, uint16_t len);
+void eos_evtq_pop(unsigned char *cmd, unsigned char **buffer, uint16_t *len);
+void eos_evtq_handle(unsigned char cmd, unsigned char *buffer, uint16_t len);
+void eos_evtq_loop(void);
+void eos_evtq_set_handler(unsigned char cmd, eos_evt_fptr_t handler); \ No newline at end of file
diff --git a/code/fe310/eos/interrupt.c b/code/fe310/eos/interrupt.c
new file mode 100644
index 0000000..def1a24
--- /dev/null
+++ b/code/fe310/eos/interrupt.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "plic/plic_driver.h"
+#include "interrupt.h"
+
+// Global Instance data for the PLIC
+// for use by the PLIC Driver.
+static plic_instance_t plic;
+
+static eos_intr_fptr_t ext_interrupt_handler[PLIC_NUM_INTERRUPTS];
+
+void handle_m_ext_interrupt(void) {
+ plic_source int_num = PLIC_claim_interrupt(&plic);
+ if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS) && (ext_interrupt_handler[int_num])) {
+ ext_interrupt_handler[int_num]();
+ } else {
+ printf("handle_m_ext_interrupt error\n\n");
+ exit(1 + (uintptr_t) int_num);
+ }
+ PLIC_complete_interrupt(&plic, int_num);
+}
+
+void eos_intr_init(void) {
+ for (int i = 0; i < PLIC_NUM_INTERRUPTS; i++){
+ ext_interrupt_handler[i] = NULL;
+ }
+
+ /**************************************************************************
+ * Set up the PLIC
+ **************************************************************************/
+ PLIC_init(&plic,
+ PLIC_CTRL_ADDR,
+ PLIC_NUM_INTERRUPTS,
+ PLIC_NUM_PRIORITIES);
+
+ // Enable Global (PLIC) interrupts.
+ set_csr(mie, MIP_MEIP);
+
+ // Enable all interrupts
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_intr_set_handler(uint8_t int_num, uint8_t priority, eos_intr_fptr_t handler) {
+ ext_interrupt_handler[int_num] = handler;
+ PLIC_enable_interrupt(&plic, int_num);
+ PLIC_set_priority(&plic, int_num, priority);
+}
diff --git a/code/fe310/eos/interrupt.h b/code/fe310/eos/interrupt.h
new file mode 100644
index 0000000..7ef81b8
--- /dev/null
+++ b/code/fe310/eos/interrupt.h
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+// Structures for registering different interrupt handlers
+// for different parts of the application.
+typedef void (*eos_intr_fptr_t) (void);
+
+void eos_intr_init(void);
+void eos_intr_set_handler(uint8_t int_num, uint8_t priority, eos_intr_fptr_t handler);
diff --git a/code/fe310/eos/msgq.c b/code/fe310/eos/msgq.c
new file mode 100644
index 0000000..d242c69
--- /dev/null
+++ b/code/fe310/eos/msgq.c
@@ -0,0 +1,66 @@
+#include <stddef.h>
+
+#include "eos.h"
+#include "msgq.h"
+
+#define EOS_MSGQ_IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1))
+
+void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size) {
+ msgq->idx_r = 0;
+ msgq->idx_w = 0;
+ msgq->array = array;
+ msgq->size = size;
+}
+
+int eos_msgq_push(EOSMsgQ *msgq, unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ if (msgq->idx_w - msgq->idx_r == msgq->size) return EOS_ERR_Q_FULL;
+
+ uint8_t idx = EOS_MSGQ_IDX_MASK(msgq->idx_w, msgq->size);
+ msgq->array[idx].cmd = cmd;
+ msgq->array[idx].buffer = buffer;
+ msgq->array[idx].len = len;
+ msgq->idx_w++;
+ return EOS_OK;
+}
+
+void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *cmd, unsigned char **buffer, uint16_t *len) {
+ if (msgq->idx_r == msgq->idx_w) {
+ *cmd = 0;
+ *buffer = NULL;
+ } else {
+ uint8_t idx = EOS_MSGQ_IDX_MASK(msgq->idx_r, msgq->size);
+ *cmd = msgq->array[idx].cmd;
+ *buffer = msgq->array[idx].buffer;
+ *len = msgq->array[idx].len;
+ msgq->idx_r++;
+ }
+}
+
+void eos_msgq_get(EOSMsgQ *msgq, unsigned char cmd, unsigned char **buffer, uint16_t *len) {
+ uint8_t idx = EOS_MSGQ_IDX_MASK(msgq->idx_r, msgq->size);
+ unsigned char _cmd = msgq->array[idx].cmd;
+ EOSMsgItem *tmp_item = &msgq->array[idx];
+
+ *buffer = msgq->array[idx].buffer;
+ *len = msgq->array[idx].len;
+ if (_cmd == cmd) {
+ msgq->idx_r++;
+ return;
+ }
+ for (idx = msgq->idx_r + 1; idx < msgq->idx_w; idx++) {
+ *tmp_item = msgq->array[EOS_MSGQ_IDX_MASK(idx, msgq->size)];
+ msgq->array[EOS_MSGQ_IDX_MASK(idx, msgq->size)].cmd = _cmd;
+ msgq->array[EOS_MSGQ_IDX_MASK(idx, msgq->size)].buffer = *buffer;
+ msgq->array[EOS_MSGQ_IDX_MASK(idx, msgq->size)].len = *len;
+ _cmd = tmp_item->cmd;
+ *buffer = tmp_item->buffer;
+ *len = tmp_item->len;
+ if (_cmd == cmd) {
+ msgq->idx_r++;
+ return;
+ }
+ }
+ *buffer = NULL;
+ *len = 0;
+}
+
diff --git a/code/fe310/eos/msgq.h b/code/fe310/eos/msgq.h
new file mode 100644
index 0000000..05a5d80
--- /dev/null
+++ b/code/fe310/eos/msgq.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+typedef struct EOSMsgItem {
+ unsigned char cmd;
+ unsigned char *buffer;
+ uint16_t len;
+} EOSMsgItem;
+
+typedef struct EOSMsgQ {
+ uint8_t idx_r;
+ uint8_t idx_w;
+ uint8_t size;
+ EOSMsgItem *array;
+} EOSMsgQ;
+
+void eos_msgq_init(EOSMsgQ *msgq, EOSMsgItem *array, uint8_t size);
+int eos_msgq_push(EOSMsgQ *msgq, unsigned char cmd, unsigned char *buffer, uint16_t len);
+void eos_msgq_pop(EOSMsgQ *msgq, unsigned char *cmd, unsigned char **buffer, uint16_t *len);
+void eos_msgq_get(EOSMsgQ *msgq, unsigned char cmd, unsigned char **buffer, uint16_t *len); \ No newline at end of file
diff --git a/code/fe310/eos/net.c b/code/fe310/eos/net.c
new file mode 100644
index 0000000..080da72
--- /dev/null
+++ b/code/fe310/eos/net.c
@@ -0,0 +1,365 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "plic/plic_driver.h"
+
+#include "eos.h"
+#include "msgq.h"
+#include "event.h"
+#include "interrupt.h"
+#include "net.h"
+#include "spi.h"
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+#define SPI_BUFQ_IDX_MASK(IDX) ((IDX) & (SPI_SIZE_BUFQ - 1))
+
+static volatile uint8_t spi_res = 0;
+static volatile uint8_t spi_res_next = 0;
+static volatile unsigned char *spi_res_buf = NULL;
+
+static EOSMsgQ spi_sndq;
+static EOSMsgItem spi_sndq_array[SPI_SIZE_BUFQ];
+
+static SPIBufQ spi_bufq;
+static unsigned char spi_bufq_array[SPI_SIZE_BUFQ][SPI_SIZE_BUF];
+
+static int spi_bufq_push(unsigned char *buffer) {
+ spi_bufq.array[SPI_BUFQ_IDX_MASK(spi_bufq.idx_w++)] = buffer;
+}
+
+static unsigned char *spi_bufq_pop(void) {
+ if (spi_bufq.idx_r == spi_bufq.idx_w) return NULL;
+ return spi_bufq.array[SPI_BUFQ_IDX_MASK(spi_bufq.idx_r++)];
+}
+
+static volatile uint8_t spi_rdy = 0;
+static volatile uint8_t spi_cts = 0;
+static volatile uint8_t spi_rts = 0;
+static SPIBuffer spi_buffer;
+
+static void spi_reset(void) {
+ int i;
+ volatile uint32_t r;
+
+ spi_cts = 0;
+ // before starting a transaction, set SPI peripheral to desired mode
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = 0;
+ while ((r = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+}
+
+static void spi_xchg(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ volatile uint32_t r1, r2;
+
+ spi_cts = 0;
+ spi_buffer.buffer = buffer;
+ spi_buffer.len_rx = 0;
+ spi_buffer.idx_tx = 0;
+ spi_buffer.idx_rx = 0;
+
+ if (spi_res_buf == NULL) {
+ if (cmd & EOS_NET_CMD_FLAG_ONEW) {
+ spi_res_next = 1;
+ } else if (spi_res) {
+ cmd |= EOS_NET_CMD_FLAG_ONEW;
+ }
+ } else if (cmd & EOS_NET_CMD_FLAG_ONEW) {
+ cmd &= ~EOS_NET_CMD_FLAG_ONEW;
+ }
+
+ // before starting a transaction, set SPI peripheral to desired mode
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD;
+
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = ((cmd << 3) | (len >> 8)) & 0xFF;
+
+ while (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL);
+ SPI1_REG(SPI_REG_TXFIFO) = len & 0xFF;
+
+ while ((r1 = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+ while ((r2 = SPI1_REG(SPI_REG_RXFIFO)) & SPI_RXFIFO_EMPTY);
+
+ if (cmd & EOS_NET_CMD_FLAG_ONEW) {
+ r1 = 0;
+ r2 = 0;
+ }
+
+ spi_buffer.cmd = ((r1 & 0xFF) >> 3);
+ spi_buffer.len_rx = ((r1 & 0x07) << 8);
+
+ spi_buffer.len_rx |= (r2 & 0xFF);
+ spi_buffer.len = MAX(len, spi_buffer.len_rx);
+
+ // Work around esp32 bug
+ if (spi_buffer.len < 6) {
+ spi_buffer.len = 6;
+ } else if ((spi_buffer.len + 2) % 4 != 0) {
+ spi_buffer.len = ((spi_buffer.len + 2)/4 + 1) * 4 - 2;
+ }
+
+ SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_CHUNK/2);
+ SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(SPI_SIZE_CHUNK - 1);
+ SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM | SPI_IP_RXWM;
+}
+
+static int spi_xchg_next(unsigned char *_buffer) {
+ unsigned char cmd;
+ unsigned char *buffer = NULL;
+ uint16_t len;
+
+ eos_msgq_pop(&spi_sndq, &cmd, &buffer, &len);
+ if (cmd) {
+ spi_xchg(cmd, buffer, len);
+ } else if (spi_rts) {
+ if (_buffer == NULL) _buffer = spi_bufq_pop();
+ if (_buffer) {
+ spi_xchg(0, _buffer, 0);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void spi_xchg_handler(void) {
+ int i;
+
+ if (SPI1_REG(SPI_REG_IP) & SPI_IP_TXWM) {
+ uint16_t sz_chunk = MIN(spi_buffer.len - spi_buffer.idx_tx, SPI_SIZE_CHUNK);
+ for (i=0; i<sz_chunk; i++) {
+ if (SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL) break;
+ SPI1_REG(SPI_REG_TXFIFO) = spi_buffer.buffer[spi_buffer.idx_tx+i];
+ }
+ spi_buffer.idx_tx += i;
+ }
+
+ for (i=0; i<spi_buffer.idx_tx - spi_buffer.idx_rx; i++) {
+ volatile uint32_t x = SPI1_REG(SPI_REG_RXFIFO);
+ if (x & SPI_RXFIFO_EMPTY) break;
+ spi_buffer.buffer[spi_buffer.idx_rx+i] = x & 0xFF;
+ }
+ spi_buffer.idx_rx += i;
+
+ if (spi_buffer.idx_rx == spi_buffer.len) {
+ SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO;
+ SPI1_REG(SPI_REG_IE) = 0x0;
+ if (spi_buffer.cmd) {
+ int r = eos_evtq_push(spi_buffer.cmd | EOS_EVT_MASK_NET, spi_buffer.buffer, spi_buffer.len_rx);
+ if (r) spi_bufq_push(spi_buffer.buffer);
+ } else if ((spi_res || spi_res_next) && (spi_res_buf == NULL)) {
+ spi_res_buf = spi_buffer.buffer;
+ spi_res_next = 0;
+ } else {
+ spi_bufq_push(spi_buffer.buffer);
+ }
+ } else if (spi_buffer.idx_tx == spi_buffer.len) {
+ SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(MIN(spi_buffer.len - spi_buffer.idx_rx - 1, SPI_SIZE_CHUNK - 1));
+ SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM;
+ }
+}
+
+static void spi_cts_hanler(void) {
+ GPIO_REG(GPIO_RISE_IP) = (0x1 << SPI_GPIO_CTS_OFFSET);
+ spi_cts = 1;
+
+ if (spi_rdy) {
+ spi_xchg_next(NULL);
+ } else {
+ uint32_t iof_mask = ((uint32_t)1 << IOF_SPI1_SS2);
+ GPIO_REG(GPIO_IOF_EN) &= ~iof_mask;
+ }
+}
+
+static void spi_rts_hanler(void) {
+ uint32_t rts_offset = (0x1 << SPI_GPIO_RTS_OFFSET);
+ if (GPIO_REG(GPIO_RISE_IP) & rts_offset) {
+ GPIO_REG(GPIO_RISE_IP) = rts_offset;
+ spi_rts = 1;
+ if (spi_rdy && spi_cts) spi_reset();
+ }
+
+ if (GPIO_REG(GPIO_FALL_IP) & rts_offset) {
+ GPIO_REG(GPIO_FALL_IP) = rts_offset;
+ spi_rts = 0;
+ }
+}
+
+void eos_net_init(void) {
+ int i;
+
+ spi_bufq.idx_r = 0;
+ spi_bufq.idx_w = 0;
+ for (i=0; i<SPI_SIZE_BUFQ; i++) {
+ spi_bufq_push(spi_bufq_array[i]);
+ }
+ eos_msgq_init(&spi_sndq, spi_sndq_array, SPI_SIZE_BUFQ);
+ GPIO_REG(GPIO_IOF_SEL) &= ~SPI_IOF_MASK;
+ GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK;
+ eos_intr_set_handler(INT_SPI1_BASE, 5, spi_xchg_handler);
+
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(0x1 << SPI_GPIO_CTS_OFFSET);
+ GPIO_REG(GPIO_PULLUP_EN) |= (0x1 << SPI_GPIO_CTS_OFFSET);
+ GPIO_REG(GPIO_INPUT_EN) |= (0x1 << SPI_GPIO_CTS_OFFSET);
+ GPIO_REG(GPIO_RISE_IE) |= (0x1 << SPI_GPIO_CTS_OFFSET);
+ eos_intr_set_handler(INT_GPIO_BASE + SPI_GPIO_CTS_OFFSET, 5, spi_cts_hanler);
+
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(0x1 << SPI_GPIO_RTS_OFFSET);
+ GPIO_REG(GPIO_PULLUP_EN) |= (0x1 << SPI_GPIO_RTS_OFFSET);
+ GPIO_REG(GPIO_INPUT_EN) |= (0x1 << SPI_GPIO_RTS_OFFSET);
+ GPIO_REG(GPIO_RISE_IE) |= (0x1 << SPI_GPIO_RTS_OFFSET);
+ GPIO_REG(GPIO_FALL_IE) |= (0x1 << SPI_GPIO_RTS_OFFSET);
+ eos_intr_set_handler(INT_GPIO_BASE + SPI_GPIO_RTS_OFFSET, 5, spi_rts_hanler);
+}
+
+void eos_net_start(uint32_t sckdiv) {
+ uint32_t iof_mask = ((uint32_t)1 << IOF_SPI1_SS2);
+
+ GPIO_REG(GPIO_IOF_SEL) &= ~iof_mask;
+ GPIO_REG(GPIO_IOF_EN) |= iof_mask;
+
+ SPI1_REG(SPI_REG_SCKDIV) = sckdiv;
+ SPI1_REG(SPI_REG_SCKMODE) = SPI_MODE0;
+ SPI1_REG(SPI_REG_FMT) = SPI_FMT_PROTO(SPI_PROTO_S) |
+ SPI_FMT_ENDIAN(SPI_ENDIAN_MSB) |
+ SPI_FMT_DIR(SPI_DIR_RX) |
+ SPI_FMT_LEN(8);
+
+ // enable CS pin for selected channel/pin
+ SPI1_REG(SPI_REG_CSID) = 2;
+
+ // There is no way here to change the CS polarity.
+ // SPI1_REG(SPI_REG_CSDEF) = 0xFFFF;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ spi_rdy = 1;
+ if (spi_cts) spi_xchg_next(NULL);
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_net_stop(void) {
+ volatile uint8_t done = 0;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ spi_rdy = 0;
+ if (spi_cts) {
+ uint32_t iof_mask = ((uint32_t)1 << IOF_SPI1_SS2);
+ GPIO_REG(GPIO_IOF_EN) &= ~iof_mask;
+ done = 1;
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ while (!done) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ done = spi_cts;
+ if (!done) asm volatile ("wfi");
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+}
+
+int eos_net_reserve(unsigned char *buffer) {
+ int rv = EOS_OK;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ spi_res++;
+ if (spi_res_buf == NULL) {
+ spi_res_buf = buffer;
+ } else {
+ rv = spi_bufq_push(buffer);
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return rv;
+}
+
+int eos_net_acquire(unsigned char reserved) {
+ int ret = 0;
+
+ if (reserved) {
+ while (!ret) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (spi_res_buf) {
+ ret = 1;
+ } else {
+ asm volatile ("wfi");
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ } else {
+ clear_csr(mstatus, MSTATUS_MIE);
+ spi_res++;
+ spi_res_buf = spi_bufq_pop();
+ ret = (spi_res_buf != NULL);
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+ return ret;
+}
+
+int eos_net_release(unsigned char reserved) {
+ int rv = EOS_OK;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (reserved) spi_res--;
+ if (!spi_res && spi_res_buf) {
+ rv = spi_bufq_push((unsigned char *)spi_res_buf);
+ if (!rv) spi_res_buf = NULL;
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return rv;
+}
+
+unsigned char *eos_net_alloc(void) {
+ volatile unsigned char *ret = NULL;
+
+ while (ret == NULL) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (spi_res_buf) {
+ ret = spi_res_buf;
+ spi_res_buf = NULL;
+ } else {
+ asm volatile ("wfi");
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+ }
+
+ return (unsigned char *)ret;
+}
+
+int eos_net_free(unsigned char *buffer, unsigned char reserve_next) {
+ int rv = EOS_OK;
+ uint8_t do_release = 1;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if ((spi_res || reserve_next) && (spi_res_buf == NULL)) {
+ spi_res_buf = buffer;
+ } else {
+ if (spi_rdy && spi_cts) do_release = spi_xchg_next(buffer);
+ if (do_release) rv = spi_bufq_push(buffer);
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return rv;
+}
+
+int eos_net_send(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ int rv = EOS_OK;
+
+ clear_csr(mstatus, MSTATUS_MIE);
+ if (spi_rdy && spi_cts) {
+ spi_xchg(cmd, buffer, len);
+ } else {
+ rv = eos_msgq_push(&spi_sndq, cmd, buffer, len);
+ }
+ set_csr(mstatus, MSTATUS_MIE);
+
+ return rv;
+}
diff --git a/code/fe310/eos/net.h b/code/fe310/eos/net.h
new file mode 100644
index 0000000..0091c3c
--- /dev/null
+++ b/code/fe310/eos/net.h
@@ -0,0 +1,20 @@
+#include <stdint.h>
+
+#define EOS_NET_CMD_FLAG_ONEW 0x10
+
+#define EOS_NET_CMD_CONNECT 1
+#define EOS_NET_CMD_DISCONNECT 2
+#define EOS_NET_CMD_SCAN 3
+#define EOS_NET_CMD_PKT 4
+
+#define EOS_NET_MAX_CMD 8
+
+void eos_net_init(void);
+void eos_net_start(uint32_t sckdiv);
+void eos_net_stop(void);
+int eos_net_reserve(unsigned char *buffer);
+int eos_net_acquire(unsigned char reserved);
+int eos_net_release(unsigned char reserved);
+unsigned char *eos_net_alloc(void);
+int eos_net_free(unsigned char *buffer, unsigned char reserve_next);
+int eos_net_send(unsigned char cmd, unsigned char *buffer, uint16_t len);
diff --git a/code/fe310/eos/spi.h b/code/fe310/eos/spi.h
new file mode 100644
index 0000000..88e54bb
--- /dev/null
+++ b/code/fe310/eos/spi.h
@@ -0,0 +1,32 @@
+#include <stdint.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#define SPI_MODE0 0x00
+#define SPI_MODE1 0x01
+#define SPI_MODE2 0x02
+#define SPI_MODE3 0x03
+
+#define SPI_SIZE_BUF 1500
+#define SPI_SIZE_CHUNK 4
+#define SPI_SIZE_BUFQ 4
+#define SPI_GPIO_CTS_OFFSET PIN_2_OFFSET
+#define SPI_GPIO_RTS_OFFSET PIN_3_OFFSET
+#define SPI_IOF_MASK (((uint32_t)1 << IOF_SPI1_SCK) | ((uint32_t)1 << IOF_SPI1_MOSI) | ((uint32_t)1 << IOF_SPI1_MISO))
+
+typedef struct SPIBuffer {
+ unsigned char cmd;
+ unsigned char *buffer;
+ uint16_t len;
+ uint16_t len_rx;
+ uint16_t idx_tx;
+ uint16_t idx_rx;
+} SPIBuffer;
+
+typedef struct SPIBufQ {
+ uint8_t idx_r;
+ uint8_t idx_w;
+ unsigned char *array[SPI_SIZE_BUFQ];
+} SPIBufQ;
+
diff --git a/code/fe310/eos/timer.c b/code/fe310/eos/timer.c
new file mode 100644
index 0000000..0a07ed9
--- /dev/null
+++ b/code/fe310/eos/timer.c
@@ -0,0 +1,86 @@
+#include <stddef.h>
+#include <stdio.h>
+
+#include "encoding.h"
+#include "platform.h"
+#include "event.h"
+#include "timer.h"
+
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+static eos_timer_fptr_t timer_ext_handler = NULL;
+volatile uint64_t timer_next = 0;
+volatile uint64_t timer_next_evt = 0;
+
+void handle_m_time_interrupt(void) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ uint64_t now = *mtime;
+
+ if (timer_next && (timer_next <= now)) {
+ uint32_t next = timer_ext_handler();
+ if (next) {
+ timer_next = now + next;
+ } else {
+ timer_next = 0;
+ }
+ }
+ if (timer_next_evt && (timer_next_evt <= now)) {
+ eos_evtq_push(EOS_EVT_TIMER, NULL, 0);
+ timer_next_evt = 0;
+ }
+ *mtimecmp = (timer_next && timer_next_evt) ? MIN(timer_next, timer_next_evt) : (timer_next ? timer_next : timer_next_evt);
+ if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP);
+}
+
+void eos_timer_init(void) {
+ volatile uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+ *mtimecmp = 0;
+ clear_csr(mie, MIP_MTIP);
+}
+
+void eos_timer_set(uint32_t tick, unsigned char is_evt) {
+ volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
+ volatile uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+ clear_csr(mstatus, MSTATUS_MIE);
+
+ uint64_t now = *mtime;
+ uint64_t then = *mtimecmp;
+ uint64_t next = now + tick;
+ if (is_evt) {
+ if ((timer_next_evt == 0) || (next < timer_next_evt)) timer_next_evt = next;
+ next = timer_next ? MIN(timer_next, timer_next_evt) : timer_next_evt;
+ } else if (timer_ext_handler) {
+ if ((timer_next == 0) || (next < timer_next)) timer_next = next;
+ next = timer_next_evt ? MIN(timer_next, timer_next_evt) : timer_next;
+ }
+ if ((then == 0) || (next < then)) *mtimecmp = next;
+ if (then == 0) set_csr(mie, MIP_MTIP);
+
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_timer_clear(unsigned char is_evt) {
+ volatile uint64_t *mtimecmp = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
+
+ clear_csr(mstatus, MSTATUS_MIE);
+
+ if (is_evt) {
+ timer_next_evt = 0;
+ *mtimecmp = timer_next;
+ } else {
+ timer_next = 0;
+ *mtimecmp = timer_next_evt;
+ }
+ if (*mtimecmp == 0) clear_csr(mie, MIP_MTIP);
+
+ set_csr(mstatus, MSTATUS_MIE);
+}
+
+void eos_timer_set_handler(eos_timer_fptr_t handler) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ timer_ext_handler = handler;
+ set_csr(mstatus, MSTATUS_MIE);
+}
diff --git a/code/fe310/eos/timer.h b/code/fe310/eos/timer.h
new file mode 100644
index 0000000..929283b
--- /dev/null
+++ b/code/fe310/eos/timer.h
@@ -0,0 +1,7 @@
+#include <stdint.h>
+
+typedef uint32_t (*eos_timer_fptr_t) (void);
+
+void eos_timer_init(void);
+void eos_timer_set(uint32_t tick, unsigned char is_evt);
+void eos_timer_set_handler(eos_timer_fptr_t handler);