1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2014 Broadcom
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker /**
25*61046927SAndroid Build Coastguard Worker * @file
26*61046927SAndroid Build Coastguard Worker *
27*61046927SAndroid Build Coastguard Worker * Validates the QPU instruction sequence after register allocation and
28*61046927SAndroid Build Coastguard Worker * scheduling.
29*61046927SAndroid Build Coastguard Worker */
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker #include <assert.h>
32*61046927SAndroid Build Coastguard Worker #include <stdio.h>
33*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
34*61046927SAndroid Build Coastguard Worker #include "v3d_compiler.h"
35*61046927SAndroid Build Coastguard Worker #include "qpu/qpu_disasm.h"
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker struct v3d_qpu_validate_state {
38*61046927SAndroid Build Coastguard Worker struct v3d_compile *c;
39*61046927SAndroid Build Coastguard Worker const struct v3d_qpu_instr *last;
40*61046927SAndroid Build Coastguard Worker int ip;
41*61046927SAndroid Build Coastguard Worker int last_sfu_write;
42*61046927SAndroid Build Coastguard Worker int last_branch_ip;
43*61046927SAndroid Build Coastguard Worker int last_thrsw_ip;
44*61046927SAndroid Build Coastguard Worker int first_tlb_z_write;
45*61046927SAndroid Build Coastguard Worker
46*61046927SAndroid Build Coastguard Worker /* Set when we've found the last-THRSW signal, or if we were started
47*61046927SAndroid Build Coastguard Worker * in single-segment mode.
48*61046927SAndroid Build Coastguard Worker */
49*61046927SAndroid Build Coastguard Worker bool last_thrsw_found;
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker /* Set when we've found the THRSW after the last THRSW */
52*61046927SAndroid Build Coastguard Worker bool thrend_found;
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Worker int thrsw_count;
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker bool rtop_hazard;
57*61046927SAndroid Build Coastguard Worker bool rtop_valid;
58*61046927SAndroid Build Coastguard Worker };
59*61046927SAndroid Build Coastguard Worker
60*61046927SAndroid Build Coastguard Worker static void
fail_instr(struct v3d_qpu_validate_state * state,const char * msg)61*61046927SAndroid Build Coastguard Worker fail_instr(struct v3d_qpu_validate_state *state, const char *msg)
62*61046927SAndroid Build Coastguard Worker {
63*61046927SAndroid Build Coastguard Worker struct v3d_compile *c = state->c;
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker fprintf(stderr, "v3d_qpu_validate at ip %d: %s:\n", state->ip, msg);
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker int dump_ip = 0;
68*61046927SAndroid Build Coastguard Worker vir_for_each_inst_inorder(inst, c) {
69*61046927SAndroid Build Coastguard Worker v3d_qpu_dump(c->devinfo, &inst->qpu);
70*61046927SAndroid Build Coastguard Worker
71*61046927SAndroid Build Coastguard Worker if (dump_ip++ == state->ip)
72*61046927SAndroid Build Coastguard Worker fprintf(stderr, " *** ERROR ***");
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker fprintf(stderr, "\n");
75*61046927SAndroid Build Coastguard Worker }
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker fprintf(stderr, "\n");
78*61046927SAndroid Build Coastguard Worker abort();
79*61046927SAndroid Build Coastguard Worker }
80*61046927SAndroid Build Coastguard Worker
81*61046927SAndroid Build Coastguard Worker static bool
in_branch_delay_slots(struct v3d_qpu_validate_state * state)82*61046927SAndroid Build Coastguard Worker in_branch_delay_slots(struct v3d_qpu_validate_state *state)
83*61046927SAndroid Build Coastguard Worker {
84*61046927SAndroid Build Coastguard Worker return (state->ip - state->last_branch_ip) < 3;
85*61046927SAndroid Build Coastguard Worker }
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker static bool
in_thrsw_delay_slots(struct v3d_qpu_validate_state * state)88*61046927SAndroid Build Coastguard Worker in_thrsw_delay_slots(struct v3d_qpu_validate_state *state)
89*61046927SAndroid Build Coastguard Worker {
90*61046927SAndroid Build Coastguard Worker return (state->ip - state->last_thrsw_ip) < 3;
91*61046927SAndroid Build Coastguard Worker }
92*61046927SAndroid Build Coastguard Worker
93*61046927SAndroid Build Coastguard Worker static bool
qpu_magic_waddr_matches(const struct v3d_qpu_instr * inst,bool (* predicate)(enum v3d_qpu_waddr waddr))94*61046927SAndroid Build Coastguard Worker qpu_magic_waddr_matches(const struct v3d_qpu_instr *inst,
95*61046927SAndroid Build Coastguard Worker bool (*predicate)(enum v3d_qpu_waddr waddr))
96*61046927SAndroid Build Coastguard Worker {
97*61046927SAndroid Build Coastguard Worker if (inst->type == V3D_QPU_INSTR_TYPE_ALU)
98*61046927SAndroid Build Coastguard Worker return false;
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker if (inst->alu.add.op != V3D_QPU_A_NOP &&
101*61046927SAndroid Build Coastguard Worker inst->alu.add.magic_write &&
102*61046927SAndroid Build Coastguard Worker predicate(inst->alu.add.waddr))
103*61046927SAndroid Build Coastguard Worker return true;
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.op != V3D_QPU_M_NOP &&
106*61046927SAndroid Build Coastguard Worker inst->alu.mul.magic_write &&
107*61046927SAndroid Build Coastguard Worker predicate(inst->alu.mul.waddr))
108*61046927SAndroid Build Coastguard Worker return true;
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker return false;
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker static void
qpu_validate_inst(struct v3d_qpu_validate_state * state,struct qinst * qinst)114*61046927SAndroid Build Coastguard Worker qpu_validate_inst(struct v3d_qpu_validate_state *state, struct qinst *qinst)
115*61046927SAndroid Build Coastguard Worker {
116*61046927SAndroid Build Coastguard Worker const struct v3d_device_info *devinfo = state->c->devinfo;
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Worker if (qinst->is_tlb_z_write && state->ip < state->first_tlb_z_write)
119*61046927SAndroid Build Coastguard Worker state->first_tlb_z_write = state->ip;
120*61046927SAndroid Build Coastguard Worker
121*61046927SAndroid Build Coastguard Worker const struct v3d_qpu_instr *inst = &qinst->qpu;
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker if (inst->type == V3D_QPU_INSTR_TYPE_BRANCH &&
124*61046927SAndroid Build Coastguard Worker state->first_tlb_z_write >= 0 &&
125*61046927SAndroid Build Coastguard Worker state->ip > state->first_tlb_z_write &&
126*61046927SAndroid Build Coastguard Worker inst->branch.msfign != V3D_QPU_MSFIGN_NONE &&
127*61046927SAndroid Build Coastguard Worker inst->branch.cond != V3D_QPU_BRANCH_COND_ALWAYS &&
128*61046927SAndroid Build Coastguard Worker inst->branch.cond != V3D_QPU_BRANCH_COND_A0 &&
129*61046927SAndroid Build Coastguard Worker inst->branch.cond != V3D_QPU_BRANCH_COND_NA0) {
130*61046927SAndroid Build Coastguard Worker fail_instr(state, "Implicit branch MSF read after TLB Z write");
131*61046927SAndroid Build Coastguard Worker }
132*61046927SAndroid Build Coastguard Worker
133*61046927SAndroid Build Coastguard Worker if (inst->type != V3D_QPU_INSTR_TYPE_ALU)
134*61046927SAndroid Build Coastguard Worker return;
135*61046927SAndroid Build Coastguard Worker
136*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.op == V3D_QPU_M_MULTOP)
137*61046927SAndroid Build Coastguard Worker state->rtop_valid = true;
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.op == V3D_QPU_M_UMUL24) {
140*61046927SAndroid Build Coastguard Worker if (state->rtop_hazard)
141*61046927SAndroid Build Coastguard Worker fail_instr(state, "UMUL24 reads rtop from MULTOP but it got cleared by a previous THRSW");
142*61046927SAndroid Build Coastguard Worker state->rtop_valid = false;
143*61046927SAndroid Build Coastguard Worker state->rtop_hazard = false;
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker if (inst->alu.add.op == V3D_QPU_A_SETMSF &&
147*61046927SAndroid Build Coastguard Worker state->first_tlb_z_write >= 0 &&
148*61046927SAndroid Build Coastguard Worker state->ip > state->first_tlb_z_write) {
149*61046927SAndroid Build Coastguard Worker fail_instr(state, "SETMSF after TLB Z write");
150*61046927SAndroid Build Coastguard Worker }
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker if (state->first_tlb_z_write >= 0 &&
153*61046927SAndroid Build Coastguard Worker state->ip > state->first_tlb_z_write &&
154*61046927SAndroid Build Coastguard Worker inst->alu.add.op == V3D_QPU_A_MSF) {
155*61046927SAndroid Build Coastguard Worker fail_instr(state, "MSF read after TLB Z write");
156*61046927SAndroid Build Coastguard Worker }
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker if (devinfo->ver < 71) {
159*61046927SAndroid Build Coastguard Worker if (inst->sig.small_imm_a || inst->sig.small_imm_c ||
160*61046927SAndroid Build Coastguard Worker inst->sig.small_imm_d) {
161*61046927SAndroid Build Coastguard Worker fail_instr(state, "small imm a/c/d added after V3D 7.1");
162*61046927SAndroid Build Coastguard Worker }
163*61046927SAndroid Build Coastguard Worker } else {
164*61046927SAndroid Build Coastguard Worker if ((inst->sig.small_imm_a || inst->sig.small_imm_b) &&
165*61046927SAndroid Build Coastguard Worker !vir_is_add(qinst)) {
166*61046927SAndroid Build Coastguard Worker fail_instr(state, "small imm a/b used but no ADD inst");
167*61046927SAndroid Build Coastguard Worker }
168*61046927SAndroid Build Coastguard Worker if ((inst->sig.small_imm_c || inst->sig.small_imm_d) &&
169*61046927SAndroid Build Coastguard Worker !vir_is_mul(qinst)) {
170*61046927SAndroid Build Coastguard Worker fail_instr(state, "small imm c/d used but no MUL inst");
171*61046927SAndroid Build Coastguard Worker }
172*61046927SAndroid Build Coastguard Worker if (inst->sig.small_imm_a + inst->sig.small_imm_b +
173*61046927SAndroid Build Coastguard Worker inst->sig.small_imm_c + inst->sig.small_imm_d > 1) {
174*61046927SAndroid Build Coastguard Worker fail_instr(state, "only one small immediate can be "
175*61046927SAndroid Build Coastguard Worker "enabled per instruction");
176*61046927SAndroid Build Coastguard Worker }
177*61046927SAndroid Build Coastguard Worker }
178*61046927SAndroid Build Coastguard Worker
179*61046927SAndroid Build Coastguard Worker /* LDVARY writes r5 two instructions later and LDUNIF writes
180*61046927SAndroid Build Coastguard Worker * r5 one instruction later, which is illegal to have
181*61046927SAndroid Build Coastguard Worker * together.
182*61046927SAndroid Build Coastguard Worker */
183*61046927SAndroid Build Coastguard Worker if (state->last && state->last->sig.ldvary &&
184*61046927SAndroid Build Coastguard Worker (inst->sig.ldunif || inst->sig.ldunifa)) {
185*61046927SAndroid Build Coastguard Worker fail_instr(state, "LDUNIF after a LDVARY");
186*61046927SAndroid Build Coastguard Worker }
187*61046927SAndroid Build Coastguard Worker
188*61046927SAndroid Build Coastguard Worker /* GFXH-1633 (fixed since V3D 4.2.14, which is Rpi4)
189*61046927SAndroid Build Coastguard Worker *
190*61046927SAndroid Build Coastguard Worker * FIXME: This would not check correctly for V3D 4.2 versions lower
191*61046927SAndroid Build Coastguard Worker * than V3D 4.2.14, but that is not a real issue because the simulator
192*61046927SAndroid Build Coastguard Worker * will still catch this, and we are not really targeting any such
193*61046927SAndroid Build Coastguard Worker * versions anyway.
194*61046927SAndroid Build Coastguard Worker */
195*61046927SAndroid Build Coastguard Worker if (state->c->devinfo->ver < 42) {
196*61046927SAndroid Build Coastguard Worker bool last_reads_ldunif = (state->last && (state->last->sig.ldunif ||
197*61046927SAndroid Build Coastguard Worker state->last->sig.ldunifrf));
198*61046927SAndroid Build Coastguard Worker bool last_reads_ldunifa = (state->last && (state->last->sig.ldunifa ||
199*61046927SAndroid Build Coastguard Worker state->last->sig.ldunifarf));
200*61046927SAndroid Build Coastguard Worker bool reads_ldunif = inst->sig.ldunif || inst->sig.ldunifrf;
201*61046927SAndroid Build Coastguard Worker bool reads_ldunifa = inst->sig.ldunifa || inst->sig.ldunifarf;
202*61046927SAndroid Build Coastguard Worker if ((last_reads_ldunif && reads_ldunifa) ||
203*61046927SAndroid Build Coastguard Worker (last_reads_ldunifa && reads_ldunif)) {
204*61046927SAndroid Build Coastguard Worker fail_instr(state,
205*61046927SAndroid Build Coastguard Worker "LDUNIF and LDUNIFA can't be next to each other");
206*61046927SAndroid Build Coastguard Worker }
207*61046927SAndroid Build Coastguard Worker }
208*61046927SAndroid Build Coastguard Worker
209*61046927SAndroid Build Coastguard Worker int tmu_writes = 0;
210*61046927SAndroid Build Coastguard Worker int sfu_writes = 0;
211*61046927SAndroid Build Coastguard Worker int vpm_writes = 0;
212*61046927SAndroid Build Coastguard Worker int tlb_writes = 0;
213*61046927SAndroid Build Coastguard Worker int tsy_writes = 0;
214*61046927SAndroid Build Coastguard Worker
215*61046927SAndroid Build Coastguard Worker if (inst->alu.add.op != V3D_QPU_A_NOP) {
216*61046927SAndroid Build Coastguard Worker if (inst->alu.add.magic_write) {
217*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tmu(state->c->devinfo,
218*61046927SAndroid Build Coastguard Worker inst->alu.add.waddr)) {
219*61046927SAndroid Build Coastguard Worker tmu_writes++;
220*61046927SAndroid Build Coastguard Worker }
221*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_sfu(inst->alu.add.waddr))
222*61046927SAndroid Build Coastguard Worker sfu_writes++;
223*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_vpm(inst->alu.add.waddr))
224*61046927SAndroid Build Coastguard Worker vpm_writes++;
225*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tlb(inst->alu.add.waddr))
226*61046927SAndroid Build Coastguard Worker tlb_writes++;
227*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tsy(inst->alu.add.waddr))
228*61046927SAndroid Build Coastguard Worker tsy_writes++;
229*61046927SAndroid Build Coastguard Worker }
230*61046927SAndroid Build Coastguard Worker }
231*61046927SAndroid Build Coastguard Worker
232*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.op != V3D_QPU_M_NOP) {
233*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.magic_write) {
234*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tmu(state->c->devinfo,
235*61046927SAndroid Build Coastguard Worker inst->alu.mul.waddr)) {
236*61046927SAndroid Build Coastguard Worker tmu_writes++;
237*61046927SAndroid Build Coastguard Worker }
238*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_sfu(inst->alu.mul.waddr))
239*61046927SAndroid Build Coastguard Worker sfu_writes++;
240*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_vpm(inst->alu.mul.waddr))
241*61046927SAndroid Build Coastguard Worker vpm_writes++;
242*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tlb(inst->alu.mul.waddr))
243*61046927SAndroid Build Coastguard Worker tlb_writes++;
244*61046927SAndroid Build Coastguard Worker if (v3d_qpu_magic_waddr_is_tsy(inst->alu.mul.waddr))
245*61046927SAndroid Build Coastguard Worker tsy_writes++;
246*61046927SAndroid Build Coastguard Worker }
247*61046927SAndroid Build Coastguard Worker }
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker if (in_thrsw_delay_slots(state)) {
250*61046927SAndroid Build Coastguard Worker /* There's no way you want to start SFU during the THRSW delay
251*61046927SAndroid Build Coastguard Worker * slots, since the result would land in the other thread.
252*61046927SAndroid Build Coastguard Worker */
253*61046927SAndroid Build Coastguard Worker if (sfu_writes) {
254*61046927SAndroid Build Coastguard Worker fail_instr(state,
255*61046927SAndroid Build Coastguard Worker "SFU write started during THRSW delay slots ");
256*61046927SAndroid Build Coastguard Worker }
257*61046927SAndroid Build Coastguard Worker
258*61046927SAndroid Build Coastguard Worker if (inst->sig.ldvary) {
259*61046927SAndroid Build Coastguard Worker if (devinfo->ver == 42)
260*61046927SAndroid Build Coastguard Worker fail_instr(state, "LDVARY during THRSW delay slots");
261*61046927SAndroid Build Coastguard Worker if (devinfo->ver >= 71 &&
262*61046927SAndroid Build Coastguard Worker state->ip - state->last_thrsw_ip == 2) {
263*61046927SAndroid Build Coastguard Worker fail_instr(state, "LDVARY in 2nd THRSW delay slot");
264*61046927SAndroid Build Coastguard Worker }
265*61046927SAndroid Build Coastguard Worker }
266*61046927SAndroid Build Coastguard Worker }
267*61046927SAndroid Build Coastguard Worker
268*61046927SAndroid Build Coastguard Worker (void)qpu_magic_waddr_matches; /* XXX */
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker /* SFU r4 results come back two instructions later. No doing
271*61046927SAndroid Build Coastguard Worker * r4 read/writes or other SFU lookups until it's done.
272*61046927SAndroid Build Coastguard Worker */
273*61046927SAndroid Build Coastguard Worker if (state->ip - state->last_sfu_write < 2) {
274*61046927SAndroid Build Coastguard Worker if (v3d_qpu_uses_mux(inst, V3D_QPU_MUX_R4))
275*61046927SAndroid Build Coastguard Worker fail_instr(state, "R4 read too soon after SFU");
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker if (v3d_qpu_writes_r4(devinfo, inst))
278*61046927SAndroid Build Coastguard Worker fail_instr(state, "R4 write too soon after SFU");
279*61046927SAndroid Build Coastguard Worker
280*61046927SAndroid Build Coastguard Worker if (sfu_writes)
281*61046927SAndroid Build Coastguard Worker fail_instr(state, "SFU write too soon after SFU");
282*61046927SAndroid Build Coastguard Worker }
283*61046927SAndroid Build Coastguard Worker
284*61046927SAndroid Build Coastguard Worker /* XXX: The docs say VPM can happen with the others, but the simulator
285*61046927SAndroid Build Coastguard Worker * disagrees.
286*61046927SAndroid Build Coastguard Worker */
287*61046927SAndroid Build Coastguard Worker if (tmu_writes +
288*61046927SAndroid Build Coastguard Worker sfu_writes +
289*61046927SAndroid Build Coastguard Worker vpm_writes +
290*61046927SAndroid Build Coastguard Worker tlb_writes +
291*61046927SAndroid Build Coastguard Worker tsy_writes +
292*61046927SAndroid Build Coastguard Worker (devinfo->ver == 42 ? inst->sig.ldtmu : 0) +
293*61046927SAndroid Build Coastguard Worker inst->sig.ldtlb +
294*61046927SAndroid Build Coastguard Worker inst->sig.ldvpm +
295*61046927SAndroid Build Coastguard Worker inst->sig.ldtlbu > 1) {
296*61046927SAndroid Build Coastguard Worker fail_instr(state,
297*61046927SAndroid Build Coastguard Worker "Only one of [TMU, SFU, TSY, TLB read, VPM] allowed");
298*61046927SAndroid Build Coastguard Worker }
299*61046927SAndroid Build Coastguard Worker
300*61046927SAndroid Build Coastguard Worker if (sfu_writes)
301*61046927SAndroid Build Coastguard Worker state->last_sfu_write = state->ip;
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker if (inst->sig.thrsw) {
304*61046927SAndroid Build Coastguard Worker if (in_branch_delay_slots(state))
305*61046927SAndroid Build Coastguard Worker fail_instr(state, "THRSW in a branch delay slot.");
306*61046927SAndroid Build Coastguard Worker
307*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_found)
308*61046927SAndroid Build Coastguard Worker state->thrend_found = true;
309*61046927SAndroid Build Coastguard Worker
310*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_ip == state->ip - 1) {
311*61046927SAndroid Build Coastguard Worker /* If it's the second THRSW in a row, then it's just a
312*61046927SAndroid Build Coastguard Worker * last-thrsw signal.
313*61046927SAndroid Build Coastguard Worker */
314*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_found)
315*61046927SAndroid Build Coastguard Worker fail_instr(state, "Two last-THRSW signals");
316*61046927SAndroid Build Coastguard Worker state->last_thrsw_found = true;
317*61046927SAndroid Build Coastguard Worker } else {
318*61046927SAndroid Build Coastguard Worker if (in_thrsw_delay_slots(state)) {
319*61046927SAndroid Build Coastguard Worker fail_instr(state,
320*61046927SAndroid Build Coastguard Worker "THRSW too close to another THRSW.");
321*61046927SAndroid Build Coastguard Worker }
322*61046927SAndroid Build Coastguard Worker state->thrsw_count++;
323*61046927SAndroid Build Coastguard Worker state->last_thrsw_ip = state->ip;
324*61046927SAndroid Build Coastguard Worker }
325*61046927SAndroid Build Coastguard Worker }
326*61046927SAndroid Build Coastguard Worker
327*61046927SAndroid Build Coastguard Worker if (state->thrend_found &&
328*61046927SAndroid Build Coastguard Worker state->last_thrsw_ip - state->ip <= 2 &&
329*61046927SAndroid Build Coastguard Worker inst->type == V3D_QPU_INSTR_TYPE_ALU) {
330*61046927SAndroid Build Coastguard Worker if ((inst->alu.add.op != V3D_QPU_A_NOP &&
331*61046927SAndroid Build Coastguard Worker !inst->alu.add.magic_write)) {
332*61046927SAndroid Build Coastguard Worker if (devinfo->ver == 42) {
333*61046927SAndroid Build Coastguard Worker fail_instr(state, "RF write after THREND");
334*61046927SAndroid Build Coastguard Worker } else if (devinfo->ver >= 71) {
335*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_ip - state->ip == 0) {
336*61046927SAndroid Build Coastguard Worker fail_instr(state,
337*61046927SAndroid Build Coastguard Worker "ADD RF write at THREND");
338*61046927SAndroid Build Coastguard Worker }
339*61046927SAndroid Build Coastguard Worker if (inst->alu.add.waddr == 2 ||
340*61046927SAndroid Build Coastguard Worker inst->alu.add.waddr == 3) {
341*61046927SAndroid Build Coastguard Worker fail_instr(state,
342*61046927SAndroid Build Coastguard Worker "RF2-3 write after THREND");
343*61046927SAndroid Build Coastguard Worker }
344*61046927SAndroid Build Coastguard Worker }
345*61046927SAndroid Build Coastguard Worker }
346*61046927SAndroid Build Coastguard Worker
347*61046927SAndroid Build Coastguard Worker if ((inst->alu.mul.op != V3D_QPU_M_NOP &&
348*61046927SAndroid Build Coastguard Worker !inst->alu.mul.magic_write)) {
349*61046927SAndroid Build Coastguard Worker if (devinfo->ver == 42) {
350*61046927SAndroid Build Coastguard Worker fail_instr(state, "RF write after THREND");
351*61046927SAndroid Build Coastguard Worker } else if (devinfo->ver >= 71) {
352*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_ip - state->ip == 0) {
353*61046927SAndroid Build Coastguard Worker fail_instr(state,
354*61046927SAndroid Build Coastguard Worker "MUL RF write at THREND");
355*61046927SAndroid Build Coastguard Worker }
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker if (inst->alu.mul.waddr == 2 ||
358*61046927SAndroid Build Coastguard Worker inst->alu.mul.waddr == 3) {
359*61046927SAndroid Build Coastguard Worker fail_instr(state,
360*61046927SAndroid Build Coastguard Worker "RF2-3 write after THREND");
361*61046927SAndroid Build Coastguard Worker }
362*61046927SAndroid Build Coastguard Worker }
363*61046927SAndroid Build Coastguard Worker }
364*61046927SAndroid Build Coastguard Worker
365*61046927SAndroid Build Coastguard Worker if (v3d_qpu_sig_writes_address(devinfo, &inst->sig) &&
366*61046927SAndroid Build Coastguard Worker !inst->sig_magic) {
367*61046927SAndroid Build Coastguard Worker if (devinfo->ver == 42) {
368*61046927SAndroid Build Coastguard Worker fail_instr(state, "RF write after THREND");
369*61046927SAndroid Build Coastguard Worker } else if (devinfo->ver >= 71 &&
370*61046927SAndroid Build Coastguard Worker (inst->sig_addr == 2 ||
371*61046927SAndroid Build Coastguard Worker inst->sig_addr == 3)) {
372*61046927SAndroid Build Coastguard Worker fail_instr(state, "RF2-3 write after THREND");
373*61046927SAndroid Build Coastguard Worker }
374*61046927SAndroid Build Coastguard Worker }
375*61046927SAndroid Build Coastguard Worker
376*61046927SAndroid Build Coastguard Worker /* GFXH-1625: No TMUWT in the last instruction */
377*61046927SAndroid Build Coastguard Worker if (state->last_thrsw_ip - state->ip == 2 &&
378*61046927SAndroid Build Coastguard Worker inst->alu.add.op == V3D_QPU_A_TMUWT)
379*61046927SAndroid Build Coastguard Worker fail_instr(state, "TMUWT in last instruction");
380*61046927SAndroid Build Coastguard Worker }
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker if (state->rtop_valid && state->ip == state->last_thrsw_ip + 2) {
383*61046927SAndroid Build Coastguard Worker state->rtop_hazard = true;
384*61046927SAndroid Build Coastguard Worker state->rtop_valid = false;
385*61046927SAndroid Build Coastguard Worker }
386*61046927SAndroid Build Coastguard Worker
387*61046927SAndroid Build Coastguard Worker if (inst->type == V3D_QPU_INSTR_TYPE_BRANCH) {
388*61046927SAndroid Build Coastguard Worker if (in_branch_delay_slots(state))
389*61046927SAndroid Build Coastguard Worker fail_instr(state, "branch in a branch delay slot.");
390*61046927SAndroid Build Coastguard Worker if (in_thrsw_delay_slots(state))
391*61046927SAndroid Build Coastguard Worker fail_instr(state, "branch in a THRSW delay slot.");
392*61046927SAndroid Build Coastguard Worker state->last_branch_ip = state->ip;
393*61046927SAndroid Build Coastguard Worker }
394*61046927SAndroid Build Coastguard Worker }
395*61046927SAndroid Build Coastguard Worker
396*61046927SAndroid Build Coastguard Worker static void
qpu_validate_block(struct v3d_qpu_validate_state * state,struct qblock * block)397*61046927SAndroid Build Coastguard Worker qpu_validate_block(struct v3d_qpu_validate_state *state, struct qblock *block)
398*61046927SAndroid Build Coastguard Worker {
399*61046927SAndroid Build Coastguard Worker vir_for_each_inst(qinst, block) {
400*61046927SAndroid Build Coastguard Worker qpu_validate_inst(state, qinst);
401*61046927SAndroid Build Coastguard Worker
402*61046927SAndroid Build Coastguard Worker state->last = &qinst->qpu;
403*61046927SAndroid Build Coastguard Worker state->ip++;
404*61046927SAndroid Build Coastguard Worker }
405*61046927SAndroid Build Coastguard Worker }
406*61046927SAndroid Build Coastguard Worker
407*61046927SAndroid Build Coastguard Worker /**
408*61046927SAndroid Build Coastguard Worker * Checks for the instruction restrictions from page 37 ("Summary of
409*61046927SAndroid Build Coastguard Worker * Instruction Restrictions").
410*61046927SAndroid Build Coastguard Worker */
411*61046927SAndroid Build Coastguard Worker void
qpu_validate(struct v3d_compile * c)412*61046927SAndroid Build Coastguard Worker qpu_validate(struct v3d_compile *c)
413*61046927SAndroid Build Coastguard Worker {
414*61046927SAndroid Build Coastguard Worker /* We don't want to do validation in release builds, but we want to
415*61046927SAndroid Build Coastguard Worker * keep compiling the validation code to make sure it doesn't get
416*61046927SAndroid Build Coastguard Worker * broken.
417*61046927SAndroid Build Coastguard Worker */
418*61046927SAndroid Build Coastguard Worker #if !MESA_DEBUG
419*61046927SAndroid Build Coastguard Worker return;
420*61046927SAndroid Build Coastguard Worker #endif
421*61046927SAndroid Build Coastguard Worker
422*61046927SAndroid Build Coastguard Worker struct v3d_qpu_validate_state state = {
423*61046927SAndroid Build Coastguard Worker .c = c,
424*61046927SAndroid Build Coastguard Worker .last_sfu_write = -10,
425*61046927SAndroid Build Coastguard Worker .last_thrsw_ip = -10,
426*61046927SAndroid Build Coastguard Worker .last_branch_ip = -10,
427*61046927SAndroid Build Coastguard Worker .first_tlb_z_write = INT_MAX,
428*61046927SAndroid Build Coastguard Worker .ip = 0,
429*61046927SAndroid Build Coastguard Worker
430*61046927SAndroid Build Coastguard Worker .last_thrsw_found = !c->last_thrsw,
431*61046927SAndroid Build Coastguard Worker .rtop_hazard = false,
432*61046927SAndroid Build Coastguard Worker .rtop_valid = false,
433*61046927SAndroid Build Coastguard Worker };
434*61046927SAndroid Build Coastguard Worker
435*61046927SAndroid Build Coastguard Worker vir_for_each_block(block, c) {
436*61046927SAndroid Build Coastguard Worker qpu_validate_block(&state, block);
437*61046927SAndroid Build Coastguard Worker }
438*61046927SAndroid Build Coastguard Worker
439*61046927SAndroid Build Coastguard Worker if (state.thrsw_count > 1 && !state.last_thrsw_found) {
440*61046927SAndroid Build Coastguard Worker fail_instr(&state,
441*61046927SAndroid Build Coastguard Worker "thread switch found without last-THRSW in program");
442*61046927SAndroid Build Coastguard Worker }
443*61046927SAndroid Build Coastguard Worker
444*61046927SAndroid Build Coastguard Worker if (!state.thrend_found)
445*61046927SAndroid Build Coastguard Worker fail_instr(&state, "No program-end THRSW found");
446*61046927SAndroid Build Coastguard Worker }
447