From 5fe913c88d8c1781de336cca3949142bd9fc370d Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Wed, 14 Mar 2018 19:08:00 +0100
Subject: i2s driver added; new amd trap entry vector added

---
 code/fe310/eos/Makefile     |   5 +-
 code/fe310/eos/event.h      |  12 +-
 code/fe310/eos/evt_def.h    |  11 ++
 code/fe310/eos/i2s.c        | 211 +++++++++++++++++++++++
 code/fe310/eos/i2s.h        |  20 +++
 code/fe310/eos/i2s_def.h    |  28 ++++
 code/fe310/eos/interrupt.c  |   1 +
 code/fe310/eos/msgq_def.h   |   6 +
 code/fe310/eos/net.c        |   1 -
 code/fe310/eos/timer.c      |   1 +
 code/fe310/eos/trap_entry.S | 398 ++++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 681 insertions(+), 13 deletions(-)
 create mode 100644 code/fe310/eos/evt_def.h
 create mode 100644 code/fe310/eos/i2s.c
 create mode 100644 code/fe310/eos/i2s.h
 create mode 100644 code/fe310/eos/i2s_def.h
 create mode 100644 code/fe310/eos/msgq_def.h
 create mode 100644 code/fe310/eos/trap_entry.S

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
-- 
cgit v1.2.3