aboutsummaryrefslogtreecommitdiff
path: root/sim/mips/sky-pke.h
blob: 27347e1ef556002b7515bad1e937c66c8d5d743f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/* Copyright (C) 1998, Cygnus Solutions */

#ifndef H_PKE_H
#define H_PKE_H

#include "sim-main.h"
#include "sky-device.h"


/* External functions */

void pke0_attach(SIM_DESC sd);
void pke0_issue(SIM_DESC sd);
void pke1_attach(SIM_DESC sd);
void pke1_issue(SIM_DESC sd);


/* structs declared below */
struct pke_fifo;
struct fifo_quadword;

struct fifo_quadword* pke_fifo_access(struct pke_fifo*, unsigned_4 qwnum);

/* Quadword data type */

typedef unsigned_4 quadword[4];

/* truncate address to quadword */
#define ADDR_TRUNC_QW(addr) ((addr) & ~0x0f)
/* extract offset in quadword */
#define ADDR_OFFSET_QW(addr) ((addr) & 0x0f)


/* SCEI memory mapping information */

#define PKE0_REGISTER_WINDOW_START 0x10003800
#define PKE1_REGISTER_WINDOW_START 0x10003C00
#define PKE0_FIFO_ADDR             0x10004000
#define PKE1_FIFO_ADDR             0x10005000


/* VU source-addr tracking tables */ /* changed from 1998-01-22 e-mail plans */
#define VU0_MEM0_SRCADDR_START 0x21000000
#define VU0_MEM1_SRCADDR_START 0x21004000
#define VU1_MEM0_SRCADDR_START 0x21008000
#define VU1_MEM1_SRCADDR_START 0x2100C000

#define VU0_CIA (VU0_REGISTER_WINDOW_START + VU_REG_CIA)
#define VU1_CIA (VU1_REGISTER_WINDOW_START + VU_REG_CIA)

/* GPUIF STAT register */
#define GPUIF_REG_STAT_APATH_E 11
#define GPUIF_REG_STAT_APATH_B 10

/* COP2 STAT register */
#define COP2_REG_STAT_ADDR VPU_STAT_ADDR
#define COP2_REG_STAT_VBS1_E 8
#define COP2_REG_STAT_VBS1_B 8
#define COP2_REG_STAT_VBS0_E 0
#define COP2_REG_STAT_VBS0_B 0


/* Quadword indices of PKE registers.  Actual registers sit at bottom
   32 bits of each quadword. */
#define PKE_REG_STAT    0x00
#define PKE_REG_FBRST   0x01
#define PKE_REG_ERR     0x02
#define PKE_REG_MARK    0x03
#define PKE_REG_CYCLE   0x04
#define PKE_REG_MODE    0x05
#define PKE_REG_NUM     0x06
#define PKE_REG_MASK    0x07
#define PKE_REG_CODE    0x08
#define PKE_REG_ITOPS   0x09
#define PKE_REG_BASE    0x0a /* pke1 only */
#define PKE_REG_OFST    0x0b /* pke1 only */
#define PKE_REG_TOPS    0x0c /* pke1 only */
#define PKE_REG_ITOP    0x0d
#define PKE_REG_TOP     0x0e /* pke1 only */
#define PKE_REG_DBF     0x0f /* pke1 only */
#define PKE_REG_R0      0x10 /* R0 .. R3 must be contiguous */
#define PKE_REG_R1      0x11
#define PKE_REG_R2      0x12
#define PKE_REG_R3      0x13
#define PKE_REG_C0      0x14 /* C0 .. C3 must be contiguous */
#define PKE_REG_C1      0x15
#define PKE_REG_C2      0x16
#define PKE_REG_C3      0x17
/* one plus last index */
#define PKE_NUM_REGS    0x18

#define PKE_REGISTER_WINDOW_SIZE  (sizeof(quadword) * PKE_NUM_REGS)



/* PKE commands */

