diff --git a/am/arch/platform/nemu.mk b/am/arch/platform/nemu.mk index 6117980c..30d54693 100644 --- a/am/arch/platform/nemu.mk +++ b/am/arch/platform/nemu.mk @@ -4,6 +4,7 @@ AM_SRCS += nemu/common/trm.c \ nemu/common/input.c \ nemu/common/timer.c \ nemu/common/video.c \ + nemu/common/audio.c \ dummy/mpe.c \ CFLAGS += -I$(AM_HOME)/am/src/nemu/include diff --git a/am/src/nemu/common/audio.c b/am/src/nemu/common/audio.c new file mode 100644 index 00000000..afc32fbf --- /dev/null +++ b/am/src/nemu/common/audio.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +static uint8_t* const sbuf = (uint8_t *)AUDIO_SBUF_ADDR; +static int sbuf_size = 0; +static int head = 0; + +void __am_audio_init() { +} + +static int audio_write(uint8_t *buf, int len) { + uint32_t count = inl(AUDIO_COUNT_ADDR); + int free = sbuf_size - count; + int nwrite = len; + if (free < len) nwrite = free; + + if (nwrite + head < sbuf_size) { + memcpy(sbuf + head, buf, nwrite); + head += nwrite; + } else { + int first_cpy_len = sbuf_size - head; + memcpy(sbuf + head, buf, first_cpy_len); + memcpy(sbuf, buf + first_cpy_len, nwrite - first_cpy_len); + head = nwrite - first_cpy_len; + } + count += nwrite; + outl(AUDIO_COUNT_ADDR, count); + return nwrite; +} + +size_t __am_audio_write(uintptr_t reg, void *buf, size_t size) { + switch (reg) { + case _DEVREG_AUDIO_INIT: { + _DEV_AUDIO_INIT_t *init = (_DEV_AUDIO_INIT_t *)buf; + outl(AUDIO_FREQ_ADDR, init->freq); + outl(AUDIO_CHANNELS_ADDR, init->channels); + outl(AUDIO_SAMPLES_ADDR, init->samples); + outl(AUDIO_SBUF_SIZE_ADDR, init->bufsize); + outl(AUDIO_INIT_ADDR, 1); + sbuf_size = init->bufsize; + + head = 0; + return size; + } + case _DEVREG_AUDIO_SBCTRL: { + _DEV_AUDIO_SBCTRL_t *ctl = (_DEV_AUDIO_SBCTRL_t *)buf; + if (ctl->wait) { + assert(ctl->len <= sbuf_size); + while (sbuf_size - inl(AUDIO_COUNT_ADDR) < ctl->len); + } + ctl->len = audio_write(ctl->stream, ctl->len); + return size; + } + } + return 0; +} + +size_t __am_audio_read(uintptr_t reg, void *buf, size_t size) { + switch (reg) { + case _DEVREG_AUDIO_SBSTAT: { + _DEV_AUDIO_SBSTAT_t *stat = (_DEV_AUDIO_SBSTAT_t *)buf; + stat->count = inl(AUDIO_COUNT_ADDR); + stat->bufsize = sbuf_size; + return size; + } + } + return 0; +} diff --git a/am/src/nemu/common/ioe.c b/am/src/nemu/common/ioe.c index b1977cb8..3a8ad38b 100644 --- a/am/src/nemu/common/ioe.c +++ b/am/src/nemu/common/ioe.c @@ -3,10 +3,12 @@ void __am_vga_init(); void __am_timer_init(); +void __am_audio_init(); int _ioe_init() { __am_vga_init(); __am_timer_init(); + __am_audio_init(); return 0; } @@ -14,12 +16,15 @@ size_t __am_timer_read(uintptr_t reg, void *buf, size_t size); size_t __am_video_read(uintptr_t reg, void *buf, size_t size); size_t __am_video_write(uintptr_t reg, void *buf, size_t size); size_t __am_input_read(uintptr_t reg, void *buf, size_t size); +size_t __am_audio_read(uintptr_t reg, void *buf, size_t size); +size_t __am_audio_write(uintptr_t reg, void *buf, size_t size); size_t _io_read(uint32_t dev, uintptr_t reg, void *buf, size_t size) { switch (dev) { case _DEV_INPUT: return __am_input_read(reg, buf, size); case _DEV_TIMER: return __am_timer_read(reg, buf, size); case _DEV_VIDEO: return __am_video_read(reg, buf, size); + case _DEV_AUDIO: return __am_audio_read(reg, buf, size); } return 0; } @@ -27,6 +32,7 @@ size_t _io_read(uint32_t dev, uintptr_t reg, void *buf, size_t size) { size_t _io_write(uint32_t dev, uintptr_t reg, void *buf, size_t size) { switch (dev) { case _DEV_VIDEO: return __am_video_write(reg, buf, size); + case _DEV_AUDIO: return __am_audio_write(reg, buf, size); } return 0; } diff --git a/am/src/nemu/include/nemu.h b/am/src/nemu/include/nemu.h index 9ff593a7..64cb4bba 100644 --- a/am/src/nemu/include/nemu.h +++ b/am/src/nemu/include/nemu.h @@ -12,6 +12,13 @@ # define SCREEN_ADDR 0x100 # define SYNC_ADDR 0x104 # define FB_ADDR 0xa0000000 +# define AUDIO_FREQ_ADDR 0x200 +# define AUDIO_CHANNELS_ADDR 0x204 +# define AUDIO_SAMPLES_ADDR 0x208 +# define AUDIO_SBUF_SIZE_ADDR 0x20c +# define AUDIO_INIT_ADDR 0x210 +# define AUDIO_COUNT_ADDR 0x214 +# define AUDIO_SBUF_ADDR 0xa0800000 #elif defined(__ARCH_RISCV64_NOOP) || defined(__ARCH_RISCV32_NOOP) # define KBD_ADDR 0x40900000 # define RTC_ADDR 0x4800bff8 @@ -25,6 +32,13 @@ # define SCREEN_ADDR 0xa1000100 # define SYNC_ADDR 0xa1000104 # define FB_ADDR 0xa0000000 +# define AUDIO_FREQ_ADDR 0xa1000200 +# define AUDIO_CHANNELS_ADDR 0xa1000204 +# define AUDIO_SAMPLES_ADDR 0xa1000208 +# define AUDIO_SBUF_SIZE_ADDR 0xa100020c +# define AUDIO_INIT_ADDR 0xa1000210 +# define AUDIO_COUNT_ADDR 0xa1000214 +# define AUDIO_SBUF_ADDR 0xa0800000 #endif #define MMIO_BASE 0xa0000000