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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
.set noreorder
.include "hwregs_a.h"
.section .text
.global DMACallback
.type DMACallback, @function
DMACallback:
# a0 - DMA channel
# a1 - Callback function
addiu $sp, -8
sw $ra, 0($sp)
beqz $a1, .Lremove_cb # Remove callback if function is NULL
nop
addiu $sp, -8 # Install IRQ handler for DMA handler
sw $a0, 0($sp) # if not set installed yet
sw $a1, 4($sp)
jal GetInterruptCallback
li $a0, 3
bnez $v0, .Lskip_install
nop
la $a1, _dma_handler
jal InterruptCallback
li $a0, 3
.Lskip_install:
lw $a0, 0($sp)
lw $a1, 4($sp)
addiu $sp, 8
la $v0, _dma_func_table
sll $v1, $a0, 2
addu $v0, $v1
lw $v1, 0($v0)
sw $a1, 0($v0)
sw $v1, 4($sp)
lui $a2, IOBASE
lw $v0, DICR($a2) # Enable DMA interrupt
lui $v1, 0x1
sll $v1, $a0
or $v0, $v1
lui $v1, 0x80
or $v0, $v1
sw $v0, DICR($a2)
b .Lskip_remove
nop
.Lremove_cb:
la $v0, _dma_func_table # Set callback address
sll $v1, $a0, 2
addu $v0, $v1
lw $v1, 0($v0)
sw $a1, 0($v0)
sw $v1, 4($sp)
lui $a2, IOBASE # Disable DMA interrupt
lw $v0, DICR($a2)
lui $v1, 0x1
sll $v1, $a0
.set noat
addiu $at, $0, -1
xor $v1, $at
and $v0, $v1
lui $v1, 0x7f00
xor $v1, $at
and $v0, $v1
.set at
sw $v0, DICR($a2)
jal _dma_has_cb # Check if callbacks are present
nop
bnez $v0, .Lskip_remove
nop
sw $0 , DICR($a2)
jal GetInterruptCallback # Check if callback is the DMA handler
li $a0, 3
la $v1, _dma_handler
bne $v0, $v1, .Lskip_remove
nop
li $a0, 3
jal InterruptCallback
move $a1, $0
.Lskip_remove:
lw $ra, 0($sp)
lw $v0, 4($sp)
jr $ra
addiu $sp, 8
.type _dma_has_cb, @function
_dma_has_cb:
la $v1, _dma_func_table
li $t0, 6
.Lscan_loop:
lw $v0, 0($v1)
addiu $v1, 4
bnez $v0, .Lhas_cb
nop
bgtz $t0, .Lscan_loop
addiu $t0, -1
jr $ra
move $v0, $0
.Lhas_cb:
jr $ra
li $v0, 1
.type _dma_handler, @function
_dma_handler:
addiu $sp, -12
sw $ra, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
move $s0, $0
la $s1, _dma_func_table
.Lhandler_loop:
lui $a0, IOBASE
lw $v0, DICR($a0)
li $v1, 24
addu $v1, $s0
srl $v0, $v1
andi $v0, 0x1
lw $v1, 0($s1)
beqz $v0, .Lno_irq
addiu $s1, 4
beqz $v1, .Lno_irq
nop
jalr $v1
nop
.Lno_irq:
blt $s0, 6, .Lhandler_loop
addi $s0, 1
lui $a0, IOBASE
lw $v0, DICR($a0)
nop
sw $v0, DICR($a0)
lw $ra, 0($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
jr $ra
addiu $sp, -12
.section .data
_dma_func_table:
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
|