093ca077e6dd6b7cb1674bf61a7863e700b30f00
[mesa.git] / src / gallium / drivers / vc4 / vc4_qpu.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 <stdbool.h>
25 #include "vc4_qpu.h"
26
27 static uint64_t
28 set_src_raddr(uint64_t inst, struct qpu_reg src)
29 {
30 if (src.mux == QPU_MUX_A) {
31 assert(QPU_GET_FIELD(inst, QPU_RADDR_A) == QPU_R_NOP ||
32 QPU_GET_FIELD(inst, QPU_RADDR_A) == src.addr);
33 return ((inst & ~QPU_RADDR_A_MASK) |
34 QPU_SET_FIELD(src.addr, QPU_RADDR_A));
35 }
36
37 if (src.mux == QPU_MUX_B) {
38 assert(QPU_GET_FIELD(inst, QPU_RADDR_B) == QPU_R_NOP ||
39 QPU_GET_FIELD(inst, QPU_RADDR_B) == src.addr);
40 return ((inst & ~QPU_RADDR_B_MASK) |
41 QPU_SET_FIELD(src.addr, QPU_RADDR_B));
42 }
43
44 return inst;
45 }
46
47 uint64_t
48 qpu_NOP()
49 {
50 uint64_t inst = 0;
51
52 inst |= QPU_SET_FIELD(QPU_A_NOP, QPU_OP_ADD);
53 inst |= QPU_SET_FIELD(QPU_M_NOP, QPU_OP_MUL);
54
55 /* Note: These field values are actually non-zero */
56 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_ADD);
57 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_MUL);
58 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A);
59 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B);
60 inst |= QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG);
61
62 return inst;
63 }
64
65 static uint64_t
66 qpu_a_dst(struct qpu_reg dst)
67 {
68 uint64_t inst = 0;
69
70 if (dst.mux <= QPU_MUX_R5) {
71 /* Translate the mux to the ACCn values. */
72 inst |= QPU_SET_FIELD(32 + dst.mux, QPU_WADDR_ADD);
73 } else {
74 inst |= QPU_SET_FIELD(dst.addr, QPU_WADDR_ADD);
75 if (dst.mux == QPU_MUX_B)
76 inst |= QPU_WS;
77 }
78
79 return inst;
80 }
81
82 static uint64_t
83 qpu_m_dst(struct qpu_reg dst)
84 {
85 uint64_t inst = 0;
86
87 if (dst.mux <= QPU_MUX_R5) {
88 /* Translate the mux to the ACCn values. */
89 inst |= QPU_SET_FIELD(32 + dst.mux, QPU_WADDR_MUL);
90 } else {
91 inst |= QPU_SET_FIELD(dst.addr, QPU_WADDR_MUL);
92 if (dst.mux == QPU_MUX_A)
93 inst |= QPU_WS;
94 }
95
96 return inst;
97 }
98
99 uint64_t
100 qpu_a_MOV(struct qpu_reg dst, struct qpu_reg src)
101 {
102 uint64_t inst = 0;
103
104 inst |= QPU_SET_FIELD(QPU_A_OR, QPU_OP_ADD);
105 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A);
106 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B);
107 inst |= qpu_a_dst(dst);
108 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_ADD);
109 inst |= QPU_SET_FIELD(src.mux, QPU_ADD_A);
110 inst |= QPU_SET_FIELD(src.mux, QPU_ADD_B);
111 inst = set_src_raddr(inst, src);
112 inst |= QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG);
113 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_MUL);
114
115 return inst;
116 }
117
118 uint64_t
119 qpu_m_MOV(struct qpu_reg dst, struct qpu_reg src)
120 {
121 uint64_t inst = 0;
122
123 inst |= QPU_SET_FIELD(QPU_M_V8MIN, QPU_OP_MUL);
124 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A);
125 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B);
126 inst |= qpu_m_dst(dst);
127 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_MUL);
128 inst |= QPU_SET_FIELD(src.mux, QPU_MUL_A);
129 inst |= QPU_SET_FIELD(src.mux, QPU_MUL_B);
130 inst = set_src_raddr(inst, src);
131 inst |= QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG);
132 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_ADD);
133
134 return inst;
135 }
136
137 uint64_t
138 qpu_load_imm_ui(struct qpu_reg dst, uint32_t val)
139 {
140 uint64_t inst = 0;
141
142 inst |= qpu_a_dst(dst);
143 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_MUL);
144 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_ADD);
145 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_MUL);
146 inst |= QPU_SET_FIELD(QPU_SIG_LOAD_IMM, QPU_SIG);
147 inst |= val;
148
149 return inst;
150 }
151
152 uint64_t
153 qpu_a_alu2(enum qpu_op_add op,
154 struct qpu_reg dst, struct qpu_reg src0, struct qpu_reg src1)
155 {
156 uint64_t inst = 0;
157
158 inst |= QPU_SET_FIELD(op, QPU_OP_ADD);
159 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A);
160 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B);
161 inst |= qpu_a_dst(dst);
162 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_ADD);
163 inst |= QPU_SET_FIELD(src0.mux, QPU_ADD_A);
164 inst = set_src_raddr(inst, src0);
165 inst |= QPU_SET_FIELD(src1.mux, QPU_ADD_B);
166 inst = set_src_raddr(inst, src1);
167 inst |= QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG);
168 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_MUL);
169
170 return inst;
171 }
172
173 uint64_t
174 qpu_m_alu2(enum qpu_op_mul op,
175 struct qpu_reg dst, struct qpu_reg src0, struct qpu_reg src1)
176 {
177 uint64_t inst = 0;
178
179 inst |= QPU_SET_FIELD(op, QPU_OP_MUL);
180 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A);
181 inst |= QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B);
182 inst |= qpu_m_dst(dst);
183 inst |= QPU_SET_FIELD(QPU_COND_ALWAYS, QPU_COND_MUL);
184 inst |= QPU_SET_FIELD(src0.mux, QPU_MUL_A);
185 inst = set_src_raddr(inst, src0);
186 inst |= QPU_SET_FIELD(src1.mux, QPU_MUL_B);
187 inst = set_src_raddr(inst, src1);
188 inst |= QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG);
189 inst |= QPU_SET_FIELD(QPU_W_NOP, QPU_WADDR_ADD);
190
191 return inst;
192 }
193
194 static uint64_t
195 merge_fields(uint64_t merge,
196 uint64_t add, uint64_t mul,
197 uint64_t mask, uint64_t ignore)
198 {
199 if ((add & mask) == ignore)
200 return (merge & ~mask) | (mul & mask);
201 else if ((mul & mask) == ignore)
202 return (merge & ~mask) | (add & mask);
203 else {
204 assert((add & mask) == (mul & mask));
205 return merge;
206 }
207 }
208
209 uint64_t
210 qpu_inst(uint64_t add, uint64_t mul)
211 {
212 uint64_t merge = ((add & ~QPU_WADDR_MUL_MASK) |
213 (mul & ~QPU_WADDR_ADD_MASK));
214
215 merge = merge_fields(merge, add, mul, QPU_SIG_MASK,
216 QPU_SET_FIELD(QPU_SIG_NONE, QPU_SIG));
217
218 merge = merge_fields(merge, add, mul, QPU_RADDR_A_MASK,
219 QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_A));
220 merge = merge_fields(merge, add, mul, QPU_RADDR_B_MASK,
221 QPU_SET_FIELD(QPU_R_NOP, QPU_RADDR_B));
222
223 return merge;
224 }
225
226 uint64_t
227 qpu_set_sig(uint64_t inst, uint32_t sig)
228 {
229 assert(QPU_GET_FIELD(inst, QPU_SIG) == QPU_SIG_NONE);
230 return (inst & ~QPU_SIG_MASK) | QPU_SET_FIELD(sig, QPU_SIG);
231 }
232
233 uint64_t
234 qpu_set_cond_add(uint64_t inst, uint32_t sig)
235 {
236 assert(QPU_GET_FIELD(inst, QPU_COND_ADD) == QPU_COND_ALWAYS);
237 return (inst & ~QPU_COND_ADD_MASK) | QPU_SET_FIELD(sig, QPU_COND_ADD);
238 }
239
240 uint64_t
241 qpu_set_cond_mul(uint64_t inst, uint32_t sig)
242 {
243 assert(QPU_GET_FIELD(inst, QPU_COND_MUL) == QPU_COND_ALWAYS);
244 return (inst & ~QPU_COND_MUL_MASK) | QPU_SET_FIELD(sig, QPU_COND_MUL);
245 }
246
247 bool
248 qpu_waddr_is_tlb(uint32_t waddr)
249 {
250 switch (waddr) {
251 case QPU_W_TLB_COLOR_ALL:
252 case QPU_W_TLB_COLOR_MS:
253 case QPU_W_TLB_Z:
254 return true;
255 default:
256 return false;
257 }
258 }
259
260 bool
261 qpu_inst_is_tlb(uint64_t inst)
262 {
263 uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);
264
265 return (qpu_waddr_is_tlb(QPU_GET_FIELD(inst, QPU_WADDR_ADD)) ||
266 qpu_waddr_is_tlb(QPU_GET_FIELD(inst, QPU_WADDR_MUL)) ||
267 sig == QPU_SIG_COLOR_LOAD ||
268 sig == QPU_SIG_WAIT_FOR_SCOREBOARD);
269 }