goutfifo.s
4.33 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
############################################################################
#
# 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
############################################################################
#
#
#
#if !(defined(OUTPUT_DRAM)||defined(OUTPUT_FIFO))
.ent OutputOpen
OutputOpen:
jr return
nop
.end OutputOpen
#endif /* !(OUTPUT_DRAM || OUTPUT_FIFO) */
#
#
#
############################################################################
############################################################################
#
#
#
.ent OutputClose
OutputClose:
# check if the packet will fit in the buffer
add $21, zero, return
lw dramp, RSP_STATE_FIFO_OUTP(rsp_state)
addi outsz, outp, (-1*RSP_OUTPUT_OFFSET)
lw outp, RSP_STATE_FIFO_BUF_END(rsp_state)
blez outsz, CloseDone
add dmemp, dramp, outsz # end data in dram
sub dmemp, outp, dmemp # bigger than buffer?
bgez dmemp, CurrentFit
WrapBuffer:
# packet will not fit, wait for current to wrap
mfc0 dmemp, CMD_STATUS
andi dmemp, dmemp, 0x0400
bne dmemp, zero, WrapBuffer
# 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
sub dmemp, dramp, outp
bgez dmemp, CloseDMA
# note delay slot
# loop if current_address <= (outp + outsz)
add dmemp, dramp, outsz
sub dmemp, dmemp, outp
bgez dmemp, CurrentFit
nop
CloseDMA:
add outp, dramp, outsz
addi outsz, outsz, -1
addi dmemp, zero, RSP_OUTPUT_OFFSET
jal DMAproc
addi $17, zero, 1 # set 'iswrite'
jal DMAwait
sw outp, RSP_STATE_FIFO_OUTP(rsp_state)
mtc0 outp, CMD_END
CloseDone:
jr $21
addi outp, zero, RSP_OUTPUT_OFFSET
.end OutputClose
#
#
#
############################################################################
.unname outsz
.unname dramp
.unname dmemp