VxKernel 0.6.0-19 : Add DMA driver

@add
<> board/fxcg50/board
  | add DMA module support
<> src/driver/mpu/sh/sh7305/dma
  | add async transfer primitives
  | add DMA memcpy algorithm
  | add DMA memset algorithm
  | add DMA wait primitives

@update
<> vhex/dma
  | [types] change dma_id_t type
  | [interface] add dma_spinwait primitives
<> vhex/driver
  | add DMA flags for driver interface
<> vhex/driver/mpu/sh/sh7305/dma
  | expose kernel-level primitives
  | add internal types definitions
<> src/driver/mpu/sh/sh7305/dma
  | proper channel cache
  | proper channel interrupt handler
  | proper channel error handler
  | proper address translation
  | proper driver installation (context save/restore)
  | proper driver interface exposition

@fix
<> vhex/keyboard/keycode
  | fix typedef again
<> src/dma
  | fix driver exposition
  | fix driver interface link dump
<> src/driver/mpu/sh/sh7305/intc
  | fix generic handler installation
This commit is contained in:
Yann MAGNIN 2022-08-17 13:23:28 +02:00
parent 7e01fb8444
commit b8abc2eae7
13 changed files with 573 additions and 61 deletions

View File

@ -11,6 +11,7 @@ modules = [
'kmalloc',
'timer',
'rtc',
'dma'
]
[drivers]

View File

@ -8,6 +8,7 @@ struct dma_drv_interface
dma_id_t (*dma_memcpy)(void * restrict, void * restrict, size_t);
dma_id_t (*dma_memset)(void * restrict, int, size_t);
int (*dma_wait)(dma_id_t);
int (*dma_spinwait)(dma_id_t);
};
#endif /* __VHEX_DMA_INTERFACE__ */

View File

@ -3,6 +3,6 @@
#include <vhex/defs/types.h>
typedef uint32_t dma_id_t;
typedef int32_t dma_id_t;
#endif /* __VHEX_DMA_TYPES__ */

View File

@ -48,7 +48,7 @@ struct vhex_driver
uint8_t TIMER :1;
uint8_t DISPLAY :1;
uint8_t :1;
uint8_t DMA :1;
uint8_t :1;
uint8_t SHARED :1;
uint8_t UNUSED :1;

View File

@ -4,6 +4,8 @@
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
#include <vhex/dma/types.h>
//---
// SH7305 Direct Memory Access Controller. Refer to:
// "Renesas SH7724 User's Manual: Hardware"
@ -94,7 +96,80 @@ struct __sh7305_dma
#define SH7305_DMA (*((volatile struct __sh7305_dma *)0xfe008020))
//---
// Kernel-level API
//---
/* dma_size_t - Transfer block size */
typedef enum
{
/* Normal transfers of 1, 2, 4, 8, 16 or 32 bytes at a time */
DMA_BLOCK_SIZE_1B = 0,
DMA_BLOCK_SIZE_2B = 1,
DMA_BLOCK_SIZE_4B = 2,
DMA_BLOCK_SIZE_8B = 7,
DMA_BLOCK_SIZE_16B = 3,
DMA_BLOCK_SIZE_32B = 4,
/* Transfers of 16 or 32 bytes divided in two operations */
DMA_BLOCK_SIZE_16B_DIV = 11,
DMA_BLOCK_SIZE_32B_DIV = 12,
} dma_block_size_t;
/* dma_addr_op_t - Addressing mode for source and destination regions */
typedef enum
{
/* Fixed address mode: the same address is read/written at each step */
DMA_ADDR_FIXED = 0,
/* Increment: address is incremented by transfer size at each step */
DMA_ADDR_INC = 1,
/* Decrement: only allowed for 1/2/4-byte transfers */
DMA_ADDR_DEC = 2,
/* Fixed division mode: address is fixed even in 16/32-divide mode */
DMA_ADDR_FIXEDDIV = 3,
} dma_addr_op_t;
/* sh7305_dma_id_t : internal DMA ID structure */
typedef union {
uint32_t lword;
struct {
uint32_t INVALID : 1;
uint32_t IDX : 3;
uint32_t KEYFRAME : 28;
};
} sh7305_dma_id_t;
/* internal cache channel information */
typedef struct {
sh7305_dma_id_t id;
volatile struct __sh7305_dma_channel *hw;
} sh7305_dma_channel_t;
extern dma_id_t sh7305_dma_transfert_async(
uintptr_t src, dma_addr_op_t src_op,
uintptr_t dst, dma_addr_op_t dst_op,
dma_block_size_t block_size,
int block_count
);
/* dma_memcpy() : memcpy using DMA */
extern dma_id_t sh7305_dma_memcpy(void * restrict, void * restrict, size_t);
/* dma_memset() : memset using the DMA */
extern dma_id_t sh7305_dma_memset(void *dst, int c, size_t sz);
/* dma_wait() : wait the end of the DMA channel transfer */
extern int sh7305_dma_wait(dma_id_t id);
/* dma_wait() : wait the end of the DMA channel transfer without interruption */
extern int sh7305_dma_spinwait(dma_id_t id);
/* sh7305_dma_wait() : wait DAM channel */
extern int sh7305_dma_channel_wait(sh7305_dma_channel_t *ch, int atomic);
/* sh7305_dma_channel_find() : find a channel using the ID */
extern sh7305_dma_channel_t *sh7305_dma_channel_find(sh7305_dma_id_t id);
#endif /* __VHEX_DRIVER_MPU_SH_SH7305_DMA__ */