#define PKE_CMD_PKENOP_MASK 0x7F
#define PKE_CMD_PKENOP_BITS 0x00
#define PKE_CMD_STCYCL_MASK 0x7F
#define PKE_CMD_STCYCL_BITS 0x01
#define PKE_CMD_OFFSET_MASK 0x7F
#define PKE_CMD_OFFSET_BITS 0x02
#define PKE_CMD_BASE_MASK 0x7F
#define PKE_CMD_BASE_BITS 0x03
#define PKE_CMD_ITOP_MASK 0x7F
#define PKE_CMD_ITOP_BITS 0x04
#define PKE_CMD_STMOD_MASK 0x7F
#define PKE_CMD_STMOD_BITS 0x05
#define PKE_CMD_MSKPATH3_MASK 0x7F
#define PKE_CMD_MSKPATH3_BITS 0x06
#define PKE_CMD_PKEMARK_MASK 0x7F
#define PKE_CMD_PKEMARK_BITS 0x07
#define PKE_CMD_FLUSHE_MASK 0x7F
#define PKE_CMD_FLUSHE_BITS 0x10
#define PKE_CMD_FLUSH_MASK 0x7F
#define PKE_CMD_FLUSH_BITS 0x11
#define PKE_CMD_FLUSHA_MASK 0x7F
#define PKE_CMD_FLUSHA_BITS 0x13
#define PKE_CMD_PKEMSCAL_MASK 0x7F  /* CAL == "call" */
#define PKE_CMD_PKEMSCAL_BITS 0x14
#define PKE_CMD_PKEMSCNT_MASK 0x7F  /* CNT == "continue" */
#define PKE_CMD_PKEMSCNT_BITS 0x17
#define PKE_CMD_PKEMSCALF_MASK 0x7F /* CALF == "call after flush" */
#define PKE_CMD_PKEMSCALF_BITS 0x15
#define PKE_CMD_STMASK_MASK 0x7F
#define PKE_CMD_STMASK_BITS 0x20
#define PKE_CMD_STROW_MASK 0x7F
#define PKE_CMD_STROW_BITS 0x30
#define PKE_CMD_STCOL_MASK 0x7F
#define PKE_CMD_STCOL_BITS 0x31
#define PKE_CMD_MPG_MASK 0x7F
#define PKE_CMD_MPG_BITS 0x4A
#define PKE_CMD_DIRECT_MASK 0x7F
#define PKE_CMD_DIRECT_BITS 0x50
#define PKE_CMD_DIRECTHL_MASK 0x7F
#define PKE_CMD_DIRECTHL_BITS 0x51
#define PKE_CMD_UNPACK_MASK 0x60
#define PKE_CMD_UNPACK_BITS 0x60

/* test given word for particular PKE command bit pattern */
#define IS_PKE_CMD(word,cmd) (((word) & PKE_CMD_##cmd##_MASK) == PKE_CMD_##cmd##_BITS)


/* register bitmasks: bit numbers for end and beginning of fields */

/* PKE opcode */
#define PKE_OPCODE_I_E 31
#define PKE_OPCODE_I_B 31
#define PKE_OPCODE_CMD_E 30
#define PKE_OPCODE_CMD_B 24
#define PKE_OPCODE_NUM_E 23
#define PKE_OPCODE_NUM_B 16
#define PKE_OPCODE_IMM_E 15
#define PKE_OPCODE_IMM_B 0

/* STAT register */
#define PKE_REG_STAT_FQC_E 28
#define PKE_REG_STAT_FQC_B 24
#define PKE_REG_STAT_FDR_E 23
#define PKE_REG_STAT_FDR_B 23
#define PKE_REG_STAT_ER1_E 13
#define PKE_REG_STAT_ER1_B 13
#define PKE_REG_STAT_ER0_E 12
#define PKE_REG_STAT_ER0_B 12
#define PKE_REG_STAT_INT_E 11
#define PKE_REG_STAT_INT_B 11
#define PKE_REG_STAT_PIS_E 10
#define PKE_REG_STAT_PIS_B 10
#define PKE_REG_STAT_PFS_E 9
#define PKE_REG_STAT_PFS_B 9
#define PKE_REG_STAT_PSS_E 8
#define PKE_REG_STAT_PSS_B 8
#define PKE_REG_STAT_DBF_E 7
#define PKE_REG_STAT_DBF_B 7
#define PKE_REG_STAT_MRK_E 6
#define PKE_REG_STAT_MRK_B 6
#define PKE_REG_STAT_PGW_E 3
#define PKE_REG_STAT_PGW_B 3
#define PKE_REG_STAT_PEW_E 2
#define PKE_REG_STAT_PEW_B 2
#define PKE_REG_STAT_PPS_E 1
#define PKE_REG_STAT_PPS_B 0

