mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
dma: add exception handler and dma_memset()
This commit is contained in:
parent
652637d475
commit
6d54a5fe0a
5 changed files with 76 additions and 43 deletions
|
@ -55,7 +55,7 @@ typedef enum
|
|||
@dst Destination address, must be aligned with transfer size
|
||||
@dst_mode Destination address mode */
|
||||
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);
|
||||
|
||||
/* 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
|
||||
only ever needed to display panic messages inside exception handlers. */
|
||||
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);
|
||||
|
||||
#endif /* GINT_DMA */
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
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)
|
||||
{
|
||||
channel_t *addr[6] = {
|
||||
|
@ -24,6 +24,36 @@ static channel_t *dma_channel(int 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
|
||||
//---
|
||||
|
@ -33,7 +63,7 @@ static channel_t *dma_channel(int channel)
|
|||
last parameter indicates whether interrupts should be used.
|
||||
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,
|
||||
void *src, dma_address_t src_mode,
|
||||
void const *src, dma_address_t src_mode,
|
||||
void *dst, dma_address_t dst_mode,
|
||||
int interrupts)
|
||||
{
|
||||
|
@ -48,8 +78,8 @@ static int dma_setup(int channel, dma_size_t size, uint blocks,
|
|||
DMA.OR.DME = 0;
|
||||
|
||||
/* Set DMA source and target address */
|
||||
ch->SAR = (uint32_t)src & 0x1fffffff;
|
||||
ch->DAR = (uint32_t)dst & 0x1fffffff;
|
||||
ch->SAR = dma_translate(src);
|
||||
ch->DAR = dma_translate(dst);
|
||||
|
||||
/* Set the number of blocks to be transferred */
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
if(dma_setup(channel, size, blocks, src, src_mode, dst, dst_mode, 0))
|
||||
|
@ -130,7 +160,6 @@ static void init(void)
|
|||
if(isSH3()) return;
|
||||
|
||||
/* Install the interrupt handler from dma/inth.s */
|
||||
/* TODO: DMA0 error gate is 0xbc0 */
|
||||
int codes[] = { 0x800, 0x820, 0x840, 0x860, 0xb80, 0xba0 };
|
||||
extern void inth_dma_te(void);
|
||||
|
||||
|
@ -146,15 +175,18 @@ static void init(void)
|
|||
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,
|
||||
IPRF[11..8] for last two and error gate */
|
||||
gint_intlevel(16, 3);
|
||||
gint_intlevel(21, 3);
|
||||
|
||||
/* Unmask the channel interrupts */
|
||||
/* TODO: DMA0 error gate is IMR5 & 0x40 */
|
||||
/* Unmask the channel interrupts and the address error */
|
||||
INTC.MSKCLR->IMR1 = 0x0f;
|
||||
INTC.MSKCLR->IMR5 = 0x30;
|
||||
INTC.MSKCLR->IMR5 = 0x70;
|
||||
|
||||
/* Clear blocking flags and enable the master switch */
|
||||
DMA.OR.AE = 0;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
.global _inth_dma_te
|
||||
.global _inth_dma_ae
|
||||
.section .gint.blocks, "ax"
|
||||
.align 4
|
||||
|
||||
|
@ -29,3 +30,20 @@ _inth_dma_te:
|
|||
|
||||
1: .long 0 /* CHCR, set dynamically */
|
||||
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
11
src/dma/memset.c
Normal 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);
|
||||
}
|
|
@ -1,38 +1,10 @@
|
|||
#define GINT_NEED_VRAM
|
||||
#include <gint/display.h>
|
||||
#include <gint/dma.h>
|
||||
|
||||
/* dclear() - fill the screen with a single color */
|
||||
void dclear(uint16_t color)
|
||||
{
|
||||
/* TOOD: render-cg: dclear(): Consider using the DMA */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
dma_memset(vram, (color << 16) | color, 396 * 224 * 2);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue