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. |