#define PKE_REG_STAT_PPS_IDLE 0x00 /* ready to execute next instruction */
#define PKE_REG_STAT_PPS_WAIT 0x01 /* not enough words in FIFO */
#define PKE_REG_STAT_PPS_DECODE 0x02 /* decoding instruction */
#define PKE_REG_STAT_PPS_STALL 0x02 /* alias state for stall (e.g., FLUSHE) */
#define PKE_REG_STAT_PPS_XFER 0x03 /* transferring instruction operands */

/* DBF register */
#define PKE_REG_DBF_DF_E 0
#define PKE_REG_DBF_DF_B 0

/* OFST register */
#define PKE_REG_OFST_OFFSET_E 9
#define PKE_REG_OFST_OFFSET_B 0

/* OFST register */
#define PKE_REG_TOPS_TOPS_E 9
#define PKE_REG_TOPS_TOPS_B 0

/* BASE register */
#define PKE_REG_BASE_BASE_E 9
#define PKE_REG_BASE_BASE_B 0

/* ITOPS register */
#define PKE_REG_ITOPS_ITOPS_E 9
#define PKE_REG_ITOPS_ITOPS_B 0

/* MODE register */
#define PKE_REG_MODE_MDE_E 1
#define PKE_REG_MODE_MDE_B 0

/* NUM register */
#define PKE_REG_NUM_NUM_E 9
#define PKE_REG_NUM_NUM_B 0

/* MARK register */
#define PKE_REG_MARK_MARK_E 15
#define PKE_REG_MARK_MARK_B 0

/* ITOP register */
#define PKE_REG_ITOP_ITOP_E 9
#define PKE_REG_ITOP_ITOP_B 0

/* TOP register */
#define PKE_REG_TOP_TOP_E 9
#define PKE_REG_TOP_TOP_B 0

/* MASK register */
#define PKE_REG_MASK_MASK_E 31
#define PKE_REG_MASK_MASK_B 0

/* CYCLE register */
#define PKE_REG_CYCLE_WL_E 15
#define PKE_REG_CYCLE_WL_B 8
#define PKE_REG_CYCLE_CL_E 7
#define PKE_REG_CYCLE_CL_B 0

/* ERR register */
#define PKE_REG_ERR_ME1_E 2
#define PKE_REG_ERR_ME1_B 2
#define PKE_REG_ERR_ME0_E 1
#define PKE_REG_ERR_ME0_B 1
#define PKE_REG_ERR_MII_E 0
#define PKE_REG_ERR_MII_B 0

/* FBRST command bitfields */
#define PKE_REG_FBRST_STC_E 3
#define PKE_REG_FBRST_STC_B 3
#define PKE_REG_FBRST_STP_E 2
#define PKE_REG_FBRST_STP_B 2
#define PKE_REG_FBRST_FBK_E 1
#define PKE_REG_FBRST_FBK_B 1
#define PKE_REG_FBRST_RST_E 0
#define PKE_REG_FBRST_RST_B 0

/* MSKPATH3 command bitfields */
#define PKE_REG_MSKPATH3_E 15
#define PKE_REG_MSKPATH3_B 15


/* UNPACK opcodes */
#define PKE_UNPACK(vn,vl) ((vn) << 2 | (vl))
#define PKE_UNPACK_S_32  PKE_UNPACK(0, 0)
#define PKE_UNPACK_S_16  PKE_UNPACK(0, 1)
#define PKE_UNPACK_S_8   PKE_UNPACK(0, 2)
#define PKE_UNPACK_V2_32 PKE_UNPACK(1, 0)
#define PKE_UNPACK_V2_16 PKE_UNPACK(1, 1)
#define PKE_UNPACK_V2_8  PKE_UNPACK(1, 2)
#define PKE_UNPACK_V3_32 PKE_UNPACK(2, 0)
#define PKE_UNPACK_V3_16 PKE_UNPACK(2, 1)
#define PKE_UNPACK_V3_8  PKE_UNPACK(2, 2)
#define PKE_UNPACK_V4_32 PKE_UNPACK(3, 0)
#define PKE_UNPACK_V4_16 PKE_UNPACK(3, 1)
#define PKE_UNPACK_V4_8  PKE_UNPACK(3, 2)
#define PKE_UNPACK_V4_5  PKE_UNPACK(3, 3)


/* MASK register sub-field definitions */
#define PKE_MASKREG_INPUT 0
#define PKE_MASKREG_ROW 1
#define PKE_MASKREG_COLUMN 2
#define PKE_MASKREG_NOTHING 3


