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