View File

@ -6,7 +6,7 @@
(((row & 0x0f) << 4) | ((column & 0x0f) << 0))
/* Define all keycode */
enum
typedef enum
{
KEY_F1 = 0x41,
KEY_F2 = 0x42,
@ -68,6 +68,6 @@ enum
KEY_UNUSED = 0xff,
KEY_NONE = 0xfe,
};
} key_t;
#endif /* __VHEX_KEYBOARD_KEYCODE__ */

View File

@ -4,6 +4,8 @@
#include <vhex/defs/types.h>
#include <vhex/defs/attributes.h>
#include <vhex/keyboard/keycode.h>
/* key_event_t: Low-level or high-level keyboard event
This structure represents an event that occurs on the keyboard. It is first
@ -54,7 +56,5 @@ enum
KEYEV_REP_NEXT = 2,
};
/* keyboard key */
typedef int key_t;
#endif /* __VHEX_KEYBOARD_TYPES__ */

View File

@ -19,7 +19,7 @@ static void __dma_init(void)
for (int i = 0; i < vhex_driver_count(); ++i) {
if (driver[i].flags.DMA) {
memcpy(
&rtc_info.driver,
&dma_info.driver,
driver[i].module_data,
sizeof(struct dma_drv_interface)
);
@ -36,7 +36,7 @@ static void __dma_quit(void)
/* declare the timer module */
struct vhex_module mod_rtc = {
struct vhex_module mod_dma = {
.name = "DMA",
.init = &__dma_init,
.quit = &__dma_quit,

View File

@ -1,31 +1,253 @@
#include <vhex/driver/mpu/sh/sh7305/dma.h>
#include <vhex/driver/mpu/sh/sh7305/intc.h>
#include <vhex/driver/cpu.h>
//#include <vhex/driver/mpu/sh/sh7305/power.h>
#include <vhex/driver.h>
#include <vhex/defs/call.h>
#include <vhex/dma/interface.h>
#include <vhex/display.h>
/* internal DMA cache information */
static struct {
uint32_t keyframe;
sh7305_dma_channel_t channel[6];
} dmac_info = {
.keyframe = 0x00000000,
.channel = {
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA0
},
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA1
},
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA2
},
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA3
},
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA4
},
{
.id = {
.INVALID = 1,
.IDX = 0b111,
.KEYFRAME = 0
},
.hw = &SH7305_DMA.DMA5
},
}
};
//---
// Driver internals
//---
/* dma_translate(): Translate virtual address to DMA-suitable form */
static uintptr_t sh7305_dma_translate_addr(uintptr_t a)
{
/* 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;
}
/* sh7305_dma_channel_reserve() : wait until a channel is free and reserve it */
static sh7305_dma_channel_t *sh7305_dma_channel_reserve(void)
{
sh7305_dma_channel_t *ch;
ch = NULL;
while (1)
{
cpu_atomic_start();
for (int i = 5; i >= 0; --i) {
if (dmac_info.channel[i].id.INVALID == 0)
continue;
dmac_info.keyframe += 1;
ch = &dmac_info.channel[i];
ch->id.INVALID = 0;
ch->id.IDX = i;
ch->id.KEYFRAME = dmac_info.keyframe;
break;
}
cpu_atomic_end();
if (ch != NULL)
break;
__asm__ volatile ("sleep");
}
return ch;
}
/* sh7305_dma_channel_release() : release DMA channel */
static int sh7305_dma_channel_release(sh7305_dma_channel_t * ch, int atomic)
{
if (sh7305_dma_channel_wait(ch, atomic) != 0)
return -1;
ch->id.INVALID = 1;
return 0;
}
/* sh7305_dma_channel_find() : find a channel using the ID */
sh7305_dma_channel_t *sh7305_dma_channel_find(sh7305_dma_id_t id)
{
if (id.INVALID == 1)
return NULL;
if (id.IDX < 0 && id.IDX >= 6)
return NULL;
return &dmac_info.channel[id.IDX];
}
/* sh7305_dma_wait() : wait DAM channel */
int sh7305_dma_channel_wait(sh7305_dma_channel_t *ch, int atomic)
{
int find;
find = -1;
cpu_atomic_start();
for (int i = 0; i < 6; ++i) {
if (ch != &dmac_info.channel[i])
continue;
find = 0;
break;
}
cpu_atomic_end();
if (find != 0)
return find;
while (1) {
if (ch->hw->CHCR.DE == 0)
break;
if (atomic == 1)
__asm__ volatile ("sleep");
}
return 0;
}
#define DMA SH7305_DMA
//#define POWER SH7305_POWER
typedef volatile struct __sh7305_dma_channel channel_t;
//---
// Driver public API
//---
static channel_t *sh7305_dma_channel(int channel)
{
if (channel < 0 || channel >= 6)
return NULL;
return (channel_t *[6]){
&DMA.DMA0, &DMA.DMA1, &DMA.DMA2,
&DMA.DMA3, &DMA.DMA4, &DMA.DMA5,
}[channel];
}
/* sh7305_dma_transfert_async() : start asynchronous transfert */
dma_id_t sh7305_dma_transfert_async(
uintptr_t src, dma_addr_op_t src_op,
uintptr_t dst, dma_addr_op_t dst_op,
dma_block_size_t block_size,
int block_count
) {
sh7305_dma_channel_t *ch;
static void sh7305_dma_spinwait(channel_t *ch)
{
(void)ch;
ch = sh7305_dma_channel_reserve();
if (ch == NULL)
return -1;
/* disable channel */
ch->hw->CHCR.DE = 0;
/* set source / destination address and block counter */
ch->hw->SAR = sh7305_dma_translate_addr(src);
ch->hw->DAR = sh7305_dma_translate_addr(dst);
ch->hw->TCR = block_count & 0x0fffffff;
/* common channel configuration
<> enable release of the bus mastership between reading and writting
<> select normal mode (channel 0..3)
<> select asynchronous DREQ sampling (channel 0)
<> detect overrun 0 (channel 0)
<> clear half-end flags
<> disable half-end interruption
<> select DACK output at read cycle (channel 0)
<> select low-active output of DACK (channel 0)
<> set the approriate destination addressing mode
<> set the approriate source addressing mode
<> select auto-request transfert
<> select DREQ detection on low-level (channel 0)
<> select cycle steal mode
<> enable interruption
<> clear interrupt flags */
ch->hw->CHCR.LCKN = 1;
ch->hw->CHCR.RPT = 0b000;
ch->hw->CHCR.DA = 0;
ch->hw->CHCR.DO = 0;
ch->hw->CHCR.HE = 0;
ch->hw->CHCR.HIE = 0;
ch->hw->CHCR.AM = 0;
ch->hw->CHCR.AL = 0;
ch->hw->CHCR.DM = dst_op;
ch->hw->CHCR.SM = src_op;
ch->hw->CHCR.RS = 0b0100;
ch->hw->CHCR.DL = 0;
ch->hw->CHCR.DS = 0;
ch->hw->CHCR.TB = 0;
ch->hw->CHCR.IE = 1;
ch->hw->CHCR.TE = 0;
/* set the block size */
ch->hw->CHCR.TS3 = (block_size & 0b1000) >> 3;
ch->hw->CHCR.TS2 = (block_size & 0b0100) >> 2;
ch->hw->CHCR.TS1 = (block_size & 0b0010) >> 1;
ch->hw->CHCR.TS0 = (block_size & 0b0001) >> 0;
/* start DMA channel */
ch->hw->CHCR.DE = 1;
return ch->id.lword;
}
//---
@ -33,9 +255,43 @@ static void sh7305_dma_spinwait(channel_t *ch)
//---
/* Interrupt handler for all finished DMA transfers */
static void sh7305_dma_interrupt_transfer_ended(channel_t *ch)
static void sh7305_dma_interrupt_transfer_ended(sh7305_dma_channel_t *ch)
{
(void)ch;
ch->hw->CHCR.IE = 0;
ch->hw->CHCR.DE = 0;
ch->hw->CHCR.TE = 0;
SH7305_DMA.DMAOR.AE = 0;
SH7305_DMA.DMAOR.NMIF = 0;
ch->id.INVALID = 1;
}
/* DMA error handler (interrupt) */
static void sh7305_dma_error_handler(void)
{
dclear(C_WHITE);
dprint(0, 0, C_BLACK,
"DMA error handler !!!\n"
" DMA0.CHCR = %p\n"
" DMA1.CHCR = %p\n"
" DMA2.CHCR = %p\n"
" DMA3.CHCR = %p\n"
" DMA4.CHCR = %p\n"
" DMA5.CHCR = %p\n"
" DMAOR = %p\n"
"reset the device..."
,
SH7305_DMA.DMA0.CHCR.lword,
SH7305_DMA.DMA1.CHCR.lword,
SH7305_DMA.DMA2.CHCR.lword,
SH7305_DMA.DMA3.CHCR.lword,
SH7305_DMA.DMA4.CHCR.lword,
SH7305_DMA.DMA5.CHCR.lword,
SH7305_DMA.DMAOR.word
);
dupdate();
while (1) { __asm__ volatile ("sleep"); }
}
//---
@ -44,7 +300,7 @@ static void sh7305_dma_interrupt_transfer_ended(channel_t *ch)
//FIXME: avoid manualy sync DMAOR with header o(x_x)o
struct dma_ctx {
channel_t ch[6];
volatile struct __sh7305_dma_channel ch[6];
word_union(DMAOR,
uint16_t CMS :4; /* Cycle steal Mode Select */
@ -73,8 +329,8 @@ static void __dma_configure(struct dma_ctx *s)
sh7305_intc_install_inth_generic(
codes[i],
VHEX_CALL(
sh7305_dma_interrupt_transfer_ended,
(void*)sh7305_dma_channel(i)
&sh7305_dma_interrupt_transfer_ended,
(void*)&dmac_info.channel[i]
)
);
@ -83,22 +339,27 @@ static void __dma_configure(struct dma_ctx *s)
s->ch[i].TCR = 0x00000000;
s->ch[i].CHCR.DE = 0;
dmac_info.channel[i].id.INVALID = 1;
}
/* Configure the DMA operations
<> select normal cycle steal mode
<> select "normal" priority (CH0->CH1->CH2->...)
<> select round-robin mode
<> clear address error flags
<> clear NMIF flags
<> enable the master switch */
s->DMAOR.CMS = 0b0000;
s->DMAOR.PR = 0b00;
s->DMAOR.PR = 0b11;
s->DMAOR.AE = 0;
s->DMAOR.NMIF = 0;
s->DMAOR.DME = 1;
/* Install Address Error interrupt gate */
sh7305_intc_install_inth_gate(0xbc0, sh7305_dma_inth_ae, 32);
sh7305_intc_install_inth_generic(
0xbc0,
VHEX_CALL(&sh7305_dma_error_handler)
);
/* Set interrupt priority to 3, except for the channels that are
used by the USB driver (channel 0) */
@ -114,37 +375,40 @@ static void __dma_configure(struct dma_ctx *s)
/* __rtc_hsave() : save hardware information */
static void __dma_hsave(struct dma_ctx *s)
{
sh7305_dma_channel_t * ch;
for(int i = 0; i < 6; i++) {
channel_t *ch = sh7305_dma_channel(i);
sh7305_dma_spinwait(ch);
ch->SAR = s->ch[i].SAR;
ch->DAR = s->ch[i].DAR;
ch->TCR = s->ch[i].TCR;
ch->CHCR.lword = s->ch[i].CHCR.lword;
ch = &dmac_info.channel[i];
sh7305_dma_channel_wait(ch, 1);
s->ch[i].SAR = ch->hw->SAR;
s->ch[i].DAR = ch->hw->DAR;
s->ch[i].TCR = ch->hw->TCR;
s->ch[i].CHCR.lword = ch->hw->CHCR.lword;
}
DMA.DMAOR.word = s->DMAOR.word;
s->DMAOR.word = SH7305_DMA.DMAOR.word;
}
/* __dma_hrestore() : restore hardware information */
static void __dma_hrestore(struct dma_ctx *s)
{
DMA.DMAOR.DME = 0;
sh7305_dma_channel_t * ch;
SH7305_DMA.DMAOR.DME = 0;
for(int i = 0; i < 6; i++)
{
channel_t *ch = sh7305_dma_channel(i);
ch->SAR = s->ch[i].SAR;
ch->DAR = s->ch[i].DAR;
ch->TCR = s->ch[i].TCR;
ch->CHCR.lword = s->ch[i].CHCR.lword;
ch = &dmac_info.channel[i];
ch->hw->SAR = s->ch[i].SAR;
ch->hw->DAR = s->ch[i].DAR;
ch->hw->TCR = s->ch[i].TCR;
ch->hw->CHCR.lword = s->ch[i].CHCR.lword;
}
DMA.DMAOR.word = s->DMAOR.word;
SH7305_DMA.DMAOR.word = s->DMAOR.word;
}
#if 0
struct vhex_driver drv_rtc = {
struct vhex_driver drv_dma = {
.name = "DMA",
.hsave = (void*)&__dma_hsave,
.hrestore = (void*)&__dma_hrestore,
@ -155,6 +419,11 @@ struct vhex_driver drv_rtc = {
.SHARED = 0,
.UNUSED = 0,
},
.module_data = &(struct dma_drv_interface){
.dma_memcpy = &sh7305_dma_memcpy,
.dma_memset = &sh7305_dma_memset,
.dma_wait = &sh7305_dma_wait,
.dma_spinwait = &sh7305_dma_spinwait
}
};
VHEX_DECLARE_DRIVER(05, drv_dma);
#endif

View File

@ -1,9 +1,79 @@
#include <vhex/driver/mpu/sh/sh7305/dma.h>
#include <vhex/dma.h>
#include <string.h>
/* dma_memcpy() : memcpy using DMA */
dma_id_t sh7305_dma_memcpy(void * restrict dst, void * restrict src, size_t sz)
{
(void)dst;
(void)src;
(void)sz;
uintptr_t _dst;
uintptr_t _src;
uintptr_t dma_src;
uintptr_t dma_dst;
ptrdiff_t delta;
int dma_block_count;
dma_block_size_t dma_block_size;
int divisor;
ptrdiff_t gap_size_pre;
ptrdiff_t gap_size_end;
dma_id_t id;
if (sz < 64) {
memcpy(dst, src, sz);
return 0;
}
_dst = (uintptr_t)dst;
_src = (uintptr_t)src;
delta = (dst > src) ? dst - src : src - dst;
if ((delta & 0x0000001f) == 0) {
dma_block_size = DMA_BLOCK_SIZE_32B;
divisor = 32;
} else if ((delta & 0x0000000f) == 0) {
dma_block_size = DMA_BLOCK_SIZE_16B;
divisor = 16;
} else if ((delta & 0x00000007) == 0) {
dma_block_size = DMA_BLOCK_SIZE_8B;
divisor = 8;
} else if ((delta & 0x00000003) == 0) {
dma_block_size = DMA_BLOCK_SIZE_4B;
divisor = 4;
} else if ((delta & 0x00000001) == 0) {
dma_block_size = DMA_BLOCK_SIZE_2B;
divisor = 2;
} else {
dma_block_size = DMA_BLOCK_SIZE_1B;
divisor = 1;
}
dma_src = ((_src + divisor - 1) / divisor) * divisor;
dma_dst = ((_dst + divisor - 1) / divisor) * divisor;
gap_size_pre = dma_dst - _dst;
dma_block_count = (sz - gap_size_pre) / divisor;
gap_size_end = (sz - gap_size_pre) - (dma_block_count * divisor);
id = sh7305_dma_transfert_async(
dma_src, DMA_ADDR_INC,
dma_dst, DMA_ADDR_INC,
dma_block_size,
dma_block_count
);
if (id < 0)
return id;
for (int i = 0; i < gap_size_pre; ++i) {
((uint8_t*)_dst)[0] = ((uint8_t*)_src)[0];
_dst += 1;
_src += 1;
}
_dst += dma_block_count * divisor;
_src += dma_block_count * divisor;
for (int i = 0; i < gap_size_end; ++i) {
((uint8_t*)_dst)[0] = ((uint8_t*)_src)[0];
_dst += 1;
_src += 1;
}
return id;
}

View File

@ -1,9 +1,66 @@
#include <vhex/driver/mpu/sh/sh7305/dma.h>
#include <vhex/dma.h>
#include <string.h>
/* Allocate a 32-byte buffer in ILRAM */
VALIGNED(32) VSECTION(".xram") static uint32_t Xbuf[8];
/* dma_memset() : memset using the DMA */
dma_id_t sh7305_dma_memset(void *dst, int c, size_t sz)
{
(void)dst;
(void)c;
(void)sz;
uintptr_t dma_src;
uintptr_t dma_dst;
ptrdiff_t gap_size_pre;
ptrdiff_t gap_size_end;
uint32_t mask;
int dma_block_count;
dma_id_t id;
if (sz < 64) {
memset(dst, c, sz);
return 0;
}
mask = ((c & 0xff) << 24)
| ((c & 0xff) << 16)
| ((c & 0xff) << 8)
| ((c & 0xff) << 0);
/* Prepare the XRAM buffer. We need to use XRAM because the DMA will
have to read the operand once per block, as opposed to an assembler
routine that would hold it in a register. If we place it in RAM, the
DMA will perform twice as many RAM accesses as the handwritten
assembler, which would be very slow. By using XRAM we use two
different memory regions, making the DMA faster than the CPU. */
for(int i = 0; i < 8; i++) Xbuf[i] = mask;
//FIXME: SPU
dma_src = (uintptr_t)Xbuf;
dma_dst = (uintptr_t)dst & 0xffffffe0;
gap_size_pre = dma_dst - (uintptr_t)dst;
dma_block_count = (sz - gap_size_pre) >> 5;
gap_size_end = (sz - gap_size_pre) - (dma_block_count << 5);
id = sh7305_dma_transfert_async(
dma_src, DMA_ADDR_FIXED,
dma_dst, DMA_ADDR_INC,
DMA_BLOCK_SIZE_32B,
dma_block_count
);
if (id < 0)
return id;
for (int i = 0; i < gap_size_pre; ++i) {
((uint8_t*)dst)[0] = c;
dst = &((uint8_t*)dst)[1];
}
dst += dma_block_count << 5;
for (int i = 0; i < gap_size_end; ++i) {
((uint8_t*)dst)[0] = c;
dst = &((uint8_t*)dst)[1];
}
return id;
}

View File

@ -0,0 +1,40 @@
#include <vhex/driver/mpu/sh/sh7305/dma.h>
//---
// Internal functions
//---
static int sh7305_dma_wait_core(sh7305_dma_id_t id, int atomic)
{
sh7305_dma_channel_t *ch;
ch = sh7305_dma_channel_find(id);
if (ch == NULL)
return -1;
if (ch->id.KEYFRAME == id.KEYFRAME)
sh7305_dma_channel_wait(ch, atomic);
return 0;
}
//---
// User-level API
//---
/* dma_wait() : wait the end of the DMA channel transfer */
int sh7305_dma_wait(dma_id_t id)
{
sh7305_dma_id_t _id;
_id.lword = id;
return sh7305_dma_wait_core(_id, 0);
}
/* dma_wait() : wait the end of the DMA channel transfer without interruption */
int sh7305_dma_spinwait(dma_id_t id)
{
sh7305_dma_id_t _id;
_id.lword = id;
return sh7305_dma_wait_core(_id, 1);
}

View File

@ -128,15 +128,14 @@ void *sh7305_intc_install_inth_generic(int event_code, vhex_call_t callback)
uint8_t *h = sh7305_intc_install_inth_gate(
event_code,
sh7305_intc_inth_generic_gate,
&sh7305_intc_inth_generic_gate,
32
);
if(h == NULL)
return false;
memcpy(&h[8], &callback, 20);
memcpy(&h[28], &sh7305_inth_callback, 4);
if(h != NULL) {
uintptr_t workaround = (uintptr_t)&sh7305_inth_callback;
memcpy(&h[8], &callback, 20);
memcpy(&h[28], &workaround, 4);
}
return h;
}