/* STMOD register field definitions */
#define PKE_MODE_INPUT 0
#define PKE_MODE_ADDROW 1
#define PKE_MODE_ACCROW 2


/* extract a MASK register sub-field for row [0..3] and column [0..3] */
/* MASK register is laid out of 2-bit values in this r-c order */
/* m33 m32 m31 m30 m23 m22 m21 m20 m13 m12 m11 m10 m03 m02 m01 m00 */
#define PKE_MASKREG_GET(me,row,col) \
((((me)->regs[PKE_REG_MASK][0]) >> (8*(row) + 2*(col))) & 0x03)


/* operations - replace with those in sim-bits.h when convenient */

/* unsigned 32-bit mask of given width */
#define BIT_MASK(width) ((width) == 31 ? 0xffffffff : (((unsigned_4)1) << (width+1)) - 1)
/* e.g.: BIT_MASK(4) = 00011111 */

/* mask between given given bits numbers (MSB) */
#define BIT_MASK_BTW(begin,end) ((BIT_MASK(end) & ~((begin) == 0 ? 0 : BIT_MASK((begin)-1))))
/* e.g.: BIT_MASK_BTW(4,11) = 0000111111110000 */

/* set bitfield value */
#define BIT_MASK_SET(lvalue,begin,end,value) \
do { \
  ASSERT((begin) <= (end)); \
  (lvalue) &= ~BIT_MASK_BTW((begin),(end)); \
  (lvalue) |= ((value) << (begin)) & BIT_MASK_BTW((begin),(end)); \
} while(0)

/* get bitfield value */
#define BIT_MASK_GET(rvalue,begin,end) \
  (((rvalue) & BIT_MASK_BTW(begin,end)) >> (begin))
/* e.g., BIT_MASK_GET(0000111100001111, 2, 8) = 0000000100001100 */

