summaryrefslogtreecommitdiff
path: root/code/fe310
diff options
context:
space:
mode:
authorUros Majstorovic <majstor@majstor.org>2018-03-14 19:08:00 +0100
committerUros Majstorovic <majstor@majstor.org>2018-03-14 19:08:00 +0100
commit5fe913c88d8c1781de336cca3949142bd9fc370d (patch)
tree6bf57e4e34fb60e46035175946b15581b2ef638c /code/fe310
parent4b655364d426f8429b063d9746c754beca6f7d1f (diff)
i2s driver added; new amd trap entry vector added
Diffstat (limited to 'code/fe310')
-rw-r--r--code/fe310/eos/Makefile5
-rw-r--r--code/fe310/eos/event.h12
-rw-r--r--code/fe310/eos/evt_def.h11
-rw-r--r--code/fe310/eos/i2s.c211
-rw-r--r--code/fe310/eos/i2s.h20
-rw-r--r--code/fe310/eos/i2s_def.h28
-rw-r--r--code/fe310/eos/interrupt.c1
-rw-r--r--code/fe310/eos/msgq_def.h6
-rw-r--r--code/fe310/eos/net.c1
-rw-r--r--code/fe310/eos/timer.c1
-rw-r--r--code/fe310/eos/trap_entry.S398
11 files changed, 681 insertions, 13 deletions
diff --git a/code/fe310/eos/Makefile b/code/fe310/eos/Makefile
index 43313fd..e84d0f6 100644
--- a/code/fe310/eos/Makefile
+++ b/code/fe310/eos/Makefile
@@ -5,12 +5,15 @@ AR = $(FE310_HOME)/work/build/riscv-gnu-toolchain/riscv64-unknown-elf/prefix/bin
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 = eos.o msgq.o event.o interrupt.o timer.o net.o ecp.o
+obj = trap_entry.o eos.o msgq.o event.o interrupt.o timer.o i2s.o net.o ecp.o
%.o: %.c %.h
$(CC) $(CFLAGS) -c $<
+%.o: %.S
+ $(CC) $(CFLAGS) -c $<
+
all: $(obj)
$(AR) rcs libeos.a $(obj)
diff --git a/code/fe310/eos/event.h b/code/fe310/eos/event.h
index ce71c0b..2dee419 100644
--- a/code/fe310/eos/event.h
+++ b/code/fe310/eos/event.h
@@ -1,16 +1,6 @@
#include <stdint.h>
-#define EOS_EVT_FLAG_WRAP 0x1
-
-#define EOS_EVT_NET 0x10
-#define EOS_EVT_TIMER 0x20
-#define EOS_EVT_AUDIO 0x30
-#define EOS_EVT_UI 0x40
-
-#define EOS_EVT_MASK 0xF0
-
-#define EOS_EVT_MAX_EVT 4
-#define EOS_EVT_SIZE_Q 4
+#include "evt_def.h"
typedef void (*eos_evt_fptr_t) (unsigned char, unsigned char *, uint16_t);
diff --git a/code/fe310/eos/evt_def.h b/code/fe310/eos/evt_def.h
new file mode 100644
index 0000000..e07b23c
--- /dev/null
+++ b/code/fe310/eos/evt_def.h
@@ -0,0 +1,11 @@
+#define EOS_EVT_FLAG_WRAP 0x1
+
+#define EOS_EVT_NET 0x10
+#define EOS_EVT_TIMER 0x20
+#define EOS_EVT_AUDIO 0x30
+#define EOS_EVT_UI 0x40
+
+#define EOS_EVT_MASK 0xF0
+
+#define EOS_EVT_MAX_EVT 4
+#define EOS_EVT_SIZE_Q 4
diff --git a/code/fe310/eos/i2s.c b/code/fe310/eos/i2s.c
new file mode 100644
index 0000000..98e2ffa
--- /dev/null
+++ b/code/fe310/eos/i2s.c
@@ -0,0 +1,211 @@
+#include <unistd.h>
+
+#include "encoding.h"
+#include "platform.h"
+
+#include "eos.h"
+#include "interrupt.h"
+#include "event.h"
+
+#include "i2s.h"
+#include "i2s_def.h"
+
+#define I2S_PWM_REG_CK PWM1_REG
+#define I2S_PWM_REG_WS PWM2_REG
+
+#define EOS_ABUF_IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1))
+
+EOSABuf _eos_i2s_mic_buf;
+EOSABuf _eos_i2s_spk_buf;
+uint16_t _eos_i2s_mic_wm;
+uint16_t _eos_i2s_spk_wm;
+uint32_t _eos_i2s_ck_period;
+uint32_t _eos_i2s_mic_volume = 3;
+static eos_evt_fptr_t evt_handler[I2S_MAX_HANDLER];
+
+static void _abuf_init(EOSABuf *buf, uint8_t *array, uint16_t size) {
+ buf->idx_r = 0;
+ buf->idx_w = 0;
+ buf->size = size;
+ buf->array = array;
+}
+
+static int _abuf_push(EOSABuf *buf, uint8_t sample) {
+ if (buf->idx_w - buf->idx_r == buf->size) return EOS_ERR_Q_FULL;
+
+ buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample;
+ buf->idx_w++;
+ return EOS_OK;
+}
+
+static int _abuf_pop(EOSABuf *buf, uint8_t *sample) {
+ if (buf->idx_r == buf->idx_w) {
+ return EOS_ERR_Q_EMPTY;
+ } else {
+ *sample = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)];
+ buf->idx_r++;
+ return EOS_OK;
+ }
+}
+
+static uint16_t _abuf_read(EOSABuf *buf, uint8_t *sample, uint16_t ssize) {
+ uint16_t i;
+
+ for (i=0; i<ssize; i++) {
+ if (buf->idx_r == buf->idx_w) break;
+ sample[i] = buf->array[EOS_ABUF_IDX_MASK(buf->idx_r, buf->size)];
+ buf->idx_r++;
+ }
+ return i;
+}
+
+static uint16_t _abuf_write(EOSABuf *buf, uint8_t *sample, uint16_t ssize) {
+ uint16_t i;
+
+ for (i=0; i<ssize; i++) {
+ if (buf->idx_w - buf->idx_r == buf->size) break;
+ buf->array[EOS_ABUF_IDX_MASK(buf->idx_w, buf->size)] = sample[i];
+ buf->idx_w++;
+ }
+ return i;
+}
+
+static uint16_t _abuf_len(EOSABuf *buf) {
+ return buf->idx_w - buf->idx_r;
+}
+
+static void audio_handler(unsigned char cmd, unsigned char *buffer, uint16_t len) {
+ if ((cmd & ~EOS_EVT_MASK) < I2S_MAX_HANDLER) {
+ evt_handler[cmd & ~EOS_EVT_MASK](cmd, buffer, len);
+ } else {
+ eos_evtq_bad_handler(cmd, buffer, len);
+ }
+}
+
+void eos_i2s_init(void) {
+ int i;
+ unsigned long f = get_cpu_freq();
+
+ _eos_i2s_ck_period = 512;
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_LR);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_LR);
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_LR);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_CK);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_CK);
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_CK);
+
+ GPIO_REG(GPIO_INPUT_EN) &= ~(1 << I2S_PIN_WS);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << I2S_PIN_WS);
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << I2S_PIN_WS);
+
+ GPIO_REG(GPIO_INPUT_EN) |= (1 << I2S_PIN_SD);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << I2S_PIN_SD);
+ GPIO_REG(GPIO_PULLUP_EN) &= ~(1 << I2S_PIN_SD);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << I2S_PIN_LR);
+
+ I2S_PWM_REG_CK(PWM_CFG) = 0;
+ I2S_PWM_REG_CK(PWM_COUNT) = 0;
+ I2S_PWM_REG_CK(PWM_CMP0) = _eos_i2s_ck_period - 1;
+ I2S_PWM_REG_CK(PWM_CMP1) = I2S_PWM_REG_CK(PWM_CMP0) / 2;
+ I2S_PWM_REG_CK(PWM_CMP2) = I2S_PWM_REG_CK(PWM_CMP0) / 4;
+
+ I2S_PWM_REG_WS(PWM_CFG) = 0;
+ I2S_PWM_REG_WS(PWM_COUNT) = 0;
+ I2S_PWM_REG_WS(PWM_CMP0) = _eos_i2s_ck_period * 64 - 1;
+ I2S_PWM_REG_WS(PWM_CMP1) = I2S_PWM_REG_WS(PWM_CMP0) / 2;
+ I2S_PWM_REG_WS(PWM_CMP2) = I2S_PWM_REG_WS(PWM_CMP0) - 1024;
+
+ eos_intr_set(I2S_IRQ_SD_ID, I2S_IRQ_SD_PRIORITY, NULL);
+ eos_intr_set(I2S_IRQ_CK_ID, I2S_IRQ_CK_PRIORITY, NULL);
+ eos_intr_set(I2S_IRQ_WS_ID, I2S_IRQ_WS_PRIORITY, NULL);
+ eos_intr_set(I2S_IRQ_CI_ID, I2S_IRQ_CI_PRIORITY, NULL);
+
+ for (i=0; i<I2S_MAX_HANDLER; i++) {
+ evt_handler[i] = eos_evtq_bad_handler;
+ }
+ eos_evtq_set_handler(EOS_EVT_AUDIO, audio_handler, EOS_EVT_FLAG_WRAP);
+}
+
+void eos_i2s_init_mic(uint8_t *mic_arr, uint16_t mic_arr_size, uint16_t mic_wm, eos_evt_fptr_t mic_wm_handler) {
+ _abuf_init(&_eos_i2s_mic_buf, mic_arr, mic_arr_size);
+ _eos_i2s_mic_wm = mic_wm;
+ evt_handler[I2S_EVT_MIC] = mic_wm_handler;
+}
+
+void eos_i2s_init_spk(uint8_t *spk_arr, uint16_t spk_arr_size, uint16_t spk_wm, eos_evt_fptr_t spk_wm_handler) {
+ _abuf_init(&_eos_i2s_spk_buf, spk_arr, spk_arr_size);
+ _eos_i2s_spk_wm = spk_wm;
+ evt_handler[I2S_EVT_SPK] = spk_wm_handler;
+}
+
+void eos_i2s_start(void) {
+ I2S_PWM_REG_CK(PWM_COUNT) = 0;
+ I2S_PWM_REG_WS(PWM_COUNT) = 0;
+
+ I2S_PWM_REG_CK(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP;
+ I2S_PWM_REG_WS(PWM_CFG) = PWM_CFG_ENALWAYS | PWM_CFG_ZEROCMP;
+
+ GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_CK);
+ GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_CK);
+
+ GPIO_REG(GPIO_IOF_SEL) |= (1 << I2S_PIN_WS);
+ GPIO_REG(GPIO_IOF_EN) |= (1 << I2S_PIN_WS);
+}
+
+void eos_i2s_stop(void) {
+ I2S_PWM_REG_CK(PWM_CFG) = 0;
+ I2S_PWM_REG_WS(PWM_CFG) = 0;
+ I2S_PWM_REG_CK(PWM_COUNT) = 0;
+ I2S_PWM_REG_WS(PWM_COUNT) = 0;
+
+ GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_CK);
+ GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_CK);
+
+ GPIO_REG(GPIO_IOF_EN) &= ~(1 << I2S_PIN_WS);
+ GPIO_REG(GPIO_IOF_SEL) &= ~(1 << I2S_PIN_WS);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~((1 << I2S_PIN_CK) | (1 << I2S_PIN_WS));
+}
+
+uint16_t eos_i2s_mic_len(void) {
+ uint16_t ret = _abuf_len(&_eos_i2s_mic_buf);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ uint16_t ret = _abuf_read(&_eos_i2s_mic_buf, sample, ssize);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+int eos_i2s_mic_pop(uint8_t *sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_pop(&_eos_i2s_mic_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+uint16_t eos_i2s_spk_len(void) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ uint16_t ret = _abuf_len(&_eos_i2s_spk_buf);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ uint16_t ret = _abuf_write(&_eos_i2s_spk_buf, sample, ssize);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
+
+int eos_i2s_spk_push(uint8_t sample) {
+ clear_csr(mstatus, MSTATUS_MIE);
+ int ret = _abuf_push(&_eos_i2s_spk_buf, sample);
+ set_csr(mstatus, MSTATUS_MIE);
+ return ret;
+}
diff --git a/code/fe310/eos/i2s.h b/code/fe310/eos/i2s.h
new file mode 100644
index 0000000..29e7a28
--- /dev/null
+++ b/code/fe310/eos/i2s.h
@@ -0,0 +1,20 @@
+#include <stdint.h>
+
+typedef struct EOSABuf {
+ uint16_t idx_r;
+ uint16_t idx_w;
+ uint16_t size;
+ uint8_t *array;
+} EOSABuf;
+
+void eos_i2s_init(void);
+void eos_i2s_init_mic(uint8_t *mic_arr, uint16_t mic_arr_size, uint16_t mic_wm, eos_evt_fptr_t mic_wm_handler);
+void eos_i2s_init_spk(uint8_t *spk_arr, uint16_t spk_arr_size, uint16_t spk_wm, eos_evt_fptr_t spk_wm_handler);
+void eos_i2s_start(void);
+void eos_i2s_stop(void);
+uint16_t eos_i2s_mic_len(void);
+uint16_t eos_i2s_mic_read(uint8_t *sample, uint16_t ssize);
+int eos_i2s_mic_pop(uint8_t *sample);
+uint16_t eos_i2s_spk_len(void);
+uint16_t eos_i2s_spk_write(uint8_t *sample, uint16_t ssize);
+int eos_i2s_spk_push(uint8_t sample);
diff --git a/code/fe310/eos/i2s_def.h b/code/fe310/eos/i2s_def.h
new file mode 100644
index 0000000..04e9c27
--- /dev/null
+++ b/code/fe310/eos/i2s_def.h
@@ -0,0 +1,28 @@
+#define I2S_EVT_MIC 0x0
+#define I2S_EVT_SPK 0x1
+#define I2S_MAX_HANDLER 2
+
+#define I2S_PIN_CK 19 // pin 3
+#define I2S_PIN_WS 11 // pin 17
+#define I2S_PIN_SD 12 // pin 18
+
+#define I2S_PIN_LR 13 // pin 19
+
+#define I2S_IRQ_SD_ID (INT_PWM1_BASE + 2)
+#define I2S_IRQ_CK_ID (INT_PWM1_BASE + 0)
+#define I2S_IRQ_WS_ID (INT_PWM2_BASE + 0)
+#define I2S_IRQ_CI_ID (INT_PWM2_BASE + 2)
+
+#define I2S_IRQ_SD_PRIORITY 7
+#define I2S_IRQ_CK_PRIORITY 7
+#define I2S_IRQ_WS_PRIORITY 6
+#define I2S_IRQ_CI_PRIORITY 6
+#define I2S_IRQ_MASK 5
+
+#define I2S_SMPL_WIDTH 13
+
+/* asm */
+#define I2S_ABUF_OFF_IDXR 0
+#define I2S_ABUF_OFF_IDXW 2
+#define I2S_ABUF_OFF_SIZE 4
+#define I2S_ABUF_OFF_ARRAY 8
diff --git a/code/fe310/eos/interrupt.c b/code/fe310/eos/interrupt.c
index 77ab6d5..b8c6540 100644
--- a/code/fe310/eos/interrupt.c
+++ b/code/fe310/eos/interrupt.c
@@ -5,6 +5,7 @@
#include "encoding.h"
#include "platform.h"
#include "plic/plic_driver.h"
+
#include "interrupt.h"
// Global Instance data for the PLIC
diff --git a/code/fe310/eos/msgq_def.h b/code/fe310/eos/msgq_def.h
new file mode 100644
index 0000000..683de9b
--- /dev/null
+++ b/code/fe310/eos/msgq_def.h
@@ -0,0 +1,6 @@
+/* asm */
+#define MSGQ_OFF_IDXR 0
+#define MSGQ_OFF_IDXW 1
+#define MSGQ_OFF_SIZE 2
+#define MSGQ_OFF_ARRAY 4
+#define MSGQ_ITEM_SIZE 12
diff --git a/code/fe310/eos/net.c b/code/fe310/eos/net.c
index 4588485..3339223 100644
--- a/code/fe310/eos/net.c
+++ b/code/fe310/eos/net.c
@@ -6,7 +6,6 @@
#include "encoding.h"
#include "platform.h"
-#include "plic/plic_driver.h"
#include "eos.h"
#include "msgq.h"
diff --git a/code/fe310/eos/timer.c b/code/fe310/eos/timer.c
index 9e2ae9d..915be6f 100644
--- a/code/fe310/eos/timer.c
+++ b/code/fe310/eos/timer.c
@@ -3,6 +3,7 @@
#include "encoding.h"
#include "platform.h"
+
#include "event.h"
#include "timer.h"
diff --git a/code/fe310/eos/trap_entry.S b/code/fe310/eos/trap_entry.S
new file mode 100644
index 0000000..1c164d3
--- /dev/null
+++ b/code/fe310/eos/trap_entry.S
@@ -0,0 +1,398 @@
+#include "encoding.h"
+#include "sifive/bits.h"
+
+#define MCAUSE_INT 0x80000000
+#define MCAUSE_EXT (MCAUSE_INT | IRQ_M_EXT)
+#define MCAUSE_TIMER (MCAUSE_INT | IRQ_M_TIMER)
+
+#define PLIC_PRIORITY 0x0C000000
+#define PLIC_THRESHOLD 0x0C200000
+#define PLIC_CLAIM 0x0C200004
+
+#define PWM0_CTRL_ADDR 0x10015000
+#define PWM1_CTRL_ADDR 0x10025000
+#define PWM2_CTRL_ADDR 0x10035000
+
+#define PWM_CFG 0x00
+#define PWM_COUNT 0x08
+
+#define PWM_CFG_CMP0IP 0x10000000
+#define PWM_CFG_CMP1IP 0x20000000
+#define PWM_CFG_CMP2IP 0x40000000
+#define PWM_CFG_CMP3IP 0x80000000
+
+#define GPIO_CTRL_ADDR 0x10012000
+#define GPIO_INPUT_VAL 0x00
+
+#define INT_PWM0_BASE 40
+#define INT_PWM1_BASE 44
+#define INT_PWM2_BASE 48
+
+#define I2S_PWM_CTRL_ADDR_CK PWM1_CTRL_ADDR
+#define I2S_PWM_CTRL_ADDR_WS PWM2_CTRL_ADDR
+
+#include "i2s_def.h"
+#include "evt_def.h"
+#include "msgq_def.h"
+
+ .section .data.entry
+ .align 2
+
+.global eos_trap_entry
+eos_trap_entry:
+ addi sp, sp, -4*REGBYTES
+
+ STORE x8, 0*REGBYTES(sp)
+ STORE x9, 1*REGBYTES(sp)
+ STORE x18, 2*REGBYTES(sp)
+ STORE x19, 3*REGBYTES(sp)
+
+ csrr x8, mcause
+ li x18, MCAUSE_EXT
+ bne x8, x18, handler
+ li x18, PLIC_CLAIM
+ lw x9, 0(x18)
+ li x18, I2S_IRQ_SD_ID
+ beq x9, x18, handler_sd
+ li x18, I2S_IRQ_CK_ID
+ beq x9, x18, handler_ck
+ li x18, I2S_IRQ_WS_ID
+ beq x9, x18, handler_ws
+ li x18, I2S_IRQ_CI_ID
+ beq x9, x18, handler_ci
+ j handler
+
+handler_sd:
+ # read mic value -> x8
+ li x18, GPIO_CTRL_ADDR
+ lw x8, GPIO_INPUT_VAL(x18)
+
+ # set bit as ws pwm counter/ck period - sd volume -> x9
+ li x18, I2S_PWM_CTRL_ADDR_WS
+ lw x9, PWM_COUNT(x18)
+ la x18, _eos_i2s_ck_period
+ lw x19, 0(x18)
+ divu x9, x9, x19
+ la x18, _eos_i2s_mic_volume
+ lw x19, 0(x18)
+ sub x9, x9, x19
+
+ # disable sd irq
+ li x18, PLIC_PRIORITY
+ sw x0, 4*I2S_IRQ_SD_ID(x18)
+
+ addi sp, sp, -1*REGBYTES
+ STORE x20, 0*REGBYTES(sp)
+
+ # bit <= 0 -> exit
+ bge x0, x9, handler_sd_exit
+
+ # sample |= sd gpio value << (32 - bit) -> x8
+ # sample_mask |= 1 << (32 - bit) -> x20
+ li x18, (0x1 << I2S_PIN_SD)
+ and x8, x8, x18
+ srli x8, x8, I2S_PIN_SD
+ li x18, 32
+ sub x19, x18, x9
+ sll x8, x8, x19
+ li x20, 1
+ sll x20, x20, x19
+ la x18, sd_sample_mask
+ lw x19, 0(x18)
+ or x19, x19, x20
+ sw x19, 0(x18)
+ mv x20, x19
+ la x18, sd_sample
+ lw x19, 0(x18)
+ or x19, x19, x8
+ sw x19, 0(x18)
+ mv x8, x19
+
+ # bit < I2S_SMPL_WIDTH -> exit
+ li x18, I2S_SMPL_WIDTH
+ blt x9, x18, handler_sd_exit
+
+ # disable ck irq
+ li x18, PLIC_PRIORITY
+ sw x0, 4*I2S_IRQ_CK_ID(x18)
+
+ # reset irq mask
+ li x18, PLIC_THRESHOLD
+ sw x0, 0(x18)
+
+ # reset sample / sample_mask
+ la x18, sd_sample
+ sw x0, 0(x18)
+ la x18, sd_sample_mask
+ sw x0, 0(x18)
+
+ # correct for missed bits
+ la x18, sd_sample_save
+ li x19, 0x80000000
+ srai x19, x19, I2S_SMPL_WIDTH-1
+ and x20, x20, x19
+ beq x19, x20, 0f
+ lw x8, 0(x18)
+0:
+ sw x8, 0(x18)
+ srai x8, x8, 32-I2S_SMPL_WIDTH
+
+ # aLaw encode -> x8
+ li x18, 0x800
+ li x19, 7
+ bgez x8, 1f
+ neg x8, x8
+ lui x9, 0x80000
+ or x8, x8, x9
+1:
+ and x9, x8, x18
+ beq x9, x18, 2f
+ beqz x19, 2f
+ srli x18, x18, 1
+ addi x19, x19, -1
+ j 1b
+2:
+ mv x9, x19
+ bnez x9, 3f
+ addi x9, x9, 1
+3:
+ sra x8, x8, x9
+ li x9, 0x8000000f
+ and x8, x8, x9
+ slli x19, x19, 4
+ or x8, x8, x19
+ bgez x8, 4f
+ ori x8, x8, 0x80
+
+4:
+ xori x8, x8, 0x55
+ andi x8, x8, 0xff
+
+ # push to mic but
+ la x9, _eos_i2s_mic_buf
+ lhu x18, I2S_ABUF_OFF_IDXR(x9)
+ lhu x19, I2S_ABUF_OFF_IDXW(x9)
+ lhu x20, I2S_ABUF_OFF_SIZE(x9)
+
+ sub x18, x19, x18
+ beq x18, x20, handler_sd_exit
+
+ addi x20, x20, -1
+ and x20, x20, x19
+ lw x18, I2S_ABUF_OFF_ARRAY(x9)
+ add x20, x20, x18
+ sb x8, 0(x20)
+
+ addi x19, x19, 1
+ sh x19, I2S_ABUF_OFF_IDXW(x9)
+
+ # push to event queue
+ la x9, _eos_i2s_mic_wm
+ lhu x20, 0(x9)
+ beqz x20, handler_sd_exit
+
+ la x9, _eos_i2s_mic_buf
+ lhu x18, I2S_ABUF_OFF_IDXR(x9)
+ sub x18, x19, x18
+ bne x18, x20, handler_sd_exit
+
+ la x9, _eos_event_q
+ lbu x18, MSGQ_OFF_IDXR(x9)
+ lbu x19, MSGQ_OFF_IDXW(x9)
+ lbu x20, MSGQ_OFF_SIZE(x9)
+
+ sub x18, x19, x18
+ beq x18, x20, handler_sd_exit
+
+ addi x20, x20, -1
+ and x20, x20, x19
+ li x18, MSGQ_ITEM_SIZE
+ mul x20, x20, x18
+ lw x18, MSGQ_OFF_ARRAY(x9)
+ add x20, x20, x18
+ li x18, (EOS_EVT_AUDIO | I2S_EVT_MIC)
+ sb x18, 0(x20)
+
+ addi x19, x19, 1
+ sb x19, MSGQ_OFF_IDXW(x9)
+ j handler_sd_exit
+
+handler_sd_exit:
+ LOAD x20, 0*REGBYTES(sp)
+ addi sp, sp, 1*REGBYTES
+
+ # complete
+ li x18, I2S_IRQ_SD_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+handler_ck:
+ # enable sd irq
+ li x18, PLIC_PRIORITY
+ li x19, I2S_IRQ_SD_PRIORITY
+ sw x19, 4*I2S_IRQ_SD_ID(x18)
+
+ # complete
+ li x18, I2S_IRQ_CK_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+handler_ws:
+ # enable wsc irq
+ li x18, PLIC_PRIORITY
+ li x19, I2S_IRQ_CI_PRIORITY
+ sw x19, 4*I2S_IRQ_CI_ID(x18)
+
+ # complete
+ li x18, I2S_IRQ_WS_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+handler_ci:
+ # disable wsc/enable ck irq
+ li x18, PLIC_PRIORITY
+ sw x0, 4*I2S_IRQ_CI_ID(x18)
+ li x19, I2S_IRQ_CK_PRIORITY
+ sw x19, 4*I2S_IRQ_CK_ID(x18)
+
+ # set irq mask
+ li x18, PLIC_THRESHOLD
+ li x19, I2S_IRQ_MASK
+ sw x19, 0(x18)
+
+ # complete
+ li x18, I2S_IRQ_CI_ID
+ li x19, PLIC_CLAIM
+ sw x18, 0(x19)
+
+ # exit
+ j trap_exit_data
+
+trap_exit_data:
+ # Remain in M-mode after mret
+ li x18, MSTATUS_MPP
+ csrs mstatus, x18
+
+ LOAD x8, 0*REGBYTES(sp)
+ LOAD x9, 1*REGBYTES(sp)
+ LOAD x18, 2*REGBYTES(sp)
+ LOAD x19, 3*REGBYTES(sp)
+
+ addi sp, sp, 4*REGBYTES
+ mret
+
+handler:
+ lui x18, %hi(trap_entry_text)
+ addi x18, x18, %lo(trap_entry_text)
+ jalr x0, x18
+
+ .align 4
+
+sd_sample:
+ .word 0
+sd_sample_save:
+ .word 0
+sd_sample_mask:
+ .word 0
+
+ .section .text.entry
+ .align 2
+
+trap_entry_text:
+ addi sp, sp, -28*REGBYTES
+
+ STORE x1, 0*REGBYTES(sp)
+ STORE x2, 1*REGBYTES(sp)
+ STORE x3, 2*REGBYTES(sp)
+ STORE x4, 3*REGBYTES(sp)
+ STORE x5, 4*REGBYTES(sp)
+ STORE x6, 5*REGBYTES(sp)
+ STORE x7, 6*REGBYTES(sp)
+ STORE x10, 7*REGBYTES(sp)
+ STORE x11, 8*REGBYTES(sp)
+ STORE x12, 9*REGBYTES(sp)
+ STORE x13, 10*REGBYTES(sp)
+ STORE x14, 11*REGBYTES(sp)
+ STORE x15, 12*REGBYTES(sp)
+ STORE x16, 13*REGBYTES(sp)
+ STORE x17, 14*REGBYTES(sp)
+ STORE x20, 15*REGBYTES(sp)
+ STORE x21, 16*REGBYTES(sp)
+ STORE x22, 17*REGBYTES(sp)
+ STORE x23, 18*REGBYTES(sp)
+ STORE x24, 19*REGBYTES(sp)
+ STORE x25, 20*REGBYTES(sp)
+ STORE x26, 21*REGBYTES(sp)
+ STORE x27, 22*REGBYTES(sp)
+ STORE x28, 23*REGBYTES(sp)
+ STORE x29, 24*REGBYTES(sp)
+ STORE x30, 25*REGBYTES(sp)
+ STORE x31, 26*REGBYTES(sp)
+
+ li x18, MCAUSE_TIMER
+ beq x8, x18, handle_timer
+ li x18, MCAUSE_EXT
+ beq x8, x18, handle_ext
+ mv a0, x8
+ call _exit
+
+handle_timer:
+ call eos_timer_handle
+ j trap_exit_text
+
+handle_ext:
+ mv a0, x9
+ call eos_intr_handle
+ li x18, PLIC_CLAIM
+ sw a0, 0(x18)
+ j trap_exit_text
+
+trap_exit_text:
+ # Remain in M-mode after mret
+ li t0, MSTATUS_MPP
+ csrs mstatus, t0
+
+ LOAD x1, 0*REGBYTES(sp)
+ LOAD x2, 1*REGBYTES(sp)
+ LOAD x3, 2*REGBYTES(sp)
+ LOAD x4, 3*REGBYTES(sp)
+ LOAD x5, 4*REGBYTES(sp)
+ LOAD x6, 5*REGBYTES(sp)
+ LOAD x7, 6*REGBYTES(sp)
+ LOAD x10, 7*REGBYTES(sp)
+ LOAD x11, 8*REGBYTES(sp)
+ LOAD x12, 9*REGBYTES(sp)
+ LOAD x13, 10*REGBYTES(sp)
+ LOAD x14, 11*REGBYTES(sp)
+ LOAD x15, 12*REGBYTES(sp)
+ LOAD x16, 13*REGBYTES(sp)
+ LOAD x17, 14*REGBYTES(sp)
+ LOAD x20, 15*REGBYTES(sp)
+ LOAD x21, 16*REGBYTES(sp)
+ LOAD x22, 17*REGBYTES(sp)
+ LOAD x23, 18*REGBYTES(sp)
+ LOAD x24, 19*REGBYTES(sp)
+ LOAD x25, 20*REGBYTES(sp)
+ LOAD x26, 21*REGBYTES(sp)
+ LOAD x27, 22*REGBYTES(sp)
+ LOAD x28, 23*REGBYTES(sp)
+ LOAD x29, 24*REGBYTES(sp)
+ LOAD x30, 25*REGBYTES(sp)
+ LOAD x31, 26*REGBYTES(sp)
+
+ LOAD x8, 28*REGBYTES(sp)
+ LOAD x9, 29*REGBYTES(sp)
+ LOAD x18, 30*REGBYTES(sp)
+ LOAD x19, 31*REGBYTES(sp)
+
+ addi sp, sp, 32*REGBYTES
+ mret