dma: add exception handler and dma_memset()

This commit is contained in:
lephe 2019-08-27 21:18:44 +02:00
parent 652637d475
commit 6d54a5fe0a
5 changed files with 76 additions and 43 deletions

View file

@ -55,7 +55,7 @@ typedef enum
@dst Destination address, must be aligned with transfer size @dst Destination address, must be aligned with transfer size
@dst_mode Destination address mode */ @dst_mode Destination address mode */
void dma_transfer(int channel, dma_size_t size, uint length, void dma_transfer(int channel, dma_size_t size, uint length,
void *src, dma_address_t src_mode, void const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode); void *dst, dma_address_t dst_mode);
/* dma_transfer_wait() - Wait for a transfer on channel 0 to finish /* dma_transfer_wait() - Wait for a transfer on channel 0 to finish
@ -76,7 +76,7 @@ void dma_transfer_wait(int channel);
Not using interrupts is a bad design idea for a majority of programs, and is Not using interrupts is a bad design idea for a majority of programs, and is
only ever needed to display panic messages inside exception handlers. */ only ever needed to display panic messages inside exception handlers. */
void dma_transfer_noint(int channel, dma_size_t size, uint blocks, void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
void *src, dma_address_t src_mode, void const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode); void *dst, dma_address_t dst_mode);
#endif /* GINT_DMA */ #endif /* GINT_DMA */

View file