/* These ugly macro hacks allow succinct bitfield accesses */
/* set a bitfield in a register by "name" */
#define PKE_REG_MASK_SET(me,reg,flag,value) \
     do { \
       unsigned_4 old = BIT_MASK_GET(((me)->regs[PKE_REG_##reg][0]), \
                    PKE_REG_##reg##_##flag##_B, PKE_REG_##reg##_##flag##_E); \
       BIT_MASK_SET(((me)->regs[PKE_REG_##reg][0]), \
                    PKE_REG_##reg##_##flag##_B, PKE_REG_##reg##_##flag##_E, \
                    (value)); \
       if( indebug ((me)->dev.name)) \
         { \
           if (old != (value)) \
           { \
             if (((me)->fifo_trace_file == NULL ) &&  \
                 ((me)->fifo_trace_file_name != NULL )) \
               sky_open_file (&((me)->fifo_trace_file), \
                              (me)->fifo_trace_file_name, \
                              (char *) NULL); \
             fprintf (((me)->fifo_trace_file != NULL) ? \
                      (me)->fifo_trace_file : stdout, \
                      "# Reg %s:%s = 0x%x\n", #reg, #flag, (unsigned)(value)); \
           } \
         } \
     } while(0)

/* get a bitfield from a register by "name" */
#define PKE_REG_MASK_GET(me,reg,flag) \
     BIT_MASK_GET(((me)->regs[PKE_REG_##reg][0]), \
                  PKE_REG_##reg##_##flag##_B, PKE_REG_##reg##_##flag##_E)


#define PKE_LIMIT(value,max) ((value) > (max) ? (max) : (value))


/* Classify words in a FIFO quadword */
enum wordclass
{
  wc_dma = 'D',
  wc_pkecode = 'P',
  wc_unknown = '?',
  wc_pkedata = '.',
  wc_gpuiftag = 'g'
};


/* One row in the FIFO */
struct fifo_quadword
{
  /* 128 bits of data */
  quadword data;
  /* source main memory address (or 0: unknown) */
  unsigned_4 source_address;
  /* classification of words in quadword; wc_dma set on DMA tags at FIFO write */
  enum wordclass word_class[4];
};


/* quadword FIFO structure for PKE */ 
typedef struct pke_fifo
{
  struct fifo_quadword** quadwords; /* pointer to fifo quadwords */
  unsigned_4 origin; /* quadword serial number of quadwords[0] */
  unsigned_4 length; /* length of quadword pointer array: 0..N */
  unsigned_4 next;   /* relative index of first unfilled quadword: 0..length-1 */
} pke_fifo;

#define PKE_FIFO_GROW_SIZE 1000 /* number of quadword pointers to allocate */
#define PKE_FIFO_ARCHEOLOGY 1000 /* number of old quadwords to keep as history */


/* PKE internal state: FIFOs, registers, handle to VU friend */
struct pke_device
{
  /* common device info */
  device dev;

  /* identity: 0=PKE0, 1=PKE1 */
  int pke_number;
  int flags;

  /* quadword registers: data in [0] word only */
  quadword regs[PKE_NUM_REGS];

  /* write buffer for FIFO address */
  quadword fifo_qw_in_progress;
  int fifo_qw_done; /* bitfield */

  /* FIFO - private: use only pke_fifo_* routines to access */
  struct pke_fifo fifo;  /* array of FIFO quadword pointers */
  FILE* fifo_trace_file; /* stdio stream open in append mode, or 0 for no trace */
  char* fifo_trace_file_name; /* user defined debug trace file name  */

  /* FIFO cache -- curry last search pke_pcrel_fifo results */
  unsigned_4 last_fifo_pc;
  unsigned_4 last_qw_pc;
  unsigned_4 last_num;
  unsigned_4 last_new_fifo_pc;
  unsigned_4 last_new_qw_pc;

  /* PC */
  int fifo_pc;  /* 0 .. (fifo_num_elements-1): quadword index of next instruction */
  int qw_pc;    /* 0 .. 3:                     word index of next instruction */

  /* Disassembly - file name and descriptor  */
  FILE *trace_file;
  char *trace_file_name;
  
};

extern struct pke_device pke0_device;
extern struct pke_device pke1_device;

int read_pke_reg (struct pke_device *device, int regno, void *buf);
int write_pke_reg (struct pke_device *device, int regno, const void *buf);
int read_pke_pc (struct pke_device *device, void *buf);
int read_pke_pcx (struct pke_device *device, void *buf);


/* Flags for PKE.flags */

#define PKE_FLAG_NONE        0x00
#define PKE_FLAG_PENDING_PSS 0x01 /* PSS bit written-to; set STAT:PSS after current instruction */
#define PKE_FLAG_INT_NOLOOP  0x02 /* INT PKEcode received; INT/PIS set; suppress loop after resumption */
#define PKE_FLAG_TRACE_ON    0x04 /* Trace file request from command line  */                                      

/* Kludge alert */

#define PKE_MEM_READ(me,addr,data,size) \
    do { \
      sim_cpu* cpu = STATE_CPU(CURRENT_STATE, 0); \
      unsigned_##size value = \
        sim_core_read_aligned_##size(cpu, CIA_GET(cpu), read_map, \
                                     (SIM_ADDR)(addr)); \
      memcpy((unsigned_##size*) (data), (void*) & value, size); \
     } while(0)

#define PKE_MEM_WRITE(me,addr,data,size) \
    do { sim_cpu* cpu = STATE_CPU(CURRENT_STATE, 0); \
         unsigned_##size value; \
         memcpy((void*) & value, (unsigned_##size*)(data), size); \
         sim_core_write_aligned_##size(cpu, CIA_GET(cpu), write_map, \
                                       (SIM_ADDR)(addr), value); \
         if (indebug ((me)->dev.name)) \
           { \
             int i; \
             unsigned_##size value_te; \
             value_te = H2T_##size(value); \
             if (((me)->fifo_trace_file == NULL ) && \
                 ((me)->fifo_trace_file_name != NULL )) \
               sky_open_file (&((me)->fifo_trace_file), \
                              (me)->fifo_trace_file_name, \
                              (char *) NULL); \
             fprintf (((me)->fifo_trace_file != NULL) ? \
                      (me)->fifo_trace_file : stdout, \
                      "# Write %2d bytes  to  ", size); \
             fprintf (((me)->fifo_trace_file != NULL) ? \
                      (me)->fifo_trace_file : stdout, \
                     "0x%08lx: ", (unsigned long)(addr)); \
             for(i=0; i<size; i++) \
               fprintf (((me)->fifo_trace_file != NULL) ? \
                        (me)->fifo_trace_file : stdout, \
                        " %02x", ((unsigned_1*)(& value_te))[i]); \
             fprintf (((me)->fifo_trace_file != NULL) ? \
                      (me)->fifo_trace_file : stdout, \
                      "\n"); \
           } \
        } while(0)      

void pke_options (struct pke_device *device, unsigned_4 option, char *option_string);

#endif /* H_PKE_H */