goutfifo.s
5.82 KB
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
192
193
194
195
196
197
############################################################################
#
# Output coordination routines:
#
# We support three cases:
#
# 1.) output directly to RDP using DMEM as buffer. Requires
# producer/consumer synchronization.
#
# 2.) output routed to DRAM. In this case, we use DMEM as
# a temporary buffer, then DMA out to DRAM.
#
# 3.) output routed to DRAM, but DRAM is utilized as a circular
# buffer
#
# Goals:
#
# - small code size.
# - efficient and non-obtrusive
# - flexible, can easily route to DRAM or RDP.
#
# In order to do this, and make it transparent to the parts of the
# code which do the writing, we implement an open/close interface.
#
# FUNCTION: OUTPUT TO RDP: OUTPUT TO DRAM:
#-------------------------------------------------------------------------
# open(size) - wait for size avail in - does nothing
# ring buffer.
# - possibly handle wrap
# - wait for 'current' to get
# out of the way
#
# close() - advance CP0 pointer - do DMA of cmd to DRAM
# - increment pointers
# - reset DMEM buffer
#
# In between the open() and close(), the ucode writes the data to DMEM.
# (to either the RDP ring buffer or a temp buffer to be DMA'd)
#
############################################################################
# DMEM is utilized as follows for this output routine:
# RSP_STATE_FIFO_OUTP: pointer in dram to next empty ring buffer entry
# RSP_STATE_FIFO_BUF_TOP: pointer in dram to beginning of ring buffer
# RSP_STATE_FIFO_BUF_END: pointer in dram to end of ring buffer
# (ie the byte following the ring buffer)
#
# These registers used by both routines.
#
.name dmemp, $20
.name dramp, $19
.name outsz, $18 # set by caller to max size to write
.name tmp, $6
############################################################################
#
#
#
#if !(defined(OUTPUT_DRAM)||defined(OUTPUT_FIFO))
.ent OutputOpen
OutputOpen:
jr return
nop
.end OutputOpen
#endif /* !(OUTPUT_DRAM || OUTPUT_FIFO) */
#
#
#
############################################################################
############################################################################
#
#
#
.ent OutputClose
#ifdef DMANOWAIT2
OutputCloseEnd:
jr return
#endif
OutputClose:
#ifdef DMANOWAIT2
addi tmp, outp, 176-RSP_OUTPUT_END
blez tmp, OutputCloseEnd
OutputCloseFlush:
#endif
# check if the packet will fit in the buffer
#ifdef DMA2BUF
lh dmemp, RSP_STATE_FIFO_DMA2BUF(rsp_state)
checkFIFO: mfc0 tmp, DMA_BUSY # ロード遅延の間に処理する
lw dramp, RSP_STATE_FIFO_OUTP(rsp_state)
add $21, zero, return
bne tmp, zero, checkFIFO
sub outsz, outp, dmemp
mtc0 dramp, CMD_END
#else
add $21, zero, return
lw dramp, RSP_STATE_FIFO_OUTP(rsp_state)
addi outsz, outp, (-1*RSP_OUTPUT_OFFSET)
#endif
lw outp, RSP_STATE_FIFO_BUF_END(rsp_state)
blez outsz, CloseDone
#if (defined(DMA2BUF)||defined(DMANOWAIT))
add tmp, dramp, outsz # end data in dram
sub tmp, outp, tmp
bgez tmp, CurrentFit
#else
add dmemp, dramp, outsz # end data in dram
sub dmemp, outp, dmemp # bigger than buffer?
bgez dmemp, CurrentFit
#endif
WrapBuffer:
# packet will not fit, wait for current to wrap
#if (defined(DMA2BUF)||defined(DMANOWAIT))
mfc0 tmp, CMD_STATUS
andi tmp, tmp, 0x0400
bne tmp, zero, WrapBuffer
#else
mfc0 dmemp, CMD_STATUS
andi dmemp, dmemp, 0x0400
bne dmemp, zero, WrapBuffer
#endif
# note delay slot
# wait for current to advance
AdvanceCurrent:
mfc0 outp, CMD_CURRENT # outp = current
lw dramp, RSP_STATE_FIFO_BUF_TOP(rsp_state) # buffer start
beq outp, dramp, AdvanceCurrent
nop
mtc0 dramp, CMD_START # reset START
CurrentFit:
# done if current_address <= dramp
mfc0 outp, CMD_CURRENT # outp = current
#if (defined(DMA2BUF)||defined(DMANOWAIT))
sub tmp, dramp, outp
bgez tmp, CloseDMA
#else
sub dmemp, dramp, outp
bgez dmemp, CloseDMA
#endif
# note delay slot
# loop if current_address <= (outp + outsz)
#if (defined(DMA2BUF)||defined(DMANOWAIT))
add tmp, dramp, outsz
sub tmp, tmp, outp
bgez tmp, CurrentFit
#else
add dmemp, dramp, outsz
sub dmemp, dmemp, outp
bgez dmemp, CurrentFit
#endif
nop
CloseDMA:
add outp, dramp, outsz
addi outsz, outsz, -1
#ifndef DMA2BUF
addi dmemp, zero, RSP_OUTPUT_OFFSET
#endif
jal DMAproc
addi $17, zero, 1 # set 'iswrite'
#ifdef DMANOWAIT
sw outp, RSP_STATE_FIFO_OUTP(rsp_state)
CloseDone: jr $21
addi outp, zero, RSP_OUTPUT_OFFSET
#else
#ifdef DMA2BUF
sw outp, RSP_STATE_FIFO_OUTP(rsp_state)
xori dmemp,dmemp,(RSP_OUTPUT_OFFSET)^(RSP_OUTPUT_OFFSET+176*2)
sh dmemp,RSP_STATE_FIFO_DMA2BUF(rsp_state)
CloseDone: jr $21
addi outp, dmemp, 0
#else
jal DMAwait
sw outp, RSP_STATE_FIFO_OUTP(rsp_state)
mtc0 outp, CMD_END
CloseDone:
jr $21
addi outp, zero, RSP_OUTPUT_OFFSET
#endif
#endif
.end OutputClose
#
#
#
############################################################################
.unname outsz
.unname dramp
.unname dmemp
.unname tmp