-
Notifications
You must be signed in to change notification settings - Fork 8
/
dma.c
92 lines (69 loc) · 2.23 KB
/
dma.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "arm.h"
#include "arm_mem.h"
#include "dma.h"
#include "io.h"
#include "sound.h"
//TODO: Timing - DMA should take some amount of cycles
void dma_transfer(dma_timing_e timing) {
uint8_t ch;
for (ch = 0; ch < 4; ch++) {
if (!(dma_ch[ch].ctrl.w & DMA_ENB) ||
((dma_ch[ch].ctrl.w >> 12) & 3) != timing)
continue;
if (ch == 3)
eeprom_idx = 0;
int8_t unit_size = (dma_ch[ch].ctrl.w & DMA_32) ? 4 : 2;
bool dst_reload = false;
int8_t dst_inc = 0;
int8_t src_inc = 0;
switch ((dma_ch[ch].ctrl.w >> 5) & 3) {
case 0: dst_inc = unit_size; break;
case 1: dst_inc = -unit_size; break;
case 3:
dst_inc = unit_size;
dst_reload = true;
break;
}
switch ((dma_ch[ch].ctrl.w >> 7) & 3) {
case 0: src_inc = unit_size; break;
case 1: src_inc = -unit_size; break;
}
while (dma_count[ch]--) {
if (dma_ch[ch].ctrl.w & DMA_32)
arm_write(dma_dst_addr[ch], arm_read(dma_src_addr[ch]));
else
arm_writeh(dma_dst_addr[ch], arm_readh(dma_src_addr[ch]));
dma_dst_addr[ch] += dst_inc;
dma_src_addr[ch] += src_inc;
}
if (dma_ch[ch].ctrl.w & DMA_IRQ)
trigger_irq(DMA0_FLAG << ch);
if (dma_ch[ch].ctrl.w & DMA_REP) {
dma_count[ch] = dma_ch[ch].count.w;
if (dst_reload) {
dma_dst_addr[ch] = dma_ch[ch].dst.w;
}
continue;
}
dma_ch[ch].ctrl.w &= ~DMA_ENB;
}
}
void dma_transfer_fifo(uint8_t ch) {
if (!(dma_ch[ch].ctrl.w & DMA_ENB) ||
((dma_ch[ch].ctrl.w >> 12) & 3) != SPECIAL)
return;
uint8_t i;
for (i = 0; i < 4; i++) {
arm_write(dma_dst_addr[ch], arm_read(dma_src_addr[ch]));
if (ch == 1)
fifo_a_copy();
else
fifo_b_copy();
switch ((dma_ch[ch].ctrl.w >> 7) & 3) {
case 0: dma_src_addr[ch] += 4; break;
case 1: dma_src_addr[ch] -= 4; break;
}
}
if (dma_ch[ch].ctrl.w & DMA_IRQ)
trigger_irq(DMA0_FLAG << ch);
}