You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(35) |
Dec
(2) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(37) |
Feb
(10) |
Mar
|
Apr
(2) |
May
(17) |
Jun
(1) |
Jul
(14) |
Aug
(14) |
Sep
(4) |
Oct
|
Nov
(14) |
Dec
(4) |
2005 |
Jan
(6) |
Feb
|
Mar
|
Apr
(6) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
(92) |
Dec
(12) |
2006 |
Jan
(3) |
Feb
(4) |
Mar
|
Apr
(5) |
May
(3) |
Jun
(15) |
Jul
(3) |
Aug
(1) |
Sep
(29) |
Oct
(1) |
Nov
(6) |
Dec
(5) |
2007 |
Jan
(2) |
Feb
(2) |
Mar
|
Apr
(3) |
May
(14) |
Jun
(2) |
Jul
(16) |
Aug
(73) |
Sep
(12) |
Oct
(9) |
Nov
(27) |
Dec
(3) |
2008 |
Jan
(4) |
Feb
(4) |
Mar
(3) |
Apr
(8) |
May
(23) |
Jun
(4) |
Jul
(1) |
Aug
(3) |
Sep
(7) |
Oct
(5) |
Nov
(1) |
Dec
(1) |
2009 |
Jan
|
Feb
(10) |
Mar
|
Apr
(4) |
May
(4) |
Jun
(10) |
Jul
|
Aug
(1) |
Sep
|
Oct
(7) |
Nov
|
Dec
(1) |
2010 |
Jan
|
Feb
(1) |
Mar
|
Apr
(6) |
May
|
Jun
(3) |
Jul
(11) |
Aug
(1) |
Sep
|
Oct
(15) |
Nov
(1) |
Dec
(5) |
2011 |
Jan
(4) |
Feb
(1) |
Mar
(6) |
Apr
|
May
(22) |
Jun
|
Jul
(8) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2012 |
Jan
|
Feb
(10) |
Mar
(1) |
Apr
(6) |
May
(27) |
Jun
(48) |
Jul
(30) |
Aug
(4) |
Sep
|
Oct
(3) |
Nov
(1) |
Dec
(11) |
2013 |
Jan
(4) |
Feb
(7) |
Mar
(6) |
Apr
(18) |
May
(28) |
Jun
(20) |
Jul
|
Aug
(4) |
Sep
(1) |
Oct
(1) |
Nov
(2) |
Dec
(7) |
2014 |
Jan
(3) |
Feb
(2) |
Mar
(4) |
Apr
(9) |
May
(11) |
Jun
(10) |
Jul
|
Aug
(18) |
Sep
(12) |
Oct
(17) |
Nov
(10) |
Dec
(16) |
2015 |
Jan
(5) |
Feb
(1) |
Mar
(5) |
Apr
(4) |
May
(28) |
Jun
(2) |
Jul
|
Aug
|
Sep
(6) |
Oct
|
Nov
(2) |
Dec
(1) |
2016 |
Jan
(14) |
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
(3) |
Jul
(4) |
Aug
(4) |
Sep
(1) |
Oct
(1) |
Nov
|
Dec
(1) |
2017 |
Jan
(11) |
Feb
|
Mar
(21) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2018 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
(2) |
Sep
(4) |
Oct
(4) |
Nov
|
Dec
(1) |
2019 |
Jan
(1) |
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(13) |
Sep
(4) |
Oct
|
Nov
|
Dec
|
2020 |
Jan
(10) |
Feb
(9) |
Mar
(5) |
Apr
(4) |
May
(3) |
Jun
(18) |
Jul
(4) |
Aug
(2) |
Sep
(20) |
Oct
(2) |
Nov
|
Dec
|
2021 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(1) |
Jun
(2) |
Jul
(1) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2022 |
Jan
(1) |
Feb
(2) |
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
(5) |
Sep
|
Oct
(1) |
Nov
|
Dec
(1) |
2023 |
Jan
(10) |
Feb
(7) |
Mar
(29) |
Apr
(31) |
May
(29) |
Jun
(34) |
Jul
(3) |
Aug
(24) |
Sep
(22) |
Oct
(10) |
Nov
(38) |
Dec
(27) |
2024 |
Jan
(15) |
Feb
(8) |
Mar
(4) |
Apr
(20) |
May
(33) |
Jun
(18) |
Jul
(15) |
Aug
(23) |
Sep
(26) |
Oct
(32) |
Nov
(6) |
Dec
(4) |
2025 |
Jan
(7) |
Feb
(1) |
Mar
(1) |
Apr
(4) |
May
(46) |
Jun
(19) |
Jul
(21) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: ljsebald <ljs...@us...> - 2023-11-13 17:17:20
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 5e0d59d084fe4ecd7a244956dbab36033e77ea83 (commit) via 2e8aaffe715ff25f312a60de122f3999528589f5 (commit) from a5a79598ba4bf76fc85a66b267eeeedf8cf6d10a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5e0d59d084fe4ecd7a244956dbab36033e77ea83 Author: Andress Barajas <and...@gm...> Date: Mon Nov 13 09:16:51 2023 -0800 ARM AICA Clean up types and spacing (#357) * Update types and spacing commit 2e8aaffe715ff25f312a60de122f3999528589f5 Author: Andress Barajas <and...@gm...> Date: Mon Nov 13 09:13:18 2023 -0800 SPU Clean (#356) * Clean SPU magic numbers and types * Apply SWAT suggestions * Added FIFO_G2 to g2_lock() * Add dbglog for deallocing channels * Use mutex when creating and destroying streams ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/hardware/spu.c | 73 ++++++++++++++------------------ kernel/arch/dreamcast/include/dc/g2bus.h | 2 +- kernel/arch/dreamcast/include/dc/spu.h | 14 +++--- kernel/arch/dreamcast/sound/snd_iface.c | 39 ++++++++--------- kernel/arch/dreamcast/sound/snd_stream.c | 48 ++++++++++++--------- 5 files changed, 87 insertions(+), 89 deletions(-) diff --git a/kernel/arch/dreamcast/hardware/spu.c b/kernel/arch/dreamcast/hardware/spu.c index 2cc796c..b5c158d 100644 --- a/kernel/arch/dreamcast/hardware/spu.c +++ b/kernel/arch/dreamcast/hardware/spu.c @@ -8,7 +8,6 @@ #include <dc/spu.h> #include <dc/g2bus.h> #include <dc/sq.h> -#include <arch/memory.h> #include <arch/timer.h> /* @@ -36,22 +35,19 @@ kernel; so don't use them if you don't need to =). /* memcpy and memset designed for sound RAM; for addresses, don't bother to include the 0xa0800000 offset that is implied. 'length' must be a multiple of 4, but if it is not it will be rounded up. */ -void spu_memload(uint32 dst, void *src_void, int length) { - uint8 *src = (uint8*)src_void; +void spu_memload(uintptr_t dst, void *src_void, size_t length) { + uint8_t *src = (uint8_t *)src_void; /* Make sure it's an even number of 32-bit words and convert the count to a 32-bit word count */ - if(length % 4) - length = (length / 4) + 1; - else - length = length / 4; + length = (length + 3) >> 2; /* Add in the SPU RAM base */ - dst += 0xa0800000; + dst += SPU_RAM_UNCACHED_BASE; while(length > 8) { g2_fifo_wait(); - g2_write_block_32((uint32*)src, dst, 8); + g2_write_block_32((uint32_t *)src, dst, 8); src += 8 * 4; dst += 8 * 4; @@ -60,32 +56,33 @@ void spu_memload(uint32 dst, void *src_void, int length) { if(length > 0) { g2_fifo_wait(); - g2_write_block_32((uint32*)src, dst, length); + g2_write_block_32((uint32_t *)src, dst, length); } } -void spu_memload_sq(uint32 dst, void *src_void, int length) { - uint8 *src = (uint8 *)src_void; - int aligned_len, old; +void spu_memload_sq(uintptr_t dst, void *src_void, size_t length) { + uint8_t *src = (uint8_t *)src_void; + int aligned_len; + g2_ctx_t ctx; - /* Make sure it's an even number of 32-bit words and convert the - count to a 32-bit word count */ + /* Round up to the nearest multiple of 4 */ if(length & 3) { length = (length + 4) & ~3; } - /* Add in the SPU RAM base (cached area) */ - dst += 0x00800000; - /* Using SQs for all that is divisible by 32 */ aligned_len = length & ~31; length &= 31; - old = irq_disable(); - do { } while(*(vuint32 *)0xa05f688c & (1 << 5)); /* FIFO_SH4 */ - do { } while(*(vuint32 *)0xa05f688c & (1 << 4)); /* FIFO_G2 */ + /* Add in the SPU RAM base (cached area) */ + dst += SPU_RAM_BASE; + + /* Make sure the FIFOs are empty */ + ctx = g2_lock(); + sq_cpy((void *)dst, src, aligned_len); - irq_restore(old); + + g2_unlock(ctx); if(length > 0) { /* Make sure the destination is in a non-cached area */ @@ -93,26 +90,23 @@ void spu_memload_sq(uint32 dst, void *src_void, int length) { dst += aligned_len; src += aligned_len; g2_fifo_wait(); - g2_write_block_32((uint32 *)src, dst, length >> 2); + g2_write_block_32((uint32_t *)src, dst, length >> 2); } } -void spu_memread(void *dst_void, uint32 src, int length) { - uint8 *dst = (uint8*)dst_void; +void spu_memread(void *dst_void, uintptr_t src, size_t length) { + uint8_t *dst = (uint8_t *)dst_void; /* Make sure it's an even number of 32-bit words and convert the count to a 32-bit word count */ - if(length % 4) - length = (length / 4) + 1; - else - length = length / 4; + length = (length + 3) >> 2; /* Add in the SPU RAM base */ - src += 0xa0800000; + src += SPU_RAM_UNCACHED_BASE; while(length > 8) { g2_fifo_wait(); - g2_read_block_32((uint32*)dst, src, 8); + g2_read_block_32((uint32_t *)dst, src, 8); src += 8 * 4; dst += 8 * 4; @@ -121,27 +115,24 @@ void spu_memread(void *dst_void, uint32 src, int length) { if(length > 0) { g2_fifo_wait(); - g2_read_block_32((uint32*)dst, src, length); + g2_read_block_32((uint32_t *)dst, src, length); } } -void spu_memset(uint32 dst, unsigned long what, int length) { - uint32 blank[8]; +void spu_memset(uintptr_t dst, uint32_t what, size_t length) { + uint32_t blank[8]; int i; /* Make sure it's an even number of 32-bit words and convert the count to a 32-bit word count */ - if(length % 4) - length = (length / 4) + 1; - else - length = length / 4; + length = (length + 3) >> 2; /* Initialize the array */ for(i = 0; i < 8; i++) blank[i] = what; /* Add in the SPU RAM base */ - dst += 0xa0800000; + dst += SPU_RAM_UNCACHED_BASE; while(length > 8) { g2_fifo_wait(); @@ -249,7 +240,7 @@ int spu_init(void) { /* Load a default "program" into the SPU that just executes an infinite loop, so that CD audio works. */ g2_fifo_wait(); - g2_write_32(0xa0800000, 0xeafffff8); + g2_write_32(SPU_RAM_UNCACHED_BASE, 0xeafffff8); /* Start the SPU again */ spu_enable(); @@ -273,7 +264,7 @@ int spu_shutdown(void) { int spu_dma_transfer(void *from, uintptr_t dest, size_t length, int block, g2_dma_callback_t callback, void *cbdata) { /* Adjust destination to SPU RAM */ - dest += 0x00800000; + dest += SPU_RAM_BASE; return g2_dma_transfer(from, (void *) dest, length, block, callback, cbdata, 0, 0, G2_DMA_CHAN_SPU, 0); diff --git a/kernel/arch/dreamcast/include/dc/g2bus.h b/kernel/arch/dreamcast/include/dc/g2bus.h index 6962e19..5ce1552 100644 --- a/kernel/arch/dreamcast/include/dc/g2bus.h +++ b/kernel/arch/dreamcast/include/dc/g2bus.h @@ -161,7 +161,7 @@ static inline g2_ctx_t g2_lock(void) { G2_DMA_SUSPEND_BBA = 1; G2_DMA_SUSPEND_CH2 = 1; - while(FIFO_STATUS & FIFO_SH4); + while(FIFO_STATUS & (FIFO_SH4 | FIFO_G2)); return ctx; } diff --git a/kernel/arch/dreamcast/include/dc/spu.h b/kernel/arch/dreamcast/include/dc/spu.h index 8522146..95ca422 100644 --- a/kernel/arch/dreamcast/include/dc/spu.h +++ b/kernel/arch/dreamcast/include/dc/spu.h @@ -22,10 +22,12 @@ __BEGIN_DECLS #include <arch/types.h> +#include <arch/memory.h> #include <dc/g2bus.h> -/** \brief Waits for the sound FIFO to empty. */ -void spu_write_wait(void); +/** \brief Sound ram address from the SH4 side */ +#define SPU_RAM_BASE 0x00800000 +#define SPU_RAM_UNCACHED_BASE (MEM_AREA_P2_BASE | SPU_RAM_BASE) /** \brief Copy a block of data to sound RAM. @@ -37,7 +39,7 @@ void spu_write_wait(void); \param length The number of bytes to copy. Automatically rounded up to be a multiple of 4. */ -void spu_memload(uint32 to, void *from, int length); +void spu_memload(uintptr_t to, void *from, size_t length); /** \brief Copy a block of data to sound RAM. @@ -51,7 +53,7 @@ void spu_memload(uint32 to, void *from, int length); \param length The number of bytes to copy. Automatically rounded up to be a multiple of 4. */ -void spu_memload_sq(uint32 to, void *from, int length); +void spu_memload_sq(uintptr_t to, void *from, size_t length); /** \brief Copy a block of data from sound RAM. @@ -63,7 +65,7 @@ void spu_memload_sq(uint32 to, void *from, int length); \param length The number of bytes to copy. Automatically rounded up to be a multiple of 4. */ -void spu_memread(void *to, uint32 from, int length); +void spu_memread(void *to, uintptr_t from, size_t length); /** \brief Set a block of sound RAM to the specified value. @@ -76,7 +78,7 @@ void spu_memread(void *to, uint32 from, int length); \param length The number of bytes to copy. Automatically rounded up to be a multiple of 4. */ -void spu_memset(uint32 to, uint32 what, int length); +void spu_memset(uintptr_t to, uint32_t what, size_t length); /* DMA copy from SH-4 RAM to SPU RAM; length must be a multiple of 32, and the source and destination addresses must be aligned on 32-byte diff --git a/kernel/arch/dreamcast/sound/snd_iface.c b/kernel/arch/dreamcast/sound/snd_iface.c index 6f22f95..a3f56ed 100644 --- a/kernel/arch/dreamcast/sound/snd_iface.c +++ b/kernel/arch/dreamcast/sound/snd_iface.c @@ -19,15 +19,12 @@ #include "arm/aica_cmd_iface.h" -/* the address of the sound ram from the SH4 side */ -#define SPU_RAM_BASE 0xa0800000 - /* Are we initted? */ static int initted = 0; /* This will come from a seperately linked object file */ -extern uint8 snd_stream_drv[]; -extern uint8 snd_stream_drv_end[]; +extern uint8_t snd_stream_drv[]; +extern uint8_t snd_stream_drv_end[]; /* Thread semaphore */ static semaphore_t sem_qram; @@ -46,7 +43,7 @@ int snd_init(void) { if(amt % 4) amt = (amt + 4) & ~3; - printf("snd_init(): loading %d bytes into SPU RAM\n", amt); + dbglog(DBG_DEBUG, "snd_init(): loading %d bytes into SPU RAM\n", amt); spu_memload(0, snd_stream_drv, amt); /* Enable the AICA and give it a few ms to start up */ @@ -76,17 +73,17 @@ void snd_shutdown(void) { } /* Submit a request to the SH4->AICA queue; size is in uint32's */ -int snd_sh4_to_aica(void *packet, uint32 size) { - uint32 qa, bot, start, top, *pkt32, cnt; +int snd_sh4_to_aica(void *packet, uint32_t size) { + uint32_t qa, bot, start, top, *pkt32, cnt; assert_msg(size < 256, "SH4->AICA packets may not be >256 uint32's long"); sem_wait(&sem_qram); /* Set these up for reference */ - qa = SPU_RAM_BASE + AICA_MEM_CMD_QUEUE; + qa = SPU_RAM_UNCACHED_BASE + AICA_MEM_CMD_QUEUE; assert_msg(g2_read_32(qa + offsetof(aica_queue_t, valid)), "Queue is not yet valid"); - bot = SPU_RAM_BASE + g2_read_32(qa + offsetof(aica_queue_t, data)); + bot = SPU_RAM_UNCACHED_BASE + g2_read_32(qa + offsetof(aica_queue_t, data)); top = bot + g2_read_32(qa + offsetof(aica_queue_t, size)); start = bot + g2_read_32(qa + offsetof(aica_queue_t, head)); pkt32 = (uint32 *)packet; @@ -125,12 +122,12 @@ int snd_sh4_to_aica(void *packet, uint32 size) { /* Start processing requests in the queue */ void snd_sh4_to_aica_start(void) { - g2_write_32(SPU_RAM_BASE + AICA_MEM_CMD_QUEUE + offsetof(aica_queue_t, process_ok), 1); + g2_write_32(SPU_RAM_UNCACHED_BASE + AICA_MEM_CMD_QUEUE + offsetof(aica_queue_t, process_ok), 1); } /* Stop processing requests in the queue */ void snd_sh4_to_aica_stop(void) { - g2_write_32(SPU_RAM_BASE + AICA_MEM_CMD_QUEUE + offsetof(aica_queue_t, process_ok), 0); + g2_write_32(SPU_RAM_UNCACHED_BASE + AICA_MEM_CMD_QUEUE + offsetof(aica_queue_t, process_ok), 0); } /* Transfer one packet of data from the AICA->SH4 queue. Expects to @@ -143,12 +140,12 @@ int snd_aica_to_sh4(void *packetout) { sem_wait(&sem_qram); /* Set these up for reference */ - bot = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE; + bot = SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE; assert_msg(g2_read_32(bot + offsetof(aica_queue_t, valid)), "Queue is not yet valid"); - top = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, size)); - start = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, tail)); - stop = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, head)); + top = SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, size)); + start = SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, tail)); + stop = SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, head)); cnt = 0; pkt32 = (uint32 *)packetout; @@ -171,7 +168,7 @@ int snd_aica_to_sh4(void *packetout) { stop = start + size * 4; if(stop > top) - stop -= top - (SPU_RAM_BASE + AICA_MEM_RESP_QUEUE); + stop -= top - (SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE); while(start != stop) { /* Fifo wait if necessary */ @@ -193,7 +190,7 @@ int snd_aica_to_sh4(void *packetout) { } /* Finally, write a new tail value to signify that we've removed a packet */ - g2_write_32(bot + offsetof(aica_queue_t, tail), start - (SPU_RAM_BASE + AICA_MEM_RESP_QUEUE)); + g2_write_32(bot + offsetof(aica_queue_t, tail), start - (SPU_RAM_UNCACHED_BASE + AICA_MEM_RESP_QUEUE)); sem_signal(&sem_qram); @@ -204,9 +201,9 @@ int snd_aica_to_sh4(void *packetout) { running in an interrupt handler (thread perhaps, of whoever is using us). */ void snd_poll_resp(void) { - int rv; - uint32 pkt[AICA_CMD_MAX_SIZE]; - aica_cmd_t * pktcmd; + int rv; + uint32_t pkt[AICA_CMD_MAX_SIZE]; + aica_cmd_t *pktcmd; pktcmd = (aica_cmd_t *)pkt; diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index 522422d..b379f6f 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -100,9 +100,6 @@ static uint32_t *sep_buffer[2] = {NULL, NULL}; static mutex_t stream_mutex = MUTEX_INITIALIZER; -/* the address of the sound ram from the SH4 side */ -#define SPU_RAM_BASE 0xa0800000 - #define LOCK_TIMEOUT_MS 1000 /* Check an incoming handle */ @@ -222,10 +219,11 @@ static void snd_pcm16_split_unaligned(void *buffer, void *left, void *right, siz } void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size) { + g2_ctx_t ctx; /* SPU memory in cached area */ - left |= 0x00800000; - right |= 0x00800000; + left |= SPU_RAM_BASE; + right |= SPU_RAM_BASE; uintptr_t masked_left = SQ_MASK_DEST_ADDR(left); uintptr_t masked_right = SQ_MASK_DEST_ADDR(right); @@ -235,8 +233,8 @@ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t /* Set store queue memory area as desired */ SET_QACR_REGS(left, right); - int old = irq_disable(); - do { } while(FIFO_STATUS & (FIFO_SH4 | FIFO_G2)); + /* Make sure the FIFOs are empty */ + ctx = g2_lock(); /* Separating channels and do fill/write queues as many times necessary. */ snd_pcm16_split_sq_start(data, masked_left, masked_right, size); @@ -245,7 +243,7 @@ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t uint32_t *d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; - irq_restore(old); + g2_unlock(ctx); sq_unlock(); } @@ -295,7 +293,7 @@ static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { spu_memload_sq(right, sep_buffer[1], got / 2); } -/* Prefill buffers -- do this before calling start() */ +/* Prefill buffers -- implicitly called by snd_stream_start() */ void snd_stream_prefill(snd_stream_hnd_t hnd) { CHECK_HND(hnd); @@ -314,7 +312,7 @@ void snd_stream_prefill(snd_stream_hnd_t hnd) { /* Initialize stream system */ int snd_stream_init(void) { - /* Create stereo seperation buffers */ + /* Create stereo separation buffers */ if(!sep_buffer[0]) { sep_buffer[0] = memalign(32, SND_STREAM_BUFFER_MAX); sep_buffer[1] = sep_buffer[0] + (SND_STREAM_BUFFER_MAX / 8); @@ -333,9 +331,10 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { int i, old; snd_stream_hnd_t hnd; + mutex_lock(&stream_mutex); + /* Get an unused handle */ hnd = -1; - old = irq_disable(); for(i = 0; i < SND_STREAM_MAX; i++) { if(!streams[i].initted) { @@ -347,10 +346,10 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { if(hnd != -1) streams[hnd].initted = 1; - irq_restore(old); - - if(hnd == -1) + if(hnd == -1) { + mutex_unlock(&stream_mutex); return SND_STREAM_INVALID; + } /* Default this for now */ streams[hnd].buffer_size = bufsize; @@ -373,6 +372,8 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { streams[hnd].ch[1] = snd_sfx_chn_alloc(); dbglog(DBG_INFO, "snd_stream: alloc'd channels %d/%d\n", streams[hnd].ch[0], streams[hnd].ch[1]); + mutex_unlock(&stream_mutex); + return hnd; } @@ -391,10 +392,14 @@ snd_stream_hnd_t snd_stream_reinit(snd_stream_hnd_t hnd, snd_stream_callback_t c void snd_stream_destroy(snd_stream_hnd_t hnd) { filter_t *c, *n; + mutex_lock(&stream_mutex); + CHECK_HND(hnd); - if(!streams[hnd].initted) + if(!streams[hnd].initted) { + mutex_unlock(&stream_mutex); return; + } snd_sfx_chn_free(streams[hnd].ch[0]); snd_sfx_chn_free(streams[hnd].ch[1]); @@ -411,7 +416,10 @@ void snd_stream_destroy(snd_stream_hnd_t hnd) { snd_stream_stop(hnd); snd_mem_free(streams[hnd].spu_ram_sch[0]); + dbglog(DBG_INFO, "snd_stream: dealloc'd channels %d/%d\n", streams[hnd].ch[0], streams[hnd].ch[1]); memset(streams + hnd, 0, sizeof(streams[0])); + + mutex_unlock(&stream_mutex); } /* Shut everything down and free mem */ @@ -503,7 +511,7 @@ static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32_t type, uint32_t /* Start both channels simultaneously */ cmd->cmd_id = (1 << streams[hnd].ch[0]) | - (1 << streams[hnd].ch[1]); + (1 << streams[hnd].ch[1]); } else { /* Start one channel */ @@ -592,12 +600,12 @@ int snd_stream_poll(snd_stream_hnd_t hnd) { } /* Get channels position */ - ch0pos = g2_read_32(SPU_RAM_BASE + + ch0pos = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(stream->ch[0]) + offsetof(aica_channel_t, pos)); if(stream->channels == 2) { - ch1pos = g2_read_32(SPU_RAM_BASE + + ch1pos = g2_read_32(SPU_RAM_UNCACHED_BASE + AICA_CHANNEL(stream->ch[1]) + ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-13 03:07:21
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via a5a79598ba4bf76fc85a66b267eeeedf8cf6d10a (commit) from e3b95d9f59db2326486f309771490479e71e05ba (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a5a79598ba4bf76fc85a66b267eeeedf8cf6d10a Author: Heel <429...@us...> Date: Mon Nov 13 12:06:04 2023 +0900 Ensure getaddrinfo() handles IP adddress inputs without using DNS (#358) * Ensure getaddrinfo() handles IP adddress inputs without sending them to resolve over DNS ----------------------------------------------------------------------- Summary of changes: kernel/libc/koslib/getaddrinfo.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/kernel/libc/koslib/getaddrinfo.c b/kernel/libc/koslib/getaddrinfo.c index eff2466..4950c9c 100644 --- a/kernel/libc/koslib/getaddrinfo.c +++ b/kernel/libc/koslib/getaddrinfo.c @@ -706,6 +706,28 @@ int getaddrinfo(const char *nodename, const char *servname, return 0; } + /* Try to handle input as an IPv4 address */ + if(ihints.ai_family == AI_INET || ihints.ai_family == AF_UNSPEC) { + uint32_t ip4_addr; + + if(inet_pton(AF_INET, nodename, &ip4_addr) > 0) { + ihints.ai_family = AF_INET; + *res = add_ipv4_ai(ip4_addr, port, &ihints, NULL); + return 0; + } + } + + /* Try to handle input as an IPv6 address */ + if(ihints.ai_family == AF_INET6 || ihints.ai_family == AF_UNSPEC) { + struct in6_addr addr; + + if(inet_pton(AF_INET6, nodename, &addr.s6_addr) > 0) { + ihints.ai_family = AF_INET6; + *res = add_ipv6_ai(&addr, port, &ihints, NULL); + return 0; + } + } + /* If we've gotten this far, do the lookup. */ if(ihints.ai_family == AF_UNSPEC) { /* It seems that some resolvers really don't like multi-part questions. hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-13 02:54:24
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via e3b95d9f59db2326486f309771490479e71e05ba (commit) via 058b33687ea42842bc8308167351ced4d4a4ce7e (commit) via 2bdbe52f02cd804429918fa274529347692bcadd (commit) via 95935be4423884fceb4b9ca7459c5449903fd003 (commit) from eadd3fb6bb7837e7eeec1d81f783f6a4b512a53b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e3b95d9f59db2326486f309771490479e71e05ba Author: Lawrence Sebald <ljs...@us...> Date: Sun Nov 12 21:53:51 2023 -0500 Fix comment to C89/C90 style. commit 058b33687ea42842bc8308167351ced4d4a4ce7e Author: Andress Barajas <and...@gm...> Date: Sun Nov 12 18:33:39 2023 -0800 Fixed typo and updated function name (#359) * Fixed typo and updated function name * Fix other examples * Fix makefile commit 2bdbe52f02cd804429918fa274529347692bcadd Merge: eadd3fb 95935be Author: Lawrence Sebald <ljs...@us...> Date: Sun Nov 12 21:31:24 2023 -0500 Merge pull request #361 from has207/getsockopt getsockopt(): add no-op handling for SO_ERROR commit 95935be4423884fceb4b9ca7459c5449903fd003 Author: Heel <he...@ex...> Date: Mon Nov 13 09:52:05 2023 +0900 getsockopt(): add no-op handling for SO_ERROR ----------------------------------------------------------------------- Summary of changes: examples/dreamcast/cpp/dcplib/fnt_test.cc | 3 --- examples/dreamcast/hello/hello.c | 6 ------ examples/dreamcast/sound/multi-stream/Makefile | 4 ++-- examples/dreamcast/sound/multi-stream/README | 2 +- examples/dreamcast/sound/multi-stream/main.c | 4 ++-- kernel/net/net_tcp.c | 5 +++++ 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/dreamcast/cpp/dcplib/fnt_test.cc b/examples/dreamcast/cpp/dcplib/fnt_test.cc index 206b57a..320e3df 100644 --- a/examples/dreamcast/cpp/dcplib/fnt_test.cc +++ b/examples/dreamcast/cpp/dcplib/fnt_test.cc @@ -5,9 +5,6 @@ #include <kos.h> #include <dcplib/fnt.h> -extern uint8 romdisk[]; -KOS_INIT_ROMDISK(romdisk); - fntRenderer *text; const int MAX_FONTS = 20; diff --git a/examples/dreamcast/hello/hello.c b/examples/dreamcast/hello/hello.c index 37a23d0..c1da1c6 100644 --- a/examples/dreamcast/hello/hello.c +++ b/examples/dreamcast/hello/hello.c @@ -6,9 +6,6 @@ #include <kos.h> -/* You can safely remove this line if you don't use a ROMDISK */ -extern uint8 romdisk[]; - /* These macros tell KOS how to initialize itself. All of this initialization happens before main() gets called, and the shutdown happens afterwards. So you need to set any flags you want here. Here are some possibilities: @@ -22,9 +19,6 @@ extern uint8 romdisk[]; the current KOS defaults, use INIT_DEFAULT (or leave it out entirely). */ KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS); -/* And specify a romdisk, if you want one (or leave it out) */ -KOS_INIT_ROMDISK(romdisk); - /* Your program's main entry point */ int main(int argc, char **argv) { /* The requisite line */ diff --git a/examples/dreamcast/sound/multi-stream/Makefile b/examples/dreamcast/sound/multi-stream/Makefile index da2fa38..aebb3f8 100644 --- a/examples/dreamcast/sound/multi-stream/Makefile +++ b/examples/dreamcast/sound/multi-stream/Makefile @@ -18,10 +18,10 @@ clean: $(TARGET): $(OBJS) kos-cc -o $(TARGET) $(OBJS) $(DATAOBJS) $(OBJEXTRA) -lwav -run: +run: $(TARGET) $(KOS_LOADER) $(TARGET) -dist: +dist: $(TARGET) rm -f $(OBJS) romdisk.o romdisk.img $(KOS_STRIP) $(TARGET) diff --git a/examples/dreamcast/sound/multi-stream/README b/examples/dreamcast/sound/multi-stream/README index 7e4504f..3cd7ac6 100644 --- a/examples/dreamcast/sound/multi-stream/README +++ b/examples/dreamcast/sound/multi-stream/README @@ -15,6 +15,6 @@ audio formats: 4-bit ADPCM data (as demonstrated in this example) 8-bit and 16-bit uncompressed PCM data -Use the following command to convert a 16-bit stereo PCM WAV file (PCM16_stereo.wav) to a 8-bit stero PCM WAV file (PCM8_mono.wav): +Use the following command to convert a 16-bit stereo PCM WAV file (PCM16_stereo.wav) to a 8-bit stereo PCM WAV file (PCM8_mono.wav): ffmpeg -i PCM16_stereo.wav -acodec pcm_u8 -ac 1 PCM8_mono.wav diff --git a/examples/dreamcast/sound/multi-stream/main.c b/examples/dreamcast/sound/multi-stream/main.c index bb64d32..513be08 100644 --- a/examples/dreamcast/sound/multi-stream/main.c +++ b/examples/dreamcast/sound/multi-stream/main.c @@ -49,11 +49,11 @@ int main(int argc, char **argv) { // Play wav files if they arent playing already if(button_pressed(current_buttons, changed_buttons, CONT_X)) { - if(!wav_isplaying(faucet)) + if(!wav_is_playing(faucet)) wav_play(faucet); } if(button_pressed(current_buttons, changed_buttons, CONT_Y)) { - if(!wav_isplaying(brushing)) + if(!wav_is_playing(brushing)) wav_play(brushing); } // Stop playing faucet diff --git a/kernel/net/net_tcp.c b/kernel/net/net_tcp.c index 32ac8a5..5a82daa 100644 --- a/kernel/net/net_tcp.c +++ b/kernel/net/net_tcp.c @@ -1688,6 +1688,10 @@ static int net_tcp_getsockopt(net_socket_t *hnd, int level, int option_name, tmp = sock->state == TCP_STATE_LISTEN; goto copy_int; + case SO_ERROR: + /* Checking/resetting errors not implemented */ + goto simply_return; + case SO_RCVBUF: tmp = sock->rcvbuf_sz; goto copy_int; @@ -1753,6 +1757,7 @@ copy_int: memcpy(option_value, &tmp, *option_len); } +simply_return: mutex_unlock(&sock->mutex); rwsem_read_unlock(&tcp_sem); return 0; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-12 01:11:19
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via eadd3fb6bb7837e7eeec1d81f783f6a4b512a53b (commit) from a15cb4318f5db8f8283e77712ca6316943c502ad (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit eadd3fb6bb7837e7eeec1d81f783f6a4b512a53b Author: Andress Barajas <and...@gm...> Date: Sat Nov 11 09:45:04 2023 -0800 Sound effect number of samples warning (#354) * Added a warning when loading a sfx that is greater than 65534 samples ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/include/dc/sound/sfxmgr.h | 2 +- kernel/arch/dreamcast/sound/snd_sfxmgr.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h index 0af3a77..ee8f69e 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h +++ b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h @@ -32,7 +32,7 @@ __BEGIN_DECLS Each loaded sound effect will be assigned one of these, which is to be used for operations related to the effect, including playing it or unloading it. */ -typedef uint32 sfxhnd_t; +typedef uint32_t sfxhnd_t; /** \brief Invalid sound effect handle value. diff --git a/kernel/arch/dreamcast/sound/snd_sfxmgr.c b/kernel/arch/dreamcast/sound/snd_sfxmgr.c index ff838af..22f690c 100644 --- a/kernel/arch/dreamcast/sound/snd_sfxmgr.c +++ b/kernel/arch/dreamcast/sound/snd_sfxmgr.c @@ -167,7 +167,7 @@ static int read_wav_header(file_t fd, wavhdr_t *wavhdr) { return 0; } -static uint8_t* read_wav_data(file_t fd, wavhdr_t *wavhdr) { +static uint8_t *read_wav_data(file_t fd, wavhdr_t *wavhdr) { /* Allocate memory for WAV data */ uint8_t *wav_data = memalign(32, wavhdr->chunk.size); @@ -340,8 +340,9 @@ err_occurred: sfxhnd_t snd_sfx_load(const char *fn) { file_t fd; wavhdr_t wavhdr; - uint8_t *wav_data; snd_effect_t *effect; + uint8_t *wav_data; + uint32_t sample_count; dbglog(DBG_DEBUG, "snd_sfx: loading effect %s\n", fn); @@ -366,6 +367,14 @@ sfxhnd_t snd_sfx_load(const char *fn) { wavhdr.chunk.size, wavhdr.fmt.format); + sample_count = wavhdr.fmt.sample_size >= 8 + ? wavhdr.chunk.size / ((wavhdr.fmt.sample_size / 8) * wavhdr.fmt.channels) + : wavhdr.chunk.size / (0.5 * wavhdr.fmt.channels); + + if(sample_count > 65534) { + dbglog(DBG_WARNING, "WAVE file is over 65534 samples\n"); + } + /* Read WAV data */ wav_data = read_wav_data(fd, &wavhdr); fs_close(fd); @@ -388,7 +397,7 @@ sfxhnd_t snd_sfx_load(const char *fn) { int snd_sfx_play_chn(int chn, sfxhnd_t idx, int vol, int pan) { int size; - snd_effect_t * t = (snd_effect_t *)idx; + snd_effect_t *t = (snd_effect_t *)idx; AICA_CMDSTR_CHANNEL(tmp, cmd, chan); size = t->len; @@ -452,7 +461,7 @@ int snd_sfx_play(sfxhnd_t idx, int vol, int pan) { return -1; } else { - sfx_nextchan = (chn + 2) % 64; // in case of stereo + sfx_nextchan = (chn + 2) % 64; /* in case of stereo */ return snd_sfx_play_chn(chn, idx, vol, pan); } } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: Allura u. <al...@so...> - 2023-11-11 04:50:52
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "UNNAMED PROJECT". The branch, master has been updated via cc2753766191bb3f9969d0b0b659362b001594a1 (commit) from 1eb6b317c1ca9ca35958e09e18c2f048acd831b9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cc2753766191bb3f9969d0b0b659362b001594a1 Author: Andress Barajas <and...@gm...> Date: Mon Oct 30 23:04:08 2023 -0700 Align pcm buffer to 32 bytes ----------------------------------------------------------------------- Summary of changes: liboggvorbisplay/sndoggvorbis.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/liboggvorbisplay/sndoggvorbis.c b/liboggvorbisplay/sndoggvorbis.c index c6a3ae1..522ece5 100644 --- a/liboggvorbisplay/sndoggvorbis.c +++ b/liboggvorbisplay/sndoggvorbis.c @@ -20,7 +20,8 @@ #define BUF_SIZE 65536 /* Size of buffer */ -static uint8 pcm_buffer[BUF_SIZE+16384]; /* complete buffer + 16KB safety */ +/* complete buffer + 16KB safety */ +static uint8 pcm_buffer[BUF_SIZE + 16384] __attribute__((aligned(32))); static uint8 *pcm_ptr=pcm_buffer; /* place we write to */ static int32 pcm_count=0; /* bytes in buffer */ hooks/post-receive -- UNNAMED PROJECT |
From: Allura u. <al...@so...> - 2023-11-11 04:50:00
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "UNNAMED PROJECT". The branch, master has been updated via e6229e496119a7665714109a0f2139f9a04661da (commit) from 2cd01d8781ef263a6c33b37ae27a5961352c5108 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e6229e496119a7665714109a0f2139f9a04661da Author: Andress Barajas <and...@gm...> Date: Mon Oct 30 23:03:15 2023 -0700 Align pcm buffer to 32 bytes ----------------------------------------------------------------------- Summary of changes: libmp3/sndmp3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmp3/sndmp3.c b/libmp3/sndmp3.c index fc26310..94b527c 100644 --- a/libmp3/sndmp3.c +++ b/libmp3/sndmp3.c @@ -174,7 +174,7 @@ static int xing_init(const char *fn) { bs_buffer = malloc(BS_SIZE); bs_ptr = bs_buffer; bs_count = 0; if (pcm_buffer == NULL) - pcm_buffer = malloc(PCM_SIZE); + pcm_buffer = memalign(32, PCM_SIZE); pcm_ptr = pcm_buffer; pcm_count = pcm_discard = 0; /* Fill bitstream buffer */ hooks/post-receive -- UNNAMED PROJECT |
From: falcovorbis <fal...@us...> - 2023-11-11 04:44:34
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via a15cb4318f5db8f8283e77712ca6316943c502ad (commit) via 2fae09f752e10328c46a6dd2a87e45575d5aa9ea (commit) via 1dfa609ffd0bab87574013af066e1b12486a7708 (commit) from 4d1b67c84f5770a1eb8ddb65507751a42d0850ae (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a15cb4318f5db8f8283e77712ca6316943c502ad Merge: 4d1b67c 2fae09f Author: Falco Girgis <gyr...@gm...> Date: Fri Nov 10 22:43:03 2023 -0600 Merge pull request #352 from Dreamcast-Projects/snd_free_fix_clean Fix accidental double free of stream and cleaning code commit 2fae09f752e10328c46a6dd2a87e45575d5aa9ea Author: Andress Barajas <and...@gm...> Date: Fri Nov 10 20:28:19 2023 -0800 Remove printf commit 1dfa609ffd0bab87574013af066e1b12486a7708 Author: Andress Barajas <and...@gm...> Date: Fri Nov 10 20:24:54 2023 -0800 Fix accidental double free of stream and cleaning code ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/sound/snd_stream.c | 49 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index e07362f..522422d 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -50,35 +50,35 @@ typedef struct filter { /* Each of these represents an active streaming channel */ typedef struct strchan { - // Which AICA channels are we using? + /* Which AICA channels are we using? */ int ch[2]; - // The last write position in the playing buffer + /* The last write position in the playing buffer */ uint32_t last_write_pos; - // The buffer size allocated for this stream. + /* The buffer size allocated for this stream. */ size_t buffer_size; - // Stream data location in AICA RAM + /* Stream data location in AICA RAM */ uint32_t spu_ram_sch[2]; - // "Get data" callback; we'll call this any time we want to get - // another buffer of output data. + /* "Get data" callback; we'll call this any time we want to get + another buffer of output data. */ snd_stream_callback_t get_data; - // Our list of filter callback functions for this stream + /* Our list of filter callback functions for this stream */ TAILQ_HEAD(filterlist, filter) filters; - // Sample type + /* Sample type */ int type; - // Sample size + /* Sample size */ int bitsize; - // Stereo/mono flag + /* Stereo/mono flag */ int channels; - // Playback frequency + /* Playback frequency */ int frequency; /* Stream queueing is where we get everything ready to go but don't @@ -92,10 +92,10 @@ typedef struct strchan { void *user_data; } strchan_t; -// Our stream structs +/* Our stream structs */ static strchan_t streams[SND_STREAM_MAX]; -// Separation buffers (for stereo) +/* Separation buffers (for stereo) */ static uint32_t *sep_buffer[2] = {NULL, NULL}; static mutex_t stream_mutex = MUTEX_INITIALIZER; @@ -105,7 +105,7 @@ static mutex_t stream_mutex = MUTEX_INITIALIZER; #define LOCK_TIMEOUT_MS 1000 -// Check an incoming handle +/* Check an incoming handle */ #define CHECK_HND(x) do { \ assert( (x) >= 0 && (x) < SND_STREAM_MAX ); \ assert( streams[(x)].initted ); \ @@ -154,7 +154,7 @@ void *snd_stream_get_userdata(snd_stream_hnd_t hnd) { } void snd_stream_filter_add(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc, void * obj) { - filter_t * f; + filter_t *f; CHECK_HND(hnd); @@ -165,7 +165,7 @@ void snd_stream_filter_add(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc, v } void snd_stream_filter_remove(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc, void * obj) { - filter_t * f; + filter_t *f; CHECK_HND(hnd); @@ -179,7 +179,7 @@ void snd_stream_filter_remove(snd_stream_hnd_t hnd, snd_stream_filter_t filtfunc } static void process_filters(snd_stream_hnd_t hnd, void **buffer, int *samplecnt) { - filter_t * f; + filter_t *f; TAILQ_FOREACH(f, &streams[hnd].filters, lent) { f->func(hnd, f->data, streams[hnd].frequency, streams[hnd].channels, buffer, samplecnt); @@ -236,7 +236,7 @@ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t SET_QACR_REGS(left, right); int old = irq_disable(); - do { } while(*(vuint32 *)0xa05f688c & ((1 << 5) | (1 << 4))); /* FIFO_SH4 | FIFO_G2 */ + do { } while(FIFO_STATUS & (FIFO_SH4 | FIFO_G2)); /* Separating channels and do fill/write queues as many times necessary. */ snd_pcm16_split_sq_start(data, masked_left, masked_right, size); @@ -333,7 +333,7 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { int i, old; snd_stream_hnd_t hnd; - // Get an unused handle + /* Get an unused handle */ hnd = -1; old = irq_disable(); @@ -352,7 +352,7 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { if(hnd == -1) return SND_STREAM_INVALID; - // Default this for now + /* Default this for now */ streams[hnd].buffer_size = bufsize; /* Start off with queueing disabled */ @@ -364,14 +364,14 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { /* Initialize our filter chain list */ TAILQ_INIT(&streams[hnd].filters); - // Allocate stream buffers + /* Allocate stream buffers */ streams[hnd].spu_ram_sch[0] = snd_mem_malloc(streams[hnd].buffer_size * 2); streams[hnd].spu_ram_sch[1] = streams[hnd].spu_ram_sch[0] + streams[hnd].buffer_size; - // And channels + /* And channels */ streams[hnd].ch[0] = snd_sfx_chn_alloc(); streams[hnd].ch[1] = snd_sfx_chn_alloc(); - printf("snd_stream: alloc'd channels %d/%d\n", streams[hnd].ch[0], streams[hnd].ch[1]); + dbglog(DBG_INFO, "snd_stream: alloc'd channels %d/%d\n", streams[hnd].ch[0], streams[hnd].ch[1]); return hnd; } @@ -389,7 +389,7 @@ snd_stream_hnd_t snd_stream_reinit(snd_stream_hnd_t hnd, snd_stream_callback_t c } void snd_stream_destroy(snd_stream_hnd_t hnd) { - filter_t * c, * n; + filter_t *c, *n; CHECK_HND(hnd); @@ -411,7 +411,6 @@ void snd_stream_destroy(snd_stream_hnd_t hnd) { snd_stream_stop(hnd); snd_mem_free(streams[hnd].spu_ram_sch[0]); - snd_mem_free(streams[hnd].spu_ram_sch[1]); memset(streams + hnd, 0, sizeof(streams[0])); } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-11 03:34:19
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 4d1b67c84f5770a1eb8ddb65507751a42d0850ae (commit) from 81a4080ba17130c9c1baeca9a4381bc6452b96f8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4d1b67c84f5770a1eb8ddb65507751a42d0850ae Author: Andress Barajas <and...@gm...> Date: Fri Nov 10 19:33:48 2023 -0800 Add multi-streaming example (#351) * Add multi-streaming example ----------------------------------------------------------------------- Summary of changes: .../dreamcast/sound/{sfx => multi-stream}/Makefile | 12 +- examples/dreamcast/sound/multi-stream/README | 20 +++ examples/dreamcast/sound/multi-stream/main.c | 152 +++++++++++++++++++++ .../sound/multi-stream/romdisk/brushing.wav | Bin 0 -> 1508444 bytes .../sound/multi-stream/romdisk/faucet.wav | Bin 0 -> 652380 bytes 5 files changed, 178 insertions(+), 6 deletions(-) copy examples/dreamcast/sound/{sfx => multi-stream}/Makefile (63%) create mode 100644 examples/dreamcast/sound/multi-stream/README create mode 100644 examples/dreamcast/sound/multi-stream/main.c create mode 100644 examples/dreamcast/sound/multi-stream/romdisk/brushing.wav create mode 100644 examples/dreamcast/sound/multi-stream/romdisk/faucet.wav diff --git a/examples/dreamcast/sound/sfx/Makefile b/examples/dreamcast/sound/multi-stream/Makefile similarity index 63% copy from examples/dreamcast/sound/sfx/Makefile copy to examples/dreamcast/sound/multi-stream/Makefile index c2d38ef..da2fa38 100644 --- a/examples/dreamcast/sound/sfx/Makefile +++ b/examples/dreamcast/sound/multi-stream/Makefile @@ -1,10 +1,10 @@ # KallistiOS ##version## # -# examples/dreamcast/sound/sfx/Makefile +# examples/dreamcast/sound/multi-stream/Makefile # -TARGET = sfx.elf -OBJS = main.o romdisk.o +TARGET = multistream.elf +OBJS = romdisk.o main.o KOS_ROMDISK_DIR = romdisk all: clean $(TARGET) @@ -16,12 +16,12 @@ clean: -rm -f romdisk.o romdisk.img $(TARGET): $(OBJS) - kos-cc -o $(TARGET) $(OBJS) + kos-cc -o $(TARGET) $(OBJS) $(DATAOBJS) $(OBJEXTRA) -lwav -run: $(TARGET) +run: $(KOS_LOADER) $(TARGET) -dist: $(TARGET) +dist: rm -f $(OBJS) romdisk.o romdisk.img $(KOS_STRIP) $(TARGET) diff --git a/examples/dreamcast/sound/multi-stream/README b/examples/dreamcast/sound/multi-stream/README new file mode 100644 index 0000000..7e4504f --- /dev/null +++ b/examples/dreamcast/sound/multi-stream/README @@ -0,0 +1,20 @@ +Overview +This example demonstrates audio playback using libwav (kos-port). The sounds utilized in this example were sourced from https://gamesounds.xyz/?dir=Sound%20Effects/Bathroom and converted to ADPCM format. + +Conversion to ADPCM Format +This conversion was achieved using FFmpeg, a powerful multimedia framework. The following command was used for conversion: + +ffmpeg -i PCM16_stereo.wav -acodec adpcm_yamaha -ac 2 ADPCM_stereo.wav + +This command converts a stereo PCM WAV file (PCM16_stereo.wav) to a stereo Yamaha ADPCM WAV file (ADPCM_stereo.wav). + +Playback Using libwav (kos-port) +The libwav (kos-port) library is used for audio playback in this project. It is versatile and supports all the Dreamcast +audio formats: + +4-bit ADPCM data (as demonstrated in this example) +8-bit and 16-bit uncompressed PCM data + +Use the following command to convert a 16-bit stereo PCM WAV file (PCM16_stereo.wav) to a 8-bit stero PCM WAV file (PCM8_mono.wav): + +ffmpeg -i PCM16_stereo.wav -acodec pcm_u8 -ac 1 PCM8_mono.wav diff --git a/examples/dreamcast/sound/multi-stream/main.c b/examples/dreamcast/sound/multi-stream/main.c new file mode 100644 index 0000000..bb64d32 --- /dev/null +++ b/examples/dreamcast/sound/multi-stream/main.c @@ -0,0 +1,152 @@ +/* KallistiOS ##version## + + main.c + Copyright (C) 2023 Andy Barajas + + This example program demonstrates playing two ADPCM wav stereo + streams at once using libwav. +*/ + +#include <kos.h> +#include <wav/sndwav.h> + +#define LOOP 1 + +static void draw_instructions(int faucet_vol, int brushing_vol); + +static cont_state_t *get_cont_state(); +static int button_pressed(uint32_t current_buttons, uint32_t changed_buttons, uint32_t button); + +int main(int argc, char **argv) { + uint8_t faucet_volume = 240; + uint8_t brushing_volume = 240; + int volume_changed = 1; + cont_state_t *cond; + uint32_t current_buttons = 0; + uint32_t changed_buttons = 0; + uint32_t previous_buttons = 0; + + vid_set_mode(DM_640x480, PM_RGB555); + // Initialize sound system and WAV + snd_stream_init(); + wav_init(); + + wav_stream_hnd_t faucet = wav_create("/rd/faucet.wav", LOOP); + wav_volume(faucet, faucet_volume); + + wav_stream_hnd_t brushing = wav_create("/rd/brushing.wav", LOOP); + wav_volume(brushing, brushing_volume); + + wav_play(faucet); + wav_play(brushing); + + + for(;;) { + cond = get_cont_state(); + current_buttons = cond->buttons; + changed_buttons = current_buttons ^ previous_buttons; + previous_buttons = current_buttons; + + // Play wav files if they arent playing already + if(button_pressed(current_buttons, changed_buttons, CONT_X)) { + if(!wav_isplaying(faucet)) + wav_play(faucet); + } + if(button_pressed(current_buttons, changed_buttons, CONT_Y)) { + if(!wav_isplaying(brushing)) + wav_play(brushing); + } + // Stop playing faucet + if(button_pressed(current_buttons, changed_buttons, CONT_A)) { + wav_stop(faucet); + } + // Stop playing brushing + if(button_pressed(current_buttons, changed_buttons, CONT_B)) { + wav_stop(brushing); + } + + // Adjust Volume + if(cond->ltrig > 0) { + if(faucet_volume < 255) + faucet_volume++; + else + faucet_volume = 0; + volume_changed = 1; + wav_volume(faucet, faucet_volume); + } + if(cond->rtrig > 0) { + if(faucet_volume < 255) + brushing_volume++; + else + brushing_volume = 0; + volume_changed = 1; + wav_volume(brushing, brushing_volume); + } + + // Exit Program + if(button_pressed(current_buttons, changed_buttons, CONT_START)) + break; + + if(volume_changed) { + volume_changed = 0; + draw_instructions(faucet_volume, brushing_volume); + } + } + + wav_shutdown(); + snd_stream_shutdown(); + + return 0; +} + +static void draw_instructions(int faucet_vol, int brushing_vol) { + int x = 20, y = 20+24; + int color = 1; + char volume_str[32]; + + bfont_draw_str(vram_s + y*640+x, 640, color, "Press X to play faucet sound"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press A to stop faucet sound"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press L-Trigger to increase faucet volume"); + y += 24; + memset(volume_str, 0, 32); + snprintf(volume_str, 32, "Faucet Volume: %3i", faucet_vol); + bfont_draw_str(vram_s + y*640+x, 640, color, volume_str); + + y += 48; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press Y to play brushing sound"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press B to stop brushing sound"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press R-Trigger to increase brushing volume"); + y += 24; + memset(volume_str, 0, 32); + snprintf(volume_str, 32, "Brushing Volume: %3i", brushing_vol); + bfont_draw_str(vram_s + y*640+x, 640, color, volume_str); + + y += 48; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press Start to exit program"); +} + +static cont_state_t *get_cont_state() { + maple_device_t *cont; + cont_state_t *state; + + cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if(cont) { + state = (cont_state_t *)maple_dev_status(cont); + return state; + } + + return NULL; +} + +static int button_pressed(uint32_t current_buttons, uint32_t changed_buttons, uint32_t button) { + if (changed_buttons & button) { + if (current_buttons & button) + return 1; + } + + return 0; +} diff --git a/examples/dreamcast/sound/multi-stream/romdisk/brushing.wav b/examples/dreamcast/sound/multi-stream/romdisk/brushing.wav new file mode 100644 index 0000000..fb42d82 Binary files /dev/null and b/examples/dreamcast/sound/multi-stream/romdisk/brushing.wav differ diff --git a/examples/dreamcast/sound/multi-stream/romdisk/faucet.wav b/examples/dreamcast/sound/multi-stream/romdisk/faucet.wav new file mode 100644 index 0000000..05d2d65 Binary files /dev/null and b/examples/dreamcast/sound/multi-stream/romdisk/faucet.wav differ hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-11 03:10:13
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 81a4080ba17130c9c1baeca9a4381bc6452b96f8 (commit) from 4b3af55c9c819c2fa1a67a20dd1d369c49be3122 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 81a4080ba17130c9c1baeca9a4381bc6452b96f8 Author: Andress Barajas <and...@gm...> Date: Fri Nov 10 19:09:43 2023 -0800 SfxMgr clean update (#348) * Updated wav parsing algo to handle different wav headers * Add warning to clarify maximum samples * Added two more changes by SWAT * Apply suggestions from code review ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG | 6 + kernel/arch/dreamcast/include/dc/sound/sfxmgr.h | 5 +- kernel/arch/dreamcast/sound/snd_sfxmgr.c | 359 ++++++++++++++---------- 3 files changed, 228 insertions(+), 142 deletions(-) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 81a1a36..c90e2ba 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -197,6 +197,12 @@ KallistiOS version 2.1.0 ----------------------------------------------- - DC Rework romdisks [PC] - DC Refactored g2bus API, converted magic values to macros, added dc/fifo.h, dc/dmac.h file [AB] +- DC Fixes and improvments for G1 ATA devices [Ruslan Rostovtsev == RR] +- DC Fixed and improved SCIF SPI reading for use with SD [RR] +- DC SH4 cache improvements [RR] +- DC Optimized separating stereo PCM [RR] +- DC Refactored sfx and streaming to add SQ fast path [RR] +- DC Added 4/8-bit wav support to sfx and streaming [RR] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Megan Potter == MP] diff --git a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h index 8737aa7..0af3a77 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h +++ b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h @@ -45,7 +45,10 @@ typedef uint32 sfxhnd_t; This function loads a sound effect from a WAV file and returns a handle to it. The sound effect can be either stereo or mono, and must either be 8-bit - or 16-bit uncompressed PCM samples or 4-bit Yamaha ADPCM. + or 16-bit uncompressed PCM samples, or 4-bit Yamaha ADPCM. + + \warning The sound effect you are loading must be at most 65534 samples + in length. \param fn The file to load. \return A handle to the sound effect on success. On error, diff --git a/kernel/arch/dreamcast/sound/snd_sfxmgr.c b/kernel/arch/dreamcast/sound/snd_sfxmgr.c index 222f92c..ff838af 100644 --- a/kernel/arch/dreamcast/sound/snd_sfxmgr.c +++ b/kernel/arch/dreamcast/sound/snd_sfxmgr.c @@ -27,12 +27,12 @@ struct snd_effect; LIST_HEAD(selist, snd_effect); typedef struct snd_effect { - uint32 locl, locr; - uint32 len; - uint32 rate; - uint32 used; - uint16 stereo; - uint32 fmt; + uint32_t locl, locr; + uint32_t len; + uint32_t rate; + uint32_t used; + uint32_t fmt; + uint16_t stereo; LIST_ENTRY(snd_effect) list; } snd_effect_t; @@ -43,11 +43,11 @@ struct selist snd_effects; static int sfx_nextchan = 0; /* Our channel-in-use mask. */ -static uint64 sfx_inuse = 0; +static uint64_t sfx_inuse = 0; /* Unload all loaded samples and free their SPU RAM */ void snd_sfx_unload_all(void) { - snd_effect_t * t, * n; + snd_effect_t *t, *n; t = LIST_FIRST(&snd_effects); @@ -69,7 +69,7 @@ void snd_sfx_unload_all(void) { /* Unload a single sample */ void snd_sfx_unload(sfxhnd_t idx) { - snd_effect_t * t = (snd_effect_t *)idx; + snd_effect_t *t = (snd_effect_t *)idx; if(idx == SFXHND_INVALID) { dbglog(DBG_WARNING, "snd_sfx: can't unload an invalid SFXHND\n"); @@ -85,228 +85,305 @@ void snd_sfx_unload(sfxhnd_t idx) { free(t); } -/* WAV header: - 0x08 -- "WAVE" - 0x14 -- 1 for PCM, 20 for ADPCM - 0x16 -- short num channels (1/2) - 0x18 -- long HZ - 0x22 -- short 8 or 16 (bits) - 0x28 -- long data length - 0x2c -- data start +typedef struct __attribute__((__packed__)) { + uint8_t riff[4]; + int32_t totalsize; + uint8_t riff_format[4]; +} wavmagic_t; + +typedef struct __attribute__((__packed__)) { + uint8_t id[4]; + size_t size; +} chunkhdr_t; + +typedef struct __attribute__((__packed__)) { + int16_t format; + int16_t channels; + int32_t sample_rate; + int32_t byte_per_sec; + int16_t blocksize; + int16_t sample_size; +} fmthdr_t; + +/* WAV header */ +typedef struct __attribute__((__packed__)) { + wavmagic_t magic; + + chunkhdr_t chunk; - */ + fmthdr_t fmt; +} wavhdr_t; /* WAV sample formats */ #define WAVE_FMT_PCM 0x0001 /* PCM */ #define WAVE_FMT_YAMAHA_ADPCM_ITU_G723 0x0014 /* ITU G.723 Yamaha ADPCM (KallistiOS) */ #define WAVE_FMT_YAMAHA_ADPCM 0x0020 /* Yamaha ADPCM (ffmpeg) */ -/* Load a sound effect from a WAV file and return a handle to it */ -sfxhnd_t snd_sfx_load(const char *fn) { - file_t fd; - uint32_t len, hz, rd; - uint8_t *tmp; - uint16_t channels, bitsize, fmt; - snd_effect_t *t; - - dbglog(DBG_DEBUG, "snd_sfx: loading effect %s\n", fn); - - fd = fs_open(fn, O_RDONLY); +static int read_wav_header(file_t fd, wavhdr_t *wavhdr) { + if(fs_read(fd, &(wavhdr->magic), sizeof(wavhdr->magic)) != sizeof(wavhdr->magic)) { + dbglog(DBG_WARNING, "snd_sfx: can't read wav header\n"); + return -1; + } - if(fd <= FILEHND_INVALID) { - dbglog(DBG_WARNING, "snd_sfx: can't open sfx %s\n", fn); - return SFXHND_INVALID; + if(strncmp((const char*)wavhdr->magic.riff, "RIFF", 4)) { + dbglog(DBG_WARNING, "snd_sfx: sfx file is not RIFF\n"); + return -1; } /* Check file magic */ - hz = 0; - fs_seek(fd, 0x08, SEEK_SET); - fs_read(fd, &hz, 4); - - if(strncmp((char *)&hz, "WAVE", 4)) { - dbglog(DBG_WARNING, "snd_sfx: file is not RIFF WAVE\n"); - fs_close(fd); - return SFXHND_INVALID; + if(strncmp((const char*)wavhdr->magic.riff_format, "WAVE", 4)) { + dbglog(DBG_WARNING, "snd_sfx: sfx file is not RIFF WAVE\n"); + return -1; } - /* Read WAV header info */ - fs_seek(fd, 0x14, SEEK_SET); - fs_read(fd, &fmt, 2); - fs_read(fd, &channels, 2); - fs_read(fd, &hz, 4); - fs_seek(fd, 0x22, SEEK_SET); - fs_read(fd, &bitsize, 2); + do { + /* Read the chunk header */ + if(fs_read(fd, &(wavhdr->chunk), sizeof(wavhdr->chunk)) != sizeof(wavhdr->chunk)) { + dbglog(DBG_WARNING, "snd_sfx: can't read chunk header\n"); + return -1; + } - /* Read WAV data */ - fs_seek(fd, 0x28, SEEK_SET); - fs_read(fd, &len, 4); + /* If it is the fmt chunk, grab the fields we care about and skip the + rest of the section if there is more */ + if(strncmp((const char *)wavhdr->chunk.id, "fmt ", 4) == 0) { + if(fs_read(fd, &(wavhdr->fmt), sizeof(wavhdr->fmt)) != sizeof(wavhdr->fmt)) { + dbglog(DBG_WARNING, "snd_sfx: can't read fmt header\n"); + return -1; + } - dbglog(DBG_DEBUG, "WAVE file is %s, %luHZ, %d bits/sample, %lu bytes total," - " format %d\n", channels == 1 ? "mono" : "stereo", hz, bitsize, len, fmt); + /* Skip the rest of the fmt chunk */ + fs_seek(fd, wavhdr->chunk.size - sizeof(wavhdr->fmt), SEEK_CUR); + } + /* If we found the data chunk, we are done */ + else if(strncmp((const char *)wavhdr->chunk.id, "data", 4) == 0) { + break; + } + /* Skip meta data */ + else { + fs_seek(fd, wavhdr->chunk.size, SEEK_CUR); + } + } while(1); - tmp = (uint8_t *)memalign(32, len); + return 0; +} - if(tmp == NULL) { - fs_close(fd); - return SFXHND_INVALID; - } +static uint8_t* read_wav_data(file_t fd, wavhdr_t *wavhdr) { + /* Allocate memory for WAV data */ + uint8_t *wav_data = memalign(32, wavhdr->chunk.size); - rd = fs_read(fd, tmp, len); - fs_close(fd); + if(wav_data == NULL) + return NULL; - if (rd != len) { + /* Read WAV data */ + if((size_t)fs_read(fd, wav_data, wavhdr->chunk.size) != wavhdr->chunk.size) { dbglog(DBG_WARNING, "snd_sfx: file has not been fully read.\n"); + free(wav_data); + return NULL; } - t = malloc(sizeof(snd_effect_t)); + return wav_data; +} - if(t == NULL) { - free(tmp); - return SFXHND_INVALID; - } +static snd_effect_t *create_snd_effect(wavhdr_t *wavhdr, uint8_t *wav_data) { + snd_effect_t *effect; + uint32_t len, rate; + uint16_t channels, bitsize, fmt; + + effect = malloc(sizeof(snd_effect_t)); + if(effect == NULL) + return NULL; + + memset(effect, 0, sizeof(snd_effect_t)); - memset(t, 0, sizeof(snd_effect_t)); + fmt = wavhdr->fmt.format; + channels = wavhdr->fmt.channels; + rate = wavhdr->fmt.sample_rate; + bitsize = wavhdr->fmt.sample_size; + len = wavhdr->chunk.size; - /* Common characteristics not impacted by stream type */ - t->rate = hz; - t->stereo = channels - 1; + effect->rate = rate; + effect->stereo = channels > 1; if(channels == 1) { /* Mono PCM/ADPCM */ if(fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723 || fmt == WAVE_FMT_YAMAHA_ADPCM) { - t->fmt = AICA_SM_ADPCM; - t->len = len * 2; /* 4-bit packed samples */ + effect->fmt = AICA_SM_ADPCM; + effect->len = len * 2; /* 4-bit packed samples */ } else if(fmt == WAVE_FMT_PCM && bitsize == 8) { - t->fmt = AICA_SM_8BIT; - t->len = len; + effect->fmt = AICA_SM_8BIT; + effect->len = len; } else if(fmt == WAVE_FMT_PCM && bitsize == 16) { - t->fmt = AICA_SM_16BIT; - t->len = len / 2; - } else { - goto err_exit; + effect->fmt = AICA_SM_16BIT; + effect->len = len / 2; + } + else { + goto err_occurred; } - t->locl = snd_mem_malloc(len); - if(t->locl) - spu_memload_sq(t->locl, tmp, len); + effect->locl = snd_mem_malloc(len); + if(effect->locl) + spu_memload_sq(effect->locl, wav_data, len); - t->locr = 0; + effect->locr = 0; } else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 16) { /* Stereo 16-bit PCM */ - t->len = len / 4; /* Two stereo, 16-bit samples */ - t->fmt = AICA_SM_16BIT; - t->locl = snd_mem_malloc(len / 2); - t->locr = snd_mem_malloc(len / 2); + effect->len = len / 4; /* Two stereo, 16-bit samples */ + effect->fmt = AICA_SM_16BIT; + effect->locl = snd_mem_malloc(len / 2); + effect->locr = snd_mem_malloc(len / 2); - if(t->locl && t->locr) - snd_pcm16_split_sq((uint32_t *)tmp, t->locl, t->locr, len); + if(effect->locl && effect->locr) + snd_pcm16_split_sq((uint32_t *)wav_data, effect->locl, effect->locr, len); } else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 8) { /* Stereo 8-bit PCM */ - uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + uint32_t *left_buf = memalign(32, len / 2), *right_buf; - if(left_buf == NULL) { - goto err_exit; - } - uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + if(left_buf == NULL) + goto err_occurred; + right_buf = memalign(32, len / 2); if(right_buf == NULL) { free(left_buf); - goto err_exit; + goto err_occurred; } - snd_pcm8_split((uint32_t *)tmp, left_buf, right_buf, len); - t->fmt = AICA_SM_8BIT; - t->len = len / 2; - t->locl = snd_mem_malloc(len / 2); - t->locr = snd_mem_malloc(len / 2); + snd_pcm8_split((uint32_t *)wav_data, left_buf, right_buf, len); + + effect->fmt = AICA_SM_8BIT; + effect->len = len / 2; + effect->locl = snd_mem_malloc(len / 2); + effect->locr = snd_mem_malloc(len / 2); - if(t->locl) - spu_memload_sq(t->locl, left_buf, len / 2); + if(effect->locl) + spu_memload_sq(effect->locl, left_buf, len / 2); - if(t->locr) - spu_memload_sq(t->locr, right_buf, len / 2); + if(effect->locr) + spu_memload_sq(effect->locr, right_buf, len / 2); free(left_buf); free(right_buf); } else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723) { /* Stereo ADPCM ITU G.723 (channels are not interleaved) */ - uint8_t *right_buf = tmp + (len / 2); + uint8_t *right_buf = wav_data + (len / 2); int ownmem = 0; if(((uintptr_t)right_buf) & 3) { right_buf = (uint8_t *)memalign(32, len / 2); - ownmem = 1; - if(right_buf == NULL) { - goto err_exit; - } - memcpy(right_buf, tmp + (len / 2), len / 2); + if(right_buf == NULL) + goto err_occurred; + + ownmem = 1; + memcpy(right_buf, wav_data + (len / 2), len / 2); } - t->len = len; /* Two stereo, 4-bit samples */ - t->fmt = AICA_SM_ADPCM; - t->locl = snd_mem_malloc(len / 2); - t->locr = snd_mem_malloc(len / 2); + effect->len = len; /* Two stereo, 4-bit samples */ + effect->fmt = AICA_SM_ADPCM; + effect->locl = snd_mem_malloc(len / 2); + effect->locr = snd_mem_malloc(len / 2); - if(t->locl) - spu_memload_sq(t->locl, tmp, len / 2); + if(effect->locl) + spu_memload_sq(effect->locl, wav_data, len / 2); - if(t->locr) - spu_memload_sq(t->locr, right_buf, len / 2); + if(effect->locr) + spu_memload_sq(effect->locr, right_buf, len / 2); if(ownmem) free(right_buf); } else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM) { /* Stereo Yamaha ADPCM (channels are interleaved) */ - uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + uint32_t *left_buf = (uint32_t *)memalign(32, len / 2), *right_buf; - if(left_buf == NULL) { - goto err_exit; - } - uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + if(left_buf == NULL) + goto err_occurred; + + + right_buf = (uint32_t *)memalign(32, len / 2); if(right_buf == NULL) { free(left_buf); - goto err_exit; + goto err_occurred; } - snd_adpcm_split((uint32_t *)tmp, left_buf, right_buf, len); - t->len = len; /* Two stereo, 4-bit samples */ - t->fmt = AICA_SM_ADPCM; - t->locl = snd_mem_malloc(len / 2); - t->locr = snd_mem_malloc(len / 2); + snd_adpcm_split((uint32_t *)wav_data, left_buf, right_buf, len); + + effect->len = len; /* Two stereo, 4-bit samples */ + effect->fmt = AICA_SM_ADPCM; + effect->locl = snd_mem_malloc(len / 2); + effect->locr = snd_mem_malloc(len / 2); - if(t->locl) - spu_memload_sq(t->locl, left_buf, len / 2); + if(effect->locl) + spu_memload_sq(effect->locl, left_buf, len / 2); - if(t->locr) - spu_memload_sq(t->locr, right_buf, len / 2); + if(effect->locr) + spu_memload_sq(effect->locr, right_buf, len / 2); free(left_buf); free(right_buf); } else { - free(t); - t = SFXHND_INVALID; +err_occurred: + free(effect); + effect = SFXHND_INVALID; } - free(tmp); + return effect; +} - if(t != SFXHND_INVALID) - LIST_INSERT_HEAD(&snd_effects, t, list); +/* Load a sound effect from a WAV file and return a handle to it */ +sfxhnd_t snd_sfx_load(const char *fn) { + file_t fd; + wavhdr_t wavhdr; + uint8_t *wav_data; + snd_effect_t *effect; - return (sfxhnd_t)t; + dbglog(DBG_DEBUG, "snd_sfx: loading effect %s\n", fn); -err_exit: - free(tmp); - free(t); - return SFXHND_INVALID; + /* Open the sound effect file */ + fd = fs_open(fn, O_RDONLY); + if(fd <= FILEHND_INVALID) { + dbglog(DBG_WARNING, "snd_sfx: can't open sfx %s\n", fn); + return SFXHND_INVALID; + } + + /* Read WAV header */ + if(read_wav_header(fd, &wavhdr) < 0) { + fs_close(fd); + return SFXHND_INVALID; + } + + dbglog(DBG_DEBUG, "WAVE file is %s, %luHZ, %d bits/sample, " + "%u bytes total, format %d\n", + wavhdr.fmt.channels == 1 ? "mono" : "stereo", + wavhdr.fmt.sample_rate, + wavhdr.fmt.sample_size, + wavhdr.chunk.size, + wavhdr.fmt.format); + + /* Read WAV data */ + wav_data = read_wav_data(fd, &wavhdr); + fs_close(fd); + if(!wav_data) + return SFXHND_INVALID; + + /* Create and initialize sound effect */ + effect = create_snd_effect(&wavhdr, wav_data); + if(!effect) { + free(wav_data); + return SFXHND_INVALID; ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-10 14:11:56
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via edf4d168ba240b82758d2bd1f45403e12e3ec896 (commit) from 50d76ac96b4e44365b14bfcafb0b3c070f21f8d5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit edf4d168ba240b82758d2bd1f45403e12e3ec896 Author: Andress Barajas <and...@gm...> Date: Fri Nov 10 06:11:29 2023 -0800 G2 refresh (#321) * Refactored g2bus API, converted magic values to macros, added dc/fifo.h, dc/dmac.h file, style changes * Added ability to suspend DMA transfer * Apply suggestions from code review * Resolve feedback ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG | 2 + kernel/arch/dreamcast/fs/fs_dcload.c | 3 +- kernel/arch/dreamcast/hardware/Makefile | 5 +- kernel/arch/dreamcast/hardware/g2bus.c | 140 ++++------ kernel/arch/dreamcast/hardware/g2dma.c | 259 ++++++++++++++++++ kernel/arch/dreamcast/hardware/hardware.c | 4 +- .../dreamcast/hardware/network/broadband_adapter.c | 63 +---- kernel/arch/dreamcast/hardware/pvr/pvr_dma.c | 129 ++++----- kernel/arch/dreamcast/hardware/pvr/pvr_irq.c | 2 +- kernel/arch/dreamcast/hardware/spu.c | 10 +- kernel/arch/dreamcast/hardware/spudma.c | 286 -------------------- kernel/arch/dreamcast/include/dc/dmac.h | 130 +++++++++ kernel/arch/dreamcast/include/dc/fifo.h | 52 ++++ kernel/arch/dreamcast/include/dc/g2bus.h | 203 ++++++++++---- kernel/arch/dreamcast/include/dc/pvr.h | 300 ++++++++++----------- kernel/arch/dreamcast/include/dc/spu.h | 15 +- kernel/arch/dreamcast/include/dc/sq.h | 2 +- kernel/arch/dreamcast/sound/snd_stream.c | 4 +- 18 files changed, 887 insertions(+), 722 deletions(-) create mode 100644 kernel/arch/dreamcast/hardware/g2dma.c delete mode 100644 kernel/arch/dreamcast/hardware/spudma.c create mode 100644 kernel/arch/dreamcast/include/dc/dmac.h create mode 100644 kernel/arch/dreamcast/include/dc/fifo.h diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 0ad497b..81a1a36 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -195,6 +195,8 @@ KallistiOS version 2.1.0 ----------------------------------------------- - DC Added Moop powered fast path to sq_cpy, added TapamN pvr related sq functions [AB] - DC Garbage-collect network stack [PC] - DC Rework romdisks [PC] +- DC Refactored g2bus API, converted magic values to macros, added + dc/fifo.h, dc/dmac.h file [AB] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Megan Potter == MP] diff --git a/kernel/arch/dreamcast/fs/fs_dcload.c b/kernel/arch/dreamcast/fs/fs_dcload.c index 46f0030..38946ab 100644 --- a/kernel/arch/dreamcast/fs/fs_dcload.c +++ b/kernel/arch/dreamcast/fs/fs_dcload.c @@ -17,6 +17,7 @@ printf goes to the dc-tool console */ +#include <dc/fifo.h> #include <dc/fs_dcload.h> #include <kos/thread.h> #include <arch/spinlock.h> @@ -38,7 +39,7 @@ static spinlock_t mutex = SPINLOCK_INITIALIZER; if(!irq_inside_int()) { \ old = irq_disable(); \ } \ - while((*(vuint32 *)0xa05f688c) & 0x20) \ + while(FIFO_STATUS & FIFO_SH4) \ ; \ rv = dcloadsyscall(__VA_ARGS__); \ if(!irq_inside_int()) \ diff --git a/kernel/arch/dreamcast/hardware/Makefile b/kernel/arch/dreamcast/hardware/Makefile index 89328b5..bd4627a 100644 --- a/kernel/arch/dreamcast/hardware/Makefile +++ b/kernel/arch/dreamcast/hardware/Makefile @@ -12,8 +12,11 @@ ifneq ($(KOS_SUBARCH), naomi) OBJS += biosfont.o cdrom.o flashrom.o endif +# G2 +OBJS += g2dma.o + # Sound -OBJS += spu.o spudma.o +OBJS += spu.o # Bus support OBJS += asic.o g2bus.o diff --git a/kernel/arch/dreamcast/hardware/g2bus.c b/kernel/arch/dreamcast/hardware/g2bus.c index 575e06d..0b1bdf4 100644 --- a/kernel/arch/dreamcast/hardware/g2bus.c +++ b/kernel/arch/dreamcast/hardware/g2bus.c @@ -19,209 +19,175 @@ #include <string.h> #include <stdio.h> -#include <arch/irq.h> #include <dc/g2bus.h> #include <arch/spinlock.h> -/* These two macros are based on NetBSD's DC port */ - -/* - G2 bus cycles must not be interrupted by IRQs or G2 DMA. - The following paired macros will take the necessary precautions. - */ - -#define DMAC_CHCR3 *((vuint32 *)0xffa0003c) - -#define G2_LOCK(OLD1, OLD2) \ - do { \ - OLD1 = irq_disable(); \ - /* suspend any G2 DMA here... */ \ - OLD2 = DMAC_CHCR3; \ - DMAC_CHCR3 = OLD2 & ~1; \ - while((*(vuint32 *)0xa05f688c) & 0x20) \ - ; \ - } while(0) - -#define G2_UNLOCK(OLD1, OLD2) \ - do { \ - /* resume any G2 DMA here... */ \ - DMAC_CHCR3 = OLD2; \ - irq_restore(OLD1); \ - } while(0) - /* Always use these functions to access G2 bus memory (includes the SPU and the expansion port, e.g., BBA) */ /* Read one byte from G2 */ -uint8 g2_read_8(uint32 address) { - int old1, old2; +uint8_t g2_read_8(uintptr_t address) { + g2_ctx_t ctx; uint8 out; - G2_LOCK(old1, old2); + ctx = g2_lock(); out = *((vuint8*)address); - G2_UNLOCK(old1, old2); + g2_unlock(ctx); return out; } /* Write one byte to G2 */ -void g2_write_8(uint32 address, uint8 value) { - int old1, old2; +void g2_write_8(uintptr_t address, uint8_t value) { + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); *((vuint8*)address) = value; - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Read one word from G2 */ -uint16 g2_read_16(uint32 address) { - int old1, old2; +uint16_t g2_read_16(uintptr_t address) { + g2_ctx_t ctx; uint16 out; - G2_LOCK(old1, old2); + ctx = g2_lock(); out = *((vuint16*)address); - G2_UNLOCK(old1, old2); + g2_unlock(ctx); return out; } /* Write one word to G2 */ -void g2_write_16(uint32 address, uint16 value) { - int old1, old2; +void g2_write_16(uintptr_t address, uint16_t value) { + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); *((vuint16*)address) = value; - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Read one dword from G2 */ -uint32 g2_read_32(uint32 address) { - int old1, old2; +uint32_t g2_read_32(uintptr_t address) { + g2_ctx_t ctx; uint32 out; - G2_LOCK(old1, old2); + ctx = g2_lock(); out = *((vuint32*)address); - G2_UNLOCK(old1, old2); + g2_unlock(ctx); return out; } /* Write one dword to G2 */ -void g2_write_32(uint32 address, uint32 value) { - int old1, old2; +void g2_write_32(uintptr_t address, uint32_t value) { + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); *((vuint32*)address) = value; - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Read a block of 8-bit values from G2 */ -void g2_read_block_8(uint8 * output, uint32 address, int amt) { +void g2_read_block_8(uint8_t * output, uintptr_t address, size_t amt) { const vuint8 * input = (const vuint8 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Write a block 8-bit values to G2 */ -void g2_write_block_8(const uint8 * input, uint32 address, int amt) { +void g2_write_block_8(const uint8 * input, uintptr_t address, size_t amt) { vuint8 * output = (vuint8 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Read a block of 16-bit values from G2 */ -void g2_read_block_16(uint16 * output, uint32 address, int amt) { +void g2_read_block_16(uint16_t * output, uintptr_t address, size_t amt) { const vuint16 * input = (const vuint16 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Write a block of 16-bit values to G2 */ -void g2_write_block_16(const uint16 * input, uint32 address, int amt) { +void g2_write_block_16(const uint16_t * input, uintptr_t address, size_t amt) { vuint16 * output = (vuint16 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Read a block of 32-bit values from G2 */ -void g2_read_block_32(uint32 * output, uint32 address, int amt) { +void g2_read_block_32(uint32_t * output, uintptr_t address, size_t amt) { const vuint32 * input = (const vuint32 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* Write a block of 32-bit values to G2 */ -void g2_write_block_32(const uint32 * input, uint32 address, int amt) { +void g2_write_block_32(const uint32_t * input, uintptr_t address, size_t amt) { vuint32 * output = (vuint32 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = *input++; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* A memset-like function for G2 */ -void g2_memset_8(uint32 address, uint8 c, int amt) { +void g2_memset_8(uintptr_t address, uint8_t c, size_t amt) { vuint8 * output = (vuint8 *)address; - int old1, old2; + g2_ctx_t ctx; - G2_LOCK(old1, old2); + ctx = g2_lock(); while(amt--) { *output++ = c; } - G2_UNLOCK(old1, old2); + g2_unlock(ctx); } /* When writing to the SPU RAM, this is required at least every 8 32-bit writes that you execute */ void g2_fifo_wait(void) { - vuint32 const *g2_fifo = (vuint32*)0xa05f688c; - int i; - - for(i = 0; i < 0x1800; i++) { - if(!(*g2_fifo & 0x11)) break; - } + while(FIFO_STATUS & (FIFO_AICA | FIFO_G2)); } - - diff --git a/kernel/arch/dreamcast/hardware/g2dma.c b/kernel/arch/dreamcast/hardware/g2dma.c new file mode 100644 index 0000000..6ad85f3 --- /dev/null +++ b/kernel/arch/dreamcast/hardware/g2dma.c @@ -0,0 +1,259 @@ +/* KallistiOS ##version## + + g2dma.c + Copyright (C) 2001, 2002, 2004 Megan Potter + Copyright (C) 2023 Andy Barajas +*/ + +#include <assert.h> +#include <stdio.h> +#include <errno.h> +#include <dc/asic.h> +#include <dc/g2bus.h> +#include <kos/sem.h> +#include <kos/thread.h> + +typedef struct { + uint32_t g2_addr; /* G2 Bus start address */ + uint32_t sh4_addr; /* SH-4 start address */ + uint32_t size; /* Size in bytes; Must be 32-byte aligned */ + uint32_t dir; /* 0: sh4->g2bus; 1: g2bus->sh4 */ + uint32_t trigger_select; /* DMA trigger select; 0-CPU, 1-HW, 2-I */ + uint32_t enable; /* DMA enable */ + uint32_t start; /* DMA start */ + uint32_t suspend; /* DMA suspend */ +} g2_dma_ctrl_t; + +typedef struct { + g2_dma_ctrl_t dma[4]; + uint32_t g2_id; /* G2 ID Bus version (Read only) */ + uint32_t u1[3]; /* Unused */ + uint32_t ds_timeout; /* G2 DS timeout in clocks (default: 0x3ff) */ + uint32_t tr_timeout; /* G2 TR timeout in clocks (default: 0x3ff) */ + uint32_t modem_timeout; /* G2 Modem timeout in cycles */ + uint32_t modem_wait; /* G2 Modem wait time in cycles */ + uint32_t u2[7]; /* Unused */ + uint32_t protection; /* System memory area protection range */ +} g2_dma_reg_t; + +/* Signaling semaphore */ +static semaphore_t dma_done[4]; +static int dma_blocking[4]; +static g2_dma_callback_t dma_callback[4]; +static void *dma_cbdata[4]; + +static int dma_init; + +/* G2 Bus DMA registers */ +#define G2_DMA_REG_BASE 0xa05f7800 +static volatile g2_dma_reg_t * const g2_dma = (g2_dma_reg_t *)G2_DMA_REG_BASE; + +/* + List of possible initiation triggers values to assign to trigger_select: + CPU_TRIGGER: Software-driven. (Setting enable and start to 1) + HARDWARE_TRIGGER: Via AICA (DMA0) or expansion device. + INTERRUPT_TRIGGER: Based on interrupt signals. +*/ +#define CPU_TRIGGER 0 +#define HARDWARE_TRIGGER 1 +#define INTERRUPT_TRIGGER 2 + +/* + Controls whether the DMA suspend register of a channel is enabled: + 0x00000004: Enables the suspend register. + 0x00000000: Disables the suspend register. + + OR '|' this value with trigger when setting the trigger select of the + DMA channel. +*/ +#define DMA_SUSPEND_ENABLED 0x00000004 +#define DMA_SUSPEND_DISABLED 0x00000000 + +/* + For sh4 and g2bus addresses, ensure bits 31-29 & 4-0 are '0' to avoid + illegal interrupts. Only bits 28-5 are used for valid addresses. +*/ +#define MASK_ADDRESS 0x1fffffe0 + +/* + Controls DMA initiation behavior after a DMA transfer completes: + 0x00000000: Preserve the current DMA enable setting. + 0x80000000: Reset the DMA enable setting to "0" after transfer. + + OR '|' this value with length when setting the size of the DMA request. +*/ +#define PRESERVE_ENABLED 0x00000000 +#define RESET_ENABLED 0x80000000 + +/* + Specifies system memory address range for G2-DMA across channels 0-3. + If a DMA transfer is generated outside of this range, an overrun error + occurs. + + Previous range (0x4659404f): + 0x0C400000 - 0x0C4F0000 + + Current range (0x4659007F): + 0x0C000000 - 0x0CFFFFFF (Effectively disabling mem protection) + + How its calculated: + + xxxx xxxx xxxx xxxx ---- ---- ---- ---- : (0x4659) + ---- ---- ---- ---- -xxx xxxx ---- ---- : Top range + ---- ---- ---- ---- ---- ---- -xxx xxxx : Bottom range + + top_range = (value & 0x7f00) >> 8; + bottom_range = (value & 0x7f); + + top_addr = (top_range << 20) | 0x08000000; + bottom_addr = (bottom_range << 20) | 0x080fffff; +*/ +#define SYS_MEM_SECURITY_CODE 0x4659 +#define DISABLE_SYS_MEM_PROTECTION (SYS_MEM_SECURITY_CODE << 16 | 0x007F) +#define ENABLE_SYS_MEM_PROTECTION (SYS_MEM_SECURITY_CODE << 16 | 0x7F00) + +/* + Set the DS# (Data Strobe) timeout to 27 clock cycles for the external DMA. + If data isn't ready for latching by this time, an interrupt will be + triggered. + + Not sure why its 27 but can be changed later. Default value + is 1023 cycles (0x3ff). +*/ +#define DS_CYCLE_OVERRIDE 27 + +/* Disable the DMA */ +inline static void dma_disable(uint32_t chn) { + g2_dma->dma[chn].enable = 0; + g2_dma->dma[chn].start = 0; +} + +static void g2_dma_irq_hnd(uint32_t code) { + int chn = code - ASIC_EVT_G2_DMA0; + + if(chn < G2_DMA_CHAN_SPU || chn > G2_DMA_CHAN_CH3) { + dbglog(DBG_ERROR, "g2_dma: Wrong channel received in g2_dma_irq_hnd"); + return; + } + + /* VP : changed the order of things so that we can chain dma calls */ + + /* Signal the calling thread to continue, if any. */ + if(dma_blocking[chn]) { + sem_signal(&dma_done[chn]); + thd_schedule(1, 0); + dma_blocking[chn] = 0; + } + + /* Call the callback, if any. */ + if(dma_callback[chn]) { + dma_callback[chn](dma_cbdata[chn]); + } +} + +int g2_dma_transfer(void *sh4, void *g2bus, size_t length, uint32_t block, + g2_dma_callback_t callback, void *cbdata, + uint32_t dir, uint32_t mode, uint32_t g2chn, uint32_t sh4chn) { + /* No longer used but we keep then around for compatibility */ + (void)mode; + (void)sh4chn; + + if(g2chn > G2_DMA_CHAN_CH3) { + errno = EINVAL; + return -1; + } ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-10 13:44:12
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 50d76ac96b4e44365b14bfcafb0b3c070f21f8d5 (commit) from 2be02ef1bc763f11f3551d0e336f17cd94124f03 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 50d76ac96b4e44365b14bfcafb0b3c070f21f8d5 Author: Paul Cercueil <pa...@cr...> Date: Fri Nov 10 13:26:08 2023 +0100 Fix built-in romdisks not mounting properly (#347) Fix kernel crash that happened when the init code was trying to execute fs_romdisk_mount_weak(). ----------------------------------------------------------------------- Summary of changes: kernel/romdisk/romdiskbase.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/romdisk/romdiskbase.c b/kernel/romdisk/romdiskbase.c index 41415d3..affd857 100644 --- a/kernel/romdisk/romdiskbase.c +++ b/kernel/romdisk/romdiskbase.c @@ -10,7 +10,9 @@ extern unsigned char romdisk[]; void *__kos_romdisk = romdisk; -int fs_romdisk_mount_weak(void) +static int do_fs_romdisk_mount(void) { return fs_romdisk_mount("/rd", __kos_romdisk, 0); } + +int (*fs_romdisk_mount_weak)(void) = do_fs_romdisk_mount; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-10 02:31:36
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 2be02ef1bc763f11f3551d0e336f17cd94124f03 (commit) from e3529c47c1e35fb3a488285e911d4cfdf06a48c0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2be02ef1bc763f11f3551d0e336f17cd94124f03 Author: Ruslan Rostovtsev <sw...@21...> Date: Fri Nov 10 09:31:10 2023 +0700 Sound stream fixes and improvements. (#346) * Sound stream fixes and improvements. - Fixed multistream support. - Fixed non-16-bit stream support. - Fixed stream prefill. - Used single channel for mono. - Clean playback. - Some cleanup and refactoring. * Apply suggestions from code review * Minor fixes ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/sound/snd_stream.c | 424 ++++++++++++++++++------------- 1 file changed, 253 insertions(+), 171 deletions(-) diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index fcbc9c2..f75f3aa 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -16,6 +16,7 @@ #include <malloc.h> #include <sys/queue.h> +#include <kos/mutex.h> #include <arch/cache.h> #include <arch/timer.h> #include <dc/g2bus.h> @@ -44,7 +45,7 @@ being available CPU time and channels. typedef struct filter { TAILQ_ENTRY(filter) lent; snd_stream_filter_t func; - void * data; + void *data; } filter_t; /* Each of these represents an active streaming channel */ @@ -53,14 +54,13 @@ typedef struct strchan { int ch[2]; // The last write position in the playing buffer - uint32 last_write_pos; // = 0 - int curbuffer; // = 0 + uint32_t last_write_pos; // The buffer size allocated for this stream. - uint32 buffer_size; // = 0x10000 + size_t buffer_size; // Stream data location in AICA RAM - uint32 spu_ram_sch[2]; + uint32_t spu_ram_sch[2]; // "Get data" callback; we'll call this any time we want to get // another buffer of output data. @@ -72,18 +72,21 @@ typedef struct strchan { // Sample type int type; + // Sample size + int bitsize; + // Stereo/mono flag - int stereo; + int channels; // Playback frequency int frequency; /* Stream queueing is where we get everything ready to go but don't actually start it playing until the signal (for music sync, etc) */ - int queueing; + int queueing; /* Have we been initialized yet? (and reserved a buffer, etc) */ - volatile int initted; + volatile int initted; /* User data. */ void *user_data; @@ -93,10 +96,14 @@ typedef struct strchan { static strchan_t streams[SND_STREAM_MAX]; // Separation buffers (for stereo) -static uint32 *sep_buffer[2] = {NULL, NULL}; +static uint32_t *sep_buffer[2] = {NULL, NULL}; + +static mutex_t stream_mutex = MUTEX_INITIALIZER; /* the address of the sound ram from the SH4 side */ -#define SPU_RAM_BASE 0xa0800000 +#define SPU_RAM_BASE 0xa0800000 + +#define LOCK_TIMEOUT_MS 1000 // Check an incoming handle #define CHECK_HND(x) do { \ @@ -106,6 +113,30 @@ static uint32 *sep_buffer[2] = {NULL, NULL}; void snd_pcm16_split_sq_start(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); +static inline size_t samples_to_bytes(snd_stream_hnd_t hnd, size_t samples) { + switch(streams[hnd].bitsize) { + case 4: + return samples >> 1; + case 8: + return samples; + case 16: + default: + return samples << 1; + } +} + +static inline size_t bytes_to_samples(snd_stream_hnd_t hnd, size_t bytes) { + switch(streams[hnd].bitsize) { + case 4: + return bytes << 1; + case 8: + return bytes; + case 16: + default: + return bytes >> 1; + } +} + /* Set "get data" callback */ void snd_stream_set_callback(snd_stream_hnd_t hnd, snd_stream_callback_t cb) { CHECK_HND(hnd); @@ -151,50 +182,42 @@ static void process_filters(snd_stream_hnd_t hnd, void **buffer, int *samplecnt) filter_t * f; TAILQ_FOREACH(f, &streams[hnd].filters, lent) { - f->func(hnd, f->data, streams[hnd].frequency, streams[hnd].stereo ? 2 : 1, buffer, samplecnt); + f->func(hnd, f->data, streams[hnd].frequency, streams[hnd].channels, buffer, samplecnt); } } -static void sep_data(void *buffer, int len, int stereo) { +static void snd_pcm16_split_unaligned(void *buffer, void *left, void *right, size_t len) { uint32_t *buf = (uint32_t *)buffer; - uint32_t *left_ptr = (uint32_t *)sep_buffer[1]; - uint32_t *right_ptr = (uint32_t *)sep_buffer[0]; + uint32_t *left_ptr = (uint32_t *)left; + uint32_t *right_ptr = (uint32_t *)right; uint32_t data; uint32_t left_val; uint32_t right_val; - if(stereo) { - len <<= 1; + for(; len > 8; len -= 8) { + dcache_pref_block(buf + 8); - for(; len > 8; len -= 8) { - dcache_pref_block(buf + 8); + data = *buf++; + left_val = (data >> 16); + right_val = (data & 0xffff); - data = *buf++; - left_val = (data >> 16); - right_val = (data & 0xffff); + data = *buf++; + left_val |= (data & 0xffff0000); + right_val |= (data & 0xffff) << 16; - data = *buf++; - left_val |= (data & 0xffff0000); - right_val |= (data & 0xffff) << 16; - - if(((uintptr_t)left_ptr & 31) == 0) { - dcache_alloc_block(left_ptr++, left_val); - dcache_alloc_block(right_ptr++, right_val); - } - else { - *left_ptr++ = left_val; - *right_ptr++ = right_val; - } + if(((uintptr_t)left_ptr & 31) == 0) { + dcache_alloc_block(left_ptr++, left_val); + dcache_alloc_block(right_ptr++, right_val); } - if(len) { - data = *buf++; - *(uint16_t *)left_ptr = (data >> 16); - *(uint16_t *)right_ptr = (data & 0xffff); + else { + *left_ptr++ = left_val; + *right_ptr++ = right_val; } } - else { - memcpy(sep_buffer[0], buffer, len); - sep_buffer[1] = sep_buffer[0]; + if(len) { + data = *buf++; + *(uint16_t *)left_ptr = (data >> 16); + *(uint16_t *)right_ptr = (data & 0xffff); } } @@ -227,47 +250,49 @@ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t } static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { - - const uint32_t buffer_size = streams[hnd].buffer_size; - uintptr_t left = streams[hnd].spu_ram_sch[0] + offset; - uintptr_t right = streams[hnd].spu_ram_sch[1] + offset; - int got = buffer_size; - void *buf; - - if(streams[hnd].stereo) { - buf = streams[hnd].get_data(hnd, buffer_size, &got); - } - else { - buf = streams[hnd].get_data(hnd, buffer_size / 2, &got); - } + const size_t buffer_size = streams[hnd].buffer_size; + const int chans = streams[hnd].channels; + const uintptr_t left = streams[hnd].spu_ram_sch[0] + offset; + const uintptr_t right = streams[hnd].spu_ram_sch[1] + offset; + const int max_got = (buffer_size / 2) * chans; + int got = max_got; + void *buf = streams[hnd].get_data(hnd, max_got, &got); if(buf == NULL) { dbglog(DBG_ERROR, "snd_stream_prefill_part(): get_data() failed\n"); return; } + if(got > max_got) { + got = max_got; + } + process_filters(hnd, &buf, &got); - if(streams[hnd].stereo == 0) { + if(chans == 1) { spu_memload_sq(left, buf, got); spu_memload_sq(right, buf, got); + return; } - else if(((uintptr_t)buf & 31) || streams[hnd].type != AICA_SM_16BIT) { - if(streams[hnd].type == AICA_SM_8BIT) { - snd_pcm8_split(buf, sep_buffer[0], sep_buffer[1], got); - } - else if(streams[hnd].type == AICA_SM_ADPCM_LS) { - snd_adpcm_split(buf, sep_buffer[0], sep_buffer[1], got); + + if(streams[hnd].bitsize == 16) { + if((uintptr_t)buf & 31) { + snd_pcm16_split_unaligned(buf, sep_buffer[0], sep_buffer[1], got); } else { - sep_data(buf, got / 2, streams[hnd].stereo); + snd_pcm16_split_sq((uint32_t *)buf, left, right, got); + return; } - spu_memload_sq(left, sep_buffer[0], got); - spu_memload_sq(right, sep_buffer[1], got); } - else { - snd_pcm16_split_sq((uint32_t *)buf, left, right, got); + else if(streams[hnd].bitsize == 8) { + snd_pcm8_split(buf, sep_buffer[0], sep_buffer[1], got); + } + else if(streams[hnd].bitsize == 4) { + snd_adpcm_split(buf, sep_buffer[0], sep_buffer[1], got); } + + spu_memload_sq(left, sep_buffer[0], got / 2); + spu_memload_sq(right, sep_buffer[1], got / 2); } /* Prefill buffers -- do this before calling start() */ @@ -278,12 +303,13 @@ void snd_stream_prefill(snd_stream_hnd_t hnd) { return; } + mutex_lock_timed(&stream_mutex, LOCK_TIMEOUT_MS); snd_stream_prefill_part(hnd, 0); snd_stream_prefill_part(hnd, streams[hnd].buffer_size / 2); - /* Start with playing on buffer 0 */ + /* Start playing from the beginning */ streams[hnd].last_write_pos = 0; - streams[hnd].curbuffer = 0; + mutex_unlock(&stream_mutex); } /* Initialize stream system */ @@ -339,8 +365,8 @@ snd_stream_hnd_t snd_stream_alloc(snd_stream_callback_t cb, int bufsize) { TAILQ_INIT(&streams[hnd].filters); // Allocate stream buffers - streams[hnd].spu_ram_sch[0] = snd_mem_malloc(streams[hnd].buffer_size); - streams[hnd].spu_ram_sch[1] = snd_mem_malloc(streams[hnd].buffer_size); + streams[hnd].spu_ram_sch[0] = snd_mem_malloc(streams[hnd].buffer_size * 2); + streams[hnd].spu_ram_sch[1] = streams[hnd].spu_ram_sch[0] + streams[hnd].buffer_size; // And channels streams[hnd].ch[0] = snd_sfx_chn_alloc(); @@ -419,7 +445,7 @@ void snd_stream_queue_disable(snd_stream_hnd_t hnd) { } /* Start streaming (or if queueing is enabled, just get ready) */ -static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32 type, uint32 freq, int st) { +static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32_t type, uint32_t freq, int st) { AICA_CMDSTR_CHANNEL(tmp, cmd, chan); CHECK_HND(hnd); @@ -427,9 +453,25 @@ static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32 type, uint32 freq if(!streams[hnd].get_data) return; streams[hnd].type = type; - streams[hnd].stereo = st; + streams[hnd].channels = st ? 2 : 1; streams[hnd].frequency = freq; + if(streams[hnd].type == AICA_SM_16BIT) { + streams[hnd].bitsize = 16; + } + else if(streams[hnd].type == AICA_SM_8BIT) { + streams[hnd].bitsize = 8; + } + else if(streams[hnd].type == AICA_SM_ADPCM_LS) { + streams[hnd].bitsize = 4; + + if(streams[hnd].buffer_size > (32 << 10)) { + /* The channel position data size is 16-bits. + Need to make sure that we don't go beyond these limits */ + streams[hnd].buffer_size = (32 << 10); + } + } + /* Make sure these are sync'd (and/or delayed) */ snd_sh4_to_aica_stop(); @@ -444,24 +486,31 @@ static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32 type, uint32 freq chan->cmd = AICA_CH_CMD_START | AICA_CH_START_DELAY; chan->base = streams[hnd].spu_ram_sch[0]; chan->type = type; - chan->length = (streams[hnd].buffer_size / 2); + chan->length = bytes_to_samples(hnd, streams[hnd].buffer_size); chan->loop = 1; chan->loopstart = 0; - chan->loopend = (streams[hnd].buffer_size / 2); + chan->loopend = chan->length - 1; chan->freq = freq; chan->vol = 255; - chan->pan = 0; + chan->pan = streams[hnd].channels == 2 ? 0 : 128; snd_sh4_to_aica(tmp, cmd->size); - /* Channel 1 */ - cmd->cmd_id = streams[hnd].ch[1]; - chan->base = streams[hnd].spu_ram_sch[1]; - chan->pan = 255; - snd_sh4_to_aica(tmp, cmd->size); + if(streams[hnd].channels == 2) { + /* Channel 1 */ + cmd->cmd_id = streams[hnd].ch[1]; + chan->base = streams[hnd].spu_ram_sch[1]; + chan->pan = 255; + snd_sh4_to_aica(tmp, cmd->size); + + /* Start both channels simultaneously */ + cmd->cmd_id = (1 << streams[hnd].ch[0]) | + (1 << streams[hnd].ch[1]); + } + else { + /* Start one channel */ + cmd->cmd_id = (1 << streams[hnd].ch[0]); + } - /* Start both channels simultaneously */ - cmd->cmd_id = (1 << streams[hnd].ch[0]) | - (1 << streams[hnd].ch[1]); chan->cmd = AICA_CH_CMD_START | AICA_CH_START_SYNC; snd_sh4_to_aica(tmp, cmd->size); @@ -470,15 +519,15 @@ static void snd_stream_start_type(snd_stream_hnd_t hnd, uint32 type, uint32 freq snd_sh4_to_aica_start(); } -void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st) { +void snd_stream_start(snd_stream_hnd_t hnd, uint32_t freq, int st) { snd_stream_start_type(hnd, AICA_SM_16BIT, freq, st); } -void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32 freq, int st) { +void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32_t freq, int st) { snd_stream_start_type(hnd, AICA_SM_8BIT, freq, st); } -void snd_stream_start_adpcm(snd_stream_hnd_t hnd, uint32 freq, int st) { +void snd_stream_start_adpcm(snd_stream_hnd_t hnd, uint32_t freq, int st) { snd_stream_start_type(hnd, AICA_SM_ADPCM_LS, freq, st); } @@ -505,124 +554,157 @@ void snd_stream_stop(snd_stream_hnd_t hnd) { chan->cmd = AICA_CH_CMD_STOP; snd_sh4_to_aica(tmp, cmd->size); - /* Channel 1 */ - cmd->cmd_id = streams[hnd].ch[1]; - snd_sh4_to_aica(tmp, cmd->size); + if(streams[hnd].channels == 2) { + /* Channel 1 */ + cmd->cmd_id = streams[hnd].ch[1]; + snd_sh4_to_aica(tmp, cmd->size); + } } /* The DMA will chain to this to start the second DMA. */ -static uint32 dmadest, dmacnt; -static void dma_chain(ptr_t data) { +static uint32_t dmacnt; +static uintptr_t dmadest; +static inline void dma_done(uint32_t data) { + (void)data; + mutex_unlock(&stream_mutex); +} + +static inline void dma_chain(uint32_t data) { (void)data; - spu_dma_transfer(sep_buffer[1], dmadest, dmacnt, 0, NULL, 0); + spu_dma_transfer(sep_buffer[1], dmadest, dmacnt, 0, dma_done, 0); } /* Poll streamer to load more data if neccessary */ int snd_stream_poll(snd_stream_hnd_t hnd) { - uint32 ch0pos, ch1pos; - //int realbuffer; - uint32 current_play_pos; - int needed_samples; - int got_samples; - void *data; - void *first_dma_buf = sep_buffer[0]; + uint32_t ch0pos, ch1pos, write_pos; + uint16_t current_play_pos; + int needed_samples = 0; + int needed_bytes = 0; + int got_bytes = 0; + void *data; + void *first_dma_buf = sep_buffer[0]; + strchan_t *stream; CHECK_HND(hnd); + stream = &streams[hnd]; - if(!streams[hnd].get_data) return -1; + if(!stream->get_data) { + return -1; + } - /* Get "real" buffer */ - ch0pos = g2_read_32(SPU_RAM_BASE + AICA_CHANNEL(streams[hnd].ch[0]) + offsetof(aica_channel_t, pos)); - ch1pos = g2_read_32(SPU_RAM_BASE + AICA_CHANNEL(streams[hnd].ch[1]) + offsetof(aica_channel_t, pos)); + /* Get channels position */ + ch0pos = g2_read_32(SPU_RAM_BASE + + AICA_CHANNEL(stream->ch[0]) + + offsetof(aica_channel_t, pos)); + + if(stream->channels == 2) { + ch1pos = g2_read_32(SPU_RAM_BASE + + AICA_CHANNEL(stream->ch[1]) + + offsetof(aica_channel_t, pos)); + /* The channel position register is 16-bit on AICA side, keep it in mind */ + current_play_pos = (ch0pos < ch1pos ? ch0pos : ch1pos) & 0xffff; + } + else { + current_play_pos = (ch0pos & 0xffff); + } - if(ch0pos >= (streams[hnd].buffer_size / 2)) { - dbglog(DBG_ERROR, "snd_stream_poll: chan0(%d).pos = %ld (%08lx)\n", streams[hnd].ch[0], ch0pos, ch0pos); + if(samples_to_bytes(hnd, current_play_pos) >= stream->buffer_size) { + dbglog(DBG_ERROR, "snd_stream_poll: chan0(%d).pos = %ld\n", stream->ch[0], ch0pos); return -1; } - //realbuffer = !((ch0pos < (streams[hnd].buffer_size / 4)) && (ch1pos < (streams[hnd].buffer_size / 4))); + /* Count just till the end of the buffer, so we don't have to + handle buffer wraps */ + if(stream->last_write_pos <= current_play_pos) { + needed_samples = current_play_pos - stream->last_write_pos - 1; + /* Round it to max sector size of supported storage devices */ + needed_samples &= ~(bytes_to_samples(hnd, 2048 / stream->channels) - 1); + } + else { + needed_samples = bytes_to_samples(hnd, stream->buffer_size); + needed_samples -= stream->last_write_pos; + } - current_play_pos = (ch0pos < ch1pos) ? (ch0pos) : (ch1pos); + if(needed_samples <= 0) { + return 0; + } - /* count just till the end of the buffer, so we don't have to - handle buffer wraps */ - if(streams[hnd].last_write_pos <= current_play_pos) - needed_samples = current_play_pos - streams[hnd].last_write_pos; - else - needed_samples = (streams[hnd].buffer_size / 2) - streams[hnd].last_write_pos; - - /* round it a little bit */ - needed_samples &= ~0x7ff; - /* printf("last_write_pos %6u, current_play_pos %6u, needed_samples %6i\n",streams[hnd].last_write_pos,current_play_pos,needed_samples); */ - - if(needed_samples > 0) { - if(streams[hnd].stereo) { - needed_samples = ((unsigned)needed_samples > streams[hnd].buffer_size/4) ? (int)streams[hnd].buffer_size/4 : needed_samples; - data = streams[hnd].get_data(hnd, needed_samples * 4, &got_samples); - process_filters(hnd, &data, &got_samples); - - if(got_samples < needed_samples * 4) { - needed_samples = got_samples / 4; - - if(needed_samples & 3) - needed_samples = (needed_samples + 4) & ~3; - } - } ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-10 01:50:44
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via e3529c47c1e35fb3a488285e911d4cfdf06a48c0 (commit) via 87f6ed33867bdbffed93da239592deda3fc30adb (commit) from 9c23016db56a8ca885765c115e8742cae65d0506 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e3529c47c1e35fb3a488285e911d4cfdf06a48c0 Author: Ruslan Rostovtsev <sw...@21...> Date: Fri Nov 10 08:49:59 2023 +0700 Added Store Queue locking and define's changes (#344) * Added Store Queue locking and define's changes * Apply suggestions from code review * Fix SQ unlocking for sound streams commit 87f6ed33867bdbffed93da239592deda3fc30adb Author: Paul Cercueil <pa...@cr...> Date: Fri Nov 10 02:43:27 2023 +0100 Rework romdisks (#341) * Rework romdisks - KOS_INIT_ROMDISK() is now useless; it is automatically added to the romdisk.o object file. The macro remains just for compatibility with older source code. - If the INIT_FS_ROMDISK init flag has been specified (it is set by default), the romdisk init/shutdown code will be included. Otherwise, it will be garbage-collected automatically. - The /rd VFS entry will only be created if a romdisk has been built-in. Signed-off-by: Paul Cercueil <pa...@cr...> * Add my garbage-collect changes to CHANGELOG Signed-off-by: Paul Cercueil <pa...@cr...> ----------------------------------------------------------------------- Summary of changes: Makefile.rules | 4 ++- doc/CHANGELOG | 2 ++ include/kos/init.h | 16 +++++---- kernel/Makefile | 4 ++- kernel/arch/dreamcast/exports-naomi.txt | 3 ++ kernel/arch/dreamcast/exports-pristine.txt | 3 ++ kernel/arch/dreamcast/hardware/sq.c | 28 +++++++++++++--- kernel/arch/dreamcast/include/dc/sq.h | 52 +++++++++++++++++++++++++----- kernel/arch/dreamcast/kernel/init.c | 17 +++++++--- kernel/arch/dreamcast/sound/snd_stream.c | 16 +++++---- kernel/romdisk/Makefile | 9 ++++++ kernel/romdisk/romdiskbase.c | 16 +++++++++ 12 files changed, 139 insertions(+), 31 deletions(-) create mode 100644 kernel/romdisk/Makefile create mode 100644 kernel/romdisk/romdiskbase.c diff --git a/Makefile.rules b/Makefile.rules index 37b14ec..e670cda 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -67,5 +67,7 @@ romdisk.img: $(KOS_GENROMFS) -f romdisk.img -d $(KOS_ROMDISK_DIR) -v -x .svn -x .keepme romdisk.o: romdisk.img - $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o + $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk_tmp.o + $(KOS_CC) -o romdisk.o -r romdisk_tmp.o $(KOS_LIB_PATHS) -Wl,--whole-archive -lromdiskbase + rm romdisk_tmp.o endif diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 19d1e75..0ad497b 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -193,6 +193,8 @@ KallistiOS version 2.1.0 ----------------------------------------------- - DC Added vmu functions to check/enable/disable the extra 41 blocks [AB] - *** Added driver for the SH4's Watchdog Timer peripheral [FG] - DC Added Moop powered fast path to sq_cpy, added TapamN pvr related sq functions [AB] +- DC Garbage-collect network stack [PC] +- DC Rework romdisks [PC] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Megan Potter == MP] diff --git a/include/kos/init.h b/include/kos/init.h index a1c94cf..c229203 100644 --- a/include/kos/init.h +++ b/include/kos/init.h @@ -48,16 +48,19 @@ __BEGIN_DECLS void (*bba_la_init_weak)(void) = ((flags) & INIT_NET) ? bba_la_init : NULL; \ extern void bba_la_shutdown(void); \ void (*bba_la_shutdown_weak)(void) = ((flags) & INIT_NET) ? bba_la_shutdown : NULL; \ + extern int fs_romdisk_init(void); \ + int (*fs_romdisk_init_weak)(void) = ((flags) & INIT_FS_ROMDISK) ? fs_romdisk_init : NULL; \ + extern int fs_romdisk_shutdown(void); \ + int (*fs_romdisk_shutdown_weak)(void) = ((flags) & INIT_FS_ROMDISK) ? fs_romdisk_shutdown : NULL; \ extern int export_init(void); \ int (*export_init_weak)(void) = ((flags) & INIT_EXPORT) ? export_init : NULL /** \brief The init flags. Do not modify this directly! */ extern uint32 __kos_init_flags; -/** \brief Define a romdisk for your program, if you'd like one. - \param rd Pointer to the romdisk image in your code. -*/ -#define KOS_INIT_ROMDISK(rd) void * __kos_romdisk = (rd) +/** \brief Deprecated and not useful anymore. */ +#define KOS_INIT_ROMDISK(rd) \ + static void *__old_romdisk __attribute__((unused)) = (rd) /** \brief Built-in romdisk. Do not modify this directly! */ extern void * __kos_romdisk; @@ -81,9 +84,9 @@ extern void * __kos_romdisk; \see dreamcast_initflags @{ */ -/** \brief Default init flags (IRQs on, preemption enabled). */ +/** \brief Default init flags (IRQs on, preemption enabled, romdisks). */ #define INIT_DEFAULT \ - (INIT_IRQ | INIT_THD_PREEMPT) + (INIT_IRQ | INIT_THD_PREEMPT | INIT_FS_ROMDISK) #define INIT_NONE 0x0000 /**< \brief Don't init optional things */ #define INIT_IRQ 0x0001 /**< \brief Enable IRQs at startup */ @@ -93,6 +96,7 @@ extern void * __kos_romdisk; #define INIT_MALLOCSTATS 0x0008 /**< \brief Enable malloc statistics */ #define INIT_QUIET 0x0010 /**< \brief Disable dbgio */ #define INIT_EXPORT 0x0020 /**< \brief Export kernel symbols */ +#define INIT_FS_ROMDISK 0x0040 /**< \brief Enable support for romdisks */ /** @} */ __END_DECLS diff --git a/kernel/Makefile b/kernel/Makefile index 748e65b..7e1b4eb 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -5,7 +5,7 @@ # OBJS = -SUBDIRS = arch debug fs thread net libc exports +SUBDIRS = arch debug fs thread net libc exports romdisk STUBS = stubs/kernel_export_stubs.o stubs/arch_export_stubs.o # Everything from here up should be plain old C. @@ -13,6 +13,7 @@ KOS_CFLAGS += $(KOS_CSTD) all: subdirs $(STUBS) rm -f $(KOS_BASE)/lib/$(KOS_ARCH)/libkallisti.a + kos-ar rcs $(KOS_BASE)/lib/$(KOS_ARCH)/libromdiskbase.a romdisk/*.o kos-ar rcs $(KOS_BASE)/lib/$(KOS_ARCH)/libkallisti.a build/*.o kos-ar rcs $(KOS_BASE)/lib/$(KOS_ARCH)/libkallisti_exports.a stubs/*.o @@ -27,6 +28,7 @@ include $(KOS_BASE)/Makefile.prefab clean: clean_subdirs rm -f build/*.o rm -f build/libc/*.o + rm -f romdisk/*.o rm -f stubs/*.o stubs/kernel_export_stubs.c stubs/arch_export_stubs.c run: diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index 2e90505..7f7a5c3 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -75,6 +75,7 @@ vmu_pkg_parse # SPU spu_memload +spu_memload_sq spu_memread spu_memset spu_dma_transfer @@ -89,6 +90,8 @@ sq_cpy sq_set sq_set16 sq_set32 +sq_lock +sq_unlock # Sound snd_mem_init diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index 9c04303..e655d0f 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -118,6 +118,7 @@ flashrom_get_region # SPU spu_memload +spu_memload_sq spu_memread spu_memset spu_dma_transfer @@ -132,6 +133,8 @@ sq_cpy sq_set sq_set16 sq_set32 +sq_lock +sq_unlock # Sound snd_mem_init diff --git a/kernel/arch/dreamcast/hardware/sq.c b/kernel/arch/dreamcast/hardware/sq.c index 561ae94..9326509 100644 --- a/kernel/arch/dreamcast/hardware/sq.c +++ b/kernel/arch/dreamcast/hardware/sq.c @@ -4,10 +4,14 @@ Copyright (C) 2001 Andrew Kieschnick Copyright (C) 2023 Falco Girgis Copyright (C) 2023 Andy Barajas + Copyright (C) 2023 Ruslan Rostovtsev */ +#include <arch/cache.h> #include <dc/sq.h> #include <kos/dbglog.h> +#include <kos/mutex.h> + /* Functions to clear, copy, and set memory using the sh4 store queues @@ -15,6 +19,16 @@ Based on code by Marcus Comstedt, TapamN, and Moop */ +static mutex_t sq_mutex = MUTEX_INITIALIZER; + +void sq_lock(void) { + mutex_lock(&sq_mutex); +} + +void sq_unlock(void) { + mutex_unlock(&sq_mutex); +} + /* Copies n bytes from src to dest, dest must be 32-byte aligned */ void * sq_cpy(void *dest, const void *src, size_t n) { uint32_t *d = SQ_MASK_DEST(dest); @@ -25,8 +39,10 @@ void * sq_cpy(void *dest, const void *src, size_t n) { _Complex float ds3; _Complex float ds4; + sq_lock(); + /* Set store queue memory area as desired */ - SET_QACR_REGS(dest); + SET_QACR_REGS(dest, dest); /* Fill/write queues as many times necessary */ n >>= 5; @@ -45,8 +61,8 @@ void * sq_cpy(void *dest, const void *src, size_t n) { d[7] = *(s++); /* Fire off store queue. __builtin would move it to the top so - use __asm__ instead */ - __asm__("pref @%0" : : "r"(d)); + use dcache_pref_block instead */ + dcache_pref_block(d); d += 8; } } else { /* If src is 8-byte aligned, fast path */ @@ -85,6 +101,7 @@ void * sq_cpy(void *dest, const void *src, size_t n) { d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; + sq_unlock(); return dest; } @@ -110,8 +127,10 @@ void * sq_set16(void *dest, uint32_t c, size_t n) { void * sq_set32(void *dest, uint32_t c, size_t n) { uint32_t *d = SQ_MASK_DEST(dest); + sq_lock(); + /* Set store queue memory area as desired */ - SET_QACR_REGS(dest); + SET_QACR_REGS(dest, dest); /* Fill both store queues with c */ d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = @@ -129,6 +148,7 @@ void * sq_set32(void *dest, uint32_t c, size_t n) { d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; + sq_unlock(); return dest; } diff --git a/kernel/arch/dreamcast/include/dc/sq.h b/kernel/arch/dreamcast/include/dc/sq.h index 5dbad30..62c9cd0 100644 --- a/kernel/arch/dreamcast/include/dc/sq.h +++ b/kernel/arch/dreamcast/include/dc/sq.h @@ -4,6 +4,7 @@ Copyright (C) 2000-2001 Andrew Kieschnick Copyright (C) 2023 Falco Girgis Copyright (C) 2023 Andy Barajas + Copyright (C) 2023 Ruslan Rostovtsev */ /** \file dc/sq.h @@ -53,20 +54,55 @@ __BEGIN_DECLS /** \brief Set Store Queue QACR* registers \ingroup store_queues */ -#define SET_QACR_REGS(dest) \ +#define SET_QACR_REGS(dest0, dest1) \ do { \ - uint32_t val = ((uint32_t)(dest)) >> 24; \ - QACR0 = val; \ - QACR1 = val; \ + QACR0 = ((uintptr_t)(dest0)) >> 24; \ + QACR1 = ((uintptr_t)(dest1)) >> 24; \ } while(0) -/** \brief Mask dest to Store Queue area +/** \brief Mask dest to Store Queue area as address + \ingroup store_queues +*/ +#define SQ_MASK_DEST_ADDR(dest) \ + (MEM_AREA_SQ_BASE | ((uintptr_t)(dest) & 0x03ffffe0)) + +/** \brief Mask dest to Store Queue area as pointer \ingroup store_queues */ #define SQ_MASK_DEST(dest) \ - ((uint32_t *)(void *) \ - (MEM_AREA_SQ_BASE | \ - (((uint32_t)(dest)) & 0x03ffffe0))) + ((uint32_t *)(void *) SQ_MASK_DEST_ADDR(dest)) + +/** \brief Lock Store Queues + \ingroup store_queues + + Locks the store queues so that they cannot be used from another thread + until unlocked. + + \warning + This function is called automatically by the store queue API provided by KOS; + however, it must be called manually when driving the SQs directly from outside + of this API. + + \sa sq_unlock() +*/ +void sq_lock(void); + +/** \brief Unlock Store Queues + \ingroup store_queues + + Unlocks the store queues so that they can be used from any thread. + + \note + sq_lock() should've already been called previously. + + \warning + sq_lock() and sq_unlock() are called automatically by the store queue API provided + by KOS; however, they must be called manually when driving the SQs directly from + outside this API. + + \sa sq_lock() +*/ +void sq_unlock(void); /** \brief Copy a block of memory. \ingroup store_queues diff --git a/kernel/arch/dreamcast/kernel/init.c b/kernel/arch/dreamcast/kernel/init.c index 641fd05..11dbd0c 100644 --- a/kernel/arch/dreamcast/kernel/init.c +++ b/kernel/arch/dreamcast/kernel/init.c @@ -89,6 +89,10 @@ void arch_init_net(void) { void (*init_net_weak)(void) __attribute__((weak)); void (*net_shutdown_weak)(void) __attribute__((weak)); +int (*fs_romdisk_init_weak)(void) __attribute__((weak)); +int (*fs_romdisk_shutdown_weak)(void) __attribute__((weak)); +int (*fs_romdisk_mount_weak)(void) __attribute__((weak)); + /* Auto-init stuff: override with a non-weak symbol if you don't want all of this to be linked into your code (and do the same with the arch_auto_shutdown function too). */ @@ -141,7 +145,10 @@ int __attribute__((weak)) arch_auto_init(void) { fs_init(); /* VFS */ fs_pty_init(); /* Pty */ fs_ramdisk_init(); /* Ramdisk */ - fs_romdisk_init(); /* Romdisk */ + + if(fs_romdisk_init_weak) { + fs_romdisk_init_weak(); /* Romdisk */ + } /* The arc4random_buf() function used for random & urandom is only available in newlib starting with version 2.4.0 */ @@ -153,8 +160,8 @@ int __attribute__((weak)) arch_auto_init(void) { hardware_periph_init(); /* DC peripheral init */ - if(__kos_romdisk != NULL) { - fs_romdisk_mount("/rd", __kos_romdisk, 0); + if(fs_romdisk_mount_weak) { + fs_romdisk_mount_weak(); } #ifndef _arch_sub_naomi @@ -210,7 +217,9 @@ void __attribute__((weak)) arch_auto_shutdown(void) { fs_dev_shutdown(); #endif fs_ramdisk_shutdown(); - fs_romdisk_shutdown(); + if(fs_romdisk_shutdown_weak) { + fs_romdisk_shutdown_weak(); + } fs_pty_shutdown(); fs_shutdown(); thd_shutdown(); diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index 1b5c83c..fcbc9c2 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -200,28 +200,30 @@ static void sep_data(void *buffer, int len, int stereo) { void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size) { + /* SPU memory in cached area */ left |= 0x00800000; right |= 0x00800000; - uint32 masked_left = (0xe0000000 | (left & 0x03ffffe0)); - uint32 masked_right = (0xe0000000 | (right & 0x03ffffe0)); + uintptr_t masked_left = SQ_MASK_DEST_ADDR(left); + uintptr_t masked_right = SQ_MASK_DEST_ADDR(right); + + sq_lock(); /* Set store queue memory area as desired */ - QACR0 = (left >> 24) & 0x1c; - QACR1 = (right >> 24) & 0x1c; + SET_QACR_REGS(left, right); int old = irq_disable(); - do { } while(*(vuint32 *)0xa05f688c & (1 << 5)) ; // FIFO_SH4 - do { } while(*(vuint32 *)0xa05f688c & (1 << 4)) ; // FIFO_G2 + do { } while(*(vuint32 *)0xa05f688c & ((1 << 5) | (1 << 4))); /* FIFO_SH4 | FIFO_G2 */ /* Separating channels and do fill/write queues as many times necessary. */ snd_pcm16_split_sq_start(data, masked_left, masked_right, size); /* Wait for both store queues to complete if they are already used */ - uint32 *d = (uint32 *)0xe0000000; + uint32_t *d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; irq_restore(old); + sq_unlock(); } static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { diff --git a/kernel/romdisk/Makefile b/kernel/romdisk/Makefile new file mode 100644 index 0000000..39d44e9 --- /dev/null +++ b/kernel/romdisk/Makefile @@ -0,0 +1,9 @@ +# KallistiOS ##version## +# +# romdisk/Makefile +# (c)2023 Paul Cercueil +# + +OBJS = romdiskbase.o + +include $(KOS_BASE)/Makefile.prefab diff --git a/kernel/romdisk/romdiskbase.c b/kernel/romdisk/romdiskbase.c new file mode 100644 index 0000000..41415d3 --- /dev/null +++ b/kernel/romdisk/romdiskbase.c @@ -0,0 +1,16 @@ +/* KallistiOS ##version## + + kernel/romdisk/romdiskbase.c + Copyright (C) 2023 Paul Cercueil +*/ + +#include <kos/fs_romdisk.h> + +extern unsigned char romdisk[]; + +void *__kos_romdisk = romdisk; + +int fs_romdisk_mount_weak(void) +{ + return fs_romdisk_mount("/rd", __kos_romdisk, 0); +} hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-09 04:02:27
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 9c23016db56a8ca885765c115e8742cae65d0506 (commit) from a6fbf57e281b4cb231fe3a3f4bb68e57df58ecf8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9c23016db56a8ca885765c115e8742cae65d0506 Author: Andress Barajas <and...@gm...> Date: Wed Nov 8 19:40:33 2023 -0800 Add sound effects example (#343) Add sound effects example ----------------------------------------------------------------------- Summary of changes: examples/dreamcast/sound/Makefile | 3 + .../yuv_converter/YUV422 => sound/sfx}/Makefile | 25 ++-- examples/dreamcast/sound/sfx/main.c | 166 +++++++++++++++++++++ examples/dreamcast/sound/sfx/romdisk/beep-1.wav | Bin 0 -> 63128 bytes examples/dreamcast/sound/sfx/romdisk/beep-2.wav | Bin 0 -> 26876 bytes examples/dreamcast/sound/sfx/romdisk/beep-3.wav | Bin 0 -> 20196 bytes examples/dreamcast/sound/sfx/romdisk/beep-4.wav | Bin 0 -> 52634 bytes 7 files changed, 181 insertions(+), 13 deletions(-) copy examples/dreamcast/{pvr/yuv_converter/YUV422 => sound/sfx}/Makefile (54%) create mode 100644 examples/dreamcast/sound/sfx/main.c create mode 100644 examples/dreamcast/sound/sfx/romdisk/beep-1.wav create mode 100644 examples/dreamcast/sound/sfx/romdisk/beep-2.wav create mode 100644 examples/dreamcast/sound/sfx/romdisk/beep-3.wav create mode 100644 examples/dreamcast/sound/sfx/romdisk/beep-4.wav diff --git a/examples/dreamcast/sound/Makefile b/examples/dreamcast/sound/Makefile index e07f635..0ab4e7c 100644 --- a/examples/dreamcast/sound/Makefile +++ b/examples/dreamcast/sound/Makefile @@ -10,6 +10,7 @@ all: $(KOS_MAKE) -C hello-mp3 $(KOS_MAKE) -C cdda $(KOS_MAKE) -C hello-opus + $(KOS_MAKE) -C sfx clean: $(KOS_MAKE) -C ghettoplay-vorbis clean @@ -17,6 +18,7 @@ clean: $(KOS_MAKE) -C hello-mp3 clean $(KOS_MAKE) -C cdda clean $(KOS_MAKE) -C hello-opus clean + $(KOS_MAKE) -C sfx clean dist: $(KOS_MAKE) -C ghettoplay-vorbis dist @@ -24,5 +26,6 @@ dist: $(KOS_MAKE) -C hello-mp3 dist $(KOS_MAKE) -C cdda dist $(KOS_MAKE) -C hello-opus dist + $(KOS_MAKE) -C sfx dist diff --git a/examples/dreamcast/pvr/yuv_converter/YUV422/Makefile b/examples/dreamcast/sound/sfx/Makefile similarity index 54% copy from examples/dreamcast/pvr/yuv_converter/YUV422/Makefile copy to examples/dreamcast/sound/sfx/Makefile index bc02280..cbfea26 100644 --- a/examples/dreamcast/pvr/yuv_converter/YUV422/Makefile +++ b/examples/dreamcast/sound/sfx/Makefile @@ -1,22 +1,20 @@ +# KallistiOS ##version## +# +# examples/dreamcast/sound/sfx/Makefile # -# YUV422 Converter example -# (c)2023 Andy Barajas -# -TARGET = yuv422.elf -OBJS = yuv422.o romdisk.o +TARGET = sfx.elf +OBJS = romdisk.o main.o -all: rm-elf $(TARGET) +all: clean $(TARGET) include $(KOS_BASE)/Makefile.rules -clean: rm-elf - -rm -f $(OBJS) romdisk.* - -rm-elf: - -rm -f $(TARGET) romdisk.* +clean: + -rm -f $(TARGET) $(OBJS) + -rm -f romdisk.o romdisk.img -$(TARGET): $(OBJS) +$(TARGET): $(OBJS) kos-cc -o $(TARGET) $(OBJS) romdisk.img: @@ -29,5 +27,6 @@ run: $(TARGET) $(KOS_LOADER) $(TARGET) dist: $(TARGET) - -rm -f $(OBJS) + rm -f $(OBJS) romdisk.o romdisk.img $(KOS_STRIP) $(TARGET) + diff --git a/examples/dreamcast/sound/sfx/main.c b/examples/dreamcast/sound/sfx/main.c new file mode 100644 index 0000000..22f140b --- /dev/null +++ b/examples/dreamcast/sound/sfx/main.c @@ -0,0 +1,166 @@ +/* KallistiOS ##version## + + main.c + Copyright (C) 2023 Andy Barajas + + This example program simply demonstrations how to load and play + sound effects on their own channels as well as on the same channel. +*/ + +#include <stdio.h> +#include <string.h> +#include <kos/init.h> +#include <dc/biosfont.h> +#include <dc/video.h> +#include <dc/sound/sound.h> +#include <dc/sound/sfxmgr.h> +#include <dc/maple.h> +#include <dc/maple/controller.h> + +#define LEFT 0 +#define CENTER 128 +#define RIGHT 255 + +extern uint8 romdisk[]; +KOS_INIT_ROMDISK(romdisk); + +static void draw_instructions(uint8_t volume); + +static cont_state_t *get_cont_state(); +static int button_pressed(uint32_t current_buttons, uint32_t changed_buttons, uint32_t button); + +int main(int argc, char **argv) { + uint8_t volume = 128; + int volume_changed = 1; + cont_state_t *cond; + + vid_set_mode(DM_640x480, PM_RGB555); + // Initialize sound system + snd_init(); + + // Load wav files found in romdisk + // Beep wav files found in the romdisk where provided by + // https://gamesounds.xyz/?dir=Sound%20Effects/Beeps + sfxhnd_t beep1 = snd_sfx_load("/rd/beep-1.wav"); + sfxhnd_t beep2 = snd_sfx_load("/rd/beep-2.wav"); + sfxhnd_t beep3 = snd_sfx_load("/rd/beep-3.wav"); + sfxhnd_t beep4 = snd_sfx_load("/rd/beep-4.wav"); + + uint32_t current_buttons = 0; + uint32_t changed_buttons = 0; + uint32_t previous_buttons = 0; + + for(;;) { + cond = get_cont_state(); + current_buttons = cond->buttons; + changed_buttons = current_buttons ^ previous_buttons; + previous_buttons = current_buttons; + + // Play sounds on different channels + if(button_pressed(current_buttons, changed_buttons, CONT_A)) { + snd_sfx_play(beep1, volume, CENTER); + } + if(button_pressed(current_buttons, changed_buttons, CONT_B)) { + snd_sfx_play(beep2, volume, RIGHT); + } + if(button_pressed(current_buttons, changed_buttons, CONT_X)) { + snd_sfx_play(beep3, volume, LEFT); + } + if(button_pressed(current_buttons, changed_buttons, CONT_Y)) { + snd_sfx_play(beep4, volume, CENTER); + } + + // Play sounds on same channel + if(button_pressed(current_buttons, changed_buttons, CONT_DPAD_DOWN)) { + snd_sfx_play_chn(0, beep1, volume, CENTER); + } + if(button_pressed(current_buttons, changed_buttons, CONT_DPAD_RIGHT)) { + snd_sfx_play_chn(0, beep2, volume, RIGHT); + } + if(button_pressed(current_buttons, changed_buttons, CONT_DPAD_LEFT)) { + snd_sfx_play_chn(0, beep3, volume, LEFT); + } + if(button_pressed(current_buttons, changed_buttons, CONT_DPAD_UP)) { + snd_sfx_play_chn(0, beep4, volume, CENTER); + } + + // Adjust Volume + if(cond->ltrig > 0) { + volume_changed = 1; + + if(volume < 255) + volume++; + } + if(cond->rtrig > 0) { + volume_changed = 1; + + if(volume > 0) + volume--; + } + + // Exit Program + if(button_pressed(current_buttons, changed_buttons, CONT_START)) + break; + + if(volume_changed) { + volume_changed = 0; + draw_instructions(volume); + } + } + + // Unload all sound effects from sound RAM + snd_sfx_unload(beep1); + snd_sfx_unload(beep2); + snd_sfx_unload(beep3); + snd_sfx_unload(beep4); + // OR + // snd_sfx_unload_all(); + + snd_shutdown(); + + return 0; +} + +static void draw_instructions(uint8_t volume) { + int x = 20, y = 20+24; + int color = 1; + char current_volume_str[32]; + + memset(current_volume_str, 0, 32); + snprintf(current_volume_str, 32, "Current Volume: %3i", volume); + + bfont_draw_str(vram_s + y*640+x, 640, color, "Press A,B,X,Y to play beeps on separate channels"); + y += 48; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press UP,DOWN,LEFT,RIGHT on D-Pad to play beeps"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, "on the same channel"); + y += 48; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press L-Trigger/R-Trigger to +/- volume"); + y += 24; + bfont_draw_str(vram_s + y*640+x, 640, color, current_volume_str); + y += 48; + bfont_draw_str(vram_s + y*640+x, 640, color, "Press Start to exit program"); +} + +static cont_state_t *get_cont_state() { + maple_device_t *cont; + cont_state_t *state; + + cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if(cont) { + state = (cont_state_t*)maple_dev_status(cont); + return state; + } + + return NULL; +} + +static int button_pressed(uint32_t current_buttons, uint32_t changed_buttons, uint32_t button) { + if(changed_buttons & button) { + if (current_buttons & button) + return 1; + } + + return 0; +} + diff --git a/examples/dreamcast/sound/sfx/romdisk/beep-1.wav b/examples/dreamcast/sound/sfx/romdisk/beep-1.wav new file mode 100644 index 0000000..f224049 Binary files /dev/null and b/examples/dreamcast/sound/sfx/romdisk/beep-1.wav differ diff --git a/examples/dreamcast/sound/sfx/romdisk/beep-2.wav b/examples/dreamcast/sound/sfx/romdisk/beep-2.wav new file mode 100644 index 0000000..8343a63 Binary files /dev/null and b/examples/dreamcast/sound/sfx/romdisk/beep-2.wav differ diff --git a/examples/dreamcast/sound/sfx/romdisk/beep-3.wav b/examples/dreamcast/sound/sfx/romdisk/beep-3.wav new file mode 100644 index 0000000..9227a3f Binary files /dev/null and b/examples/dreamcast/sound/sfx/romdisk/beep-3.wav differ diff --git a/examples/dreamcast/sound/sfx/romdisk/beep-4.wav b/examples/dreamcast/sound/sfx/romdisk/beep-4.wav new file mode 100644 index 0000000..90b1287 Binary files /dev/null and b/examples/dreamcast/sound/sfx/romdisk/beep-4.wav differ hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-08 03:23:14
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via a6fbf57e281b4cb231fe3a3f4bb68e57df58ecf8 (commit) from da29948e4c088cbbb2e475a59e0e0ce2e18af970 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a6fbf57e281b4cb231fe3a3f4bb68e57df58ecf8 Author: Andress Barajas <and...@gm...> Date: Tue Nov 7 19:21:14 2023 -0800 Cache Refresh (#342) * Add two new cache manipulation functions. Speed up the old ones for ranges larger than the cache * Edited algorithm checks to get the fastest speed. Added warnings to let user know that range flush and purges can still be faster under a certain threshold of bytes ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/include/arch/cache.h | 80 ++++-- kernel/arch/dreamcast/kernel/cache.s | 392 ++++++++++++++++++----------- 2 files changed, 308 insertions(+), 164 deletions(-) diff --git a/kernel/arch/dreamcast/include/arch/cache.h b/kernel/arch/dreamcast/include/arch/cache.h index 602f2b3..d5df496 100644 --- a/kernel/arch/dreamcast/include/arch/cache.h +++ b/kernel/arch/dreamcast/include/arch/cache.h @@ -3,7 +3,7 @@ arch/dreamcast/include/cache.h Copyright (C) 2001 Megan Potter Copyright (C) 2014, 2016, 2023 Ruslan Rostovtsev - + Copyright (C) 2023 Andy Barajas */ /** \file arch/cache.h @@ -15,6 +15,7 @@ \author Megan Potter \author Ruslan Rostovtsev + \author Andy Barajas */ #ifndef __ARCH_CACHE_H @@ -23,12 +24,12 @@ #include <sys/cdefs.h> __BEGIN_DECLS +#include <stdint.h> #include <arch/types.h> /** \brief SH4 cache block size. - The physical address will be aligned to this size in all - functions except dcache_alloc_write. + The size of a cache block. */ #define CPU_CACHE_BLOCK_SIZE 32 @@ -39,7 +40,7 @@ __BEGIN_DECLS \param start The physical address to begin flushing at. \param count The number of bytes to flush. */ -void icache_flush_range(uint32 start, uint32 count); +void icache_flush_range(uintptr_t start, size_t count); /** \brief Invalidate the data/operand cache. @@ -50,42 +51,77 @@ void icache_flush_range(uint32 start, uint32 count); \param start The physical address to begin invalidating at. \param count The number of bytes to invalidate. */ -void dcache_inval_range(uint32 start, uint32 count); +void dcache_inval_range(uintptr_t start, size_t count); /** \brief Flush the data/operand cache. This function flushes a range of the data/operand cache, forcing a write- - back on all of the data in the specified range. This does not invalidate the - cache in the process (meaning the blocks will still be in the cache, just - not marked as dirty after this has completed). If you wish to invalidate the - cache as well, call dcache_inval_range() after calling this function or - use dcache_purge_range() instead of dcache_flush_range(). + back on all of the data in the specified range. This does not invalidate + the cache in the process (meaning the blocks will still be in the cache, + just not marked as dirty after this has completed). If you wish to + invalidate the cache as well, call dcache_inval_range() after calling this + function or use dcache_purge_range() instead of dcache_flush_range(). \param start The physical address to begin flushing at. \param count The number of bytes to flush. */ -void dcache_flush_range(uint32 start, uint32 count); +void dcache_flush_range(uintptr_t start, size_t count); + +/** \brief Flush all the data/operand cache. + + This function flushes all the data/operand cache, forcing a write- + back on all of the cache blocks that are marked as dirty. + + \note + dcache_flush_range() is faster than dcache_flush_all() if the count + param is 66560 or less. +*/ +void dcache_flush_all(void); /** \brief Purge the data/operand cache. This function flushes a range of the data/operand cache, forcing a write- - back and invalidate on all of the data in the specified range. + back and then invalidates all of the data in the specified range. \param start The physical address to begin purging at. \param count The number of bytes to purge. */ -void dcache_purge_range(uint32 start, uint32 count); +void dcache_purge_range(uintptr_t start, size_t count); /** \brief Purge all the data/operand cache. - This function flushes all the data/operand cache, forcing a write- - back and invalidate on all of the cache blocks. + This function flushes the entire data/operand cache, ensuring that all + cache blocks marked as dirty are written back to memory and all cache + entries are invalidated. It does not require an additional buffer and is + preferred when memory resources are constrained. - \param start The physical address for temporary buffer (32-byte aligned) - \param count The number of bytes of temporary buffer (8 KB or 16 KB) + \note + dcache_purge_range() is faster than dcache_purge_all() if the count + param is 39936 or less. +*/ +void dcache_purge_all(void); + +/** \brief Purge all the data/operand cache with buffer. + + This function performs a purge of all data/operand cache blocks by + utilizing an external buffer to speed up the write-back and invalidation + process. It is always faster than dcache_purge_all() and is recommended + where maximum speed is required. + + \note While this function offers a superior purge rate, it does require + the use of a temporary buffer. So use this function if you have an extra + 8/16 kb of memory laying around that you can utilize for no other purpose + than for this function. + + \param start The physical address for temporary buffer (32-byte + aligned) + \param count The size of the temporary buffer, which can be + either 8 KB or 16 KB, depending on cache + configuration - 8 KB buffer with OCRAM enabled, + otherwise 16 KB. */ -void dcache_purge_all(uint32 start, uint32 count); +void dcache_purge_all_with_buffer(uintptr_t start, size_t count); /** \brief Prefetch one block to the data/operand cache. @@ -108,15 +144,15 @@ static __always_inline void dcache_pref_block(const void *src) { \param src The physical address to allocate. \param value The value written to first 4-byte. */ -static __always_inline void dcache_alloc_block(const void *src, uint32 value) { - register int __value __asm__("r0") = value; - __asm__ __volatile__ ("movca.l r0,@%0\n\t" +static __always_inline void dcache_alloc_block(const void *src, uint32_t value) { + __asm__ __volatile__ ("movca.l r0, @%0\n\t" : - : "r" (src), "r" (__value) + : "r" (src), "z" (value) : "memory" ); } + __END_DECLS #endif /* __ARCH_CACHE_H */ diff --git a/kernel/arch/dreamcast/kernel/cache.s b/kernel/arch/dreamcast/kernel/cache.s index c2b8bdc..cdbceb7 100644 --- a/kernel/arch/dreamcast/kernel/cache.s +++ b/kernel/arch/dreamcast/kernel/cache.s @@ -1,172 +1,280 @@ -! This routine was such a PIA to get working in inside the C program -! that I finally gave up and moved it out to an assembler file. -! Routine to flush parts of cache.. thanks to the Linux-SH guys -! for the algorithm. The original version of this routine was -! taken from sh-stub.c. +! KallistiOS ##version## +! +! arch/dreamcast/kernel/cache.s +! +! Copyright (C) 2001 Megan Potter +! Copyright (C) 2014, 2016, 2023 Ruslan Rostovtsev +! Copyright (C) 2023 Andy Barajas +! +! Optimized assembler code for managing the cache. +! - .text - .globl _icache_flush_range - .globl _dcache_inval_range - .globl _dcache_flush_range - .globl _dcache_purge_range - .globl _dcache_purge_all + .text + .globl _icache_flush_range + .globl _dcache_inval_range + .globl _dcache_flush_range + .globl _dcache_flush_all + .globl _dcache_purge_range + .globl _dcache_purge_all + .globl _dcache_purge_all_with_buffer +! Routine to flush parts of cache.. Thanks to the Linux-SH guys +! for the algorithm. The original version of this routine was +! taken from sh-stub.c. +! ! r4 is starting address ! r5 is count + .align 2 _icache_flush_range: - mov.l fraddr,r0 - mov.l p2mask,r1 - or r1,r0 - jmp @r0 - nop - - .align 2 -fraddr: .long flush_real -p2mask: .long 0x20000000 - - -flush_real: - ! Save old SR and disable interrupts - stc sr,r0 - mov.l r0,@-r15 - mov.l ormask,r1 - or r1,r0 - ldc r0,sr - - ! Get ending address from count and align start address - add r4,r5 - mov.l l1align,r0 - and r0,r4 - mov.l addrarray,r1 - mov.l entrymask,r2 - mov.l validmask,r3 - -flush_loop: - ! Write back O cache - ocbwb @r4 - - ! Invalidate I cache - mov r4,r6 ! v & CACHE_IC_ENTRY_MASK - and r2,r6 - or r1,r6 ! CACHE_IC_ADDRESS_ARRAY | ^ - - mov r4,r7 ! v & 0xfffffc00 - and r3,r7 - - add #32,r4 ! += CPU_CACHE_BLOCK_SIZE - cmp/hs r4,r5 - bt/s flush_loop - mov.l r7,@r6 ! *addr = data - - ! Restore old SR - mov.l @r15+,r0 - ldc r0,sr - - ! make sure we have enough instrs before returning to P1 - nop - nop - nop - nop - nop - nop - nop - rts - nop - - .align 2 -ormask: - .long 0x100000f0 -addrarray: - .long 0xf0000000 ! CACHE_IC_ADDRESS_ARRAY -entrymask: - .long 0x1fe0 ! CACHE_IC_ENTRY_MASK -validmask: - .long 0xfffffc00 - - -! Goes through and invalidates the O-cache for a given block of -! RAM. Make sure that you've called dcache_flush_range first if -! you care about the contents. + mov.l ifr_addr, r0 + mov.l p2_mask, r1 + or r1, r0 + jmp @r0 + nop + +.iflush_real: + ! Save old SR and disable interrupts + stc sr, r0 + mov.l r0, @-r15 + mov.l ormask, r1 + or r1, r0 + ldc r0, sr + + ! Get ending address from count and align start address + add r4, r5 + mov.l align_mask, r0 + and r0, r4 + mov.l ica_addr, r1 + mov.l ic_entry_mask, r2 + mov.l ic_valid_mask, r3 + +.flush_loop: + ! Write back D cache + ocbwb @r4 + + ! Invalidate I cache + mov r4, r6 ! v & CACHE_IC_ENTRY_MASK + and r2, r6 + or r1, r6 ! CACHE_IC_ADDRESS_ARRAY | ^ + + mov r4, r7 ! v & 0xfffffc00 + and r3, r7 + + add #32, r4 ! Move on to next cache block + cmp/hs r4, r5 + bt/s .flush_loop + mov.l r7, @r6 ! *addr = data + + ! Restore old SR + mov.l @r15+, r0 + ldc r0, sr + + ! make sure we have enough instrs before returning to P1 + nop + nop + nop + nop + nop + nop + nop + rts + nop + + +! This routine goes through and invalidates the dcache for a given +! range of RAM. Make sure that you've called dcache_flush_range first +! if you care about the contents. +! ! r4 is starting address ! r5 is count + .align 2 _dcache_inval_range: - ! Get ending address from count and align start address - add r4,r5 - mov.l l1align,r0 - and r0,r4 + ! Get ending address from count and align start address + add r4, r5 + mov.l align_mask, r0 + and r0, r4 -dinval_loop: - ! Invalidate the O cache - ocbi @r4 - cmp/hs r4,r5 - bt/s dinval_loop - add #32,r4 ! += CPU_CACHE_BLOCK_SIZE +.dinval_loop: + ! Invalidate the dcache + ocbi @r4 + cmp/hs r4, r5 + bt/s .dinval_loop + add #32, r4 ! Move on to next cache block - rts - nop + rts + nop -! This routine just goes through and forces a write-back on the +! This routine goes through and forces a write-back on the ! specified data range. Use prior to dcache_inval_range if you -! care about the contents. +! care about the contents. If the range is bigger than the dcache, +! we flush the whole cache instead. +! ! r4 is starting address ! r5 is count + .align 2 _dcache_flush_range: - ! Get ending address from count and align start address - add r4,r5 - mov.l l1align,r0 - and r0,r4 + ! Divide byte count by 32 + mov #-5, r1 + shad r1, r5 + + ! Compare with flush_check + mov.w flush_check, r2 + cmp/hi r2, r5 + bt _dcache_flush_all ! If lines > flush_check, jump to _dcache_flush_all + + ! Align start address + mov.l align_mask, r0 + and r0, r4 + +.dflush_loop: + ! Write back the dcache + ocbwb @r4 + dt r5 + bf/s .dflush_loop + add #32, r4 ! Move on to next cache block + + rts + nop + -dflush_loop: - ! Write back the O cache - ocbwb @r4 - cmp/hs r4,r5 - bt/s dflush_loop - add #32,r4 ! += CPU_CACHE_BLOCK_SIZE +! This routine uses the OC address array to have direct access to the +! dcache entries. It forces a write-back on all dcache entries where +! the U bit and V bit are set to 1. Then updates the entry with +! U bit cleared. + .align 2 +_dcache_flush_all: + mov.l dca_addr, r1 + mov.w cache_lines, r2 + mov.l dc_ubit_mask, r3 - rts - nop +.dflush_all_loop: + mov.l @r1, r0 ! Get dcache array entry value + and r3, r0 ! Zero out U bit + dt r2 + mov.l r0, @r1 ! Update dcache entry + bf/s .dflush_all_loop + add #32, r1 ! Move on to next entry -! This routine just goes through and forces a write-back and invalidate -! on the specified data range. + rts + nop + + +! This routine goes through and forces a write-back and invalidate +! on the specified data range. If the range is bigger than the dcache, +! we purge the whole cache instead. +! ! r4 is starting address ! r5 is count + .align 2 _dcache_purge_range: - ! Get ending address from count and align start address - add r4,r5 - mov.l l1align,r0 - and r0,r4 + ! Divide byte count by 32 + mov #-5, r1 + shad r1, r5 + + ! Compare with purge_check + mov.w purge_check, r2 + cmp/hi r2, r5 + bt _dcache_purge_all ! If lines > purge_check, jump to _dcache_purge_all + + ! Align start address + mov.l align_mask, r0 + and r0, r4 + +.dpurge_loop: + ! Write back and invalidate the D cache + ocbp @r4 + dt r5 + bf/s .dpurge_loop + add #32, r4 ! Move on to next cache block -dpurge_loop: - ! Write back and invalidate the O cache - ocbp @r4 - cmp/hs r4,r5 - bt/s dpurge_loop - add #32,r4 ! += CPU_CACHE_BLOCK_SIZE + rts + nop - rts - nop + +! This routine uses the OC address array to have direct access to the +! dcache entries. It goes through and forces a write-back and invalidate +! on all of the dcache. + .align 2 +_dcache_purge_all: + mov.l dca_addr, r1 + mov.w cache_lines, r2 + mov #0, r3 + +.dpurge_all_loop: + mov.l r3, @r1 ! Update dcache entry + dt r2 + bf/s .dpurge_all_loop + add #32, r1 ! Move on to next entry + + rts + nop -! This routine just forces a write-back and invalidate all O cache. +! This routine forces a write-back and invalidate all dcache +! using a 8kb or 16kb 32-byte aligned buffer. +! ! r4 is address for temporary buffer 32-byte aligned ! r5 is size of temporary buffer (8 KB or 16 KB) -_dcache_purge_all: ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-06 02:56:56
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via da29948e4c088cbbb2e475a59e0e0ce2e18af970 (commit) via d2a80c5c8b053acd7df796ef23e5a04d6c4302a2 (commit) via a47865639ff1afed05494b69b79608794a0c61d0 (commit) from 3065978c74fe2e03df1eda3464d35a1115d8f830 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit da29948e4c088cbbb2e475a59e0e0ce2e18af970 Merge: 3065978 d2a80c5 Author: Lawrence Sebald <ljs...@us...> Date: Sun Nov 5 21:56:35 2023 -0500 Merge pull request #340 from DC-SWAT/snd_sfx_fmt Added 8-bit PCM for stream and SFX and added interleaved ADPCM support for SFX commit d2a80c5c8b053acd7df796ef23e5a04d6c4302a2 Author: DC-SWAT <sw...@21...> Date: Sun Nov 5 22:08:15 2023 +0700 Added support for 8-bit PCM stream commit a47865639ff1afed05494b69b79608794a0c61d0 Author: DC-SWAT <sw...@21...> Date: Sun Nov 5 18:12:05 2023 +0700 Added 8-bit PCM and interleaved ADPCM support for SFX ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/exports-naomi.txt | 3 + kernel/arch/dreamcast/exports-pristine.txt | 3 + kernel/arch/dreamcast/include/dc/sound/sfxmgr.h | 9 +- kernel/arch/dreamcast/include/dc/sound/sound.h | 14 ++++ kernel/arch/dreamcast/include/dc/sound/stream.h | 11 +++ kernel/arch/dreamcast/sound/snd_pcm_split.s | 27 ++++++ kernel/arch/dreamcast/sound/snd_sfxmgr.c | 105 ++++++++++++++++++++---- kernel/arch/dreamcast/sound/snd_stream.c | 14 +++- 8 files changed, 163 insertions(+), 23 deletions(-) diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index 3a5587d..2e90505 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -120,6 +120,8 @@ snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable snd_stream_start +snd_stream_start_pcm8 +snd_stream_start_adpcm snd_stream_queue_go snd_stream_stop snd_stream_poll @@ -130,6 +132,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_pcm8_split snd_adpcm_split # Video diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index 93e0c14..9c04303 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -163,6 +163,8 @@ snd_stream_shutdown snd_stream_queue_enable snd_stream_queue_disable snd_stream_start +snd_stream_start_pcm8 +snd_stream_start_adpcm snd_stream_queue_go snd_stream_stop snd_stream_poll @@ -173,6 +175,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_pcm8_split snd_adpcm_split # Video diff --git a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h index 338cdcb..8737aa7 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h +++ b/kernel/arch/dreamcast/include/dc/sound/sfxmgr.h @@ -2,6 +2,7 @@ dc/sound/sfxmgr.h Copyright (C) 2002 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev */ @@ -9,8 +10,8 @@ \brief Basic sound effect support. This file contains declarations for doing simple sound effects. This code is - only usable for simple WAV files containing either 16-bit samples (stereo or - mono) or Yamaha ADPCM (4-bits, stereo or mono). Also, all sounds played in + only usable for simple WAV files containing either 8-bit or 16-bit samples (stereo + or mono) or Yamaha ADPCM (4-bits, stereo or mono). Also, all sounds played in this manner must be at most 65534 samples in length, as this does not handle buffer chaining or anything else complex. For more interesting stuff, you should probably look at the sound stream stuff instead. @@ -43,8 +44,8 @@ typedef uint32 sfxhnd_t; /** \brief Load a sound effect. This function loads a sound effect from a WAV file and returns a handle to - it. The sound effect can be either stereo or mono, and must either be 16-bit - uncompressed PCM samples or 4-bit Yamaha ADPCM. + it. The sound effect can be either stereo or mono, and must either be 8-bit + or 16-bit uncompressed PCM samples or 4-bit Yamaha ADPCM. \param fn The file to load. \return A handle to the sound effect on success. On error, diff --git a/kernel/arch/dreamcast/include/dc/sound/sound.h b/kernel/arch/dreamcast/include/dc/sound/sound.h index 02bcdbe..0fb8d8f 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sound.h +++ b/kernel/arch/dreamcast/include/dc/sound/sound.h @@ -176,6 +176,20 @@ void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t siz */ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); +/** \brief Separates stereo PCM samples into 2 mono channels. + + Splits a buffer containing 2 interleaved channels of 8-bit PCM samples + into 2 separate buffers of 8-bit PCM samples. + + \param data Source buffer of interleaved stereo samples + \param left Destination buffer for left mono samples + \param right Destination buffer for right mono samples + \param size Size of the source buffer in bytes + + \sa snd_adpcm_split() +*/ +void snd_pcm8_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); + /** \brief Separates stereo ADPCM samples into 2 mono channels. Splits a buffer containing 2 interleaved channels of 4-bit ADPCM samples diff --git a/kernel/arch/dreamcast/include/dc/sound/stream.h b/kernel/arch/dreamcast/include/dc/sound/stream.h index 97825ff..ad69192 100644 --- a/kernel/arch/dreamcast/include/dc/sound/stream.h +++ b/kernel/arch/dreamcast/include/dc/sound/stream.h @@ -249,6 +249,17 @@ void snd_stream_queue_go(snd_stream_hnd_t hnd); */ void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st); +/** \brief Start a 8-bit PCM stream. + + This function starts processing the given stream, prefilling the buffers as + necessary. In queueing mode, this will not start playback. + + \param hnd The stream to start. + \param freq The frequency of the sound. + \param st 1 if the sound is stereo, 0 if mono. +*/ +void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32 freq, int st); + /** \brief Start a 4-bit ADPCM stream. This function starts processing the given stream, prefilling the buffers as diff --git a/kernel/arch/dreamcast/sound/snd_pcm_split.s b/kernel/arch/dreamcast/sound/snd_pcm_split.s index 1752b41..f9aad72 100644 --- a/kernel/arch/dreamcast/sound/snd_pcm_split.s +++ b/kernel/arch/dreamcast/sound/snd_pcm_split.s @@ -9,6 +9,7 @@ .section .text .globl _snd_pcm16_split .globl _snd_pcm16_split_sq_start +.globl _snd_pcm8_split .globl _snd_adpcm_split .align 2 @@ -114,6 +115,32 @@ _snd_pcm16_split_sq_start: rts nop +! +! void snd_pcm8_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); +! +_snd_pcm8_split: + mov #-5, r1 + shld r1, r7 + mov #0, r0 + mov #16, r1 +.pcm8_pref: + add #32, r4 + pref @r4 + add #-32, r4 +.pcm8_copy: + mov.b @r4+, r3 + mov.b r3, @(r0,r5) + dt r1 + mov.b @r4+, r3 + mov.b r3, @(r0,r6) + bf/s .pcm8_copy + add #1, r0 + dt r7 + bf/s .pcm8_pref + mov #16, r1 + rts + nop + ! ! void snd_adpcm_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); ! diff --git a/kernel/arch/dreamcast/sound/snd_sfxmgr.c b/kernel/arch/dreamcast/sound/snd_sfxmgr.c index d0eb44a..222f92c 100644 --- a/kernel/arch/dreamcast/sound/snd_sfxmgr.c +++ b/kernel/arch/dreamcast/sound/snd_sfxmgr.c @@ -96,10 +96,15 @@ void snd_sfx_unload(sfxhnd_t idx) { */ +/* WAV sample formats */ +#define WAVE_FMT_PCM 0x0001 /* PCM */ +#define WAVE_FMT_YAMAHA_ADPCM_ITU_G723 0x0014 /* ITU G.723 Yamaha ADPCM (KallistiOS) */ +#define WAVE_FMT_YAMAHA_ADPCM 0x0020 /* Yamaha ADPCM (ffmpeg) */ + /* Load a sound effect from a WAV file and return a handle to it */ sfxhnd_t snd_sfx_load(const char *fn) { file_t fd; - uint32_t len, hz; + uint32_t len, hz, rd; uint8_t *tmp; uint16_t channels, bitsize, fmt; snd_effect_t *t; @@ -146,7 +151,7 @@ sfxhnd_t snd_sfx_load(const char *fn) { return SFXHND_INVALID; } - uint32_t rd = fs_read(fd, tmp, len); + rd = fs_read(fd, tmp, len); fs_close(fd); if (rd != len) { @@ -168,23 +173,29 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(channels == 1) { /* Mono PCM/ADPCM */ - t->len = len / 2; /* 16-bit samples */ + if(fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723 || fmt == WAVE_FMT_YAMAHA_ADPCM) { + t->fmt = AICA_SM_ADPCM; + t->len = len * 2; /* 4-bit packed samples */ + } + else if(fmt == WAVE_FMT_PCM && bitsize == 8) { + t->fmt = AICA_SM_8BIT; + t->len = len; + } + else if(fmt == WAVE_FMT_PCM && bitsize == 16) { + t->fmt = AICA_SM_16BIT; + t->len = len / 2; + } else { + goto err_exit; + } t->locl = snd_mem_malloc(len); if(t->locl) spu_memload_sq(t->locl, tmp, len); t->locr = 0; - - if(fmt == 20) { - t->fmt = AICA_SM_ADPCM; - t->len *= 4; /* 4-bit packed samples */ - } - else - t->fmt = AICA_SM_16BIT; } - else if(channels == 2 && fmt == 1) { - /* Stereo PCM */ + else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 16) { + /* Stereo 16-bit PCM */ t->len = len / 4; /* Two stereo, 16-bit samples */ t->fmt = AICA_SM_16BIT; t->locl = snd_mem_malloc(len / 2); @@ -193,7 +204,36 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(t->locl && t->locr) snd_pcm16_split_sq((uint32_t *)tmp, t->locl, t->locr, len); } - else if(channels == 2 && fmt == 20) { + else if(channels == 2 && fmt == WAVE_FMT_PCM && bitsize == 8) { + /* Stereo 8-bit PCM */ + uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + + if(left_buf == NULL) { + goto err_exit; + } + uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + + if(right_buf == NULL) { + free(left_buf); + goto err_exit; + } + snd_pcm8_split((uint32_t *)tmp, left_buf, right_buf, len); + + t->fmt = AICA_SM_8BIT; + t->len = len / 2; + t->locl = snd_mem_malloc(len / 2); + t->locr = snd_mem_malloc(len / 2); + + if(t->locl) + spu_memload_sq(t->locl, left_buf, len / 2); + + if(t->locr) + spu_memload_sq(t->locr, right_buf, len / 2); + + free(left_buf); + free(right_buf); + } + else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM_ITU_G723) { /* Stereo ADPCM ITU G.723 (channels are not interleaved) */ uint8_t *right_buf = tmp + (len / 2); int ownmem = 0; @@ -203,11 +243,8 @@ sfxhnd_t snd_sfx_load(const char *fn) { ownmem = 1; if(right_buf == NULL) { - free(tmp); - free(t); - return SFXHND_INVALID; + goto err_exit; } - memcpy(right_buf, tmp + (len / 2), len / 2); } @@ -225,6 +262,35 @@ sfxhnd_t snd_sfx_load(const char *fn) { if(ownmem) free(right_buf); } + else if(channels == 2 && fmt == WAVE_FMT_YAMAHA_ADPCM) { + /* Stereo Yamaha ADPCM (channels are interleaved) */ + uint32_t *left_buf = (uint32_t *)memalign(32, len / 2); + + if(left_buf == NULL) { + goto err_exit; + } + uint32_t *right_buf = (uint32_t *)memalign(32, len / 2); + + if(right_buf == NULL) { + free(left_buf); + goto err_exit; + } + snd_adpcm_split((uint32_t *)tmp, left_buf, right_buf, len); + + t->len = len; /* Two stereo, 4-bit samples */ + t->fmt = AICA_SM_ADPCM; + t->locl = snd_mem_malloc(len / 2); + t->locr = snd_mem_malloc(len / 2); + + if(t->locl) + spu_memload_sq(t->locl, left_buf, len / 2); + + if(t->locr) + spu_memload_sq(t->locr, right_buf, len / 2); + + free(left_buf); + free(right_buf); + } else { free(t); t = SFXHND_INVALID; @@ -236,6 +302,11 @@ sfxhnd_t snd_sfx_load(const char *fn) { LIST_INSERT_HEAD(&snd_effects, t, list); return (sfxhnd_t)t; + +err_exit: + free(tmp); + free(t); + return SFXHND_INVALID; } int snd_sfx_play_chn(int chn, sfxhnd_t idx, int vol, int pan) { diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index 2b802cb..1b5c83c 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -250,8 +250,11 @@ static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { spu_memload_sq(left, buf, got); spu_memload_sq(right, buf, got); } - else if(((uintptr_t)buf & 31) || streams[hnd].type == AICA_SM_ADPCM_LS) { - if(streams[hnd].type == AICA_SM_ADPCM_LS) { + else if(((uintptr_t)buf & 31) || streams[hnd].type != AICA_SM_16BIT) { + if(streams[hnd].type == AICA_SM_8BIT) { + snd_pcm8_split(buf, sep_buffer[0], sep_buffer[1], got); + } + else if(streams[hnd].type == AICA_SM_ADPCM_LS) { snd_adpcm_split(buf, sep_buffer[0], sep_buffer[1], got); } else { @@ -469,6 +472,10 @@ void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st) { snd_stream_start_type(hnd, AICA_SM_16BIT, freq, st); } +void snd_stream_start_pcm8(snd_stream_hnd_t hnd, uint32 freq, int st) { + snd_stream_start_type(hnd, AICA_SM_8BIT, freq, st); +} + void snd_stream_start_adpcm(snd_stream_hnd_t hnd, uint32 freq, int st) { snd_stream_start_type(hnd, AICA_SM_ADPCM_LS, freq, st); } @@ -590,6 +597,9 @@ int snd_stream_poll(snd_stream_hnd_t hnd) { if(streams[hnd].type == AICA_SM_16BIT) { snd_pcm16_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); } + else if(streams[hnd].type == AICA_SM_8BIT) { + snd_pcm8_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); + } else { snd_adpcm_split(data, sep_buffer[0], sep_buffer[1], needed_samples * 4); } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-05 03:48:28
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 3065978c74fe2e03df1eda3464d35a1115d8f830 (commit) via a8b0bc3d72a2fe0b86dd63a95b35d3442b15620f (commit) via 17633dc9bd128356050292c885c9cebd8c21b7a0 (commit) via 8a0f03efb8d469c780804d6f65bbe7f1c2055565 (commit) via a2c13f5b879dee33ead90488e94fcfed30d2bb7d (commit) from a113876777c99e0ed3edded98f226a6c902af97e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3065978c74fe2e03df1eda3464d35a1115d8f830 Author: Ruslan Rostovtsev <sw...@21...> Date: Sun Nov 5 10:47:47 2023 +0700 Improvements for sound FX and added ADPCM long stream support. (#334) * Added spu_memload_sq(). * Added ADPCM long stream AICA sample format. * Changed API for snd_pcm16_split_sq(). * Improved sound FX samples loading. * 4-byte align support for spu_memload_sq() * Added support for ADPCM streams. * Added G2 Bus locking for SQ's with SPU memory. * Cleanup for SFX loading * Workaround for sound stream memory allocation bug. * Apply suggestions from code review commit a8b0bc3d72a2fe0b86dd63a95b35d3442b15620f Merge: 17633dc a2c13f5 Author: Lawrence Sebald <ljs...@us...> Date: Sat Nov 4 23:46:16 2023 -0400 Merge pull request #338 from KallistiOS/timerfix Fix race condition while getting timer info commit 17633dc9bd128356050292c885c9cebd8c21b7a0 Merge: a113876 8a0f03e Author: Lawrence Sebald <ljs...@us...> Date: Sat Nov 4 23:44:25 2023 -0400 Merge pull request #339 from KallistiOS/abortused Add __attribute__((used)) to abort to fix linking issues when using LTO commit 8a0f03efb8d469c780804d6f65bbe7f1c2055565 Author: darc <da...@pr...> Date: Sat Nov 4 19:00:46 2023 -0500 Add __attribute__((used)) to abort to fix linking issues when using LTO commit a2c13f5b879dee33ead90488e94fcfed30d2bb7d Author: darc <da...@pr...> Date: Sat Nov 4 18:29:03 2023 -0500 Fix race condition while getting timer info ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/exports-naomi.txt | 1 + kernel/arch/dreamcast/exports-pristine.txt | 1 + kernel/arch/dreamcast/hardware/spu.c | 38 ++++++- kernel/arch/dreamcast/include/dc/sound/aica_comm.h | 8 +- kernel/arch/dreamcast/include/dc/sound/sound.h | 22 +++- kernel/arch/dreamcast/include/dc/sound/stream.h | 13 ++- kernel/arch/dreamcast/include/dc/spu.h | 18 ++- kernel/arch/dreamcast/kernel/timer.c | 22 +++- kernel/arch/dreamcast/sound/snd_pcm_split.s | 53 ++++++++- kernel/arch/dreamcast/sound/snd_sfxmgr.c | 126 ++++++++------------- kernel/arch/dreamcast/sound/snd_stream.c | 93 +++++++++------ kernel/libc/koslib/abort.c | 2 +- 12 files changed, 263 insertions(+), 134 deletions(-) diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index 1744f16..3a5587d 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -130,6 +130,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_adpcm_split # Video vid_check_cable diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index 361b525..93e0c14 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -173,6 +173,7 @@ snd_stream_reinit snd_stream_prefill snd_pcm16_split snd_pcm16_split_sq +snd_adpcm_split # Video vid_check_cable diff --git a/kernel/arch/dreamcast/hardware/spu.c b/kernel/arch/dreamcast/hardware/spu.c index f4d393f..9f500ac 100644 --- a/kernel/arch/dreamcast/hardware/spu.c +++ b/kernel/arch/dreamcast/hardware/spu.c @@ -1,11 +1,14 @@ /* KallistiOS ##version## spu.c - (c)2000-2001 Megan Potter + Copyright (C) 2000, 2001 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev */ #include <dc/spu.h> #include <dc/g2bus.h> +#include <dc/sq.h> +#include <arch/memory.h> #include <arch/timer.h> /* @@ -62,6 +65,39 @@ void spu_memload(uint32 dst, void *src_void, int length) { } } +void spu_memload_sq(uint32 dst, void *src_void, int length) { + uint8 *src = (uint8 *)src_void; + int aligned_len, old; + + /* Make sure it's an even number of 32-bit words and convert the + count to a 32-bit word count */ + if(length & 3) { + length = (length + 4) & ~3; + } + + /* Add in the SPU RAM base (cached area) */ + dst += 0x00800000; + + /* Using SQs for all that is divisible by 32 */ + aligned_len = length & ~31; + length &= 31; + + old = irq_disable(); + do { } while(*(vuint32 *)0xa05f688c & (1 << 5)); /* FIFO_SH4 */ + do { } while(*(vuint32 *)0xa05f688c & (1 << 4)); /* FIFO_G2 */ + sq_cpy((void *)dst, src, aligned_len); + irq_restore(old); + + if(length > 0) { + /* Make sure the destination is in a non-cached area */ + dst |= MEM_AREA_P2_BASE; + dst += aligned_len; + src += aligned_len; + g2_fifo_wait(); + g2_write_block_32((uint32 *)src, dst, length >> 2); + } +} + void spu_memread(void *dst_void, uint32 src, int length) { uint8 *dst = (uint8*)dst_void; diff --git a/kernel/arch/dreamcast/include/dc/sound/aica_comm.h b/kernel/arch/dreamcast/include/dc/sound/aica_comm.h index f51b70d..3e280a2 100644 --- a/kernel/arch/dreamcast/include/dc/sound/aica_comm.h +++ b/kernel/arch/dreamcast/include/dc/sound/aica_comm.h @@ -2,6 +2,7 @@ aica_comm.h Copyright (C) 2000-2002 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev Structure and constant definitions for the SH-4/AICA interface. This file is included from both the ARM and SH-4 sides of the fence. @@ -100,8 +101,9 @@ typedef struct aica_channel { #define AICA_CH_UPDATE_SET_PAN 0x00004000 /* panning */ /* Sample types */ -#define AICA_SM_8BIT 1 -#define AICA_SM_16BIT 0 -#define AICA_SM_ADPCM 2 +#define AICA_SM_16BIT 0 /* Linear PCM 16-bit */ +#define AICA_SM_8BIT 1 /* Linear PCM 8-bit */ +#define AICA_SM_ADPCM 2 /* Yamaha ADPCM 4-bit */ +#define AICA_SM_ADPCM_LS 3 /* Long stream ADPCM 4-bit */ #endif /* !__DC_SOUND_AICA_COMM_H */ diff --git a/kernel/arch/dreamcast/include/dc/sound/sound.h b/kernel/arch/dreamcast/include/dc/sound/sound.h index 86ed253..02bcdbe 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sound.h +++ b/kernel/arch/dreamcast/include/dc/sound/sound.h @@ -166,13 +166,9 @@ void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t siz \warning All arguments must be 32-byte aligned. - \warning - The store queues must be configured for transferring to the left and right - destination buffers beforehand (QACRO <= left, QACRO1 <= right). - \param data Source buffer of interleaved stereo samples - \param left SQ-masked left destination buffer address - \param right SQ-masked right destination buffer address + \param left Destination buffer address for left mono samples + \param right Destination buffer address for right mono samples \param size Size of the source buffer in bytes (must be divisible by 32) \sa snd_pcm16_split() @@ -180,6 +176,20 @@ void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t siz */ void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); +/** \brief Separates stereo ADPCM samples into 2 mono channels. + + Splits a buffer containing 2 interleaved channels of 4-bit ADPCM samples + into 2 separate buffers of 4-bit ADPCM samples. + + \param data Source buffer of interleaved stereo samples + \param left Destination buffer for left mono samples + \param right Destination buffer for right mono samples + \param size Size of the source buffer in bytes + + \sa snd_pcm16_split() +*/ +void snd_adpcm_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); + __END_DECLS #endif /* __DC_SOUND_SOUND_H */ diff --git a/kernel/arch/dreamcast/include/dc/sound/stream.h b/kernel/arch/dreamcast/include/dc/sound/stream.h index 80c8204..97825ff 100644 --- a/kernel/arch/dreamcast/include/dc/sound/stream.h +++ b/kernel/arch/dreamcast/include/dc/sound/stream.h @@ -238,7 +238,7 @@ void snd_stream_queue_disable(snd_stream_hnd_t hnd); */ void snd_stream_queue_go(snd_stream_hnd_t hnd); -/** \brief Start a stream. +/** \brief Start a 16-bit PCM stream. This function starts processing the given stream, prefilling the buffers as necessary. In queueing mode, this will not start playback. @@ -249,6 +249,17 @@ void snd_stream_queue_go(snd_stream_hnd_t hnd); */ void snd_stream_start(snd_stream_hnd_t hnd, uint32 freq, int st); +/** \brief Start a 4-bit ADPCM stream. + + This function starts processing the given stream, prefilling the buffers as + necessary. In queueing mode, this will not start playback. + + \param hnd The stream to start. + \param freq The frequency of the sound. + \param st 1 if the sound is stereo, 0 if mono. +*/ +void snd_stream_start_adpcm(snd_stream_hnd_t hnd, uint32 freq, int st); + /** \brief Stop a stream. This function stops a stream, stopping any sound playing from it. This will diff --git a/kernel/arch/dreamcast/include/dc/spu.h b/kernel/arch/dreamcast/include/dc/spu.h index a425d33..3ea8e73 100644 --- a/kernel/arch/dreamcast/include/dc/spu.h +++ b/kernel/arch/dreamcast/include/dc/spu.h @@ -1,7 +1,8 @@ /* KallistiOS ##version## dc/spu.h - Copyright (C) 2000-2001 Megan Potter + Copyright (C) 2000, 2001 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev */ @@ -11,6 +12,7 @@ This file deals with memory transfers and the like for the sound hardware. \author Megan Potter + \author Ruslan Rostovtsev */ #ifndef __DC_SPU_H @@ -37,6 +39,20 @@ void spu_write_wait(void); */ void spu_memload(uint32 to, void *from, int length); + +/** \brief Copy a block of data to sound RAM. + + This function acts much like memcpy() but copies to the sound RAM area + by using the store queues. + + \param to The offset in sound RAM to copy to. Do not include + the 0xA0800000 part, it is implied. + \param from A pointer to copy from. + \param length The number of bytes to copy. Automatically rounded + up to be a multiple of 4. +*/ +void spu_memload_sq(uint32 to, void *from, int length); + /** \brief Copy a block of data from sound RAM. This function acts much like memcpy() but copies from the sound RAM area. diff --git a/kernel/arch/dreamcast/kernel/timer.c b/kernel/arch/dreamcast/kernel/timer.c index b9276d8..39bf2d4 100644 --- a/kernel/arch/dreamcast/kernel/timer.c +++ b/kernel/arch/dreamcast/kernel/timer.c @@ -146,6 +146,9 @@ static void timer_ms_handler(irq_t source, irq_context_t *context) { (void)source; (void)context; timer_ms_counter++; + + /* Clear overflow bit so we can check it when returning time */ + TIMER16(tcrs[TMU2]) &= ~0x100; } void timer_ms_enable(void) { @@ -165,6 +168,8 @@ void timer_ms_disable(void) { void timer_ms_gettime(uint32 *secs, uint32 *msecs) { uint32 used; + int irq_status = irq_disable(); + /* Seconds part comes from ms_counter */ if(secs) *secs = timer_ms_counter; @@ -172,9 +177,14 @@ void timer_ms_gettime(uint32 *secs, uint32 *msecs) { /* Milliseconds, we check how much of the timer has elapsed */ if(msecs) { assert(timer_ms_countdown > 0); - used = timer_ms_countdown - timer_count(TMU2); - *msecs = used * 1000 / timer_ms_countdown; + /* Overflow is only notable if we have seconds we can + overflow into, so avoid read of TCR if secs is null */ + if (secs && TIMER16(tcrs[TMU2]) & 0x100) + *secs += 1; + used = timer_count(TMU2); + *msecs = (timer_ms_countdown - used) * 1000 / timer_ms_countdown; } + irq_restore(irq_status); } uint64 timer_ms_gettime64(void) { @@ -192,8 +202,15 @@ uint64 timer_us_gettime64(void) { uint64 usec; uint64 used; + int irq_status = irq_disable(); scnt = timer_ms_counter; cnt = timer_count(TMU2); + if (TIMER16(tcrs[TMU2]) & 0x100) { + /* If we underflowed, add an extra second and reload microseconds */ + scnt++; + cnt = timer_count(TMU2); + } + irq_restore(irq_status); assert(timer_ms_countdown > 0); used = timer_ms_countdown - cnt; @@ -389,4 +406,3 @@ inline uint64 timer_ns_gettime64(void) { return micro_secs * 1000; } } - diff --git a/kernel/arch/dreamcast/sound/snd_pcm_split.s b/kernel/arch/dreamcast/sound/snd_pcm_split.s index 276507a..1752b41 100644 --- a/kernel/arch/dreamcast/sound/snd_pcm_split.s +++ b/kernel/arch/dreamcast/sound/snd_pcm_split.s @@ -8,12 +8,13 @@ .section .text .globl _snd_pcm16_split -.globl _snd_pcm16_split_sq +.globl _snd_pcm16_split_sq_start +.globl _snd_adpcm_split .align 2 ! -! void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, uint32_t size); +! void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); ! _snd_pcm16_split: mov #-5, r3 @@ -64,9 +65,9 @@ _snd_pcm16_split: mov #0, r0 ! -! void snd_pcm16_split_sq(uint32_t *data, uint32_t left, uint32_t right, uint32_t size); +! void snd_pcm16_split_sq_start(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); ! -_snd_pcm16_split_sq: +_snd_pcm16_split_sq_start: mov #-5, r3 shld r3, r7 mov.l r8, @-r15 @@ -112,3 +113,47 @@ _snd_pcm16_split_sq: mov.l @r15+, r8 rts nop + +! +! void snd_adpcm_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); +! +_snd_adpcm_split: + mov #-5, r1 + shld r1, r7 + mov.l r10, @-r15 + mov #16, r1 +.adpcm_pref: + add #32, r4 + pref @r4 + add #-32, r4 +.adpcm_copy: + dt r1 + mov.w @r4+, r10 + mov r10, r0 + and #0xf0, r0 + mov r0, r2 + shlr2 r2 + mov r10, r0 + shlr2 r2 + and #0x0f, r0 + mov r0, r3 + shlr8 r10 + mov r10, r0 + and #0xf0, r0 + or r0, r2 + mov.b r2, @r5 + add #1, r5 + mov r10, r0 + and #0x0f, r0 + shll2 r0 + shll2 r0 + or r0, r3 + mov.b r3, @r6 + bf/s .adpcm_copy + add #1, r6 + dt r7 + bf/s .adpcm_pref + mov #16, r1 + mov.l @r15+, r10 + rts + nop diff --git a/kernel/arch/dreamcast/sound/snd_sfxmgr.c b/kernel/arch/dreamcast/sound/snd_sfxmgr.c index 9d0fade..d0eb44a 100644 --- a/kernel/arch/dreamcast/sound/snd_sfxmgr.c +++ b/kernel/arch/dreamcast/sound/snd_sfxmgr.c @@ -2,6 +2,7 @@ snd_sfxmgr.c Copyright (C) 2000, 2001, 2002, 2003, 2004 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev Sound effects management system; this thing loads and plays sound effects during game operation. @@ -11,6 +12,7 @@ #include <stdlib.h> #include <assert.h> #include <string.h> +#include <malloc.h> #include <sys/queue.h> #include <kos/fs.h> @@ -96,11 +98,11 @@ void snd_sfx_unload(sfxhnd_t idx) { /* Load a sound effect from a WAV file and return a handle to it */ sfxhnd_t snd_sfx_load(const char *fn) { - file_t fd; - uint32 len, hz; - uint16 *tmp, stereo, bitsize, fmt; + file_t fd; + uint32_t len, hz; + uint8_t *tmp; + uint16_t channels, bitsize, fmt; snd_effect_t *t; - int ownmem; dbglog(DBG_DEBUG, "snd_sfx: loading effect %s\n", fn); @@ -116,7 +118,7 @@ sfxhnd_t snd_sfx_load(const char *fn) { fs_seek(fd, 0x08, SEEK_SET); fs_read(fd, &hz, 4); - if(strncmp((char*)&hz, "WAVE", 4)) { + if(strncmp((char *)&hz, "WAVE", 4)) { dbglog(DBG_WARNING, "snd_sfx: file is not RIFF WAVE\n"); fs_close(fd); return SFXHND_INVALID; @@ -125,7 +127,7 @@ sfxhnd_t snd_sfx_load(const char *fn) { /* Read WAV header info */ fs_seek(fd, 0x14, SEEK_SET); fs_read(fd, &fmt, 2); - fs_read(fd, &stereo, 2); + fs_read(fd, &channels, 2); fs_read(fd, &hz, 4); fs_seek(fd, 0x22, SEEK_SET); fs_read(fd, &bitsize, 2); @@ -135,35 +137,26 @@ sfxhnd_t snd_sfx_load(const char *fn) { fs_read(fd, &len, 4); dbglog(DBG_DEBUG, "WAVE file is %s, %luHZ, %d bits/sample, %lu bytes total," - " format %d\n", stereo == 1 ? "mono" : "stereo", hz, bitsize, len, fmt); + " format %d\n", channels == 1 ? "mono" : "stereo", hz, bitsize, len, fmt); - /* Try to mmap it and if that works, no need to copy it again */ - ownmem = 0; - tmp = (uint16 *)fs_mmap(fd); + tmp = (uint8_t *)memalign(32, len); - if(!tmp) { - tmp = malloc(len); - - if(tmp == NULL) { - fs_close(fd); - return SFXHND_INVALID; - } - - fs_read(fd, tmp, len); - ownmem = 1; - } - else { - tmp = (uint16 *)(((uint8 *)tmp) + fs_tell(fd)); + if(tmp == NULL) { + fs_close(fd); + return SFXHND_INVALID; } + uint32_t rd = fs_read(fd, tmp, len); fs_close(fd); + if (rd != len) { + dbglog(DBG_WARNING, "snd_sfx: file has not been fully read.\n"); + } + t = malloc(sizeof(snd_effect_t)); if(t == NULL) { - if(ownmem) - free(tmp); - + free(tmp); return SFXHND_INVALID; } @@ -171,19 +164,17 @@ sfxhnd_t snd_sfx_load(const char *fn) { /* Common characteristics not impacted by stream type */ t->rate = hz; - t->stereo = stereo - 1; + t->stereo = channels - 1; - if(stereo == 1) { + if(channels == 1) { /* Mono PCM/ADPCM */ t->len = len / 2; /* 16-bit samples */ - t->rate = hz; t->locl = snd_mem_malloc(len); if(t->locl) - spu_memload(t->locl, tmp, len); + spu_memload_sq(t->locl, tmp, len); t->locr = 0; - t->stereo = 0; if(fmt == 20) { t->fmt = AICA_SM_ADPCM; @@ -192,77 +183,54 @@ sfxhnd_t snd_sfx_load(const char *fn) { else t->fmt = AICA_SM_16BIT; } - else if(stereo == 2 && fmt == 1) { + else if(channels == 2 && fmt == 1) { /* Stereo PCM */ - uint32 i; - uint16 * sepbuf; ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-11-04 17:45:20
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via a113876777c99e0ed3edded98f226a6c902af97e (commit) from ad6a4726a081cdfda00294369cb90832eb419cb8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a113876777c99e0ed3edded98f226a6c902af97e Author: Andress Barajas <and...@gm...> Date: Sat Nov 4 10:42:15 2023 -0700 Use uint32_t and size_t in store queues (#337) Change uint32 -> uint32_t, sizes to actually be size_t. ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/hardware/sq.c | 14 +++++++------- kernel/arch/dreamcast/include/dc/sq.h | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/kernel/arch/dreamcast/hardware/sq.c b/kernel/arch/dreamcast/hardware/sq.c index 8fa9947..561ae94 100644 --- a/kernel/arch/dreamcast/hardware/sq.c +++ b/kernel/arch/dreamcast/hardware/sq.c @@ -16,7 +16,7 @@ */ /* Copies n bytes from src to dest, dest must be 32-byte aligned */ -void * sq_cpy(void *dest, const void *src, int n) { +void * sq_cpy(void *dest, const void *src, size_t n) { uint32_t *d = SQ_MASK_DEST(dest); const uint32_t *s = src; @@ -89,7 +89,7 @@ void * sq_cpy(void *dest, const void *src, int n) { } /* Fills n bytes at dest with byte c, dest must be 32-byte aligned */ -void * sq_set(void *dest, uint32_t c, int n) { +void * sq_set(void *dest, uint32_t c, size_t n) { /* Duplicate low 8-bits of c into high 24-bits */ c = c & 0xff; c = (c << 24) | (c << 16) | (c << 8) | c; @@ -98,7 +98,7 @@ void * sq_set(void *dest, uint32_t c, int n) { } /* Fills n bytes at dest with short c, dest must be 32-byte aligned */ -void * sq_set16(void *dest, uint32_t c, int n) { +void * sq_set16(void *dest, uint32_t c, size_t n) { /* Duplicate low 16-bits of c into high 16-bits */ c = c & 0xffff; c = (c << 16) | c; @@ -107,7 +107,7 @@ void * sq_set16(void *dest, uint32_t c, int n) { } /* Fills n bytes at dest with int c, dest must be 32-byte aligned */ -void * sq_set32(void *dest, uint32_t c, int n) { +void * sq_set32(void *dest, uint32_t c, size_t n) { uint32_t *d = SQ_MASK_DEST(dest); /* Set store queue memory area as desired */ @@ -133,7 +133,7 @@ void * sq_set32(void *dest, uint32_t c, int n) { } /* Clears n bytes at dest, dest must be 32-byte aligned */ -void sq_clr(void *dest, int n) { +void sq_clr(void *dest, size_t n) { sq_set32(dest, 0, n); } @@ -141,7 +141,7 @@ void sq_clr(void *dest, int n) { #define PVR_DMA_DEST (*(volatile uint32_t *)(void *)0xa05f6808) /* Copies n bytes from src to dest (in VRAM), dest must be 32-byte aligned */ -void * sq_cpy_pvr(void *dest, const void *src, int n) { +void * sq_cpy_pvr(void *dest, const void *src, size_t n) { if(PVR_DMA_DEST != 0) { dbglog(DBG_ERROR, "sq_cpy_pvr: Previous DMA has not finished\n"); return NULL; @@ -159,7 +159,7 @@ void * sq_cpy_pvr(void *dest, const void *src, int n) { } /* Fills n bytes at PVR dest with short c, dest must be 32-byte aligned */ -void * sq_set_pvr(void *dest, uint32_t c, int n) { +void * sq_set_pvr(void *dest, uint32_t c, size_t n) { if(PVR_DMA_DEST != 0) { dbglog(DBG_ERROR, "sq_set_pvr: Previous DMA has not finished\n"); return NULL; diff --git a/kernel/arch/dreamcast/include/dc/sq.h b/kernel/arch/dreamcast/include/dc/sq.h index c570a0e..5dbad30 100644 --- a/kernel/arch/dreamcast/include/dc/sq.h +++ b/kernel/arch/dreamcast/include/dc/sq.h @@ -63,10 +63,10 @@ __BEGIN_DECLS /** \brief Mask dest to Store Queue area \ingroup store_queues */ -#define SQ_MASK_DEST(dest) \ - ((uint32_t *)(void *) \ - (MEM_AREA_SQ_BASE | \ - (((uint32_t)(dest)) & 0x03ffffe0))) +#define SQ_MASK_DEST(dest) \ + ((uint32_t *)(void *) \ + (MEM_AREA_SQ_BASE | \ + (((uint32_t)(dest)) & 0x03ffffe0))) /** \brief Copy a block of memory. \ingroup store_queues @@ -86,7 +86,7 @@ __BEGIN_DECLS \sa sq_cpy_pvr() */ -void * sq_cpy(void *dest, const void *src, int n); +void * sq_cpy(void *dest, const void *src, size_t n); /** \brief Set a block of memory to an 8-bit value. \ingroup store_queues @@ -105,7 +105,7 @@ void * sq_cpy(void *dest, const void *src, int n); \sa sq_set16(), sq_set32(), sq_set_pvr() */ -void * sq_set(void *dest, uint32 c, int n); +void * sq_set(void *dest, uint32_t c, size_t n); /** \brief Set a block of memory to a 16-bit value. \ingroup store_queues @@ -124,7 +124,7 @@ void * sq_set(void *dest, uint32 c, int n); \sa sq_set(), sq_set32(), sq_set_pvr() */ -void * sq_set16(void *dest, uint32 c, int n); +void * sq_set16(void *dest, uint32_t c, size_t n); /** \brief Set a block of memory to a 32-bit value. \ingroup store_queues @@ -142,7 +142,7 @@ void * sq_set16(void *dest, uint32 c, int n); \sa sq_set(), sq_set16(), sq_set_pvr() */ -void * sq_set32(void *dest, uint32 c, int n); +void * sq_set32(void *dest, uint32_t c, size_t n); /** \brief Clear a block of memory. \ingroup store_queues @@ -156,7 +156,7 @@ void * sq_set32(void *dest, uint32 c, int n); \param dest The address to begin clearing at (32-byte aligned). \param n The number of bytes to clear (multiple of 32). */ -void sq_clr(void *dest, int n); +void sq_clr(void *dest, size_t n); /** \brief Copy a block of memory to VRAM \ingroup store_queues @@ -183,7 +183,7 @@ void sq_clr(void *dest, int n); \sa sq_cpy() */ -void * sq_cpy_pvr(void *dest, const void *src, int n); +void * sq_cpy_pvr(void *dest, const void *src, size_t n); /** \brief Set a block of PVR memory to a 16-bit value. \ingroup store_queues @@ -205,7 +205,7 @@ void * sq_cpy_pvr(void *dest, const void *src, int n); \sa sq_set(), sq_set16(), sq_set32() */ -void * sq_set_pvr(void *dest, uint32 c, int n); +void * sq_set_pvr(void *dest, uint32_t c, size_t n); __END_DECLS hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-10-30 03:51:35
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via ad6a4726a081cdfda00294369cb90832eb419cb8 (commit) from 75ed45d4fe1112f5f1434ca6a6fcd6dbe0c6d002 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ad6a4726a081cdfda00294369cb90832eb419cb8 Author: Ruslan Rostovtsev <sw...@21...> Date: Mon Oct 30 10:51:13 2023 +0700 Fix sound streams for unaligned buffers. (#332) * Fixed sound streams for unaligned buffers. Rewrite strange sep_data(). Fixed memory for SQ's. * Apply suggestions from code review * Speedup sep_data() more than x2 for unaligned buffers ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/sound/snd_stream.c | 118 ++++++++++++++++++------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index 14efad6..1033ed1 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -151,40 +151,41 @@ static void process_filters(snd_stream_hnd_t hnd, void **buffer, int *samplecnt) } static void sep_data(void *buffer, int len, int stereo) { - register int16 *bufsrc, *bufdst; - register int x, y, cnt; + uint32_t *buf = (uint32_t *)buffer; + uint32_t *left_ptr = (uint32_t *)sep_buffer[1]; + uint32_t *right_ptr = (uint32_t *)sep_buffer[0]; + uint32_t data; + uint32_t left_val; + uint32_t right_val; if(stereo) { - bufsrc = (int16*)buffer; - bufdst = (int16 *)sep_buffer[0]; - x = 0; - y = 0; - cnt = len / 2; - - do { - *bufdst = *bufsrc; - bufdst++; - bufsrc += 2; - cnt--; + len <<= 1; + + for(; len > 8; len -= 8) { + dcache_pref_block(buf + 8); + + data = *buf++; + left_val = (data >> 16); + right_val = (data & 0xffff); + + data = *buf++; + left_val |= (data & 0xffff0000); + right_val |= (data & 0xffff) << 16; + + if(((uintptr_t)left_ptr & 31) == 0) { + dcache_alloc_block(left_ptr++, left_val); + dcache_alloc_block(right_ptr++, right_val); + } + else { + *left_ptr++ = left_val; + *right_ptr++ = right_val; + } } - while(cnt > 0); - - bufsrc = (int16*)buffer; - bufsrc++; - bufdst = (int16 *)sep_buffer[1]; - x = 1; - y = 0; - cnt = len / 2; - - do { - *bufdst = *bufsrc; - bufdst++; - bufsrc += 2; - cnt--; - x += 2; - y++; + if(len) { + data = *buf++; + *(uint16_t *)left_ptr = (data >> 16); + *(uint16_t *)right_ptr = (data & 0xffff); } - while(cnt > 0); } else { memcpy(sep_buffer[0], buffer, len); @@ -211,43 +212,58 @@ static void stereo_pcm16_split_sq(uint32 *data, uint32 aica_left, uint32 aica_ri snd_pcm16_split_sq(data, masked_left, masked_right, size); } -/* Prefill buffers -- do this before calling start() */ -void snd_stream_prefill(snd_stream_hnd_t hnd) { - void *buf; - int got; - - CHECK_HND(hnd); - - if(!streams[hnd].get_data) return; +static void snd_stream_prefill_part(snd_stream_hnd_t hnd, uint32_t offset) { - const uint32 buffer_size = streams[hnd].buffer_size; + const uint32_t buffer_size = streams[hnd].buffer_size; + uintptr_t left = streams[hnd].spu_ram_sch[0] + offset; + uintptr_t right = streams[hnd].spu_ram_sch[1] + offset; + int got = buffer_size; + void *buf; - if(streams[hnd].stereo) - buf = streams[hnd].get_data(hnd, buffer_size * 2, &got); - else + if(streams[hnd].stereo) { buf = streams[hnd].get_data(hnd, buffer_size, &got); + } + else { + buf = streams[hnd].get_data(hnd, buffer_size / 2, &got); + } + + if(buf == NULL) { + dbglog(DBG_ERROR, "snd_stream_prefill_part(): get_data() failed\n"); + return; + } process_filters(hnd, &buf, &got); if ((uintptr_t)buf & 31) { - sep_data(buf, got, streams[hnd].stereo); - spu_memload(streams[hnd].spu_ram_sch[0], (uint8*)sep_buffer[0], got); - spu_memload(streams[hnd].spu_ram_sch[1], (uint8*)sep_buffer[1], got); + sep_data(buf, got / 2, streams[hnd].stereo); + spu_memload(left, sep_buffer[0], got); + spu_memload(right, sep_buffer[1], got); } else { + left |= 0x00800000; + right |= 0x00800000; if (streams[hnd].stereo) { - stereo_pcm16_split_sq((uint32 *)buf, - streams[hnd].spu_ram_sch[0], - streams[hnd].spu_ram_sch[1], - got); + stereo_pcm16_split_sq((uint32_t *)buf, left, right, got); } else { g2_fifo_wait(); - sq_cpy((uint32 *)streams[hnd].spu_ram_sch[0], buf, got); + sq_cpy((void *)left, buf, got); g2_fifo_wait(); - sq_cpy((uint32 *)streams[hnd].spu_ram_sch[1], buf, got); + sq_cpy((void *)right, buf, got); } } +} + +/* Prefill buffers -- do this before calling start() */ +void snd_stream_prefill(snd_stream_hnd_t hnd) { + CHECK_HND(hnd); + + if(!streams[hnd].get_data) { + return; + } + + snd_stream_prefill_part(hnd, 0); + snd_stream_prefill_part(hnd, streams[hnd].buffer_size / 2); /* Start with playing on buffer 0 */ streams[hnd].last_write_pos = 0; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-10-29 21:16:41
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 75ed45d4fe1112f5f1434ca6a6fcd6dbe0c6d002 (commit) from b1ddc3dcdd776ee4ce7d38d2cd68f161ee493e3e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 75ed45d4fe1112f5f1434ca6a6fcd6dbe0c6d002 Author: Paul Cercueil <pa...@cr...> Date: Sun Oct 29 22:15:57 2023 +0100 Garbage-collect network stack (#329) * Disable exports by default Add INIT_EXPORT init flag. When set (with the KOS_INIT_FLAGS macro), the KOS symbols will be exported. The default is to not export them. This helps reduce the size of the executables, as the vast majority of them don't need the symbol export feature, by telling the compiler that it's okay to garbage-collect them. Signed-off-by: Paul Cercueil <pa...@cr...> * Garbage-collect the network stack when unused Make it so that the network stack (and BBA and LAN adapter code) is garbage-collected when a KOS program has been compiled without the INIT_NET flag (and doesn't use any of the symbols). This really drops the size of the compiled binaries. For instance, the dreamcast "hello" example dropped from 284 KiB to 156 KiB (both stripped). Signed-off-by: Paul Cercueil <pa...@cr...> ----------------------------------------------------------------------- Summary of changes: include/kos/init.h | 14 ++++++- kernel/arch/dreamcast/hardware/hardware.c | 23 ++++++++--- kernel/arch/dreamcast/kernel/init.c | 67 ++++++++++++++++--------------- kernel/exports/nmmgr.c | 5 ++- 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/include/kos/init.h b/include/kos/init.h index 92b52b3..a1c94cf 100644 --- a/include/kos/init.h +++ b/include/kos/init.h @@ -38,7 +38,18 @@ __BEGIN_DECLS \see kos_initflags \see dreamcast_initflags */ -#define KOS_INIT_FLAGS(flags) uint32 __kos_init_flags = (flags) +#define KOS_INIT_FLAGS(flags) \ + uint32 __kos_init_flags = (flags); \ + extern void arch_init_net(void); \ + void (*init_net_weak)(void) = ((flags) & INIT_NET) ? arch_init_net : NULL; \ + extern void net_shutdown(void); \ + void (*net_shutdown_weak)(void) = ((flags) & INIT_NET) ? net_shutdown : NULL; \ + extern void bba_la_init(void); \ + void (*bba_la_init_weak)(void) = ((flags) & INIT_NET) ? bba_la_init : NULL; \ + extern void bba_la_shutdown(void); \ + void (*bba_la_shutdown_weak)(void) = ((flags) & INIT_NET) ? bba_la_shutdown : NULL; \ + extern int export_init(void); \ + int (*export_init_weak)(void) = ((flags) & INIT_EXPORT) ? export_init : NULL /** \brief The init flags. Do not modify this directly! */ extern uint32 __kos_init_flags; @@ -81,6 +92,7 @@ extern void * __kos_romdisk; #define INIT_NET 0x0004 /**< \brief Enable built-in networking */ #define INIT_MALLOCSTATS 0x0008 /**< \brief Enable malloc statistics */ #define INIT_QUIET 0x0010 /**< \brief Disable dbgio */ +#define INIT_EXPORT 0x0020 /**< \brief Export kernel symbols */ /** @} */ __END_DECLS diff --git a/kernel/arch/dreamcast/hardware/hardware.c b/kernel/arch/dreamcast/hardware/hardware.c index c5aff77..36459f9 100644 --- a/kernel/arch/dreamcast/hardware/hardware.c +++ b/kernel/arch/dreamcast/hardware/hardware.c @@ -40,6 +40,20 @@ int hardware_sys_init(void) { return 0; } +void (*bba_la_init_weak)(void) __attribute__((weak)); +void (*bba_la_shutdown_weak)(void) __attribute__((weak)); + +void bba_la_init(void) { + /* Setup network (this won't do anything unless we enable netcore) */ + bba_init(); + la_init(); +} + +void bba_la_shutdown(void) { + la_shutdown(); + bba_shutdown(); +} + int hardware_periph_init(void) { /* Init sound */ spu_init(); @@ -57,9 +71,8 @@ int hardware_periph_init(void) { vid_init(DEFAULT_VID_MODE, DEFAULT_PIXEL_MODE); #ifndef _arch_sub_naomi - /* Setup network (this won't do anything unless we enable netcore) */ - bba_init(); - la_init(); + if(bba_la_init_weak) + (*bba_la_init_weak)(); #endif initted = 2; @@ -71,8 +84,8 @@ void hardware_shutdown(void) { switch(initted) { case 2: #ifndef _arch_sub_naomi - la_shutdown(); - bba_shutdown(); + if(bba_la_shutdown_weak) + (*bba_la_shutdown_weak)(); #endif maple_shutdown(); #if 0 diff --git a/kernel/arch/dreamcast/kernel/init.c b/kernel/arch/dreamcast/kernel/init.c index 82373b5..641fd05 100644 --- a/kernel/arch/dreamcast/kernel/init.c +++ b/kernel/arch/dreamcast/kernel/init.c @@ -59,17 +59,40 @@ dbgio_handler_t * dbgio_handlers[] = { }; int dbgio_handler_cnt = sizeof(dbgio_handlers) / sizeof(dbgio_handler_t *); -/* Auto-init stuff: override with a non-weak symbol if you don't want all of - this to be linked into your code (and do the same with the - arch_auto_shutdown function too). */ -int __attribute__((weak)) arch_auto_init(void) { -#ifndef _arch_sub_naomi +void arch_init_net(void) { union { uint32 ipl; uint8 ipb[4]; - } ip; -#endif + } ip = { 0 }; + + if(!(__kos_init_flags & INIT_NO_DCLOAD) && dcload_type == DCLOAD_TYPE_IP) { + /* Grab the IP address from dcload before we disable dbgio... */ + ip.ipl = _fs_dclsocket_get_ip(); + dbglog(DBG_INFO, "dc-load says our IP is %d.%d.%d.%d\n", ip.ipb[3], + ip.ipb[2], ip.ipb[1], ip.ipb[0]); + dbgio_disable(); + } + + net_init(ip.ipl); /* Enable networking (and drivers) */ + + if(!(__kos_init_flags & INIT_NO_DCLOAD) && dcload_type == DCLOAD_TYPE_IP) { + fs_dclsocket_init_console(); + + if(!fs_dclsocket_init()) { + dbgio_dev_select("fs_dclsocket"); + dbgio_enable(); + dbglog(DBG_INFO, "fs_dclsocket console support enabled\n"); + } + } +} +void (*init_net_weak)(void) __attribute__((weak)); +void (*net_shutdown_weak)(void) __attribute__((weak)); + +/* Auto-init stuff: override with a non-weak symbol if you don't want all of + this to be linked into your code (and do the same with the + arch_auto_shutdown function too). */ +int __attribute__((weak)) arch_auto_init(void) { /* Initialize memory management */ mm_init(); @@ -155,31 +178,8 @@ int __attribute__((weak)) arch_auto_init(void) { } #ifndef _arch_sub_naomi - if(__kos_init_flags & INIT_NET) { - ip.ipl = 0; - - /* Check if the dcload-ip console is up, and if so, disable it, - otherwise we'll crash when we attempt to bring up the BBA */ - if(!(__kos_init_flags & INIT_NO_DCLOAD) && dcload_type == DCLOAD_TYPE_IP) { - /* Grab the IP address from dcload before we disable dbgio... */ - ip.ipl = _fs_dclsocket_get_ip(); - dbglog(DBG_INFO, "dc-load says our IP is %d.%d.%d.%d\n", ip.ipb[3], - ip.ipb[2], ip.ipb[1], ip.ipb[0]); - dbgio_disable(); - } - - net_init(ip.ipl); /* Enable networking (and drivers) */ - - if(!(__kos_init_flags & INIT_NO_DCLOAD) && dcload_type == DCLOAD_TYPE_IP) { - fs_dclsocket_init_console(); - - if(!fs_dclsocket_init()) { - dbgio_dev_select("fs_dclsocket"); - dbgio_enable(); - dbglog(DBG_INFO, "fs_dclsocket console support enabled\n"); - } - } - } + if(init_net_weak) + (*init_net_weak)(); #endif return 0; @@ -188,7 +188,8 @@ int __attribute__((weak)) arch_auto_init(void) { void __attribute__((weak)) arch_auto_shutdown(void) { #ifndef _arch_sub_naomi fs_dclsocket_shutdown(); - net_shutdown(); + if(net_shutdown_weak) + (*net_shutdown_weak)(); #endif irq_disable(); diff --git a/kernel/exports/nmmgr.c b/kernel/exports/nmmgr.c index 06e6972..6288b0b 100644 --- a/kernel/exports/nmmgr.c +++ b/kernel/exports/nmmgr.c @@ -88,6 +88,8 @@ int nmmgr_handler_remove(nmmgr_handler_t *hnd) { return rv; } +int (*export_init_weak)(void) __attribute__((weak)); + /* Initialize structures */ int nmmgr_init(void) { int rv = 0; @@ -96,7 +98,8 @@ int nmmgr_init(void) { LIST_INIT(&nmmgr_handlers); /* Initialize our internal exports */ - export_init(); + if(export_init_weak) + (*export_init_weak)(); return rv; } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-10-25 03:16:55
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via b1ddc3dcdd776ee4ce7d38d2cd68f161ee493e3e (commit) from 56564f79b67478b7c5b68692f1200768cec6c983 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b1ddc3dcdd776ee4ce7d38d2cd68f161ee493e3e Author: Ruslan Rostovtsev <sw...@21...> Date: Wed Oct 25 10:16:28 2023 +0700 Optimized functions for separating stereo PCM 16-bit for streams (#326) * Optimized separating stereo PCM 16-bit for streams ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/exports-naomi.txt | 19 ++++ kernel/arch/dreamcast/exports-pristine.txt | 19 ++++ kernel/arch/dreamcast/include/dc/sound/sound.h | 42 +++++++++ kernel/arch/dreamcast/include/dc/sound/stream.h | 5 +- kernel/arch/dreamcast/sound/Makefile | 9 +- kernel/arch/dreamcast/sound/snd_pcm_split.s | 114 ++++++++++++++++++++++++ kernel/arch/dreamcast/sound/snd_stream.c | 112 ++++++++++++++--------- 7 files changed, 278 insertions(+), 42 deletions(-) create mode 100644 kernel/arch/dreamcast/sound/snd_pcm_split.s diff --git a/kernel/arch/dreamcast/exports-naomi.txt b/kernel/arch/dreamcast/exports-naomi.txt index ed14140..1744f16 100644 --- a/kernel/arch/dreamcast/exports-naomi.txt +++ b/kernel/arch/dreamcast/exports-naomi.txt @@ -91,14 +91,27 @@ sq_set16 sq_set32 # Sound +snd_mem_init +snd_mem_shutdown snd_mem_malloc snd_mem_free snd_mem_available +snd_init +snd_shutdown +snd_sh4_to_aica +snd_sh4_to_aica_start +snd_sh4_to_aica_stop +snd_aica_to_sh4 +snd_poll_resp snd_sfx_unload_all snd_sfx_unload snd_sfx_load snd_sfx_play snd_sfx_stop_all +snd_sfx_play_chn +snd_sfx_stop +snd_sfx_chn_alloc +snd_sfx_chn_free snd_stream_set_callback snd_stream_filter_add snd_stream_filter_remove @@ -111,6 +124,12 @@ snd_stream_queue_go snd_stream_stop snd_stream_poll snd_stream_volume +snd_stream_alloc +snd_stream_destroy +snd_stream_reinit +snd_stream_prefill +snd_pcm16_split +snd_pcm16_split_sq # Video vid_check_cable diff --git a/kernel/arch/dreamcast/exports-pristine.txt b/kernel/arch/dreamcast/exports-pristine.txt index 8ce4182..361b525 100644 --- a/kernel/arch/dreamcast/exports-pristine.txt +++ b/kernel/arch/dreamcast/exports-pristine.txt @@ -134,14 +134,27 @@ sq_set16 sq_set32 # Sound +snd_mem_init +snd_mem_shutdown snd_mem_malloc snd_mem_free snd_mem_available +snd_init +snd_shutdown +snd_sh4_to_aica +snd_sh4_to_aica_start +snd_sh4_to_aica_stop +snd_aica_to_sh4 +snd_poll_resp snd_sfx_unload_all snd_sfx_unload snd_sfx_load snd_sfx_play snd_sfx_stop_all +snd_sfx_play_chn +snd_sfx_stop +snd_sfx_chn_alloc +snd_sfx_chn_free snd_stream_set_callback snd_stream_filter_add snd_stream_filter_remove @@ -154,6 +167,12 @@ snd_stream_queue_go snd_stream_stop snd_stream_poll snd_stream_volume +snd_stream_alloc +snd_stream_destroy +snd_stream_reinit +snd_stream_prefill +snd_pcm16_split +snd_pcm16_split_sq # Video vid_check_cable diff --git a/kernel/arch/dreamcast/include/dc/sound/sound.h b/kernel/arch/dreamcast/include/dc/sound/sound.h index abe9dd4..86ed253 100644 --- a/kernel/arch/dreamcast/include/dc/sound/sound.h +++ b/kernel/arch/dreamcast/include/dc/sound/sound.h @@ -2,6 +2,7 @@ dc/sound/sound.h Copyright (C) 2002 Megan Potter + Copyright (C) 2023 Ruslan Rostovtsev */ @@ -23,6 +24,7 @@ __BEGIN_DECLS #include <arch/types.h> +#include <stdint.h> /** \brief Allocate memory in the SPU RAM pool @@ -138,6 +140,46 @@ int snd_aica_to_sh4(void *packetout); */ void snd_poll_resp(void); +/** \brief Separates stereo PCM samples into 2 mono channels. + + Splits a buffer containing 2 interleaved channels of 16-bit PCM samples + into 2 separate buffers of 16-bit PCM samples. + + \warning + All arguments must be 32-byte aligned. + + \param data Source buffer of interleaved stereo samples + \param left Destination buffer for left mono samples + \param right Destination buffer for right mono samples + \param size Size of the source buffer in bytes (must be divisible by 32) + + \sa snd_pcm16_split_sq() +*/ +void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, size_t size); + +/** \brief Separates stereo PCM samples into 2 mono channels with SQ transfer. + + Splits a buffer containing 2 interleaved channels of 16-bit PCM samples + into 2 separate buffers of 16-bit PCM samples by using the store queues + for data transfer. + + \warning + All arguments must be 32-byte aligned. + + \warning + The store queues must be configured for transferring to the left and right + destination buffers beforehand (QACRO <= left, QACRO1 <= right). + + \param data Source buffer of interleaved stereo samples + \param left SQ-masked left destination buffer address + \param right SQ-masked right destination buffer address + \param size Size of the source buffer in bytes (must be divisible by 32) + + \sa snd_pcm16_split() + Store queues must be prepared before. +*/ +void snd_pcm16_split_sq(uint32_t *data, uintptr_t left, uintptr_t right, size_t size); + __END_DECLS #endif /* __DC_SOUND_SOUND_H */ diff --git a/kernel/arch/dreamcast/include/dc/sound/stream.h b/kernel/arch/dreamcast/include/dc/sound/stream.h index 98371ef..80c8204 100644 --- a/kernel/arch/dreamcast/include/dc/sound/stream.h +++ b/kernel/arch/dreamcast/include/dc/sound/stream.h @@ -3,6 +3,7 @@ dc/sound/stream.h Copyright (C) 2002, 2004 Megan Potter Copyright (C) 2020 Lawrence Sebald + Copyright (C) 2023 Ruslan Rostovtsev */ @@ -17,6 +18,7 @@ \author Megan Potter \author Florian Schulze \author Lawrence Sebald + \author Ruslan Rostovtsev */ #ifndef __DC_SOUND_STREAM_H @@ -56,7 +58,8 @@ typedef int snd_stream_hnd_t; \param smp_req The number of samples requested. \param smp_recv Used to return the number of samples available. \return A pointer to the buffer of samples. If stereo, the - samples should be interleaved. + samples should be interleaved. For best perfomance + use 32-byte aligned pointer. */ typedef void *(*snd_stream_callback_t)(snd_stream_hnd_t hnd, int smp_req, int *smp_recv); diff --git a/kernel/arch/dreamcast/sound/Makefile b/kernel/arch/dreamcast/sound/Makefile index 5a3f98b..51db029 100644 --- a/kernel/arch/dreamcast/sound/Makefile +++ b/kernel/arch/dreamcast/sound/Makefile @@ -2,9 +2,16 @@ # # libmp3/Makefile # (c)2001 Megan Potter +# (c)2023 Ruslan Rostovtsev # -OBJS = snd_iface.o snd_sfxmgr.o snd_stream.o snd_stream_drv.o snd_mem.o +OBJS = snd_iface.o \ + snd_sfxmgr.o \ + snd_stream.o \ + snd_stream_drv.o \ + snd_mem.o \ + snd_pcm_split.o + KOS_CFLAGS += -I $(KOS_BASE)/kernel/arch/dreamcast/include/dc/sound SUBDIRS = arm diff --git a/kernel/arch/dreamcast/sound/snd_pcm_split.s b/kernel/arch/dreamcast/sound/snd_pcm_split.s new file mode 100644 index 0000000..276507a --- /dev/null +++ b/kernel/arch/dreamcast/sound/snd_pcm_split.s @@ -0,0 +1,114 @@ +! KallistiOS ##version## +! +! arch/dreamcast/sound/snd_pcm_split.s +! Copyright (C) 2023 Ruslan Rostovtsev +! +! Optimized assembler code for separating stereo PCM 16-bit to single channels +! + +.section .text +.globl _snd_pcm16_split +.globl _snd_pcm16_split_sq + +.align 2 + +! +! void snd_pcm16_split(uint32_t *data, uint32_t *left, uint32_t *right, uint32_t size); +! +_snd_pcm16_split: + mov #-5, r3 + shld r3, r7 + mov.l r8, @-r15 + mov.l r11, @-r15 + mov.l r12, @-r15 + mov r4, r8 + add #32, r8 + mov #31, r3 + mov #0, r0 +.pcm16_pref: + pref @r8 +.pcm16_load: + tst r3, r0 + mov.l @r4+, r1 + mov.l @r4+, r2 + swap.w r1, r11 + mov r2, r12 + xtrct r11, r12 + swap.w r2, r11 + bt/s .pcm16_store_alloc + xtrct r1, r11 +.pcm16_store: + mov.l r11, @(r0,r5) + mov.l r12, @(r0,r6) +.pcm16_loops: + tst r3, r4 + bf/s .pcm16_load + add #4, r0 + dt r7 + bf/s .pcm16_pref + add #32, r8 +.pcm16_exit: + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r8 + rts + nop +.pcm16_store_alloc: + add r0, r5 + add r0, r6 + mov r11, r0 + movca.l r0, @r5 + mov r12, r0 + movca.l r0, @r6 + bra .pcm16_loops + mov #0, r0 + +! +! void snd_pcm16_split_sq(uint32_t *data, uint32_t left, uint32_t right, uint32_t size); +! +_snd_pcm16_split_sq: + mov #-5, r3 + shld r3, r7 + mov.l r8, @-r15 + mov.l r11, @-r15 + mov.l r12, @-r15 + mov r4, r8 + add #32, r8 + mov #31, r3 + mov #0, r0 +.pcm16_sq_pref: + pref @r8 +.pcm16_sq_load: + mov.l @r4+, r1 + mov.l @r4+, r2 + swap.w r1, r11 + mov r2, r12 + xtrct r11, r12 + swap.w r2, r11 + xtrct r1, r11 + mov.l r11, @(r0,r5) + mov.l r12, @(r0,r6) + tst r3, r4 + bf/s .pcm16_sq_load + add #4, r0 + tst r3, r0 + bf .pcm16_sq_count +.pcm16_sq_flush: + mov r5, r1 + add r0, r1 + add #-32, r1 + pref @r1 + mov r6, r2 + add r0, r2 + add #-32, r2 + pref @r2 +.pcm16_sq_count: + dt r7 + bf/s .pcm16_sq_pref + add #32, r8 +.pcm16_sq_exit: + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r8 + rts + nop diff --git a/kernel/arch/dreamcast/sound/snd_stream.c b/kernel/arch/dreamcast/sound/snd_stream.c index e1063a1..14efad6 100644 --- a/kernel/arch/dreamcast/sound/snd_stream.c +++ b/kernel/arch/dreamcast/sound/snd_stream.c @@ -4,6 +4,7 @@ Copyright (C) 2000, 2001, 2002, 2003, 2004 Megan Potter Copyright (C) 2002 Florian Schulze Copyright (C) 2020 Lawrence Sebald + Copyright (C) 2023 Ruslan Rostovtsev SH-4 support routines for SPU streaming sound driver */ @@ -18,6 +19,7 @@ #include <arch/cache.h> #include <arch/timer.h> #include <dc/g2bus.h> +#include <dc/sq.h> #include <dc/spu.h> #include <dc/sound/sound.h> #include <dc/sound/stream.h> @@ -88,7 +90,7 @@ typedef struct strchan { static strchan_t streams[SND_STREAM_MAX]; // Separation buffers (for stereo) -int16 * sep_buffer[2] = { NULL, NULL }; +static uint32 *sep_buffer[2] = {NULL, NULL}; /* the address of the sound ram from the SH4 side */ #define SPU_RAM_BASE 0xa0800000 @@ -148,16 +150,13 @@ static void process_filters(snd_stream_hnd_t hnd, void **buffer, int *samplecnt) } } - -/* Performs stereo seperation for the two channels; this routine - has been optimized for the SH-4. */ static void sep_data(void *buffer, int len, int stereo) { register int16 *bufsrc, *bufdst; register int x, y, cnt; if(stereo) { bufsrc = (int16*)buffer; - bufdst = sep_buffer[0]; + bufdst = (int16 *)sep_buffer[0]; x = 0; y = 0; cnt = len / 2; @@ -172,7 +171,7 @@ static void sep_data(void *buffer, int len, int stereo) { bufsrc = (int16*)buffer; bufsrc++; - bufdst = sep_buffer[1]; + bufdst = (int16 *)sep_buffer[1]; x = 1; y = 0; cnt = len / 2; @@ -189,10 +188,29 @@ static void sep_data(void *buffer, int len, int stereo) { } else { memcpy(sep_buffer[0], buffer, len); - memcpy(sep_buffer[1], buffer, len); + sep_buffer[1] = sep_buffer[0]; } } +static void stereo_pcm16_split_sq(uint32 *data, uint32 aica_left, uint32 aica_right, uint32 size) { + + /* Wait for both store queues to complete if they are already used */ + uint32 *d = (uint32 *)0xe0000000; + d[0] = d[8] = 0; + + uint32 masked_left = (0xe0000000 | (aica_left & 0x03ffffe0)); + uint32 masked_right = (0xe0000000 | (aica_right & 0x03ffffe0)); + + /* Set store queue memory area as desired */ + QACR0 = (aica_left >> 24) & 0x1c; + QACR1 = (aica_right >> 24) & 0x1c; + + g2_fifo_wait(); + + /* Separating channels and do fill/write queues as many times necessary. */ + snd_pcm16_split_sq(data, masked_left, masked_right, size); +} + /* Prefill buffers -- do this before calling start() */ void snd_stream_prefill(snd_stream_hnd_t hnd) { void *buf; @@ -202,37 +220,34 @@ void snd_stream_prefill(snd_stream_hnd_t hnd) { if(!streams[hnd].get_data) return; - /* Load first buffer */ - /* XXX Note: This will not work if the full data size is less than - buffer_size or buffer_size/2. */ - if(streams[hnd].stereo) - buf = streams[hnd].get_data(hnd, streams[hnd].buffer_size, &got); - else - buf = streams[hnd].get_data(hnd, streams[hnd].buffer_size / 2, &got); + const uint32 buffer_size = streams[hnd].buffer_size; - process_filters(hnd, &buf, &got); - sep_data(buf, (streams[hnd].buffer_size / 2), streams[hnd].stereo); - spu_memload( - streams[hnd].spu_ram_sch[0] + (streams[hnd].buffer_size / 2) * 0, - (uint8*)sep_buffer[0], streams[hnd].buffer_size / 2); - spu_memload( - streams[hnd].spu_ram_sch[1] + (streams[hnd].buffer_size / 2) * 0, - (uint8*)sep_buffer[1], streams[hnd].buffer_size / 2); - - /* Load second buffer */ if(streams[hnd].stereo) - buf = streams[hnd].get_data(hnd, streams[hnd].buffer_size, &got); + buf = streams[hnd].get_data(hnd, buffer_size * 2, &got); else - buf = streams[hnd].get_data(hnd, streams[hnd].buffer_size / 2, &got); + buf = streams[hnd].get_data(hnd, buffer_size, &got); process_filters(hnd, &buf, &got); - sep_data(buf, (streams[hnd].buffer_size / 2), streams[hnd].stereo); - spu_memload( - streams[hnd].spu_ram_sch[0] + (streams[hnd].buffer_size / 2) * 1, - (uint8*)sep_buffer[0], streams[hnd].buffer_size / 2); - spu_memload( - streams[hnd].spu_ram_sch[1] + (streams[hnd].buffer_size / 2) * 1, - (uint8*)sep_buffer[1], streams[hnd].buffer_size / 2); + + if ((uintptr_t)buf & 31) { + sep_data(buf, got, streams[hnd].stereo); + spu_memload(streams[hnd].spu_ram_sch[0], (uint8*)sep_buffer[0], got); + spu_memload(streams[hnd].spu_ram_sch[1], (uint8*)sep_buffer[1], got); + } + else { + if (streams[hnd].stereo) { + stereo_pcm16_split_sq((uint32 *)buf, + streams[hnd].spu_ram_sch[0], + streams[hnd].spu_ram_sch[1], + got); + } + else { + g2_fifo_wait(); + sq_cpy((uint32 *)streams[hnd].spu_ram_sch[0], buf, got); + g2_fifo_wait(); + sq_cpy((uint32 *)streams[hnd].spu_ram_sch[1], buf, got); + } + } /* Start with playing on buffer 0 */ streams[hnd].last_write_pos = 0; @@ -243,8 +258,8 @@ void snd_stream_prefill(snd_stream_hnd_t hnd) { int snd_stream_init(void) { /* Create stereo seperation buffers */ if(!sep_buffer[0]) { - sep_buffer[0] = memalign(32, (SND_STREAM_BUFFER_MAX / 2)); - sep_buffer[1] = memalign(32, (SND_STREAM_BUFFER_MAX / 2)); + sep_buffer[0] = memalign(32, SND_STREAM_BUFFER_MAX); + sep_buffer[1] = sep_buffer[0] + (SND_STREAM_BUFFER_MAX / 8); } /* Finish loading the stream driver */ @@ -355,7 +370,6 @@ void snd_stream_shutdown(void) { if(sep_buffer[0]) { free(sep_buffer[0]); sep_buffer[0] = NULL; - free(sep_buffer[1]); sep_buffer[1] = NULL; } } @@ -465,6 +479,7 @@ int snd_stream_poll(snd_stream_hnd_t hnd) { int needed_samples; int got_samples; void *data; + void *first_dma_buf = sep_buffer[0]; ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: darcagn <da...@us...> - 2023-10-25 03:11:43
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 56564f79b67478b7c5b68692f1200768cec6c983 (commit) via 4dfbac4fe6f4562c7d29a413b135313466e49fd3 (commit) from d7ccfb255387c3c8c97367e1203588ae34a10721 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 56564f79b67478b7c5b68692f1200768cec6c983 Merge: d7ccfb2 4dfbac4 Author: darcagn <da...@pr...> Date: Tue Oct 24 22:10:58 2023 -0500 Merge pull request #331 from KallistiOS/maple_fix Added include for maple.h to fix KGL examples commit 4dfbac4fe6f4562c7d29a413b135313466e49fd3 Author: Falco Girgis <gyr...@gm...> Date: Tue Oct 24 22:09:24 2023 -0500 Added include for maple.h to fix KGL examples ----------------------------------------------------------------------- Summary of changes: examples/dreamcast/kgl/basic/elements/gl-elements.c | 1 + examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/dreamcast/kgl/basic/elements/gl-elements.c b/examples/dreamcast/kgl/basic/elements/gl-elements.c index fd70fe4..e1638a9 100644 --- a/examples/dreamcast/kgl/basic/elements/gl-elements.c +++ b/examples/dreamcast/kgl/basic/elements/gl-elements.c @@ -16,6 +16,7 @@ #include <GL/glut.h> #include <kos/init.h> +#include <dc/maple.h> #include <dc/maple/controller.h> /* Load a PVR texture - located in pvr-texture.c */ diff --git a/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c b/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c index 49fa666..ee3ba5f 100644 --- a/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c +++ b/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c @@ -16,6 +16,7 @@ #include <GL/glut.h> #include <kos/init.h> +#include <dc/maple.h> #include <dc/maple/controller.h> /* Load a PVR texture - located in pvr-texture.c */ hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: darcagn <da...@us...> - 2023-10-25 02:57:01
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via d7ccfb255387c3c8c97367e1203588ae34a10721 (commit) via 531663982cbef4b265ffd8cb79918687837e0c40 (commit) from 6da37bf27613e8cb64db4ae00f46af20ed98330e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d7ccfb255387c3c8c97367e1203588ae34a10721 Merge: 6da37bf 5316639 Author: darcagn <da...@pr...> Date: Tue Oct 24 21:55:23 2023 -0500 Merge pull request #330 from KallistiOS/maple_fix Fixed broken KGL examples commit 531663982cbef4b265ffd8cb79918687837e0c40 Author: Falco Girgis <gyr...@gm...> Date: Tue Oct 24 21:51:41 2023 -0500 Fixed broken KGL examples - When we added "press start to exit," we forgot to include controller.h in a few places ----------------------------------------------------------------------- Summary of changes: examples/dreamcast/kgl/basic/elements/gl-elements.c | 1 + examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/dreamcast/kgl/basic/elements/gl-elements.c b/examples/dreamcast/kgl/basic/elements/gl-elements.c index 2a2fd2e..fd70fe4 100644 --- a/examples/dreamcast/kgl/basic/elements/gl-elements.c +++ b/examples/dreamcast/kgl/basic/elements/gl-elements.c @@ -16,6 +16,7 @@ #include <GL/glut.h> #include <kos/init.h> +#include <dc/maple/controller.h> /* Load a PVR texture - located in pvr-texture.c */ extern GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap); diff --git a/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c b/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c index a18e829..49fa666 100644 --- a/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c +++ b/examples/dreamcast/kgl/basic/zclip_arrays/gl-arrays.c @@ -16,6 +16,7 @@ #include <GL/glut.h> #include <kos/init.h> +#include <dc/maple/controller.h> /* Load a PVR texture - located in pvr-texture.c */ extern GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap); hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-10-24 17:14:47
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 6da37bf27613e8cb64db4ae00f46af20ed98330e (commit) from 8b380271151dea406c82ff4dd9179621ef1247cd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6da37bf27613e8cb64db4ae00f46af20ed98330e Author: Ruslan Rostovtsev <sw...@21...> Date: Wed Oct 25 00:14:12 2023 +0700 SH4 cache improvements (#327) * Add support for purge the entire data/operand cache * Add support for allocate a block of data/operand cache. ----------------------------------------------------------------------- Summary of changes: kernel/arch/dreamcast/include/arch/cache.h | 43 +++++++++++++++++++----------- kernel/arch/dreamcast/kernel/cache.s | 33 +++++++++++------------ kernel/exports.txt | 2 +- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/kernel/arch/dreamcast/include/arch/cache.h b/kernel/arch/dreamcast/include/arch/cache.h index 5208ddb..602f2b3 100644 --- a/kernel/arch/dreamcast/include/arch/cache.h +++ b/kernel/arch/dreamcast/include/arch/cache.h @@ -76,32 +76,45 @@ void dcache_flush_range(uint32 start, uint32 count); */ void dcache_purge_range(uint32 start, uint32 count); -/** \brief Prefetch memory to the data/operand cache. +/** \brief Purge all the data/operand cache. - This function prefetch a range of the data/operand cache. + This function flushes all the data/operand cache, forcing a write- + back and invalidate on all of the cache blocks. + + \param start The physical address for temporary buffer (32-byte aligned) + \param count The number of bytes of temporary buffer (8 KB or 16 KB) - \param start The physical address to begin prefetching at. - \param count The number of bytes to prefetch. - \return The physical address aligned to cache block size. */ -void *dcache_pref_range(uint32 start, uint32 count); +void dcache_purge_all(uint32 start, uint32 count); /** \brief Prefetch one block to the data/operand cache. - This function prefetch a range of the data/operand cache. + This function prefetch a block of the data/operand cache. - \param src The buffer to prefetch. - \return The buffer aligned to cache block size. + \param src The physical address to prefetch. */ -static __always_inline void *dcache_pref_block(const void *src) { - uint32 __cache_aligned = ((uint32)src) & ~(CPU_CACHE_BLOCK_SIZE - 1); - __asm__ __volatile__("pref @%[ptr]\n" - : - : [ptr] "r" (__cache_aligned) +static __always_inline void dcache_pref_block(const void *src) { + __asm__ __volatile__("pref @%0\n" : + : "r" (src) + : "memory" ); +} + +/** \brief Allocate one block of the data/operand cache. - return (void *)__cache_aligned; + This function allocate a block of the data/operand cache. + + \param src The physical address to allocate. + \param value The value written to first 4-byte. +*/ +static __always_inline void dcache_alloc_block(const void *src, uint32 value) { + register int __value __asm__("r0") = value; + __asm__ __volatile__ ("movca.l r0,@%0\n\t" + : + : "r" (src), "r" (__value) + : "memory" + ); } __END_DECLS diff --git a/kernel/arch/dreamcast/kernel/cache.s b/kernel/arch/dreamcast/kernel/cache.s index 9172a20..c2b8bdc 100644 --- a/kernel/arch/dreamcast/kernel/cache.s +++ b/kernel/arch/dreamcast/kernel/cache.s @@ -10,7 +10,7 @@ .globl _dcache_inval_range .globl _dcache_flush_range .globl _dcache_purge_range - .globl _dcache_pref_range + .globl _dcache_purge_all ! r4 is starting address ! r5 is count @@ -149,25 +149,22 @@ dpurge_loop: rts nop -! This routine prefetch to operand cache the specified data range. -! r4 is starting address -! r5 is count -_dcache_pref_range: - ! Get ending address from count and align start address - add r4,r5 - mov.l l1align,r0 - and r0,r4 - mov r4,r6 - -dpref_loop: - ! Prefetch to the O cache - pref @r4 - cmp/hs r4,r5 - bt/s dpref_loop - add #32,r4 ! += CPU_CACHE_BLOCK_SIZE +! This routine just forces a write-back and invalidate all O cache. +! r4 is address for temporary buffer 32-byte aligned +! r5 is size of temporary buffer (8 KB or 16 KB) +_dcache_purge_all: + mov #0, r0 + add r4, r5 +dpurge_all_loop: + ! Allocate and then invalidate the O cache block + movca.l r0, @r4 + ocbi @r4 + cmp/hs r4, r5 + bt/s dpurge_all_loop + add #32, r4 ! += CPU_CACHE_BLOCK_SIZE rts - mov r6,r0 + nop .align 2 diff --git a/kernel/exports.txt b/kernel/exports.txt index 3052c20..961ea1d 100644 --- a/kernel/exports.txt +++ b/kernel/exports.txt @@ -174,7 +174,7 @@ icache_flush_range dcache_inval_range dcache_flush_range dcache_purge_range -dcache_pref_range +dcache_purge_all # Low-level debug I/O dbgio_set_irq_usage hooks/post-receive -- A pseudo Operating System for the Dreamcast. |
From: ljsebald <ljs...@us...> - 2023-10-24 01:49:32
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 8b380271151dea406c82ff4dd9179621ef1247cd (commit) from 1526b24db29723634ae096a139f70a918eb428fd (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8b380271151dea406c82ff4dd9179621ef1247cd Author: Andress Barajas <and...@gm...> Date: Mon Oct 23 18:48:59 2023 -0700 Store Queue Refresh (#320) * Refresh store queue code with some potential (big) speed improvements under certain circumstances. * Use __builtin_prefetch where appropriate in SQ code. * Add specific SQ function for accessing PVR RAM with 64-bit access. * Improve doxygen comments for SQ functions. ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG | 1 + kernel/arch/dreamcast/hardware/sq.c | 223 ++++++++++++++++++---------------- kernel/arch/dreamcast/include/dc/sq.h | 176 ++++++++++++++++++++++----- 3 files changed, 265 insertions(+), 135 deletions(-) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index b52310c..19d1e75 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -192,6 +192,7 @@ KallistiOS version 2.1.0 ----------------------------------------------- - *** Added toolchain and KOS support for C/C++ compiler-level TLS [CP && FG] - DC Added vmu functions to check/enable/disable the extra 41 blocks [AB] - *** Added driver for the SH4's Watchdog Timer peripheral [FG] +- DC Added Moop powered fast path to sq_cpy, added TapamN pvr related sq functions [AB] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Megan Potter == MP] diff --git a/kernel/arch/dreamcast/hardware/sq.c b/kernel/arch/dreamcast/hardware/sq.c index 263074a..8fa9947 100644 --- a/kernel/arch/dreamcast/hardware/sq.c +++ b/kernel/arch/dreamcast/hardware/sq.c @@ -2,165 +2,176 @@ kernel/arch/dreamcast/hardware/sq.c Copyright (C) 2001 Andrew Kieschnick + Copyright (C) 2023 Falco Girgis + Copyright (C) 2023 Andy Barajas */ -#include <arch/memory.h> #include <dc/sq.h> +#include <kos/dbglog.h> /* Functions to clear, copy, and set memory using the sh4 store queues - Based on code by Marcus Comstedt (store_q_clear from tatest) + Based on code by Marcus Comstedt, TapamN, and Moop */ -/* clears n bytes at dest, dest must be 32-byte aligned */ -void sq_clr(void *dest, int n) { - unsigned int *d = (unsigned int *)(void *) - (MEM_AREA_SQ_BASE | (((unsigned long)dest) & 0x03ffffe0)); - - /* Set store queue memory area as desired */ - QACR0 = ((((unsigned int)dest) >> 26) << 2) & 0x1c; - QACR1 = ((((unsigned int)dest) >> 26) << 2) & 0x1c; - - /* Fill both store queues with zeroes */ - d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = - d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = 0; - - /* Write them as many times necessary */ - n >>= 5; - - while(n--) { - __asm__("pref @%0" : : "r"(d)); - d += 8; - } - - /* Wait for both store queues to complete */ - d = (unsigned int *)MEM_AREA_SQ_BASE; - d[0] = d[8] = 0; -} - -/* copies n bytes from src to dest, dest must be 32-byte aligned */ +/* Copies n bytes from src to dest, dest must be 32-byte aligned */ void * sq_cpy(void *dest, const void *src, int n) { - unsigned int *d = (unsigned int *)(void *) - (MEM_AREA_SQ_BASE | (((unsigned long)dest) & 0x03ffffe0)); - const unsigned int *s = src; + uint32_t *d = SQ_MASK_DEST(dest); + const uint32_t *s = src; + + _Complex float ds; + _Complex float ds2; + _Complex float ds3; + _Complex float ds4; /* Set store queue memory area as desired */ - QACR0 = ((((unsigned int)dest) >> 26) << 2) & 0x1c; - QACR1 = ((((unsigned int)dest) >> 26) << 2) & 0x1c; + SET_QACR_REGS(dest); - /* fill/write queues as many times necessary */ + /* Fill/write queues as many times necessary */ n >>= 5; - while(n--) { - __asm__("pref @%0" : : "r"(s + 8)); /* prefetch 32 bytes */ - d[0] = *(s++); - d[1] = *(s++); - d[2] = *(s++); - d[3] = *(s++); - d[4] = *(s++); - d[5] = *(s++); - d[6] = *(s++); - d[7] = *(s++); - __asm__("pref @%0" : : "r"(d)); - d += 8; + /* If src is not 8-byte aligned, slow path */ + if ((uintptr_t)src & 7) { + while(n--) { + __builtin_prefetch(s + 8); /* Prefetch 32 bytes for next loop */ + d[0] = *(s++); + d[1] = *(s++); + d[2] = *(s++); + d[3] = *(s++); + d[4] = *(s++); + d[5] = *(s++); + d[6] = *(s++); + d[7] = *(s++); + + /* Fire off store queue. __builtin would move it to the top so + use __asm__ instead */ + __asm__("pref @%0" : : "r"(d)); + d += 8; + } + } else { /* If src is 8-byte aligned, fast path */ + /* Moop algorithm; Using the fpu we can fill the queue faster before + firing it out off */ + __asm__ __volatile__ ( + "fschg\n\t" + "clrs\n" + ".align 2\n" + "1:\n\t" + /* *d++ = *s++ */ + "fmov.d @%[in]+, %[scratch]\n\t" + "fmov.d @%[in]+, %[scratch2]\n\t" + "fmov.d @%[in]+, %[scratch3]\n\t" + "fmov.d @%[in]+, %[scratch4]\n\t" + "add #32, %[out]\n\t" + "pref @%[in]\n\t" /* Prefetch 32 bytes for next loop */ + "dt %[size]\n\t" /* while(n--) */ + "fmov.d %[scratch4], @-%[out]\n\t" + "fmov.d %[scratch3], @-%[out]\n\t" + "fmov.d %[scratch2], @-%[out]\n\t" + "fmov.d %[scratch], @-%[out]\n\t" + "pref @%[out]\n\t" /* Fire off store queue */ + "bf.s 1b\n\t" + "add #32, %[out]\n\t" + "fschg\n" + : [in] "+&r" ((uint32_t)s), [out] "+&r" ((uint32_t)d), + [size] "+&r" (n), [scratch] "=&d" (ds), [scratch2] "=&d" (ds2), + [scratch3] "=&d" (ds3), [scratch4] "=&d" (ds4) /* outputs */ + : /* inputs */ + : "t", "memory" /* clobbers */ + ); } /* Wait for both store queues to complete */ - d = (unsigned int *)MEM_AREA_SQ_BASE; + d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; return dest; } -/* fills n bytes at s with byte c, s must be 32-byte aligned */ -void * sq_set(void *s, uint32 c, int n) { - unsigned int *d = (unsigned int *)(void *) - (MEM_AREA_SQ_BASE | (((unsigned long)s) & 0x03ffffe0)); - - /* Set store queue memory area as desired */ - QACR0 = ((((unsigned int)s) >> 26) << 2) & 0x1c; - QACR1 = ((((unsigned int)s) >> 26) << 2) & 0x1c; - - /* duplicate low 8-bits of c into high 24-bits */ +/* Fills n bytes at dest with byte c, dest must be 32-byte aligned */ +void * sq_set(void *dest, uint32_t c, int n) { + /* Duplicate low 8-bits of c into high 24-bits */ c = c & 0xff; c = (c << 24) | (c << 16) | (c << 8) | c; - /* Fill both store queues with c */ - d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = - d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = c; - - /* Write them as many times necessary */ - n >>= 5; - - while(n--) { - __asm__("pref @%0" : : "r"(d)); - d += 8; - } + return sq_set32(dest, c, n); +} - /* Wait for both store queues to complete */ - d = (unsigned int *)MEM_AREA_SQ_BASE; - d[0] = d[8] = 0; +/* Fills n bytes at dest with short c, dest must be 32-byte aligned */ +void * sq_set16(void *dest, uint32_t c, int n) { + /* Duplicate low 16-bits of c into high 16-bits */ + c = c & 0xffff; + c = (c << 16) | c; - return s; + return sq_set32(dest, c, n); } -/* fills n bytes at s with short c, s must be 32-byte aligned */ -void * sq_set16(void *s, uint32 c, int n) { - unsigned int *d = (unsigned int *)(void *) - (MEM_AREA_SQ_BASE | (((unsigned long)s) & 0x03ffffe0)); +/* Fills n bytes at dest with int c, dest must be 32-byte aligned */ +void * sq_set32(void *dest, uint32_t c, int n) { + uint32_t *d = SQ_MASK_DEST(dest); /* Set store queue memory area as desired */ - QACR0 = ((((unsigned int)s) >> 26) << 2) & 0x1c; - QACR1 = ((((unsigned int)s) >> 26) << 2) & 0x1c; - - /* duplicate low 16-bits of c into high 16-bits */ - c = c & 0xffff; - c = (c << 16) | c; + SET_QACR_REGS(dest); /* Fill both store queues with c */ d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = - d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = c; + d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = c; /* Write them as many times necessary */ n >>= 5; while(n--) { - __asm__("pref @%0" : : "r"(d)); + __builtin_prefetch(d); d += 8; } /* Wait for both store queues to complete */ - d = (unsigned int *)MEM_AREA_SQ_BASE; + d = (uint32_t *)MEM_AREA_SQ_BASE; d[0] = d[8] = 0; - return s; + return dest; } -/* fills n bytes at s with int c, s must be 32-byte aligned */ -void * sq_set32(void *s, uint32 c, int n) { - unsigned int *d = (unsigned int *)(void *) - (MEM_AREA_SQ_BASE | (((unsigned long)s) & 0x03ffffe0)); +/* Clears n bytes at dest, dest must be 32-byte aligned */ +void sq_clr(void *dest, int n) { + sq_set32(dest, 0, n); +} - /* Set store queue memory area as desired */ - QACR0 = ((((unsigned int)s) >> 26) << 2) & 0x1c; - QACR1 = ((((unsigned int)s) >> 26) << 2) & 0x1c; +#define PVR_LMMODE (*(volatile uint32_t *)(void *)0xa05f6884) +#define PVR_DMA_DEST (*(volatile uint32_t *)(void *)0xa05f6808) - /* Fill both store queues with c */ - d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = - d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = c; +/* Copies n bytes from src to dest (in VRAM), dest must be 32-byte aligned */ +void * sq_cpy_pvr(void *dest, const void *src, int n) { + if(PVR_DMA_DEST != 0) { + dbglog(DBG_ERROR, "sq_cpy_pvr: Previous DMA has not finished\n"); + return NULL; + } - /* Write them as many times necessary */ - n >>= 5; + /* Set PVR LMMODE register */ + PVR_LMMODE = 0; - while(n--) { - __asm__("pref @%0" : : "r"(d)); - d += 8; + /* Convert read/write area pointer to DMA write only area pointer */ + uint32_t dma_area_ptr = (((uintptr_t)dest & 0xffffff) | 0x11000000); + + sq_cpy((void *)dma_area_ptr, src, n); + + return dest; +} + +/* Fills n bytes at PVR dest with short c, dest must be 32-byte aligned */ +void * sq_set_pvr(void *dest, uint32_t c, int n) { + if(PVR_DMA_DEST != 0) { + dbglog(DBG_ERROR, "sq_set_pvr: Previous DMA has not finished\n"); + return NULL; } - /* Wait for both store queues to complete */ - d = (unsigned int *)MEM_AREA_SQ_BASE; - d[0] = d[8] = 0; + /* Set PVR LMMODE register */ + PVR_LMMODE = 0; - return s; + /* Convert read/write area pointer to DMA write only area pointer */ + uint32_t dma_area_ptr = (((uintptr_t)dest & 0xffffff) | 0x11000000); + + sq_set16((void *)dma_area_ptr, c, n); + + return dest; } diff --git a/kernel/arch/dreamcast/include/dc/sq.h b/kernel/arch/dreamcast/include/dc/sq.h index 011f557..c570a0e 100644 --- a/kernel/arch/dreamcast/include/dc/sq.h +++ b/kernel/arch/dreamcast/include/dc/sq.h @@ -1,19 +1,33 @@ /* KallistiOS ##version## kernel/arch/dreamcast/include/dc/sq.h - (C)2000-2001 Andrew Kieschnick + Copyright (C) 2000-2001 Andrew Kieschnick + Copyright (C) 2023 Falco Girgis + Copyright (C) 2023 Andy Barajas +*/ + +/** \file dc/sq.h + \ingroup store_queues + \brief Functions to access the SH4 Store Queues. + \author Andrew Kieschnick */ -/** \file dc/sq.h - \brief Functions to access the SH4 Store Queues. +/** \defgroup store_queues Store Queues + \brief SH4 CPU Peripheral for burst memory transactions. The store queues are a way to do efficient burst transfers from the CPU to external memory. They can be used in a variety of ways, such as to transfer a texture to PVR memory. The transfers are in units of 32-bytes, and the destinations must be 32-byte aligned. - \author Andrew Kieschnick + \note + Mastery over knowing when and how to utilize the store queues is + important when trying to push the limits of the Dreamcast, specifically + when transferring chunks of data between regions of memory. It is often + the case that the DMA is faster for transactions which are consistently + large; however, the store queues tend to have better performance and + have less configuration overhead when bursting smaller chunks of data. */ #ifndef __DC_SQ_H @@ -22,73 +36,177 @@ #include <sys/cdefs.h> __BEGIN_DECLS +#include <stdint.h> #include <arch/types.h> +#include <arch/memory.h> -/** \brief Store Queue 0 access register */ -#define QACR0 (*(volatile unsigned int *)(void *)0xff000038) - -/** \brief Store Queue 1 access register */ -#define QACR1 (*(volatile unsigned int *)(void *)0xff00003c) - -/** \brief Clear a block of memory. +/** \brief Store Queue 0 access register + \ingroup store_queues +*/ +#define QACR0 (*(volatile uint32_t *)(void *)0xff000038) - This function is similar to calling memset() with a value to set of 0, but - uses the store queues to do its work. +/** \brief Store Queue 1 access register + \ingroup store_queues +*/ +#define QACR1 (*(volatile uint32_t *)(void *)0xff00003c) - \param dest The address to begin clearing at (32-byte aligned). - \param n The number of bytes to clear (multiple of 32). +/** \brief Set Store Queue QACR* registers + \ingroup store_queues */ -void sq_clr(void *dest, int n); +#define SET_QACR_REGS(dest) \ + do { \ + uint32_t val = ((uint32_t)(dest)) >> 24; \ + QACR0 = val; \ + QACR1 = val; \ + } while(0) + +/** \brief Mask dest to Store Queue area + \ingroup store_queues +*/ +#define SQ_MASK_DEST(dest) \ + ((uint32_t *)(void *) \ + (MEM_AREA_SQ_BASE | \ + (((uint32_t)(dest)) & 0x03ffffe0))) -/** \brief Copy a block of memory. +/** \brief Copy a block of memory. + \ingroup store_queues This function is similar to memcpy4(), but uses the store queues to do its work. + \warning + The dest pointer must be at least 32-byte aligned, the src pointer + must be at least 4-byte aligned (8-byte aligned uses fast path), + and n must be a multiple of 32! + \param dest The address to copy to (32-byte aligned). - \param src The address to copy from (32-bit (4-byte) aligned). + \param src The address to copy from (32-bit (4/8-byte) aligned). \param n The number of bytes to copy (multiple of 32). \return The original value of dest. + + \sa sq_cpy_pvr() */ void * sq_cpy(void *dest, const void *src, int n); -/** \brief Set a block of memory to an 8-bit value. +/** \brief Set a block of memory to an 8-bit value. + \ingroup store_queues This function is similar to calling memset(), but uses the store queues to do its work. - \param s The address to begin setting at (32-byte aligned). - \param c The value to set (in the low 8-bits). + \warning + The dest pointer must be a 32-byte aligned with n being a multiple of 32, + and only the low 8-bits are used from c. + + \param dest The address to begin setting at (32-byte aligned). + \param src The value to set (in the low 8-bits). \param n The number of bytes to set (multiple of 32). \return The original value of dest. + + \sa sq_set16(), sq_set32(), sq_set_pvr() */ -void * sq_set(void *s, uint32 c, int n); +void * sq_set(void *dest, uint32 c, int n); -/** \brief Set a block of memory to a 16-bit value. +/** \brief Set a block of memory to a 16-bit value. + \ingroup store_queues This function is similar to calling memset2(), but uses the store queues to do its work. - \param s The address to begin setting at (32-byte aligned). + \warning + The dest pointer must be a 32-byte aligned with n being a multiple of 32, + and only the low 16-bits are used from c. + + \param dest The address to begin setting at (32-byte aligned). \param c The value to set (in the low 16-bits). \param n The number of bytes to set (multiple of 32). \return The original value of dest. + + \sa sq_set(), sq_set32(), sq_set_pvr() */ -void * sq_set16(void *s, uint32 c, int n); +void * sq_set16(void *dest, uint32 c, int n); -/** \brief Set a block of memory to a 32-bit value. +/** \brief Set a block of memory to a 32-bit value. + \ingroup store_queues This function is similar to calling memset4(), but uses the store queues to do its work. - \param s The address to begin setting at (32-byte aligned). + \warning + The dest pointer must be a 32-byte aligned with n being a multiple of 32! + + \param dest The address to begin setting at (32-byte aligned). \param c The value to set (all 32-bits). \param n The number of bytes to set (multiple of 32). \return The original value of dest. + + \sa sq_set(), sq_set16(), sq_set_pvr() */ -void * sq_set32(void *s, uint32 c, int n); +void * sq_set32(void *dest, uint32 c, int n); + +/** \brief Clear a block of memory. + \ingroup store_queues + + This function is similar to calling memset() with a value to set of 0, but + uses the store queues to do its work. + + \warning + The dest pointer must be a 32-byte aligned with n being a multiple of 32! + + \param dest The address to begin clearing at (32-byte aligned). + \param n The number of bytes to clear (multiple of 32). +*/ +void sq_clr(void *dest, int n); + +/** \brief Copy a block of memory to VRAM + \ingroup store_queues + \author TapamN + + This function is similar to sq_cpy(), but it has been + optimized for writing to a destination residing within VRAM. + + \note + TapamN has reported over a 2x speedup versus the regular + sq_cpy() when using this function to write to VRAM. + + \warning + This function cannot be used at the same time as a PVR DMA transfer. + + The dest pointer must be at least 32-byte aligned and reside + in video memory, the src pointer must be at least 8-byte aligned, ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |