vc4: Stop complaining about unknown texture channel types.
[mesa.git] / src / gallium / drivers / vc4 / vc4_qpu_validate.c
1 /*
2 * Copyright © 2014 Broadcom
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "vc4_qpu.h"
25
26 static bool
27 writes_reg(uint64_t inst, uint32_t w)
28 {
29 return (QPU_GET_FIELD(inst, QPU_WADDR_ADD) == w ||
30 QPU_GET_FIELD(inst, QPU_WADDR_MUL) == w);
31 }
32
33 static bool
34 _reads_reg(uint64_t inst, uint32_t r, bool ignore_a, bool ignore_b)
35 {
36 struct {
37 uint32_t mux, addr;
38 } src_regs[] = {
39 { QPU_GET_FIELD(inst, QPU_ADD_A) },
40 { QPU_GET_FIELD(inst, QPU_ADD_B) },
41 { QPU_GET_FIELD(inst, QPU_MUL_A) },
42 { QPU_GET_FIELD(inst, QPU_MUL_B) },
43 };
44
45 for (int i = 0; i < ARRAY_SIZE(src_regs); i++) {
46 if (!ignore_a &&
47 src_regs[i].mux == QPU_MUX_A &&
48 (QPU_GET_FIELD(inst, QPU_RADDR_A) == r))
49 return true;
50
51 if (!ignore_b &&
52 src_regs[i].mux == QPU_MUX_B &&
53 (QPU_GET_FIELD(inst, QPU_RADDR_B) == r))
54 return true;
55 }
56
57 return false;
58 }
59
60 static bool
61 reads_reg(uint64_t inst, uint32_t r)
62 {
63 return _reads_reg(inst, r, false, false);
64 }
65
66 static bool
67 reads_a_reg(uint64_t inst, uint32_t r)
68 {
69 return _reads_reg(inst, r, false, true);
70 }
71
72 static bool
73 writes_sfu(uint64_t inst)
74 {
75 return (writes_reg(inst, QPU_W_SFU_RECIP) ||
76 writes_reg(inst, QPU_W_SFU_RECIPSQRT) ||
77 writes_reg(inst, QPU_W_SFU_EXP) ||
78 writes_reg(inst, QPU_W_SFU_LOG));
79 }
80
81 /**
82 * Checks for the instruction restrictions from page 37 ("Summary of
83 * Instruction Restrictions").
84 */
85 void
86 vc4_qpu_validate(uint64_t *insts, uint32_t num_inst)
87 {
88 for (int i = 0; i < num_inst; i++) {
89 uint64_t inst = insts[i];
90
91 if (QPU_GET_FIELD(inst, QPU_SIG) != QPU_SIG_PROG_END)
92 continue;
93
94 /* "The Thread End instruction must not write to either physical
95 * regfile A or B."
96 */
97 assert(QPU_GET_FIELD(inst, QPU_WADDR_ADD) >= 32);
98 assert(QPU_GET_FIELD(inst, QPU_WADDR_MUL) >= 32);
99
100 /* Two delay slots will be executed. */
101 assert(i + 2 <= num_inst);
102
103 for (int j = i; j < i + 2; j++) {
104 /* "The last three instructions of any program
105 * (Thread End plus the following two delay-slot
106 * instructions) must not do varyings read, uniforms
107 * read or any kind of VPM, VDR, or VDW read or
108 * write."
109 */
110 assert(!writes_reg(insts[j], QPU_W_VPM));
111 assert(!reads_reg(insts[j], QPU_R_VARY));
112 assert(!reads_reg(insts[j], QPU_R_UNIF));
113 assert(!reads_reg(insts[j], QPU_R_VPM));
114
115 /* "The Thread End instruction and the following two
116 * delay slot instructions must not write or read
117 * address 14 in either regfile A or B."
118 */
119 assert(!writes_reg(insts[j], 14));
120 assert(!reads_reg(insts[j], 14));
121
122 }
123
124 /* "The final program instruction (the second delay slot
125 * instruction) must not do a TLB Z write."
126 */
127 assert(!writes_reg(insts[i + 2], QPU_W_TLB_Z));
128 }
129
130 /* "A scoreboard wait must not occur in the first two instructions of
131 * a fragment shader. This is either the explicit Wait for Scoreboard
132 * signal or an implicit wait with the first tile-buffer read or
133 * write instruction."
134 */
135 for (int i = 0; i < 2; i++) {
136 uint64_t inst = insts[i];
137
138 assert(QPU_GET_FIELD(inst, QPU_SIG) != QPU_SIG_COLOR_LOAD);
139 assert(QPU_GET_FIELD(inst, QPU_SIG) !=
140 QPU_SIG_WAIT_FOR_SCOREBOARD);
141 assert(!writes_reg(inst, QPU_W_TLB_COLOR_MS));
142 assert(!writes_reg(inst, QPU_W_TLB_COLOR_ALL));
143 assert(!writes_reg(inst, QPU_W_TLB_Z));
144
145 }
146
147 /* "If TMU_NOSWAP is written, the write must be three instructions
148 * before the first TMU write instruction. For example, if
149 * TMU_NOSWAP is written in the first shader instruction, the first
150 * TMU write cannot occur before the 4th shader instruction."
151 */
152 int last_tmu_noswap = -10;
153 for (int i = 0; i < num_inst; i++) {
154 uint64_t inst = insts[i];
155
156 assert((i - last_tmu_noswap) > 3 ||
157 (!writes_reg(inst, QPU_W_TMU0_S) &&
158 !writes_reg(inst, QPU_W_TMU1_S)));
159
160 if (writes_reg(inst, QPU_W_TMU_NOSWAP))
161 last_tmu_noswap = i;
162 }
163
164 /* "An instruction must not read from a location in physical regfile A
165 * or B that was written to by the previous instruction."
166 */
167 for (int i = 0; i < num_inst - 1; i++) {
168 uint64_t inst = insts[i];
169 uint32_t add_waddr = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
170 uint32_t mul_waddr = QPU_GET_FIELD(inst, QPU_WADDR_ADD);
171
172 assert(add_waddr >= 32 || !reads_reg(insts[i + 1], add_waddr));
173 assert(mul_waddr >= 32 || !reads_reg(insts[i + 1], mul_waddr));
174 }
175
176 /* "After an SFU lookup instruction, accumulator r4 must not be read
177 * in the following two instructions. Any other instruction that
178 * results in r4 being written (that is, TMU read, TLB read, SFU
179 * lookup) cannot occur in the two instructions following an SFU
180 * lookup."
181 */
182 int last_sfu_inst = -10;
183 for (int i = 0; i < num_inst - 1; i++) {
184 uint64_t inst = insts[i];
185
186 assert(i - last_sfu_inst > 2 ||
187 (!writes_sfu(inst) &&
188 !writes_reg(inst, QPU_W_TMU0_S) &&
189 !writes_reg(inst, QPU_W_TMU1_S) &&
190 QPU_GET_FIELD(inst, QPU_SIG) != QPU_SIG_COLOR_LOAD));
191
192 if (writes_sfu(inst))
193 last_sfu_inst = i;
194 }
195
196 int last_r5_write = -10;
197 for (int i = 0; i < num_inst - 1; i++) {
198 uint64_t inst = insts[i];
199
200 /* "An instruction that does a vector rotate by r5 must not
201 * immediately follow an instruction that writes to r5."
202 */
203 assert(last_r5_write != i - 1 ||
204 QPU_GET_FIELD(inst, QPU_SIG) != QPU_SIG_SMALL_IMM ||
205 QPU_GET_FIELD(inst, QPU_SMALL_IMM) != 48);
206 }
207
208 /* "An instruction that does a vector rotate must not immediately
209 * follow an instruction that writes to the accumulator that is being
210 * rotated.
211 *
212 * XXX: TODO.
213 */
214
215 /* "After an instruction that does a TLB Z write, the multisample mask
216 * must not be read as an instruction input argument in the following
217 * two instruction. The TLB Z write instruction can, however, be
218 * followed immediately by a TLB color write."
219 */
220 for (int i = 0; i < num_inst - 1; i++) {
221 uint64_t inst = insts[i];
222 if (writes_reg(inst, QPU_W_TLB_Z)) {
223 assert(!reads_a_reg(insts[i + 1], QPU_R_MS_REV_FLAGS));
224 assert(!reads_a_reg(insts[i + 2], QPU_R_MS_REV_FLAGS));
225 }
226 }
227
228 /*
229 * "A single instruction can only perform a maximum of one of the
230 * following closely coupled peripheral accesses in a single
231 * instruction: TMU write, TMU read, TLB write, TLB read, TLB
232 * combined color read and write, SFU write, Mutex read or Semaphore
233 * access."
234 */
235 for (int i = 0; i < num_inst - 1; i++) {
236 uint64_t inst = insts[i];
237 int accesses = 0;
238 static const uint32_t specials[] = {
239 QPU_W_TLB_COLOR_MS,
240 QPU_W_TLB_COLOR_ALL,
241 QPU_W_TLB_Z,
242 QPU_W_TMU0_S,
243 QPU_W_TMU0_T,
244 QPU_W_TMU0_R,
245 QPU_W_TMU0_B,
246 QPU_W_TMU1_S,
247 QPU_W_TMU1_T,
248 QPU_W_TMU1_R,
249 QPU_W_TMU1_B,
250 QPU_W_SFU_RECIP,
251 QPU_W_SFU_RECIPSQRT,
252 QPU_W_SFU_EXP,
253 QPU_W_SFU_LOG,
254 };
255
256 for (int j = 0; j < ARRAY_SIZE(specials); j++) {
257 if (writes_reg(inst, specials[j]))
258 accesses++;
259 }
260
261 if (reads_reg(inst, QPU_R_MUTEX_ACQUIRE))
262 accesses++;
263
264 /* XXX: semaphore, combined color read/write? */
265 switch (QPU_GET_FIELD(inst, QPU_SIG)) {
266 case QPU_SIG_COLOR_LOAD:
267 case QPU_SIG_COLOR_LOAD_END:
268 case QPU_SIG_LOAD_TMU0:
269 case QPU_SIG_LOAD_TMU1:
270 accesses++;
271 }
272
273 assert(accesses <= 1);
274 }
275 }