@ -13,7 +13,7 @@
typedef volatile sh7305_dma_channel_t channel_t; typedef volatile sh7305_dma_channel_t channel_t;
/* dma_channel(): returns address of the specified DMA channel */ /* dma_channel(): Get address of a DMA channel */
static channel_t *dma_channel(int channel) static channel_t *dma_channel(int channel)
{ {
channel_t *addr[6] = { channel_t *addr[6] = {
@ -24,6 +24,36 @@ static channel_t *dma_channel(int channel)
return ((uint)channel >= 6 ? NULL : addr[channel]); return ((uint)channel >= 6 ? NULL : addr[channel]);
} }
/* dma_translate(): Translate virtual address to DMA-suitable form */
static uint32_t dma_translate(void const *address)
{
uint32_t a = (uint32_t)address;
/* Preserve RS addresses (as of SH7724 Reference, 11.2.2) */
if(a >= 0xfd800000 && a < 0xfd800800)
return a;
/* Translate virtual addresses to IL memory to physical addresses; the
same address is used (as of SH7724 Reference, 10.3.3) */
if(a >= 0xe5200000 && a < 0xe5204000)
return a;
/* First additional on-chip memory area (XRAM) */
if(a >= 0xe5007000 && a < 0xE5009000)
return a;
/* Second on-chip memory area (YRAM) */
if(a >= 0xe5017000 && a < 0xe5019000)
return a;
/* Translate P1 and P2 addresses to ROM and RAM to physical form */
if(a >= 0x80000000 && a < 0xc0000000)
return a & 0x1fffffff;
/* By default: I don't know what this is, let's preserve it */
return a;
}
//--- //---
// Driver interface // Driver interface
//--- //---
@ -33,7 +63,7 @@ static channel_t *dma_channel(int channel)
last parameter indicates whether interrupts should be used. last parameter indicates whether interrupts should be used.
Returns non-zero if the DMA is busy or a configuration error occurs. */ Returns non-zero if the DMA is busy or a configuration error occurs. */
static int dma_setup(int channel, dma_size_t size, uint blocks, static int dma_setup(int channel, dma_size_t size, uint blocks,
void *src, dma_address_t src_mode, void const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode, void *dst, dma_address_t dst_mode,
int interrupts) int interrupts)
{ {
@ -48,8 +78,8 @@ static int dma_setup(int channel, dma_size_t size, uint blocks,
DMA.OR.DME = 0; DMA.OR.DME = 0;
/* Set DMA source and target address */ /* Set DMA source and target address */
ch->SAR = (uint32_t)src & 0x1fffffff; ch->SAR = dma_translate(src);
ch->DAR = (uint32_t)dst & 0x1fffffff; ch->DAR = dma_translate(dst);
/* Set the number of blocks to be transferred */ /* Set the number of blocks to be transferred */
ch->TCR = blocks; ch->TCR = blocks;
@ -74,7 +104,7 @@ static int dma_setup(int channel, dma_size_t size, uint blocks,
/* dma_transfer(): Perform a data transfer */ /* dma_transfer(): Perform a data transfer */
void dma_transfer(int channel, dma_size_t size, uint blocks, void dma_transfer(int channel, dma_size_t size, uint blocks,
void *src, dma_address_t src_mode, void const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode) void *dst, dma_address_t dst_mode)
{ {
if(dma_setup(channel, size, blocks, src, src_mode, dst, dst_mode, 1)) if(dma_setup(channel, size, blocks, src, src_mode, dst, dst_mode, 1))
@ -97,7 +127,7 @@ void dma_transfer_wait(int channel)
/* dma_transfer_noint(): Perform a data transfer without interruptions */ /* dma_transfer_noint(): Perform a data transfer without interruptions */
void dma_transfer_noint(int channel, dma_size_t size, uint blocks, void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
void *src, dma_address_t src_mode, void const *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode) void *dst, dma_address_t dst_mode)
{ {
if(dma_setup(channel, size, blocks, src, src_mode, dst, dst_mode, 0)) if(dma_setup(channel, size, blocks, src, src_mode, dst, dst_mode, 0))
@ -130,7 +160,6 @@ static void init(void)
if(isSH3()) return; if(isSH3()) return;
/* Install the interrupt handler from dma/inth.s */ /* Install the interrupt handler from dma/inth.s */
/* TODO: DMA0 error gate is 0xbc0 */
int codes[] = { 0x800, 0x820, 0x840, 0x860, 0xb80, 0xba0 }; int codes[] = { 0x800, 0x820, 0x840, 0x860, 0xb80, 0xba0 };
extern void inth_dma_te(void); extern void inth_dma_te(void);
@ -146,15 +175,18 @@ static void init(void)
ch->CHCR.DE = 0; ch->CHCR.DE = 0;
} }
/* Install the address error gate */
extern void inth_dma_ae(void);
gint_inthandler(0xbc0, inth_dma_ae, 32);
/* Set interrupt priority to 3 (IPRE[15..12] for first three channels, /* Set interrupt priority to 3 (IPRE[15..12] for first three channels,
IPRF[11..8] for last two and error gate */ IPRF[11..8] for last two and error gate */
gint_intlevel(16, 3); gint_intlevel(16, 3);
gint_intlevel(21, 3); gint_intlevel(21, 3);
/* Unmask the channel interrupts */ /* Unmask the channel interrupts and the address error */
/* TODO: DMA0 error gate is IMR5 & 0x40 */
INTC.MSKCLR->IMR1 = 0x0f; INTC.MSKCLR->IMR1 = 0x0f;
INTC.MSKCLR->IMR5 = 0x30; INTC.MSKCLR->IMR5 = 0x70;
/* Clear blocking flags and enable the master switch */ /* Clear blocking flags and enable the master switch */
DMA.OR.AE = 0; DMA.OR.AE = 0;

View file

@ -4,6 +4,7 @@
*/ */
.global _inth_dma_te .global _inth_dma_te
.global _inth_dma_ae
.section .gint.blocks, "ax" .section .gint.blocks, "ax"
.align 4 .align 4
@ -29,3 +30,20 @@ _inth_dma_te:
1: .long 0 /* CHCR, set dynamically */ 1: .long 0 /* CHCR, set dynamically */
2: .long 0xfe008060 /* DMA.OR */ 2: .long 0xfe008060 /* DMA.OR */
/* DMA ADDRESS ERROR INTERRUPT HANDLER - 18 BYTES */
_inth_dma_ae:
/* Call a fixed function */
sts.l pr, @-r15
mov.l 1f, r1
jsr @r1
nop
lds.l @r15+, pr
rte
nop
.zero 14
1: .long _dma_address_error

11
src/dma/memset.c Normal file
View file

@ -0,0 +1,11 @@
#include <gint/dma.h>
/* dma_memset(): Fast memset for highly-aligned addresses */
void dma_memset(void *dst, uint32_t l, size_t size)
{
/* TODO: Use a proper IL memory allocation scheme */
uint32_t *IL = (void *)0xe5200000;
for(int i = 0; i < 8; i++) IL[i] = l;
dma_transfer_noint(1, DMA_32B, size >> 5, IL, DMA_FIXED, dst, DMA_INC);
}

View file

@ -1,38 +1,10 @@
#define GINT_NEED_VRAM #define GINT_NEED_VRAM
#include <gint/display.h> #include <gint/display.h>
#include <gint/dma.h>
/* dclear() - fill the screen with a single color */ /* dclear() - fill the screen with a single color */
void dclear(uint16_t color) void dclear(uint16_t color)
{ {
/* TOOD: render-cg: dclear(): Consider using the DMA */ dma_memset(vram, (color << 16) | color, 396 * 224 * 2);
return;
/* Operate in longwords to clear faster. Also start at the end of the
VRAM to take advantage of pre-decrement writes. */
uint32_t *v = (void *)(vram + 88704);
uint32_t op = (color << 16) | color;
/* Split the VRAM into 2772 blocks of 16 longwords to reduce the
overhead of the loop */
for(int blocks = 2772; blocks; blocks--)
{
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
*--v = op;
}
} }