Commit | Line | Data |
---|---|---|
aea481da DE |
1 | /* Copyright (C) 1998, Cygnus Solutions */ |
2 | ||
e2306992 | 3 | |
43a6998b FCE |
4 | /* Debugguing PKE? */ |
5 | #define PKE_DEBUG | |
6 | ||
e2306992 | 7 | |
aea481da | 8 | #include <stdlib.h> |
fba9bfed FCE |
9 | #include "sky-pke.h" |
10 | #include "sky-dma.h" | |
db6dac32 | 11 | #include "sim-bits.h" |
fba9bfed FCE |
12 | #include "sim-assert.h" |
13 | #include "sky-vu0.h" | |
14 | #include "sky-vu1.h" | |
15 | #include "sky-gpuif.h" | |
fd909089 | 16 | #include "sky-device.h" |
aea481da DE |
17 | |
18 | ||
19 | /* Internal function declarations */ | |
20 | ||
21 | static int pke_io_read_buffer(device*, void*, int, address_word, | |
22 | unsigned, sim_cpu*, sim_cia); | |
23 | static int pke_io_write_buffer(device*, const void*, int, address_word, | |
24 | unsigned, sim_cpu*, sim_cia); | |
e2306992 | 25 | static void pke_issue(SIM_DESC, struct pke_device*); |
fba9bfed | 26 | static void pke_pc_advance(struct pke_device*, int num_words); |
43a6998b | 27 | static unsigned_4* pke_pc_operand(struct pke_device*, int operand_num); |
db6dac32 FCE |
28 | static unsigned_4 pke_pc_operand_bits(struct pke_device*, int bit_offset, |
29 | int bit_width, unsigned_4* sourceaddr); | |
43a6998b FCE |
30 | static struct fifo_quadword* pke_pc_fifo(struct pke_device*, int operand_num, |
31 | unsigned_4** operand); | |
fba9bfed | 32 | static void pke_attach(SIM_DESC sd, struct pke_device* me); |
43a6998b FCE |
33 | enum pke_check_target { chk_vu, chk_path1, chk_path2, chk_path3 }; |
34 | static int pke_check_stall(struct pke_device* me, enum pke_check_target what); | |
35 | static void pke_flip_dbf(struct pke_device* me); | |
36 | /* PKEcode handlers */ | |
37 | static void pke_code_nop(struct pke_device* me, unsigned_4 pkecode); | |
38 | static void pke_code_stcycl(struct pke_device* me, unsigned_4 pkecode); | |
39 | static void pke_code_offset(struct pke_device* me, unsigned_4 pkecode); | |
40 | static void pke_code_base(struct pke_device* me, unsigned_4 pkecode); | |
41 | static void pke_code_itop(struct pke_device* me, unsigned_4 pkecode); | |
42 | static void pke_code_stmod(struct pke_device* me, unsigned_4 pkecode); | |
43 | static void pke_code_mskpath3(struct pke_device* me, unsigned_4 pkecode); | |
44 | static void pke_code_pkemark(struct pke_device* me, unsigned_4 pkecode); | |
45 | static void pke_code_flushe(struct pke_device* me, unsigned_4 pkecode); | |
46 | static void pke_code_flush(struct pke_device* me, unsigned_4 pkecode); | |
47 | static void pke_code_flusha(struct pke_device* me, unsigned_4 pkecode); | |
48 | static void pke_code_pkemscal(struct pke_device* me, unsigned_4 pkecode); | |
49 | static void pke_code_pkemscnt(struct pke_device* me, unsigned_4 pkecode); | |
50 | static void pke_code_pkemscalf(struct pke_device* me, unsigned_4 pkecode); | |
51 | static void pke_code_stmask(struct pke_device* me, unsigned_4 pkecode); | |
52 | static void pke_code_strow(struct pke_device* me, unsigned_4 pkecode); | |
53 | static void pke_code_stcol(struct pke_device* me, unsigned_4 pkecode); | |
54 | static void pke_code_mpg(struct pke_device* me, unsigned_4 pkecode); | |
55 | static void pke_code_direct(struct pke_device* me, unsigned_4 pkecode); | |
56 | static void pke_code_directhl(struct pke_device* me, unsigned_4 pkecode); | |
57 | static void pke_code_unpack(struct pke_device* me, unsigned_4 pkecode); | |
58 | static void pke_code_error(struct pke_device* me, unsigned_4 pkecode); | |
fba9bfed | 59 | |
aea481da DE |
60 | |
61 | ||
62 | /* Static data */ | |
63 | ||
64 | struct pke_device pke0_device = | |
65 | { | |
66 | { "pke0", &pke_io_read_buffer, &pke_io_write_buffer }, /* device */ | |
67 | 0, 0, /* ID, flags */ | |
aea481da | 68 | {}, /* regs */ |
db6dac32 | 69 | {}, 0, /* FIFO write buffer */ |
aea481da | 70 | NULL, 0, 0, NULL, /* FIFO */ |
fba9bfed | 71 | 0, 0 /* pc */ |
aea481da DE |
72 | }; |
73 | ||
74 | ||
75 | struct pke_device pke1_device = | |
76 | { | |
77 | { "pke1", &pke_io_read_buffer, &pke_io_write_buffer }, /* device */ | |
78 | 1, 0, /* ID, flags */ | |
aea481da | 79 | {}, /* regs */ |
db6dac32 | 80 | {}, 0, /* FIFO write buffer */ |
aea481da | 81 | NULL, 0, 0, NULL, /* FIFO */ |
fba9bfed | 82 | 0, 0 /* pc */ |
aea481da DE |
83 | }; |
84 | ||
85 | ||
86 | ||
87 | /* External functions */ | |
88 | ||
89 | ||
fba9bfed | 90 | /* Attach PKE addresses to main memory */ |
aea481da DE |
91 | |
92 | void | |
93 | pke0_attach(SIM_DESC sd) | |
94 | { | |
fba9bfed FCE |
95 | pke_attach(sd, & pke0_device); |
96 | } | |
aea481da | 97 | |
fba9bfed FCE |
98 | void |
99 | pke1_attach(SIM_DESC sd) | |
100 | { | |
101 | pke_attach(sd, & pke1_device); | |
aea481da DE |
102 | } |
103 | ||
104 | ||
fba9bfed FCE |
105 | |
106 | /* Issue a PKE instruction if possible */ | |
aea481da DE |
107 | |
108 | void | |
e2306992 | 109 | pke0_issue(SIM_DESC sd) |
aea481da | 110 | { |
e2306992 | 111 | pke_issue(sd, & pke0_device); |
fba9bfed FCE |
112 | } |
113 | ||
114 | void | |
e2306992 | 115 | pke1_issue(SIM_DESC sd) |
fba9bfed | 116 | { |
653c2590 | 117 | pke_issue(sd, & pke1_device); |
fba9bfed FCE |
118 | } |
119 | ||
120 | ||
121 | ||
122 | /* Internal functions */ | |
123 | ||
124 | ||
125 | /* Attach PKE memory regions to simulator */ | |
126 | ||
127 | void | |
128 | pke_attach(SIM_DESC sd, struct pke_device* me) | |
129 | { | |
130 | /* register file */ | |
e2306992 | 131 | sim_core_attach (sd, NULL, 0, access_read_write, 0, |
fba9bfed | 132 | (me->pke_number == 0) ? PKE0_REGISTER_WINDOW_START : PKE1_REGISTER_WINDOW_START, |
aea481da DE |
133 | PKE_REGISTER_WINDOW_SIZE /*nr_bytes*/, |
134 | 0 /*modulo*/, | |
e2306992 | 135 | (device*) me, |
aea481da DE |
136 | NULL /*buffer*/); |
137 | ||
fba9bfed | 138 | /* FIFO port */ |
e2306992 | 139 | sim_core_attach (sd, NULL, 0, access_read_write, 0, |
fba9bfed | 140 | (me->pke_number == 0) ? PKE0_FIFO_ADDR : PKE1_FIFO_ADDR, |
aea481da DE |
141 | sizeof(quadword) /*nr_bytes*/, |
142 | 0 /*modulo*/, | |
e2306992 | 143 | (device*) me, |
aea481da | 144 | NULL /*buffer*/); |
aea481da | 145 | |
534a3d5c | 146 | /* VU MEM0 tracking table */ |
e2306992 | 147 | sim_core_attach (sd, NULL, 0, access_read_write, 0, |
534a3d5c FCE |
148 | ((me->pke_number == 0) ? VU0_MEM0_SRCADDR_START : VU1_MEM0_SRCADDR_START), |
149 | ((me->pke_number == 0) ? VU0_MEM0_SIZE : VU1_MEM0_SIZE) / 2, | |
fba9bfed | 150 | 0 /*modulo*/, |
534a3d5c FCE |
151 | NULL, |
152 | NULL /*buffer*/); | |
153 | ||
154 | /* VU MEM1 tracking table */ | |
155 | sim_core_attach (sd, NULL, 0, access_read_write, 0, | |
156 | ((me->pke_number == 0) ? VU0_MEM1_SRCADDR_START : VU1_MEM1_SRCADDR_START), | |
157 | ((me->pke_number == 0) ? VU0_MEM1_SIZE : VU1_MEM1_SIZE) / 4, | |
158 | 0 /*modulo*/, | |
159 | NULL, | |
160 | NULL /*buffer*/); | |
161 | ||
e2306992 FCE |
162 | |
163 | /* attach to trace file if appropriate */ | |
164 | { | |
165 | char trace_envvar[80]; | |
166 | char* trace_filename = NULL; | |
167 | sprintf(trace_envvar, "VIF%d_TRACE_FILE", me->pke_number); | |
168 | trace_filename = getenv(trace_envvar); | |
169 | if(trace_filename != NULL) | |
170 | { | |
171 | me->fifo_trace_file = fopen(trace_filename, "w"); | |
172 | if(me->fifo_trace_file == NULL) | |
e2306992 | 173 | perror("VIF FIFO trace error on fopen"); |
b4d2f483 FCE |
174 | else |
175 | setvbuf(me->fifo_trace_file, NULL, _IOLBF, 0); | |
e2306992 FCE |
176 | } |
177 | } | |
aea481da DE |
178 | } |
179 | ||
180 | ||
181 | ||
aea481da DE |
182 | /* Handle a PKE read; return no. of bytes read */ |
183 | ||
184 | int | |
185 | pke_io_read_buffer(device *me_, | |
186 | void *dest, | |
187 | int space, | |
188 | address_word addr, | |
189 | unsigned nr_bytes, | |
fba9bfed | 190 | sim_cpu *cpu, |
aea481da DE |
191 | sim_cia cia) |
192 | { | |
193 | /* downcast to gather embedding pke_device struct */ | |
194 | struct pke_device* me = (struct pke_device*) me_; | |
195 | ||
fba9bfed FCE |
196 | /* find my address ranges */ |
197 | address_word my_reg_start = | |
198 | (me->pke_number == 0) ? PKE0_REGISTER_WINDOW_START : PKE1_REGISTER_WINDOW_START; | |
199 | address_word my_fifo_addr = | |
200 | (me->pke_number == 0) ? PKE0_FIFO_ADDR : PKE1_FIFO_ADDR; | |
201 | ||
aea481da DE |
202 | /* enforce that an access does not span more than one quadword */ |
203 | address_word low = ADDR_TRUNC_QW(addr); | |
204 | address_word high = ADDR_TRUNC_QW(addr + nr_bytes - 1); | |
205 | if(low != high) | |
206 | return 0; | |
207 | ||
208 | /* classify address & handle */ | |
fba9bfed | 209 | if((addr >= my_reg_start) && (addr < my_reg_start + PKE_REGISTER_WINDOW_SIZE)) |
aea481da DE |
210 | { |
211 | /* register bank */ | |
fba9bfed FCE |
212 | int reg_num = ADDR_TRUNC_QW(addr - my_reg_start) >> 4; |
213 | int reg_byte = ADDR_OFFSET_QW(addr); /* find byte-offset inside register bank */ | |
aea481da | 214 | int readable = 1; |
fba9bfed FCE |
215 | quadword result; |
216 | ||
217 | /* clear result */ | |
218 | result[0] = result[1] = result[2] = result[3] = 0; | |
aea481da | 219 | |
fba9bfed | 220 | /* handle reads to individual registers; clear `readable' on error */ |
aea481da DE |
221 | switch(reg_num) |
222 | { | |
fba9bfed FCE |
223 | /* handle common case of register reading, side-effect free */ |
224 | /* PKE1-only registers*/ | |
aea481da DE |
225 | case PKE_REG_BASE: |
226 | case PKE_REG_OFST: | |
227 | case PKE_REG_TOPS: | |
228 | case PKE_REG_TOP: | |
229 | case PKE_REG_DBF: | |
fba9bfed | 230 | if(me->pke_number == 0) |
aea481da | 231 | readable = 0; |
fba9bfed FCE |
232 | /* fall through */ |
233 | /* PKE0 & PKE1 common registers*/ | |
234 | case PKE_REG_STAT: | |
235 | case PKE_REG_ERR: | |
236 | case PKE_REG_MARK: | |
237 | case PKE_REG_CYCLE: | |
238 | case PKE_REG_MODE: | |
239 | case PKE_REG_NUM: | |
240 | case PKE_REG_MASK: | |
241 | case PKE_REG_CODE: | |
242 | case PKE_REG_ITOPS: | |
243 | case PKE_REG_ITOP: | |
244 | case PKE_REG_R0: | |
245 | case PKE_REG_R1: | |
246 | case PKE_REG_R2: | |
247 | case PKE_REG_R3: | |
248 | case PKE_REG_C0: | |
249 | case PKE_REG_C1: | |
250 | case PKE_REG_C2: | |
251 | case PKE_REG_C3: | |
f0bb94cd | 252 | result[0] = H2T_4(me->regs[reg_num][0]); |
fba9bfed FCE |
253 | break; |
254 | ||
255 | /* handle common case of write-only registers */ | |
256 | case PKE_REG_FBRST: | |
257 | readable = 0; | |
258 | break; | |
259 | ||
260 | default: | |
261 | ASSERT(0); /* test above should prevent this possibility */ | |
aea481da DE |
262 | } |
263 | ||
fba9bfed | 264 | /* perform transfer & return */ |
aea481da DE |
265 | if(readable) |
266 | { | |
aea481da | 267 | /* copy the bits */ |
fba9bfed | 268 | memcpy(dest, ((unsigned_1*) &result) + reg_byte, nr_bytes); |
aea481da | 269 | /* okay */ |
aea481da DE |
270 | } |
271 | else | |
272 | { | |
b4d2f483 FCE |
273 | /* return zero bits */ |
274 | memset(dest, 0, nr_bytes); | |
aea481da DE |
275 | } |
276 | ||
b4d2f483 | 277 | return nr_bytes; |
aea481da DE |
278 | /* NOTREACHED */ |
279 | } | |
fba9bfed FCE |
280 | else if(addr >= my_fifo_addr && |
281 | addr < my_fifo_addr + sizeof(quadword)) | |
aea481da DE |
282 | { |
283 | /* FIFO */ | |
284 | ||
fba9bfed FCE |
285 | /* FIFO is not readable: return a word of zeroes */ |
286 | memset(dest, 0, nr_bytes); | |
287 | return nr_bytes; | |
aea481da DE |
288 | } |
289 | ||
290 | /* NOTREACHED */ | |
fba9bfed | 291 | return 0; |
aea481da DE |
292 | } |
293 | ||
294 | ||
295 | /* Handle a PKE read; return no. of bytes written */ | |
296 | ||
297 | int | |
298 | pke_io_write_buffer(device *me_, | |
299 | const void *src, | |
300 | int space, | |
301 | address_word addr, | |
302 | unsigned nr_bytes, | |
fba9bfed | 303 | sim_cpu *cpu, |
aea481da DE |
304 | sim_cia cia) |
305 | { | |
306 | /* downcast to gather embedding pke_device struct */ | |
307 | struct pke_device* me = (struct pke_device*) me_; | |
308 | ||
fba9bfed FCE |
309 | /* find my address ranges */ |
310 | address_word my_reg_start = | |
311 | (me->pke_number == 0) ? PKE0_REGISTER_WINDOW_START : PKE1_REGISTER_WINDOW_START; | |
312 | address_word my_fifo_addr = | |
313 | (me->pke_number == 0) ? PKE0_FIFO_ADDR : PKE1_FIFO_ADDR; | |
314 | ||
aea481da DE |
315 | /* enforce that an access does not span more than one quadword */ |
316 | address_word low = ADDR_TRUNC_QW(addr); | |
317 | address_word high = ADDR_TRUNC_QW(addr + nr_bytes - 1); | |
318 | if(low != high) | |
319 | return 0; | |
320 | ||
321 | /* classify address & handle */ | |
fba9bfed | 322 | if((addr >= my_reg_start) && (addr < my_reg_start + PKE_REGISTER_WINDOW_SIZE)) |
aea481da DE |
323 | { |
324 | /* register bank */ | |
fba9bfed FCE |
325 | int reg_num = ADDR_TRUNC_QW(addr - my_reg_start) >> 4; |
326 | int reg_byte = ADDR_OFFSET_QW(addr); /* find byte-offset inside register bank */ | |
aea481da | 327 | int writeable = 1; |
fba9bfed FCE |
328 | quadword input; |
329 | ||
330 | /* clear input */ | |
331 | input[0] = input[1] = input[2] = input[3] = 0; | |
aea481da | 332 | |
fba9bfed FCE |
333 | /* write user-given bytes into input */ |
334 | memcpy(((unsigned_1*) &input) + reg_byte, src, nr_bytes); | |
335 | ||
f0bb94cd FCE |
336 | /* make words host-endian */ |
337 | input[0] = T2H_4(input[0]); | |
338 | /* we may ignore other words */ | |
339 | ||
fba9bfed | 340 | /* handle writes to individual registers; clear `writeable' on error */ |
aea481da DE |
341 | switch(reg_num) |
342 | { | |
fba9bfed | 343 | case PKE_REG_FBRST: |
43a6998b FCE |
344 | /* Order these tests from least to most overriding, in case |
345 | multiple bits are set. */ | |
b4d2f483 | 346 | if(BIT_MASK_GET(input[0], PKE_REG_FBRST_STC_B, PKE_REG_FBRST_STC_E)) |
fba9bfed FCE |
347 | { |
348 | /* clear a bunch of status bits */ | |
349 | PKE_REG_MASK_SET(me, STAT, PSS, 0); | |
350 | PKE_REG_MASK_SET(me, STAT, PFS, 0); | |
351 | PKE_REG_MASK_SET(me, STAT, PIS, 0); | |
352 | PKE_REG_MASK_SET(me, STAT, INT, 0); | |
353 | PKE_REG_MASK_SET(me, STAT, ER0, 0); | |
354 | PKE_REG_MASK_SET(me, STAT, ER1, 0); | |
db6dac32 | 355 | me->flags &= ~PKE_FLAG_PENDING_PSS; |
fba9bfed FCE |
356 | /* will allow resumption of possible stalled instruction */ |
357 | } | |
b4d2f483 | 358 | if(BIT_MASK_GET(input[0], PKE_REG_FBRST_STP_B, PKE_REG_FBRST_STP_E)) |
43a6998b | 359 | { |
db6dac32 | 360 | me->flags |= PKE_FLAG_PENDING_PSS; |
43a6998b | 361 | } |
b4d2f483 | 362 | if(BIT_MASK_GET(input[0], PKE_REG_FBRST_FBK_B, PKE_REG_FBRST_FBK_E)) |
43a6998b FCE |
363 | { |
364 | PKE_REG_MASK_SET(me, STAT, PFS, 1); | |
365 | } | |
b4d2f483 | 366 | if(BIT_MASK_GET(input[0], PKE_REG_FBRST_RST_B, PKE_REG_FBRST_RST_E)) |
43a6998b FCE |
367 | { |
368 | /* clear FIFO by skipping to word after PC: also | |
369 | prevents re-execution attempt of possible stalled | |
370 | instruction */ | |
371 | me->fifo_num_elements = me->fifo_pc; | |
db6dac32 | 372 | /* clear registers, flag, other state */ |
43a6998b | 373 | memset(me->regs, 0, sizeof(me->regs)); |
db6dac32 | 374 | me->fifo_qw_done = 0; |
43a6998b FCE |
375 | me->flags = 0; |
376 | me->qw_pc = 0; | |
377 | } | |
fba9bfed FCE |
378 | break; |
379 | ||
380 | case PKE_REG_ERR: | |
381 | /* copy bottom three bits */ | |
382 | BIT_MASK_SET(me->regs[PKE_REG_ERR][0], 0, 2, BIT_MASK_GET(input[0], 0, 2)); | |
383 | break; | |
384 | ||
385 | case PKE_REG_MARK: | |
386 | /* copy bottom sixteen bits */ | |
387 | PKE_REG_MASK_SET(me, MARK, MARK, BIT_MASK_GET(input[0], 0, 15)); | |
388 | /* reset MRK bit in STAT */ | |
389 | PKE_REG_MASK_SET(me, STAT, MRK, 0); | |
390 | break; | |
391 | ||
392 | /* handle common case of read-only registers */ | |
393 | /* PKE1-only registers - not really necessary to handle separately */ | |
aea481da DE |
394 | case PKE_REG_BASE: |
395 | case PKE_REG_OFST: | |
396 | case PKE_REG_TOPS: | |
397 | case PKE_REG_TOP: | |
398 | case PKE_REG_DBF: | |
fba9bfed | 399 | if(me->pke_number == 0) |
aea481da | 400 | writeable = 0; |
fba9bfed FCE |
401 | /* fall through */ |
402 | /* PKE0 & PKE1 common registers*/ | |
403 | case PKE_REG_STAT: | |
404 | /* ignore FDR bit for PKE1_STAT -- simulator does not implement PKE->RAM transfers */ | |
405 | case PKE_REG_CYCLE: | |
406 | case PKE_REG_MODE: | |
407 | case PKE_REG_NUM: | |
408 | case PKE_REG_MASK: | |
409 | case PKE_REG_CODE: | |
410 | case PKE_REG_ITOPS: | |
411 | case PKE_REG_ITOP: | |
412 | case PKE_REG_R0: | |
413 | case PKE_REG_R1: | |
414 | case PKE_REG_R2: | |
415 | case PKE_REG_R3: | |
416 | case PKE_REG_C0: | |
417 | case PKE_REG_C1: | |
418 | case PKE_REG_C2: | |
419 | case PKE_REG_C3: | |
420 | writeable = 0; | |
421 | break; | |
422 | ||
423 | default: | |
424 | ASSERT(0); /* test above should prevent this possibility */ | |
aea481da DE |
425 | } |
426 | ||
fba9bfed | 427 | /* perform return */ |
b4d2f483 | 428 | if(! writeable) |
aea481da | 429 | { |
b4d2f483 | 430 | ; /* error */ |
aea481da DE |
431 | } |
432 | ||
b4d2f483 FCE |
433 | return nr_bytes; |
434 | ||
aea481da DE |
435 | /* NOTREACHED */ |
436 | } | |
fba9bfed FCE |
437 | else if(addr >= my_fifo_addr && |
438 | addr < my_fifo_addr + sizeof(quadword)) | |
aea481da DE |
439 | { |
440 | /* FIFO */ | |
fba9bfed | 441 | struct fifo_quadword* fqw; |
db6dac32 | 442 | int fifo_byte = ADDR_OFFSET_QW(addr); /* find byte-offset inside fifo quadword */ |
e2306992 | 443 | unsigned_4 dma_tag_present = 0; |
db6dac32 FCE |
444 | int i; |
445 | ||
f0bb94cd | 446 | /* collect potentially-partial quadword in write buffer; LE byte order */ |
db6dac32 FCE |
447 | memcpy(((unsigned_1*)& me->fifo_qw_in_progress) + fifo_byte, src, nr_bytes); |
448 | /* mark bytes written */ | |
449 | for(i = fifo_byte; i < fifo_byte + nr_bytes; i++) | |
450 | BIT_MASK_SET(me->fifo_qw_done, i, i, 1); | |
451 | ||
452 | /* return if quadword not quite written yet */ | |
453 | if(BIT_MASK_GET(me->fifo_qw_done, 0, sizeof(quadword)-1) != | |
e2306992 | 454 | BIT_MASK_BTW(0, sizeof(quadword)-1)) |
db6dac32 | 455 | return nr_bytes; |
aea481da | 456 | |
db6dac32 FCE |
457 | /* all done - process quadword after clearing flag */ |
458 | BIT_MASK_SET(me->fifo_qw_done, 0, sizeof(quadword)-1, 0); | |
aea481da DE |
459 | |
460 | /* ensure FIFO has enough elements */ | |
461 | if(me->fifo_num_elements == me->fifo_buffer_size) | |
462 | { | |
463 | /* time to grow */ | |
464 | int new_fifo_buffer_size = me->fifo_buffer_size + 20; | |
534a3d5c | 465 | void* ptr = realloc((void*) me->fifo, new_fifo_buffer_size*sizeof(struct fifo_quadword)); |
e2306992 | 466 | |
aea481da DE |
467 | if(ptr == NULL) |
468 | { | |
469 | /* oops, cannot enlarge FIFO any more */ | |
470 | device_error(me_, "Cannot enlarge FIFO buffer\n"); | |
471 | return 0; | |
472 | } | |
473 | ||
e2306992 | 474 | me->fifo = ptr; |
aea481da DE |
475 | me->fifo_buffer_size = new_fifo_buffer_size; |
476 | } | |
477 | ||
f0bb94cd | 478 | /* add new quadword at end of FIFO; store data in host-endian */ |
fba9bfed | 479 | fqw = & me->fifo[me->fifo_num_elements]; |
e2306992 FCE |
480 | fqw->word_class[0] = fqw->word_class[1] = |
481 | fqw->word_class[2] = fqw->word_class[3] = wc_unknown; | |
f0bb94cd FCE |
482 | fqw->data[0] = T2H_4(me->fifo_qw_in_progress[0]); |
483 | fqw->data[1] = T2H_4(me->fifo_qw_in_progress[1]); | |
484 | fqw->data[2] = T2H_4(me->fifo_qw_in_progress[2]); | |
485 | fqw->data[3] = T2H_4(me->fifo_qw_in_progress[3]); | |
e2306992 | 486 | ASSERT(sizeof(unsigned_4) == 4); |
534a3d5c | 487 | PKE_MEM_READ(me, (me->pke_number == 0 ? DMA_D0_MADR : DMA_D1_MADR), |
f0bb94cd | 488 | & fqw->source_address, /* converted to host-endian */ |
e2306992 | 489 | 4); |
534a3d5c | 490 | PKE_MEM_READ(me, (me->pke_number == 0 ? DMA_D0_PKTFLAG : DMA_D1_PKTFLAG), |
e2306992 FCE |
491 | & dma_tag_present, |
492 | 4); | |
493 | ||
494 | if(dma_tag_present) | |
495 | { | |
496 | /* lower two words are DMA tags */ | |
497 | fqw->word_class[0] = fqw->word_class[1] = wc_dma; | |
498 | } | |
499 | ||
fba9bfed FCE |
500 | me->fifo_num_elements++; |
501 | ||
502 | /* set FQC to "1" as FIFO is now not empty */ | |
503 | PKE_REG_MASK_SET(me, STAT, FQC, 1); | |
aea481da DE |
504 | |
505 | /* okay */ | |
506 | return nr_bytes; | |
507 | } | |
508 | ||
509 | /* NOTREACHED */ | |
fba9bfed | 510 | return 0; |
aea481da DE |
511 | } |
512 | ||
513 | ||
514 | ||
fba9bfed | 515 | /* Issue & swallow next PKE opcode if possible/available */ |
aea481da DE |
516 | |
517 | void | |
e2306992 | 518 | pke_issue(SIM_DESC sd, struct pke_device* me) |
aea481da | 519 | { |
fba9bfed FCE |
520 | struct fifo_quadword* fqw; |
521 | unsigned_4 fw; | |
522 | unsigned_4 cmd, intr, num; | |
523 | unsigned_4 imm; | |
fba9bfed | 524 | |
fd909089 FCE |
525 | /* 1 -- fetch PKE instruction */ |
526 | ||
527 | /* confirm availability of new quadword of PKE instructions */ | |
528 | if(me->fifo_num_elements <= me->fifo_pc) | |
529 | return; | |
530 | ||
531 | /* skip over DMA tag, if present */ | |
532 | pke_pc_advance(me, 0); | |
533 | ||
534 | /* "fetch" instruction quadword and word */ | |
535 | fqw = & me->fifo[me->fifo_pc]; | |
536 | fw = fqw->data[me->qw_pc]; | |
537 | ||
538 | /* store word in PKECODE register */ | |
539 | me->regs[PKE_REG_CODE][0] = fw; | |
540 | ||
541 | ||
542 | /* 2 -- test go / no-go for PKE execution */ | |
fba9bfed | 543 | |
db6dac32 FCE |
544 | /* switch on STAT:PSS if PSS-pending and in idle state */ |
545 | if((PKE_REG_MASK_GET(me, STAT, PPS) == PKE_REG_STAT_PPS_IDLE) && | |
546 | (me->flags & PKE_FLAG_PENDING_PSS) != 0) | |
547 | { | |
548 | me->flags &= ~PKE_FLAG_PENDING_PSS; | |
549 | PKE_REG_MASK_SET(me, STAT, PSS, 1); | |
550 | } | |
551 | ||
fba9bfed | 552 | /* check for stall/halt control bits */ |
db6dac32 FCE |
553 | if(PKE_REG_MASK_GET(me, STAT, PFS) || |
554 | PKE_REG_MASK_GET(me, STAT, PSS) || /* note special treatment below */ | |
43a6998b FCE |
555 | /* PEW bit not a reason to keep stalling - it's re-checked below */ |
556 | /* PGW bit not a reason to keep stalling - it's re-checked below */ | |
fba9bfed | 557 | /* maskable stall controls: ER0, ER1, PIS */ |
fd909089 FCE |
558 | PKE_REG_MASK_GET(me, STAT, ER0) || |
559 | PKE_REG_MASK_GET(me, STAT, ER1) || | |
560 | PKE_REG_MASK_GET(me, STAT, PIS)) | |
fba9bfed | 561 | { |
fd909089 FCE |
562 | /* (still) stalled */ |
563 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
564 | /* try again next cycle */ | |
43a6998b | 565 | return; |
fba9bfed | 566 | } |
fba9bfed | 567 | |
fba9bfed FCE |
568 | |
569 | /* 3 -- decode PKE instruction */ | |
570 | ||
fd909089 FCE |
571 | /* decoding */ |
572 | if(PKE_REG_MASK_GET(me, STAT, PPS) == PKE_REG_STAT_PPS_IDLE) | |
573 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_DECODE); | |
574 | ||
575 | /* Extract relevant bits from PKEcode */ | |
fba9bfed FCE |
576 | intr = BIT_MASK_GET(fw, PKE_OPCODE_I_B, PKE_OPCODE_I_E); |
577 | cmd = BIT_MASK_GET(fw, PKE_OPCODE_CMD_B, PKE_OPCODE_CMD_E); | |
fba9bfed | 578 | |
d22ea5d0 | 579 | /* handle interrupts */ |
fba9bfed FCE |
580 | if(intr) |
581 | { | |
fd909089 | 582 | /* are we resuming an interrupt-stalled instruction? */ |
d22ea5d0 FCE |
583 | if(me->flags & PKE_FLAG_INT_NOLOOP) |
584 | { | |
585 | /* clear loop-prevention flag */ | |
586 | me->flags &= ~PKE_FLAG_INT_NOLOOP; | |
fd909089 FCE |
587 | |
588 | /* fall through to decode & execute */ | |
589 | /* The pke_code_* functions should not check the MSB in the | |
590 | pkecode. */ | |
d22ea5d0 FCE |
591 | } |
592 | else /* new interrupt-flagged instruction */ | |
593 | { | |
fd909089 FCE |
594 | /* XXX: send interrupt to 5900? */ |
595 | ||
d22ea5d0 FCE |
596 | /* set INT flag in STAT register */ |
597 | PKE_REG_MASK_SET(me, STAT, INT, 1); | |
598 | /* set loop-prevention flag */ | |
599 | me->flags |= PKE_FLAG_INT_NOLOOP; | |
600 | ||
fd909089 FCE |
601 | /* set PIS if stall not masked */ |
602 | if(!PKE_REG_MASK_GET(me, ERR, MII)) | |
603 | PKE_REG_MASK_SET(me, STAT, PIS, 1); | |
604 | ||
605 | /* suspend this instruction unless it's PKEMARK */ | |
606 | if(!IS_PKE_CMD(cmd, PKEMARK)) | |
607 | { | |
608 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
609 | return; | |
610 | } | |
611 | else | |
612 | { | |
613 | ; /* fall through to decode & execute */ | |
614 | } | |
d22ea5d0 | 615 | } |
fba9bfed FCE |
616 | } |
617 | ||
5068e793 | 618 | |
43a6998b | 619 | /* decode & execute */ |
fd909089 | 620 | if(IS_PKE_CMD(cmd, PKENOP)) |
43a6998b | 621 | pke_code_nop(me, fw); |
fd909089 | 622 | else if(IS_PKE_CMD(cmd, STCYCL)) |
43a6998b | 623 | pke_code_stcycl(me, fw); |
fd909089 | 624 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, OFFSET)) |
43a6998b | 625 | pke_code_offset(me, fw); |
fd909089 | 626 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, BASE)) |
43a6998b | 627 | pke_code_base(me, fw); |
fd909089 | 628 | else if(IS_PKE_CMD(cmd, ITOP)) |
43a6998b | 629 | pke_code_itop(me, fw); |
fd909089 | 630 | else if(IS_PKE_CMD(cmd, STMOD)) |
43a6998b | 631 | pke_code_stmod(me, fw); |
fd909089 | 632 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, MSKPATH3)) |
43a6998b | 633 | pke_code_mskpath3(me, fw); |
fba9bfed | 634 | else if(IS_PKE_CMD(cmd, PKEMARK)) |
43a6998b | 635 | pke_code_pkemark(me, fw); |
fd909089 | 636 | else if(IS_PKE_CMD(cmd, FLUSHE)) |
43a6998b | 637 | pke_code_flushe(me, fw); |
fd909089 | 638 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, FLUSH)) |
43a6998b | 639 | pke_code_flush(me, fw); |
fd909089 | 640 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, FLUSHA)) |
43a6998b | 641 | pke_code_flusha(me, fw); |
fd909089 | 642 | else if(IS_PKE_CMD(cmd, PKEMSCAL)) |
43a6998b | 643 | pke_code_pkemscal(me, fw); |
fd909089 | 644 | else if(IS_PKE_CMD(cmd, PKEMSCNT)) |
43a6998b | 645 | pke_code_pkemscnt(me, fw); |
fd909089 | 646 | else if(me->pke_number == 1 && IS_PKE_CMD(cmd, PKEMSCALF)) |
43a6998b | 647 | pke_code_pkemscalf(me, fw); |
fd909089 | 648 | else if(IS_PKE_CMD(cmd, STMASK)) |
43a6998b | 649 | pke_code_stmask(me, fw); |
fd909089 | 650 | else if(IS_PKE_CMD(cmd, STROW)) |
43a6998b | 651 | pke_code_strow(me, fw); |
fd909089 | 652 | else if(IS_PKE_CMD(cmd, STCOL)) |
43a6998b | 653 | pke_code_stcol(me, fw); |
fd909089 | 654 | else if(IS_PKE_CMD(cmd, MPG)) |
43a6998b | 655 | pke_code_mpg(me, fw); |
fd909089 | 656 | else if(IS_PKE_CMD(cmd, DIRECT)) |
43a6998b | 657 | pke_code_direct(me, fw); |
fd909089 | 658 | else if(IS_PKE_CMD(cmd, DIRECTHL)) |
43a6998b | 659 | pke_code_directhl(me, fw); |
fd909089 | 660 | else if(IS_PKE_CMD(cmd, UNPACK)) |
43a6998b | 661 | pke_code_unpack(me, fw); |
db6dac32 | 662 | /* ... no other commands ... */ |
43a6998b FCE |
663 | else |
664 | pke_code_error(me, fw); | |
665 | } | |
666 | ||
667 | ||
668 | ||
669 | /* advance the PC by given number of data words; update STAT/FQC | |
e2306992 FCE |
670 | field; assume FIFO is filled enough; classify passed-over words; |
671 | write FIFO trace line */ | |
43a6998b FCE |
672 | |
673 | void | |
674 | pke_pc_advance(struct pke_device* me, int num_words) | |
675 | { | |
676 | int num = num_words; | |
e2306992 | 677 | struct fifo_quadword* fq = NULL; |
e2306992 | 678 | ASSERT(num_words >= 0); |
43a6998b | 679 | |
b4d2f483 FCE |
680 | /* printf("pke %d pc_advance num_words %d\n", me->pke_number, num_words); */ |
681 | ||
682 | while(1) | |
fba9bfed | 683 | { |
e2306992 | 684 | fq = & me->fifo[me->fifo_pc]; |
43a6998b FCE |
685 | |
686 | /* skip over DMA tag words if present in word 0 or 1 */ | |
e2306992 | 687 | if(fq->word_class[me->qw_pc] == wc_dma) |
fba9bfed | 688 | { |
43a6998b FCE |
689 | /* skip by going around loop an extra time */ |
690 | num ++; | |
fba9bfed | 691 | } |
b4d2f483 FCE |
692 | |
693 | /* nothing left to skip / no DMA tag here */ | |
694 | if(num == 0) | |
695 | break; | |
e2306992 | 696 | |
b4d2f483 FCE |
697 | /* one word skipped */ |
698 | num --; | |
699 | ||
700 | /* point to next word */ | |
701 | me->qw_pc ++; | |
702 | if(me->qw_pc == 4) | |
e2306992 | 703 | { |
b4d2f483 FCE |
704 | me->qw_pc = 0; |
705 | me->fifo_pc ++; | |
e2306992 | 706 | |
b4d2f483 FCE |
707 | /* trace the consumption of the FIFO quadword we just skipped over */ |
708 | /* fq still points to it */ | |
709 | if(me->fifo_trace_file != NULL) | |
e2306992 | 710 | { |
b4d2f483 FCE |
711 | /* assert complete classification */ |
712 | ASSERT(fq->word_class[3] != wc_unknown); | |
713 | ASSERT(fq->word_class[2] != wc_unknown); | |
714 | ASSERT(fq->word_class[1] != wc_unknown); | |
715 | ASSERT(fq->word_class[0] != wc_unknown); | |
e2306992 | 716 | |
b4d2f483 FCE |
717 | /* print trace record */ |
718 | fprintf(me->fifo_trace_file, | |
719 | "%d 0x%08x_%08x_%08x_%08x 0x%08x %c%c%c%c\n", | |
720 | (me->pke_number == 0 ? 0 : 1), | |
721 | (unsigned) fq->data[3], (unsigned) fq->data[2], | |
722 | (unsigned) fq->data[1], (unsigned) fq->data[0], | |
723 | (unsigned) fq->source_address, | |
724 | fq->word_class[3], fq->word_class[2], | |
725 | fq->word_class[1], fq->word_class[0]); | |
726 | } | |
727 | ||
728 | /* XXX: zap old entries in FIFO */ | |
729 | } /* next quadword */ | |
730 | } | |
43a6998b FCE |
731 | |
732 | /* clear FQC if FIFO is now empty */ | |
733 | if(me->fifo_num_elements == me->fifo_pc) | |
fba9bfed | 734 | { |
43a6998b | 735 | PKE_REG_MASK_SET(me, STAT, FQC, 0); |
fba9bfed | 736 | } |
e2306992 FCE |
737 | else /* annote the word where the PC lands as an PKEcode */ |
738 | { | |
b4d2f483 | 739 | fq = & me->fifo[me->fifo_pc]; |
e2306992 FCE |
740 | ASSERT(fq->word_class[me->qw_pc] == wc_pkecode || |
741 | fq->word_class[me->qw_pc] == wc_unknown); | |
742 | fq->word_class[me->qw_pc] = wc_pkecode; | |
743 | } | |
43a6998b | 744 | } |
fba9bfed | 745 | |
fba9bfed | 746 | |
fba9bfed | 747 | |
43a6998b FCE |
748 | /* Return pointer to FIFO quadword containing given operand# in FIFO. |
749 | `operand_num' starts at 1. Return pointer to operand word in last | |
750 | argument, if non-NULL. If FIFO is not full enough, return 0. | |
751 | Signal an ER0 indication upon skipping a DMA tag. */ | |
fba9bfed | 752 | |
43a6998b FCE |
753 | struct fifo_quadword* |
754 | pke_pc_fifo(struct pke_device* me, int operand_num, unsigned_4** operand) | |
755 | { | |
756 | int num = operand_num; | |
757 | int new_qw_pc, new_fifo_pc; | |
e2306992 | 758 | struct fifo_quadword* fq = NULL; |
fba9bfed | 759 | |
43a6998b | 760 | ASSERT(num > 0); |
fba9bfed | 761 | |
43a6998b FCE |
762 | /* snapshot current pointers */ |
763 | new_fifo_pc = me->fifo_pc; | |
764 | new_qw_pc = me->qw_pc; | |
fba9bfed | 765 | |
b4d2f483 FCE |
766 | /* printf("pke %d pc_fifo operand_num %d\n", me->pke_number, operand_num); */ |
767 | ||
e2306992 | 768 | do |
43a6998b FCE |
769 | { |
770 | /* one word skipped */ | |
771 | num --; | |
fba9bfed | 772 | |
43a6998b FCE |
773 | /* point to next word */ |
774 | new_qw_pc ++; | |
775 | if(new_qw_pc == 4) | |
fba9bfed | 776 | { |
43a6998b FCE |
777 | new_qw_pc = 0; |
778 | new_fifo_pc ++; | |
fba9bfed | 779 | } |
fba9bfed | 780 | |
43a6998b FCE |
781 | /* check for FIFO underflow */ |
782 | if(me->fifo_num_elements == new_fifo_pc) | |
fba9bfed | 783 | { |
e2306992 | 784 | fq = NULL; |
43a6998b | 785 | break; |
fba9bfed | 786 | } |
43a6998b FCE |
787 | |
788 | /* skip over DMA tag words if present in word 0 or 1 */ | |
e2306992 FCE |
789 | fq = & me->fifo[new_fifo_pc]; |
790 | if(fq->word_class[new_qw_pc] == wc_dma) | |
fba9bfed | 791 | { |
43a6998b | 792 | /* mismatch error! */ |
fd909089 FCE |
793 | if(! PKE_REG_MASK_GET(me, ERR, ME0)) |
794 | { | |
795 | PKE_REG_MASK_SET(me, STAT, ER0, 1); | |
796 | /* don't stall just yet -- finish this instruction */ | |
797 | /* the PPS_STALL state will be entered by pke_issue() next time */ | |
798 | } | |
43a6998b FCE |
799 | /* skip by going around loop an extra time */ |
800 | num ++; | |
fba9bfed FCE |
801 | } |
802 | } | |
e2306992 | 803 | while(num > 0); |
fba9bfed | 804 | |
43a6998b | 805 | /* return pointer to operand word itself */ |
e2306992 FCE |
806 | if(fq != NULL) |
807 | { | |
808 | *operand = & fq->data[new_qw_pc]; | |
fba9bfed | 809 | |
e2306992 FCE |
810 | /* annote the word where the pseudo lands as an PKE operand */ |
811 | ASSERT(fq->word_class[new_qw_pc] == wc_pkedata || | |
812 | fq->word_class[new_qw_pc] == wc_unknown); | |
813 | fq->word_class[new_qw_pc] = wc_pkedata; | |
814 | } | |
815 | ||
816 | return fq; | |
43a6998b | 817 | } |
fba9bfed | 818 | |
fba9bfed | 819 | |
43a6998b FCE |
820 | /* Return pointer to given operand# in FIFO. `operand_num' starts at 1. |
821 | If FIFO is not full enough, return 0. Skip over DMA tags, but mark | |
822 | them as an error (ER0). */ | |
fba9bfed | 823 | |
43a6998b FCE |
824 | unsigned_4* |
825 | pke_pc_operand(struct pke_device* me, int operand_num) | |
826 | { | |
827 | unsigned_4* operand = NULL; | |
828 | struct fifo_quadword* fifo_operand; | |
fba9bfed | 829 | |
43a6998b | 830 | fifo_operand = pke_pc_fifo(me, operand_num, & operand); |
fba9bfed | 831 | |
43a6998b FCE |
832 | if(fifo_operand == NULL) |
833 | ASSERT(operand == NULL); /* pke_pc_fifo() ought leave it untouched */ | |
fba9bfed | 834 | |
43a6998b FCE |
835 | return operand; |
836 | } | |
fba9bfed | 837 | |
fba9bfed | 838 | |
db6dac32 FCE |
839 | /* Return a bit-field extract of given operand# in FIFO, and its |
840 | source-addr. `bit_offset' starts at 0, referring to LSB after PKE | |
841 | instruction word. Width must be >0, <=32. Assume FIFO is full | |
842 | enough. Skip over DMA tags, but mark them as an error (ER0). */ | |
843 | ||
844 | unsigned_4 | |
845 | pke_pc_operand_bits(struct pke_device* me, int bit_offset, int bit_width, unsigned_4* source_addr) | |
846 | { | |
847 | unsigned_4* word = NULL; | |
848 | unsigned_4 value; | |
849 | struct fifo_quadword* fifo_operand; | |
534a3d5c FCE |
850 | int wordnumber, bitnumber; |
851 | ||
852 | wordnumber = bit_offset/32; | |
853 | bitnumber = bit_offset%32; | |
db6dac32 FCE |
854 | |
855 | /* find operand word with bitfield */ | |
534a3d5c FCE |
856 | fifo_operand = pke_pc_fifo(me, wordnumber + 1, &word); |
857 | ASSERT(word != NULL); | |
db6dac32 FCE |
858 | |
859 | /* extract bitfield from word */ | |
534a3d5c | 860 | value = BIT_MASK_GET(*word, bitnumber, bitnumber + bit_width - 1); |
db6dac32 FCE |
861 | |
862 | /* extract source addr from fifo word */ | |
863 | *source_addr = fifo_operand->source_address; | |
864 | ||
865 | return value; | |
866 | } | |
867 | ||
fba9bfed | 868 | |
fba9bfed | 869 | |
d22ea5d0 FCE |
870 | /* check for stall conditions on indicated devices (path* only on |
871 | PKE1), do not change status; return 0 iff no stall */ | |
43a6998b FCE |
872 | int |
873 | pke_check_stall(struct pke_device* me, enum pke_check_target what) | |
874 | { | |
875 | int any_stall = 0; | |
e2306992 | 876 | unsigned_4 cop2_stat, gpuif_stat; |
43a6998b | 877 | |
e2306992 | 878 | /* read status words */ |
534a3d5c FCE |
879 | ASSERT(sizeof(unsigned_4) == 4); |
880 | PKE_MEM_READ(me, (GIF_REG_STAT), | |
881 | & gpuif_stat, | |
882 | 4); | |
883 | PKE_MEM_READ(me, (COP2_REG_STAT_ADDR), | |
884 | & cop2_stat, | |
885 | 4); | |
e2306992 | 886 | |
43a6998b FCE |
887 | /* perform checks */ |
888 | if(what == chk_vu) | |
889 | { | |
e2306992 FCE |
890 | if(me->pke_number == 0) |
891 | any_stall = BIT_MASK_GET(cop2_stat, COP2_REG_STAT_VBS0_B, COP2_REG_STAT_VBS0_E); | |
892 | else /* if(me->pke_number == 1) */ | |
893 | any_stall = BIT_MASK_GET(cop2_stat, COP2_REG_STAT_VBS1_B, COP2_REG_STAT_VBS1_E); | |
db6dac32 FCE |
894 | } |
895 | else if(what == chk_path1) /* VU -> GPUIF */ | |
896 | { | |
897 | if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 1) | |
43a6998b | 898 | any_stall = 1; |
fba9bfed | 899 | } |
db6dac32 | 900 | else if(what == chk_path2) /* PKE -> GPUIF */ |
fba9bfed | 901 | { |
db6dac32 FCE |
902 | if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 2) |
903 | any_stall = 1; | |
904 | } | |
905 | else if(what == chk_path3) /* DMA -> GPUIF */ | |
906 | { | |
907 | if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 3) | |
43a6998b FCE |
908 | any_stall = 1; |
909 | } | |
910 | else | |
911 | { | |
db6dac32 FCE |
912 | /* invalid what */ |
913 | ASSERT(0); | |
43a6998b | 914 | } |
fba9bfed | 915 | |
43a6998b FCE |
916 | /* any stall reasons? */ |
917 | return any_stall; | |
918 | } | |
fba9bfed | 919 | |
fba9bfed | 920 | |
d22ea5d0 | 921 | /* PKE1 only: flip the DBF bit; recompute TOPS, TOP */ |
43a6998b FCE |
922 | void |
923 | pke_flip_dbf(struct pke_device* me) | |
924 | { | |
370e0ef7 | 925 | int newdf; |
d22ea5d0 | 926 | /* compute new TOP */ |
733cfc78 IC |
927 | PKE_REG_MASK_SET(me, TOP, TOP, |
928 | PKE_REG_MASK_GET(me, TOPS, TOPS)); | |
43a6998b | 929 | /* flip DBF */ |
370e0ef7 FCE |
930 | newdf = PKE_REG_MASK_GET(me, DBF, DF) ? 0 : 1; |
931 | PKE_REG_MASK_SET(me, DBF, DF, newdf); | |
932 | PKE_REG_MASK_SET(me, STAT, DBF, newdf); | |
43a6998b FCE |
933 | /* compute new TOPS */ |
934 | PKE_REG_MASK_SET(me, TOPS, TOPS, | |
935 | (PKE_REG_MASK_GET(me, BASE, BASE) + | |
370e0ef7 FCE |
936 | newdf * PKE_REG_MASK_GET(me, OFST, OFFSET))); |
937 | ||
d22ea5d0 FCE |
938 | /* this is equivalent to last word from okadaa (98-02-25): |
939 | 1) TOP=TOPS; | |
940 | 2) TOPS=BASE + !DBF*OFFSET | |
941 | 3) DBF=!DBF */ | |
43a6998b | 942 | } |
fba9bfed | 943 | |
fba9bfed | 944 | |
fba9bfed | 945 | |
43a6998b FCE |
946 | /* PKEcode handler functions -- responsible for checking and |
947 | confirming old stall conditions, executing pkecode, updating PC and | |
948 | status registers -- may assume being run on correct PKE unit */ | |
949 | ||
950 | void | |
951 | pke_code_nop(struct pke_device* me, unsigned_4 pkecode) | |
952 | { | |
953 | /* done */ | |
954 | pke_pc_advance(me, 1); | |
955 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
956 | } | |
fba9bfed | 957 | |
fba9bfed | 958 | |
43a6998b FCE |
959 | void |
960 | pke_code_stcycl(struct pke_device* me, unsigned_4 pkecode) | |
961 | { | |
962 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
d22ea5d0 | 963 | |
43a6998b | 964 | /* copy immediate value into CYCLE reg */ |
534a3d5c FCE |
965 | PKE_REG_MASK_SET(me, CYCLE, WL, BIT_MASK_GET(imm, 8, 15)); |
966 | PKE_REG_MASK_SET(me, CYCLE, CL, BIT_MASK_GET(imm, 0, 7)); | |
43a6998b FCE |
967 | /* done */ |
968 | pke_pc_advance(me, 1); | |
969 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
970 | } | |
fba9bfed | 971 | |
fba9bfed | 972 | |
43a6998b FCE |
973 | void |
974 | pke_code_offset(struct pke_device* me, unsigned_4 pkecode) | |
975 | { | |
976 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
d22ea5d0 | 977 | |
43a6998b FCE |
978 | /* copy 10 bits to OFFSET field */ |
979 | PKE_REG_MASK_SET(me, OFST, OFFSET, BIT_MASK_GET(imm, 0, 9)); | |
980 | /* clear DBF bit */ | |
981 | PKE_REG_MASK_SET(me, DBF, DF, 0); | |
982 | /* clear other DBF bit */ | |
983 | PKE_REG_MASK_SET(me, STAT, DBF, 0); | |
984 | /* set TOPS = BASE */ | |
985 | PKE_REG_MASK_SET(me, TOPS, TOPS, PKE_REG_MASK_GET(me, BASE, BASE)); | |
986 | /* done */ | |
987 | pke_pc_advance(me, 1); | |
988 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
989 | } | |
fba9bfed | 990 | |
fba9bfed | 991 | |
43a6998b FCE |
992 | void |
993 | pke_code_base(struct pke_device* me, unsigned_4 pkecode) | |
994 | { | |
995 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
d22ea5d0 | 996 | |
43a6998b FCE |
997 | /* copy 10 bits to BASE field */ |
998 | PKE_REG_MASK_SET(me, BASE, BASE, BIT_MASK_GET(imm, 0, 9)); | |
43a6998b FCE |
999 | /* done */ |
1000 | pke_pc_advance(me, 1); | |
1001 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1002 | } | |
fba9bfed | 1003 | |
fba9bfed | 1004 | |
43a6998b FCE |
1005 | void |
1006 | pke_code_itop(struct pke_device* me, unsigned_4 pkecode) | |
1007 | { | |
1008 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
d22ea5d0 | 1009 | |
43a6998b FCE |
1010 | /* copy 10 bits to ITOPS field */ |
1011 | PKE_REG_MASK_SET(me, ITOPS, ITOPS, BIT_MASK_GET(imm, 0, 9)); | |
1012 | /* done */ | |
1013 | pke_pc_advance(me, 1); | |
1014 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1015 | } | |
fba9bfed | 1016 | |
fba9bfed | 1017 | |
43a6998b FCE |
1018 | void |
1019 | pke_code_stmod(struct pke_device* me, unsigned_4 pkecode) | |
1020 | { | |
1021 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
d22ea5d0 | 1022 | |
43a6998b FCE |
1023 | /* copy 2 bits to MODE register */ |
1024 | PKE_REG_MASK_SET(me, MODE, MDE, BIT_MASK_GET(imm, 0, 2)); | |
1025 | /* done */ | |
1026 | pke_pc_advance(me, 1); | |
1027 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1028 | } | |
fba9bfed | 1029 | |
43a6998b FCE |
1030 | |
1031 | void | |
1032 | pke_code_mskpath3(struct pke_device* me, unsigned_4 pkecode) | |
1033 | { | |
b4d2f483 FCE |
1034 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); |
1035 | unsigned_4 gif_mode; | |
1036 | ||
89154e47 | 1037 | /* set appropriate bit */ |
b4d2f483 | 1038 | if(BIT_MASK_GET(imm, PKE_REG_MSKPATH3_B, PKE_REG_MSKPATH3_E) != 0) |
89154e47 | 1039 | gif_mode = GIF_REG_MODE_M3R_MASK; |
b4d2f483 | 1040 | else |
89154e47 | 1041 | gif_mode = 0; |
b4d2f483 | 1042 | |
89154e47 | 1043 | /* write register; patrickm code will look at M3R bit only */ |
b4d2f483 FCE |
1044 | PKE_MEM_WRITE(me, GIF_REG_MODE, & gif_mode, 4); |
1045 | ||
b4d2f483 FCE |
1046 | /* done */ |
1047 | pke_pc_advance(me, 1); | |
1048 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
43a6998b FCE |
1049 | } |
1050 | ||
1051 | ||
1052 | void | |
1053 | pke_code_pkemark(struct pke_device* me, unsigned_4 pkecode) | |
1054 | { | |
1055 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
1056 | /* copy 16 bits to MARK register */ | |
1057 | PKE_REG_MASK_SET(me, MARK, MARK, BIT_MASK_GET(imm, 0, 15)); | |
1058 | /* set MRK bit in STAT register - CPU2 v2.1 docs incorrect */ | |
1059 | PKE_REG_MASK_SET(me, STAT, MRK, 1); | |
1060 | /* done */ | |
1061 | pke_pc_advance(me, 1); | |
1062 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1063 | } | |
1064 | ||
1065 | ||
1066 | void | |
1067 | pke_code_flushe(struct pke_device* me, unsigned_4 pkecode) | |
1068 | { | |
1069 | /* compute next PEW bit */ | |
1070 | if(pke_check_stall(me, chk_vu)) | |
1071 | { | |
1072 | /* VU busy */ | |
1073 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
1074 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
1075 | /* try again next cycle */ | |
fba9bfed | 1076 | } |
fba9bfed FCE |
1077 | else |
1078 | { | |
43a6998b FCE |
1079 | /* VU idle */ |
1080 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
1081 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
fba9bfed FCE |
1082 | pke_pc_advance(me, 1); |
1083 | } | |
fba9bfed FCE |
1084 | } |
1085 | ||
1086 | ||
43a6998b FCE |
1087 | void |
1088 | pke_code_flush(struct pke_device* me, unsigned_4 pkecode) | |
1089 | { | |
1090 | int something_busy = 0; | |
1091 | ||
1092 | /* compute next PEW, PGW bits */ | |
1093 | if(pke_check_stall(me, chk_vu)) | |
1094 | { | |
1095 | something_busy = 1; | |
1096 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
1097 | } | |
1098 | else | |
1099 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
fba9bfed FCE |
1100 | |
1101 | ||
43a6998b FCE |
1102 | if(pke_check_stall(me, chk_path1) || |
1103 | pke_check_stall(me, chk_path2)) | |
1104 | { | |
1105 | something_busy = 1; | |
1106 | PKE_REG_MASK_SET(me, STAT, PGW, 1); | |
1107 | } | |
1108 | else | |
1109 | PKE_REG_MASK_SET(me, STAT, PGW, 0); | |
fba9bfed | 1110 | |
43a6998b FCE |
1111 | /* go or no go */ |
1112 | if(something_busy) | |
1113 | { | |
1114 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1115 | /* try again next cycle */ | |
1116 | } | |
1117 | else | |
1118 | { | |
1119 | /* all idle */ | |
1120 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1121 | pke_pc_advance(me, 1); | |
1122 | } | |
1123 | } | |
fba9bfed | 1124 | |
fba9bfed FCE |
1125 | |
1126 | void | |
43a6998b | 1127 | pke_code_flusha(struct pke_device* me, unsigned_4 pkecode) |
fba9bfed | 1128 | { |
43a6998b | 1129 | int something_busy = 0; |
fba9bfed | 1130 | |
43a6998b FCE |
1131 | /* compute next PEW, PGW bits */ |
1132 | if(pke_check_stall(me, chk_vu)) | |
fba9bfed | 1133 | { |
43a6998b FCE |
1134 | something_busy = 1; |
1135 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
fba9bfed | 1136 | } |
43a6998b FCE |
1137 | else |
1138 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
fba9bfed | 1139 | |
43a6998b FCE |
1140 | |
1141 | if(pke_check_stall(me, chk_path1) || | |
1142 | pke_check_stall(me, chk_path2) || | |
1143 | pke_check_stall(me, chk_path3)) | |
fba9bfed | 1144 | { |
43a6998b FCE |
1145 | something_busy = 1; |
1146 | PKE_REG_MASK_SET(me, STAT, PGW, 1); | |
fba9bfed | 1147 | } |
43a6998b FCE |
1148 | else |
1149 | PKE_REG_MASK_SET(me, STAT, PGW, 0); | |
fba9bfed | 1150 | |
43a6998b FCE |
1151 | if(something_busy) |
1152 | { | |
1153 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1154 | /* try again next cycle */ | |
1155 | } | |
1156 | else | |
1157 | { | |
1158 | /* all idle */ | |
1159 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1160 | pke_pc_advance(me, 1); | |
1161 | } | |
fba9bfed FCE |
1162 | } |
1163 | ||
1164 | ||
43a6998b FCE |
1165 | void |
1166 | pke_code_pkemscal(struct pke_device* me, unsigned_4 pkecode) | |
1167 | { | |
1168 | /* compute next PEW bit */ | |
1169 | if(pke_check_stall(me, chk_vu)) | |
1170 | { | |
1171 | /* VU busy */ | |
1172 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
1173 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
1174 | /* try again next cycle */ | |
1175 | } | |
1176 | else | |
1177 | { | |
1178 | unsigned_4 vu_pc; | |
1179 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
1180 | ||
1181 | /* VU idle */ | |
1182 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
1183 | ||
1184 | /* flip DBF on PKE1 */ | |
1185 | if(me->pke_number == 1) | |
1186 | pke_flip_dbf(me); | |
1187 | ||
f0bb94cd | 1188 | /* compute new PC for VU (host byte-order) */ |
db6dac32 | 1189 | vu_pc = BIT_MASK_GET(imm, 0, 15); |
f0bb94cd | 1190 | vu_pc = T2H_4(vu_pc); |
534a3d5c | 1191 | |
43a6998b | 1192 | /* write new PC; callback function gets VU running */ |
534a3d5c FCE |
1193 | ASSERT(sizeof(unsigned_4) == 4); |
1194 | PKE_MEM_WRITE(me, (me->pke_number == 0 ? VU0_CIA : VU1_CIA), | |
1195 | & vu_pc, | |
1196 | 4); | |
43a6998b | 1197 | |
d22ea5d0 FCE |
1198 | /* copy ITOPS field to ITOP */ |
1199 | PKE_REG_MASK_SET(me, ITOP, ITOP, PKE_REG_MASK_GET(me, ITOPS, ITOPS)); | |
1200 | ||
43a6998b FCE |
1201 | /* done */ |
1202 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1203 | pke_pc_advance(me, 1); | |
1204 | } | |
1205 | } | |
fba9bfed | 1206 | |
fba9bfed | 1207 | |
43a6998b FCE |
1208 | |
1209 | void | |
1210 | pke_code_pkemscnt(struct pke_device* me, unsigned_4 pkecode) | |
fba9bfed | 1211 | { |
43a6998b FCE |
1212 | /* compute next PEW bit */ |
1213 | if(pke_check_stall(me, chk_vu)) | |
1214 | { | |
1215 | /* VU busy */ | |
1216 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
1217 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
1218 | /* try again next cycle */ | |
1219 | } | |
1220 | else | |
1221 | { | |
1222 | unsigned_4 vu_pc; | |
fba9bfed | 1223 | |
43a6998b FCE |
1224 | /* VU idle */ |
1225 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
fba9bfed | 1226 | |
43a6998b FCE |
1227 | /* flip DBF on PKE1 */ |
1228 | if(me->pke_number == 1) | |
1229 | pke_flip_dbf(me); | |
fba9bfed | 1230 | |
43a6998b | 1231 | /* read old PC */ |
534a3d5c FCE |
1232 | ASSERT(sizeof(unsigned_4) == 4); |
1233 | PKE_MEM_READ(me, (me->pke_number == 0 ? VU0_CIA : VU1_CIA), | |
1234 | & vu_pc, | |
1235 | 4); | |
43a6998b FCE |
1236 | |
1237 | /* rewrite new PC; callback function gets VU running */ | |
534a3d5c FCE |
1238 | ASSERT(sizeof(unsigned_4) == 4); |
1239 | PKE_MEM_WRITE(me, (me->pke_number == 0 ? VU0_CIA : VU1_CIA), | |
1240 | & vu_pc, | |
1241 | 4); | |
43a6998b | 1242 | |
d22ea5d0 FCE |
1243 | /* copy ITOPS field to ITOP */ |
1244 | PKE_REG_MASK_SET(me, ITOP, ITOP, PKE_REG_MASK_GET(me, ITOPS, ITOPS)); | |
1245 | ||
43a6998b FCE |
1246 | /* done */ |
1247 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1248 | pke_pc_advance(me, 1); | |
1249 | } | |
1250 | } | |
1251 | ||
1252 | ||
1253 | void | |
1254 | pke_code_pkemscalf(struct pke_device* me, unsigned_4 pkecode) | |
1255 | { | |
1256 | int something_busy = 0; | |
1257 | ||
1258 | /* compute next PEW, PGW bits */ | |
1259 | if(pke_check_stall(me, chk_vu)) | |
fba9bfed | 1260 | { |
43a6998b FCE |
1261 | something_busy = 1; |
1262 | PKE_REG_MASK_SET(me, STAT, PEW, 1); | |
fba9bfed | 1263 | } |
43a6998b FCE |
1264 | else |
1265 | PKE_REG_MASK_SET(me, STAT, PEW, 0); | |
fba9bfed | 1266 | |
43a6998b FCE |
1267 | |
1268 | if(pke_check_stall(me, chk_path1) || | |
1269 | pke_check_stall(me, chk_path2) || | |
1270 | pke_check_stall(me, chk_path3)) | |
1271 | { | |
1272 | something_busy = 1; | |
1273 | PKE_REG_MASK_SET(me, STAT, PGW, 1); | |
1274 | } | |
fba9bfed | 1275 | else |
43a6998b | 1276 | PKE_REG_MASK_SET(me, STAT, PGW, 0); |
fba9bfed | 1277 | |
43a6998b FCE |
1278 | /* go or no go */ |
1279 | if(something_busy) | |
1280 | { | |
1281 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1282 | /* try again next cycle */ | |
1283 | } | |
1284 | else | |
1285 | { | |
1286 | unsigned_4 vu_pc; | |
1287 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
1288 | ||
1289 | /* flip DBF on PKE1 */ | |
1290 | if(me->pke_number == 1) | |
1291 | pke_flip_dbf(me); | |
1292 | ||
f0bb94cd | 1293 | /* compute new PC for VU (host byte-order) */ |
db6dac32 | 1294 | vu_pc = BIT_MASK_GET(imm, 0, 15); |
f0bb94cd | 1295 | vu_pc = T2H_4(vu_pc); |
534a3d5c FCE |
1296 | |
1297 | /* rewrite new PC; callback function gets VU running */ | |
1298 | ASSERT(sizeof(unsigned_4) == 4); | |
1299 | PKE_MEM_WRITE(me, (me->pke_number == 0 ? VU0_CIA : VU1_CIA), | |
1300 | & vu_pc, | |
1301 | 4); | |
43a6998b | 1302 | |
d22ea5d0 FCE |
1303 | /* copy ITOPS field to ITOP */ |
1304 | PKE_REG_MASK_SET(me, ITOP, ITOP, PKE_REG_MASK_GET(me, ITOPS, ITOPS)); | |
1305 | ||
43a6998b FCE |
1306 | /* done */ |
1307 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1308 | pke_pc_advance(me, 1); | |
1309 | } | |
fba9bfed FCE |
1310 | } |
1311 | ||
1312 | ||
43a6998b FCE |
1313 | void |
1314 | pke_code_stmask(struct pke_device* me, unsigned_4 pkecode) | |
1315 | { | |
43a6998b | 1316 | unsigned_4* mask; |
d22ea5d0 | 1317 | |
d22ea5d0 | 1318 | /* check that FIFO has one more word for STMASK operand */ |
43a6998b FCE |
1319 | mask = pke_pc_operand(me, 1); |
1320 | if(mask != NULL) | |
1321 | { | |
1322 | /* "transferring" operand */ | |
1323 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
db6dac32 FCE |
1324 | |
1325 | /* set NUM */ | |
1326 | PKE_REG_MASK_SET(me, NUM, NUM, 1); | |
1327 | ||
43a6998b FCE |
1328 | /* fill the register */ |
1329 | PKE_REG_MASK_SET(me, MASK, MASK, *mask); | |
db6dac32 FCE |
1330 | |
1331 | /* set NUM */ | |
1332 | PKE_REG_MASK_SET(me, NUM, NUM, 0); | |
1333 | ||
43a6998b FCE |
1334 | /* done */ |
1335 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
e2306992 | 1336 | pke_pc_advance(me, 2); |
43a6998b FCE |
1337 | } |
1338 | else | |
1339 | { | |
1340 | /* need to wait for another word */ | |
1341 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1342 | /* try again next cycle */ | |
1343 | } | |
1344 | } | |
fba9bfed | 1345 | |
fba9bfed | 1346 | |
43a6998b FCE |
1347 | void |
1348 | pke_code_strow(struct pke_device* me, unsigned_4 pkecode) | |
fba9bfed | 1349 | { |
43a6998b FCE |
1350 | /* check that FIFO has four more words for STROW operand */ |
1351 | unsigned_4* last_op; | |
1352 | ||
1353 | last_op = pke_pc_operand(me, 4); | |
1354 | if(last_op != NULL) | |
1355 | { | |
1356 | /* "transferring" operand */ | |
1357 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
1358 | ||
db6dac32 FCE |
1359 | /* set NUM */ |
1360 | PKE_REG_MASK_SET(me, NUM, NUM, 1); | |
1361 | ||
43a6998b FCE |
1362 | /* copy ROW registers: must all exist if 4th operand exists */ |
1363 | me->regs[PKE_REG_R0][0] = * pke_pc_operand(me, 1); | |
1364 | me->regs[PKE_REG_R1][0] = * pke_pc_operand(me, 2); | |
1365 | me->regs[PKE_REG_R2][0] = * pke_pc_operand(me, 3); | |
1366 | me->regs[PKE_REG_R3][0] = * pke_pc_operand(me, 4); | |
1367 | ||
db6dac32 FCE |
1368 | /* set NUM */ |
1369 | PKE_REG_MASK_SET(me, NUM, NUM, 0); | |
1370 | ||
43a6998b FCE |
1371 | /* done */ |
1372 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1373 | pke_pc_advance(me, 5); | |
1374 | } | |
1375 | else | |
1376 | { | |
1377 | /* need to wait for another word */ | |
1378 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1379 | /* try again next cycle */ | |
1380 | } | |
1381 | } | |
aea481da | 1382 | |
fba9bfed | 1383 | |
43a6998b FCE |
1384 | void |
1385 | pke_code_stcol(struct pke_device* me, unsigned_4 pkecode) | |
1386 | { | |
1387 | /* check that FIFO has four more words for STCOL operand */ | |
1388 | unsigned_4* last_op; | |
1389 | ||
1390 | last_op = pke_pc_operand(me, 4); | |
1391 | if(last_op != NULL) | |
fba9bfed | 1392 | { |
43a6998b FCE |
1393 | /* "transferring" operand */ |
1394 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
1395 | ||
db6dac32 FCE |
1396 | /* set NUM */ |
1397 | PKE_REG_MASK_SET(me, NUM, NUM, 1); | |
1398 | ||
43a6998b FCE |
1399 | /* copy COL registers: must all exist if 4th operand exists */ |
1400 | me->regs[PKE_REG_C0][0] = * pke_pc_operand(me, 1); | |
1401 | me->regs[PKE_REG_C1][0] = * pke_pc_operand(me, 2); | |
1402 | me->regs[PKE_REG_C2][0] = * pke_pc_operand(me, 3); | |
1403 | me->regs[PKE_REG_C3][0] = * pke_pc_operand(me, 4); | |
1404 | ||
db6dac32 FCE |
1405 | /* set NUM */ |
1406 | PKE_REG_MASK_SET(me, NUM, NUM, 0); | |
1407 | ||
43a6998b FCE |
1408 | /* done */ |
1409 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1410 | pke_pc_advance(me, 5); | |
fba9bfed | 1411 | } |
fba9bfed | 1412 | else |
43a6998b FCE |
1413 | { |
1414 | /* need to wait for another word */ | |
1415 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1416 | /* try again next cycle */ | |
1417 | } | |
1418 | } | |
fba9bfed | 1419 | |
43a6998b FCE |
1420 | |
1421 | void | |
1422 | pke_code_mpg(struct pke_device* me, unsigned_4 pkecode) | |
1423 | { | |
1424 | unsigned_4* last_mpg_word; | |
1425 | int num = BIT_MASK_GET(pkecode, PKE_OPCODE_NUM_B, PKE_OPCODE_NUM_E); | |
1426 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
1427 | ||
653c2590 FCE |
1428 | /* assert 64-bit alignment of MPG operand */ |
1429 | if(me->qw_pc != 3 && me->qw_pc != 1) | |
1430 | return pke_code_error(me, pkecode); | |
1431 | ||
43a6998b FCE |
1432 | /* map zero to max+1 */ |
1433 | if(num==0) num=0x100; | |
1434 | ||
1435 | /* check that FIFO has a few more words for MPG operand */ | |
1436 | last_mpg_word = pke_pc_operand(me, num*2); /* num: number of 64-bit words */ | |
1437 | if(last_mpg_word != NULL) | |
1438 | { | |
1439 | /* perform implied FLUSHE */ | |
db6dac32 | 1440 | if(pke_check_stall(me, chk_vu)) |
653c2590 FCE |
1441 | { |
1442 | /* VU busy */ | |
1443 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
1444 | /* retry this instruction next clock */ | |
1445 | } | |
1446 | else | |
43a6998b FCE |
1447 | { |
1448 | /* VU idle */ | |
1449 | int i; | |
1450 | ||
1451 | /* "transferring" operand */ | |
1452 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
1453 | ||
534a3d5c FCE |
1454 | /* set NUM */ |
1455 | PKE_REG_MASK_SET(me, NUM, NUM, num); | |
1456 | ||
1457 | /* transfer VU instructions, one word-pair per iteration */ | |
1458 | for(i=0; i<num; i++) | |
43a6998b FCE |
1459 | { |
1460 | address_word vu_addr_base, vu_addr; | |
1461 | address_word vutrack_addr_base, vutrack_addr; | |
89154e47 | 1462 | address_word vu_addr_max_size; |
653c2590 | 1463 | unsigned_4 vu_lower_opcode, vu_upper_opcode; |
43a6998b | 1464 | unsigned_4* operand; |
534a3d5c FCE |
1465 | struct fifo_quadword* fq; |
1466 | int next_num; | |
1467 | ||
1468 | /* decrement NUM */ | |
1469 | next_num = PKE_REG_MASK_GET(me, NUM, NUM) - 1; | |
1470 | PKE_REG_MASK_SET(me, NUM, NUM, next_num); | |
43a6998b | 1471 | |
db6dac32 | 1472 | /* imm: in 64-bit units for MPG instruction */ |
43a6998b FCE |
1473 | /* VU*_MEM0 : instruction memory */ |
1474 | vu_addr_base = (me->pke_number == 0) ? | |
733cfc78 | 1475 | VU0_MEM0_WINDOW_START : VU1_MEM0_WINDOW_START; |
89154e47 FCE |
1476 | vu_addr_max_size = (me->pke_number == 0) ? |
1477 | VU0_MEM0_SIZE : VU1_MEM0_SIZE; | |
43a6998b FCE |
1478 | vutrack_addr_base = (me->pke_number == 0) ? |
1479 | VU0_MEM0_SRCADDR_START : VU1_MEM0_SRCADDR_START; | |
89154e47 FCE |
1480 | |
1481 | /* compute VU address for this word-pair */ | |
1482 | vu_addr = vu_addr_base + (imm + i) * 8; | |
1483 | /* check for vu_addr overflow */ | |
1484 | while(vu_addr >= vu_addr_base + vu_addr_max_size) | |
1485 | vu_addr -= vu_addr_max_size; | |
1486 | ||
1487 | /* compute VU tracking address */ | |
1488 | vutrack_addr = vutrack_addr_base + ((signed_8)vu_addr - (signed_8)vu_addr_base) / 2; | |
534a3d5c | 1489 | |
653c2590 FCE |
1490 | /* Fetch operand words; assume they are already little-endian for VU imem */ |
1491 | fq = pke_pc_fifo(me, i*2 + 1, & operand); | |
1492 | vu_lower_opcode = *operand; | |
1493 | vu_upper_opcode = *pke_pc_operand(me, i*2 + 2); | |
43a6998b FCE |
1494 | |
1495 | /* write data into VU memory */ | |
f0bb94cd | 1496 | /* lower (scalar) opcode comes in first word ; macro performs H2T! */ |
534a3d5c | 1497 | PKE_MEM_WRITE(me, vu_addr, |
b4d2f483 | 1498 | & vu_lower_opcode, |
653c2590 | 1499 | 4); |
f0bb94cd | 1500 | /* upper (vector) opcode comes in second word ; H2T */ |
b4d2f483 | 1501 | ASSERT(sizeof(unsigned_4) == 4); |
653c2590 | 1502 | PKE_MEM_WRITE(me, vu_addr + 4, |
b4d2f483 | 1503 | & vu_upper_opcode, |
653c2590 | 1504 | 4); |
43a6998b | 1505 | |
653c2590 | 1506 | /* write tracking address in target byte-order */ |
653c2590 | 1507 | ASSERT(sizeof(unsigned_4) == 4); |
534a3d5c | 1508 | PKE_MEM_WRITE(me, vutrack_addr, |
f0bb94cd | 1509 | & fq->source_address, |
534a3d5c | 1510 | 4); |
43a6998b | 1511 | } /* VU xfer loop */ |
db6dac32 FCE |
1512 | |
1513 | /* check NUM */ | |
1514 | ASSERT(PKE_REG_MASK_GET(me, NUM, NUM) == 0); | |
43a6998b FCE |
1515 | |
1516 | /* done */ | |
1517 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1518 | pke_pc_advance(me, 1 + num*2); | |
1519 | } | |
43a6998b FCE |
1520 | } /* if FIFO full enough */ |
1521 | else | |
1522 | { | |
1523 | /* need to wait for another word */ | |
1524 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1525 | /* retry this instruction next clock */ | |
1526 | } | |
aea481da DE |
1527 | } |
1528 | ||
1529 | ||
43a6998b FCE |
1530 | void |
1531 | pke_code_direct(struct pke_device* me, unsigned_4 pkecode) | |
1532 | { | |
1533 | /* check that FIFO has a few more words for DIRECT operand */ | |
1534 | unsigned_4* last_direct_word; | |
1535 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
43a6998b | 1536 | |
653c2590 FCE |
1537 | /* assert 128-bit alignment of DIRECT operand */ |
1538 | if(me->qw_pc != 3) | |
1539 | return pke_code_error(me, pkecode); | |
1540 | ||
43a6998b FCE |
1541 | /* map zero to max+1 */ |
1542 | if(imm==0) imm=0x10000; | |
1543 | ||
653c2590 | 1544 | last_direct_word = pke_pc_operand(me, imm*4); /* imm: number of 128-bit words */ |
43a6998b FCE |
1545 | if(last_direct_word != NULL) |
1546 | { | |
1547 | /* VU idle */ | |
1548 | int i; | |
f0bb94cd | 1549 | unsigned_16 fifo_data; |
43a6998b FCE |
1550 | |
1551 | /* "transferring" operand */ | |
1552 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
1553 | ||
1554 | /* transfer GPUIF quadwords, one word per iteration */ | |
1555 | for(i=0; i<imm*4; i++) | |
1556 | { | |
653c2590 | 1557 | unsigned_4* operand = pke_pc_operand(me, 1+i); |
43a6998b FCE |
1558 | |
1559 | /* collect word into quadword */ | |
f0bb94cd | 1560 | *A4_16(&fifo_data, 3 - (i % 4)) = *operand; |
43a6998b | 1561 | |
534a3d5c FCE |
1562 | /* write to GPUIF FIFO only with full quadword */ |
1563 | if(i % 4 == 3) | |
43a6998b | 1564 | { |
534a3d5c FCE |
1565 | ASSERT(sizeof(fifo_data) == 16); |
1566 | PKE_MEM_WRITE(me, GIF_PATH2_FIFO_ADDR, | |
f0bb94cd | 1567 | & fifo_data, |
534a3d5c | 1568 | 16); |
43a6998b FCE |
1569 | } /* write collected quadword */ |
1570 | ||
1571 | } /* GPUIF xfer loop */ | |
1572 | ||
1573 | /* done */ | |
1574 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1575 | pke_pc_advance(me, 1 + imm*4); | |
1576 | } /* if FIFO full enough */ | |
1577 | else | |
1578 | { | |
1579 | /* need to wait for another word */ | |
1580 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1581 | /* retry this instruction next clock */ | |
1582 | } | |
1583 | } | |
fba9bfed | 1584 | |
43a6998b FCE |
1585 | |
1586 | void | |
1587 | pke_code_directhl(struct pke_device* me, unsigned_4 pkecode) | |
fba9bfed | 1588 | { |
43a6998b FCE |
1589 | /* treat the same as DIRECTH */ |
1590 | pke_code_direct(me, pkecode); | |
1591 | } | |
fba9bfed | 1592 | |
43a6998b FCE |
1593 | |
1594 | void | |
1595 | pke_code_unpack(struct pke_device* me, unsigned_4 pkecode) | |
1596 | { | |
1597 | int imm = BIT_MASK_GET(pkecode, PKE_OPCODE_IMM_B, PKE_OPCODE_IMM_E); | |
1598 | int cmd = BIT_MASK_GET(pkecode, PKE_OPCODE_CMD_B, PKE_OPCODE_CMD_E); | |
1599 | int num = BIT_MASK_GET(pkecode, PKE_OPCODE_NUM_B, PKE_OPCODE_NUM_E); | |
db6dac32 | 1600 | short vn = BIT_MASK_GET(cmd, 2, 3); /* unpack shape controls */ |
43a6998b | 1601 | short vl = BIT_MASK_GET(cmd, 0, 1); |
43a6998b | 1602 | int m = BIT_MASK_GET(cmd, 4, 4); |
db6dac32 | 1603 | short cl = PKE_REG_MASK_GET(me, CYCLE, CL); /* cycle controls */ |
43a6998b | 1604 | short wl = PKE_REG_MASK_GET(me, CYCLE, WL); |
db6dac32 | 1605 | int r = BIT_MASK_GET(imm, 15, 15); /* indicator bits in imm value */ |
653c2590 | 1606 | int usn = BIT_MASK_GET(imm, 14, 14); |
db6dac32 | 1607 | |
43a6998b | 1608 | int n, num_operands; |
534a3d5c | 1609 | unsigned_4* last_operand_word = NULL; |
fba9bfed | 1610 | |
43a6998b FCE |
1611 | /* compute PKEcode length, as given in CPU2 spec, v2.1 pg. 11 */ |
1612 | if(wl <= cl) | |
1613 | n = num; | |
1614 | else | |
1615 | n = cl * (num/wl) + PKE_LIMIT(num % wl, cl); | |
fd909089 | 1616 | num_operands = (31 + (32 >> vl) * (vn+1) * n)/32; /* round up to next word */ |
43a6998b FCE |
1617 | |
1618 | /* confirm that FIFO has enough words in it */ | |
534a3d5c FCE |
1619 | if(num_operands > 0) |
1620 | last_operand_word = pke_pc_operand(me, num_operands); | |
1621 | if(last_operand_word != NULL || num_operands == 0) | |
43a6998b | 1622 | { |
534a3d5c FCE |
1623 | address_word vu_addr_base, vutrack_addr_base; |
1624 | address_word vu_addr_max_size; | |
1625 | int vector_num_out, vector_num_in; | |
43a6998b FCE |
1626 | |
1627 | /* "transferring" operand */ | |
1628 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_XFER); | |
1629 | ||
1630 | /* don't check whether VU is idle */ | |
db6dac32 FCE |
1631 | |
1632 | /* compute VU address base */ | |
43a6998b | 1633 | if(me->pke_number == 0) |
534a3d5c | 1634 | { |
d22ea5d0 | 1635 | vu_addr_base = VU0_MEM1_WINDOW_START; |
534a3d5c | 1636 | vu_addr_max_size = VU0_MEM1_SIZE; |
d22ea5d0 FCE |
1637 | vutrack_addr_base = VU0_MEM1_SRCADDR_START; |
1638 | r = 0; | |
534a3d5c | 1639 | } |
43a6998b FCE |
1640 | else |
1641 | { | |
d22ea5d0 | 1642 | vu_addr_base = VU1_MEM1_WINDOW_START; |
534a3d5c | 1643 | vu_addr_max_size = VU1_MEM1_SIZE; |
d22ea5d0 | 1644 | vutrack_addr_base = VU1_MEM1_SRCADDR_START; |
43a6998b | 1645 | } |
db6dac32 FCE |
1646 | |
1647 | /* set NUM */ | |
534a3d5c | 1648 | PKE_REG_MASK_SET(me, NUM, NUM, num == 0 ? 0x100 : num ); |
db6dac32 | 1649 | |
43a6998b | 1650 | /* transfer given number of vectors */ |
534a3d5c FCE |
1651 | vector_num_out = 0; /* output vector number being processed */ |
1652 | vector_num_in = 0; /* argument vector number being processed */ | |
db6dac32 | 1653 | do |
43a6998b FCE |
1654 | { |
1655 | quadword vu_old_data; | |
1656 | quadword vu_new_data; | |
1657 | quadword unpacked_data; | |
1658 | address_word vu_addr; | |
534a3d5c | 1659 | address_word vutrack_addr; |
db6dac32 | 1660 | unsigned_4 source_addr = 0; |
43a6998b | 1661 | int i; |
534a3d5c FCE |
1662 | int next_num; |
1663 | ||
db6dac32 | 1664 | /* decrement NUM */ |
534a3d5c FCE |
1665 | next_num = PKE_REG_MASK_GET(me, NUM, NUM) - 1; |
1666 | PKE_REG_MASK_SET(me, NUM, NUM, next_num); | |
1667 | ||
43a6998b FCE |
1668 | /* compute VU destination address, as bytes in R5900 memory */ |
1669 | if(cl >= wl) | |
1670 | { | |
1671 | /* map zero to max+1 */ | |
b4d2f483 | 1672 | int addrwl = (wl == 0) ? 0x0100 : wl; |
d22ea5d0 | 1673 | vu_addr = vu_addr_base + 16 * (BIT_MASK_GET(imm, 0, 9) + |
fd909089 FCE |
1674 | (vector_num_out / addrwl) * cl + |
1675 | (vector_num_out % addrwl)); | |
43a6998b FCE |
1676 | } |
1677 | else | |
d22ea5d0 | 1678 | vu_addr = vu_addr_base + 16 * (BIT_MASK_GET(imm, 0, 9) + |
d22ea5d0 | 1679 | vector_num_out); |
fd909089 FCE |
1680 | |
1681 | /* handle "R" double-buffering bit */ | |
1682 | if(r) | |
1683 | vu_addr += 16 * PKE_REG_MASK_GET(me, TOPS, TOPS); | |
534a3d5c FCE |
1684 | |
1685 | /* check for vu_addr overflow */ | |
1686 | while(vu_addr >= vu_addr_base + vu_addr_max_size) | |
1687 | vu_addr -= vu_addr_max_size; | |
1688 | ||
1689 | /* compute address of tracking table entry */ | |
1690 | vutrack_addr = vutrack_addr_base + ((signed_8)vu_addr - (signed_8)vu_addr_base) / 4; | |
db6dac32 | 1691 | |
f0bb94cd FCE |
1692 | /* read old VU data word at address; reverse words if needed */ |
1693 | { | |
1694 | unsigned_16 vu_old_badwords; | |
1695 | ASSERT(sizeof(vu_old_badwords) == 16); | |
1696 | PKE_MEM_READ(me, vu_addr, | |
1697 | &vu_old_badwords, 16); | |
1698 | vu_old_data[0] = * A4_16(& vu_old_badwords, 3); | |
1699 | vu_old_data[1] = * A4_16(& vu_old_badwords, 2); | |
1700 | vu_old_data[2] = * A4_16(& vu_old_badwords, 1); | |
1701 | vu_old_data[3] = * A4_16(& vu_old_badwords, 0); | |
1702 | } | |
653c2590 | 1703 | |
43a6998b FCE |
1704 | /* For cyclic unpack, next operand quadword may come from instruction stream |
1705 | or be zero. */ | |
b4d2f483 | 1706 | if((num == 0 && cl == 0 && wl == 0) || /* shortcut clear */ |
fd909089 | 1707 | ((cl < wl) && ((vector_num_out % wl) >= cl))) /* && short-circuit asserts wl != 0 */ |
43a6998b FCE |
1708 | { |
1709 | /* clear operand - used only in a "indeterminate" state */ | |
1710 | for(i = 0; i < 4; i++) | |
1711 | unpacked_data[i] = 0; | |
1712 | } | |
1713 | else | |
1714 | { | |
db6dac32 FCE |
1715 | /* compute packed vector dimensions */ |
1716 | int vectorbits, unitbits; | |
1717 | ||
1718 | if(vl < 3) /* PKE_UNPACK_*_{32,16,8} */ | |
43a6998b | 1719 | { |
db6dac32 FCE |
1720 | unitbits = (32 >> vl); |
1721 | vectorbits = unitbits * (vn+1); | |
1722 | } | |
1723 | else if(vl == 3 && vn == 3) /* PKE_UNPACK_V4_5 */ | |
1724 | { | |
1725 | unitbits = 5; | |
1726 | vectorbits = 16; | |
1727 | } | |
1728 | else /* illegal unpack variant */ | |
1729 | { | |
1730 | /* treat as illegal instruction */ | |
1731 | pke_code_error(me, pkecode); | |
1732 | return; | |
1733 | } | |
1734 | ||
1735 | /* loop over columns */ | |
1736 | for(i=0; i<=vn; i++) | |
1737 | { | |
1738 | unsigned_4 operand; | |
fba9bfed | 1739 | |
db6dac32 FCE |
1740 | /* offset in bits in current operand word */ |
1741 | int bitoffset = | |
534a3d5c | 1742 | (vector_num_in * vectorbits) + (i * unitbits); /* # of bits from PKEcode */ |
43a6998b | 1743 | |
db6dac32 FCE |
1744 | /* last unit of V4_5 is only one bit wide */ |
1745 | if(vl == 3 && vn == 3 && i == 3) /* PKE_UNPACK_V4_5 */ | |
1746 | unitbits = 1; | |
1747 | ||
1748 | /* fetch bitfield operand */ | |
1749 | operand = pke_pc_operand_bits(me, bitoffset, unitbits, & source_addr); | |
1750 | ||
1751 | /* selectively sign-extend; not for V4_5 1-bit value */ | |
653c2590 | 1752 | if(usn || unitbits == 1) |
db6dac32 | 1753 | unpacked_data[i] = operand; |
653c2590 FCE |
1754 | else |
1755 | unpacked_data[i] = SEXT32(operand, unitbits-1); | |
43a6998b | 1756 | } |
534a3d5c | 1757 | |
fd909089 FCE |
1758 | /* clear remaining top words in vector */ |
1759 | for(; i<4; i++) | |
1760 | unpacked_data[i] = 0; | |
1761 | ||
534a3d5c FCE |
1762 | /* consumed a vector from the PKE instruction stream */ |
1763 | vector_num_in ++; | |
db6dac32 | 1764 | } /* unpack word from instruction operand */ |
43a6998b | 1765 | |
db6dac32 | 1766 | /* compute replacement word */ |
43a6998b FCE |
1767 | if(m) /* use mask register? */ |
1768 | { | |
1769 | /* compute index into mask register for this word */ | |
b4d2f483 FCE |
1770 | int addrwl = (wl == 0) ? 0x0100 : wl; |
1771 | int mask_index = PKE_LIMIT(vector_num_out % addrwl, 3); | |
43a6998b | 1772 | |
534a3d5c | 1773 | for(i=0; i<4; i++) /* loop over columns */ |
43a6998b FCE |
1774 | { |
1775 | int mask_op = PKE_MASKREG_GET(me, mask_index, i); | |
1776 | unsigned_4* masked_value = NULL; | |
1777 | unsigned_4 zero = 0; | |
1778 | ||
1779 | switch(mask_op) | |
1780 | { | |
1781 | case PKE_MASKREG_INPUT: | |
1782 | /* for vn == 0, all columns are copied from column 0 */ | |
1783 | if(vn == 0) | |
1784 | masked_value = & unpacked_data[0]; | |
1785 | else if(i > vn) | |
1786 | masked_value = & zero; /* arbitrary data: undefined in spec */ | |
1787 | else | |
1788 | masked_value = & unpacked_data[i]; | |
1789 | break; | |
1790 | ||
1791 | case PKE_MASKREG_ROW: /* exploit R0..R3 contiguity */ | |
1792 | masked_value = & me->regs[PKE_REG_R0 + i][0]; | |
1793 | break; | |
1794 | ||
1795 | case PKE_MASKREG_COLUMN: /* exploit C0..C3 contiguity */ | |
534a3d5c | 1796 | masked_value = & me->regs[PKE_REG_C0 + mask_index][0]; |
43a6998b FCE |
1797 | break; |
1798 | ||
1799 | case PKE_MASKREG_NOTHING: | |
1800 | /* "write inhibit" by re-copying old data */ | |
1801 | masked_value = & vu_old_data[i]; | |
1802 | break; | |
1803 | ||
1804 | default: | |
1805 | ASSERT(0); | |
1806 | /* no other cases possible */ | |
1807 | } | |
1808 | ||
1809 | /* copy masked value for column */ | |
db6dac32 | 1810 | vu_new_data[i] = *masked_value; |
43a6998b | 1811 | } /* loop over columns */ |
db6dac32 | 1812 | } /* mask */ |
43a6998b FCE |
1813 | else |
1814 | { | |
1815 | /* no mask - just copy over entire unpacked quadword */ | |
1816 | memcpy(vu_new_data, unpacked_data, sizeof(unpacked_data)); | |
1817 | } | |
1818 | ||
1819 | /* process STMOD register for accumulation operations */ | |
1820 | switch(PKE_REG_MASK_GET(me, MODE, MDE)) | |
1821 | { | |
1822 | case PKE_MODE_ADDROW: /* add row registers to output data */ | |
1823 | for(i=0; i<4; i++) | |
1824 | /* exploit R0..R3 contiguity */ | |
1825 | vu_new_data[i] += me->regs[PKE_REG_R0 + i][0]; | |
1826 | break; | |
1827 | ||
1828 | case PKE_MODE_ACCROW: /* add row registers to output data; accumulate */ | |
1829 | for(i=0; i<4; i++) | |
1830 | { | |
1831 | /* exploit R0..R3 contiguity */ | |
1832 | vu_new_data[i] += me->regs[PKE_REG_R0 + i][0]; | |
1833 | me->regs[PKE_REG_R0 + i][0] = vu_new_data[i]; | |
1834 | } | |
1835 | break; | |
1836 | ||
1837 | case PKE_MODE_INPUT: /* pass data through */ | |
1838 | default: | |
1839 | ; | |
1840 | } | |
1841 | ||
f0bb94cd FCE |
1842 | /* write new VU data word at address; reverse words if needed */ |
1843 | { | |
1844 | unsigned_16 vu_new_badwords; | |
1845 | * A4_16(& vu_new_badwords, 3) = vu_new_data[0]; | |
1846 | * A4_16(& vu_new_badwords, 2) = vu_new_data[1]; | |
1847 | * A4_16(& vu_new_badwords, 1) = vu_new_data[2]; | |
1848 | * A4_16(& vu_new_badwords, 0) = vu_new_data[3]; | |
1849 | ASSERT(sizeof(vu_new_badwords) == 16); | |
1850 | PKE_MEM_WRITE(me, vu_addr, | |
1851 | &vu_new_badwords, 16); | |
1852 | } | |
1853 | ||
1854 | /* write tracking address */ | |
534a3d5c FCE |
1855 | ASSERT(sizeof(unsigned_4) == 4); |
1856 | PKE_MEM_WRITE(me, vutrack_addr, | |
1857 | & source_addr, | |
1858 | 4); | |
43a6998b FCE |
1859 | |
1860 | /* next vector please */ | |
534a3d5c | 1861 | vector_num_out ++; |
43a6998b | 1862 | } /* vector transfer loop */ |
db6dac32 | 1863 | while(PKE_REG_MASK_GET(me, NUM, NUM) > 0); |
43a6998b FCE |
1864 | |
1865 | /* done */ | |
1866 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
e2306992 | 1867 | pke_pc_advance(me, 1 + num_operands); |
43a6998b FCE |
1868 | } /* PKE FIFO full enough */ |
1869 | else | |
1870 | { | |
1871 | /* need to wait for another word */ | |
1872 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_WAIT); | |
1873 | /* retry this instruction next clock */ | |
1874 | } | |
1875 | } | |
1876 | ||
1877 | ||
1878 | void | |
1879 | pke_code_error(struct pke_device* me, unsigned_4 pkecode) | |
1880 | { | |
fd909089 FCE |
1881 | if(! PKE_REG_MASK_GET(me, ERR, ME1)) |
1882 | { | |
1883 | /* set ER1 flag in STAT register */ | |
1884 | PKE_REG_MASK_SET(me, STAT, ER1, 1); | |
1885 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_STALL); | |
1886 | } | |
1887 | else | |
1888 | { | |
1889 | PKE_REG_MASK_SET(me, STAT, PPS, PKE_REG_STAT_PPS_IDLE); | |
1890 | } | |
1891 | ||
43a6998b | 1892 | /* advance over faulty word */ |
43a6998b | 1893 | pke_pc_advance(me, 1); |
fba9bfed | 1894 | } |