#include "config.h"
#include <stdlib.h>
-#include "sky-pke.h"
-#include "sky-dma.h"
+#include "sim-main.h"
#include "sim-bits.h"
#include "sim-assert.h"
-#include "sky-vu0.h"
-#include "sky-vu1.h"
+#include "sky-pke.h"
+#include "sky-dma.h"
+#include "sky-vu.h"
#include "sky-gpuif.h"
#include "sky-device.h"
+
#ifdef HAVE_STRING_H
#include <string.h>
#else
static void pke_code_directhl(struct pke_device* me, unsigned_4 pkecode);
static void pke_code_unpack(struct pke_device* me, unsigned_4 pkecode);
static void pke_code_error(struct pke_device* me, unsigned_4 pkecode);
+unsigned_4 pke_fifo_flush(struct pke_fifo*);
+void pke_fifo_reset(struct pke_fifo*);
+struct fifo_quadword* pke_fifo_fit(struct pke_fifo*);
+struct fifo_quadword* pke_fifo_access(struct pke_fifo*, unsigned_4 qwnum);
+void pke_fifo_old(struct pke_fifo*, unsigned_4 qwnum);
}
+/* Read PKE Pseudo-PC into buf in target order */
+int
+read_pke_pc (struct pke_device *me, void *buf)
+{
+ *((int *) buf) = H2T_4( (me->fifo_pc << 2) | me->qw_pc );
+ return 4;
+}
+
+
+/* Read PKE reg into buf in target order */
+int
+read_pke_reg (struct pke_device *me, int reg_num, void *buf)
+{
+ /* handle reads to individual registers; clear `readable' on error */
+ switch (reg_num)
+ {
+ /* handle common case of register reading, side-effect free */
+ /* PKE1-only registers*/
+ case PKE_REG_BASE:
+ case PKE_REG_OFST:
+ case PKE_REG_TOPS:
+ case PKE_REG_TOP:
+ case PKE_REG_DBF:
+ if (me->pke_number == 0)
+ {
+ *((int *) buf) = 0;
+ break;
+ }
+ /* fall through */
+
+ /* PKE0 & PKE1 common registers*/
+ case PKE_REG_STAT:
+ case PKE_REG_ERR:
+ case PKE_REG_MARK:
+ case PKE_REG_CYCLE:
+ case PKE_REG_MODE:
+ case PKE_REG_NUM:
+ case PKE_REG_MASK:
+ case PKE_REG_CODE:
+ case PKE_REG_ITOPS:
+ case PKE_REG_ITOP:
+ case PKE_REG_R0:
+ case PKE_REG_R1:
+ case PKE_REG_R2:
+ case PKE_REG_R3:
+ case PKE_REG_C0:
+ case PKE_REG_C1:
+ case PKE_REG_C2:
+ case PKE_REG_C3:
+ *((int *) buf) = H2T_4(me->regs[reg_num][0]);
+ break;
+
+ /* handle common case of write-only registers */
+ case PKE_REG_FBRST:
+ *((int *) buf) = 0;
+ break;
+
+ default:
+ ASSERT(0); /* tests above should prevent this possibility */
+ }
+
+ return 4;
+}
+
/* Handle a PKE read; return no. of bytes read */
/* register bank */
int reg_num = ADDR_TRUNC_QW(addr - my_reg_start) >> 4;
int reg_byte = ADDR_OFFSET_QW(addr); /* find byte-offset inside register bank */
- int readable = 1;
quadword result;
/* clear result */
result[0] = result[1] = result[2] = result[3] = 0;
- /* handle reads to individual registers; clear `readable' on error */
- switch(reg_num)
- {
- /* handle common case of register reading, side-effect free */
- /* PKE1-only registers*/
- case PKE_REG_BASE:
- case PKE_REG_OFST:
- case PKE_REG_TOPS:
- case PKE_REG_TOP:
- case PKE_REG_DBF:
- if(me->pke_number == 0)
- readable = 0;
- /* fall through */
- /* PKE0 & PKE1 common registers*/
- case PKE_REG_STAT:
- case PKE_REG_ERR:
- case PKE_REG_MARK:
- case PKE_REG_CYCLE:
- case PKE_REG_MODE:
- case PKE_REG_NUM:
- case PKE_REG_MASK:
- case PKE_REG_CODE:
- case PKE_REG_ITOPS:
- case PKE_REG_ITOP:
- case PKE_REG_R0:
- case PKE_REG_R1:
- case PKE_REG_R2:
- case PKE_REG_R3:
- case PKE_REG_C0:
- case PKE_REG_C1:
- case PKE_REG_C2:
- case PKE_REG_C3:
- result[0] = H2T_4(me->regs[reg_num][0]);
- break;
-
- /* handle common case of write-only registers */
- case PKE_REG_FBRST:
- readable = 0;
- break;
-
- default:
- ASSERT(0); /* test above should prevent this possibility */
- }
+ read_pke_reg (me, reg_num, result);
/* perform transfer & return */
- if(readable)
- {
- /* copy the bits */
- memcpy(dest, ((unsigned_1*) &result) + reg_byte, nr_bytes);
- /* okay */
- }
- else
- {
- /* return zero bits */
- memset(dest, 0, nr_bytes);
- }
+ memcpy(dest, ((unsigned_1*) &result) + reg_byte, nr_bytes);
return nr_bytes;
/* NOTREACHED */
return 0;
}
+/* Write PKE reg from buf, which is in target order */
+int
+write_pke_reg (struct pke_device *me, int reg_num, const void *buf)
+{
+ int writeable = 1;
+ /* make words host-endian */
+ unsigned_4 input = T2H_4( *((unsigned_4 *) buf) );
+
+ /* handle writes to individual registers; clear `writeable' on error */
+ switch (reg_num)
+ {
+ case PKE_REG_FBRST:
+ /* Order these tests from least to most overriding, in case
+ multiple bits are set. */
+ if(BIT_MASK_GET(input, PKE_REG_FBRST_STC_B, PKE_REG_FBRST_STC_E))
+ {
+ /* clear a bunch of status bits */
+ PKE_REG_MASK_SET(me, STAT, PSS, 0);
+ PKE_REG_MASK_SET(me, STAT, PFS, 0);
+ PKE_REG_MASK_SET(me, STAT, PIS, 0);
+ PKE_REG_MASK_SET(me, STAT, INT, 0);
+ PKE_REG_MASK_SET(me, STAT, ER0, 0);
+ PKE_REG_MASK_SET(me, STAT, ER1, 0);
+ me->flags &= ~PKE_FLAG_PENDING_PSS;
+ /* will allow resumption of possible stalled instruction */
+ }
+ if(BIT_MASK_GET(input, PKE_REG_FBRST_STP_B, PKE_REG_FBRST_STP_E))
+ {
+ me->flags |= PKE_FLAG_PENDING_PSS;
+ }
+ if(BIT_MASK_GET(input, PKE_REG_FBRST_FBK_B, PKE_REG_FBRST_FBK_E))
+ {
+ PKE_REG_MASK_SET(me, STAT, PFS, 1);
+ }
+ if(BIT_MASK_GET(input, PKE_REG_FBRST_RST_B, PKE_REG_FBRST_RST_E))
+ {
+ pke_reset(me);
+ }
+ break;
+
+ case PKE_REG_ERR:
+ /* copy bottom three bits */
+ BIT_MASK_SET(me->regs[PKE_REG_ERR][0], 0, 2, BIT_MASK_GET(input, 0, 2));
+ break;
+
+ case PKE_REG_MARK:
+ /* copy bottom sixteen bits */
+ PKE_REG_MASK_SET(me, MARK, MARK, BIT_MASK_GET(input, 0, 15));
+ /* reset MRK bit in STAT */
+ PKE_REG_MASK_SET(me, STAT, MRK, 0);
+ break;
+
+ /* handle common case of read-only registers */
+ /* PKE1-only registers - not really necessary to handle separately */
+ case PKE_REG_BASE:
+ case PKE_REG_OFST:
+ case PKE_REG_TOPS:
+ case PKE_REG_TOP:
+ case PKE_REG_DBF:
+ if(me->pke_number == 0)
+ writeable = 0;
+ /* fall through */
+ /* PKE0 & PKE1 common registers*/
+ case PKE_REG_STAT:
+ /* ignore FDR bit for PKE1_STAT -- simulator does not implement PKE->RAM transfers */
+ case PKE_REG_CYCLE:
+ case PKE_REG_MODE:
+ case PKE_REG_NUM:
+ case PKE_REG_MASK:
+ case PKE_REG_CODE:
+ case PKE_REG_ITOPS:
+ case PKE_REG_ITOP:
+ case PKE_REG_R0:
+ case PKE_REG_R1:
+ case PKE_REG_R2:
+ case PKE_REG_R3:
+ case PKE_REG_C0:
+ case PKE_REG_C1:
+ case PKE_REG_C2:
+ case PKE_REG_C3:
+ writeable = 0;
+ break;
+
+ default:
+ ASSERT(0); /* test above should prevent this possibility */
+ }
+
+ /* perform return */
+ if(! writeable)
+ {
+ return 0; /* error */
+ }
+
+ return 4;
+}
+
-/* Handle a PKE read; return no. of bytes written */
+/* Handle a PKE write; return no. of bytes written */
int
pke_io_write_buffer(device *me_,
/* register bank */
int reg_num = ADDR_TRUNC_QW(addr - my_reg_start) >> 4;
int reg_byte = ADDR_OFFSET_QW(addr); /* find byte-offset inside register bank */
- int writeable = 1;
quadword input;
/* clear input */
/* write user-given bytes into input */
memcpy(((unsigned_1*) &input) + reg_byte, src, nr_bytes);
- /* make words host-endian */
- input[0] = T2H_4(input[0]);
- /* we may ignore other words */
-
- /* handle writes to individual registers; clear `writeable' on error */
- switch(reg_num)
- {
- case PKE_REG_FBRST:
- /* Order these tests from least to most overriding, in case
- multiple bits are set. */
- if(BIT_MASK_GET(input[0], PKE_REG_FBRST_STC_B, PKE_REG_FBRST_STC_E))
- {
- /* clear a bunch of status bits */
- PKE_REG_MASK_SET(me, STAT, PSS, 0);
- PKE_REG_MASK_SET(me, STAT, PFS, 0);
- PKE_REG_MASK_SET(me, STAT, PIS, 0);
- PKE_REG_MASK_SET(me, STAT, INT, 0);
- PKE_REG_MASK_SET(me, STAT, ER0, 0);
- PKE_REG_MASK_SET(me, STAT, ER1, 0);
- me->flags &= ~PKE_FLAG_PENDING_PSS;
- /* will allow resumption of possible stalled instruction */
- }
- if(BIT_MASK_GET(input[0], PKE_REG_FBRST_STP_B, PKE_REG_FBRST_STP_E))
- {
- me->flags |= PKE_FLAG_PENDING_PSS;
- }
- if(BIT_MASK_GET(input[0], PKE_REG_FBRST_FBK_B, PKE_REG_FBRST_FBK_E))
- {
- PKE_REG_MASK_SET(me, STAT, PFS, 1);
- }
- if(BIT_MASK_GET(input[0], PKE_REG_FBRST_RST_B, PKE_REG_FBRST_RST_E))
- {
- pke_reset(me);
- }
- break;
-
- case PKE_REG_ERR:
- /* copy bottom three bits */
- BIT_MASK_SET(me->regs[PKE_REG_ERR][0], 0, 2, BIT_MASK_GET(input[0], 0, 2));
- break;
-
- case PKE_REG_MARK:
- /* copy bottom sixteen bits */
- PKE_REG_MASK_SET(me, MARK, MARK, BIT_MASK_GET(input[0], 0, 15));
- /* reset MRK bit in STAT */
- PKE_REG_MASK_SET(me, STAT, MRK, 0);
- break;
-
- /* handle common case of read-only registers */
- /* PKE1-only registers - not really necessary to handle separately */
- case PKE_REG_BASE:
- case PKE_REG_OFST:
- case PKE_REG_TOPS:
- case PKE_REG_TOP:
- case PKE_REG_DBF:
- if(me->pke_number == 0)
- writeable = 0;
- /* fall through */
- /* PKE0 & PKE1 common registers*/
- case PKE_REG_STAT:
- /* ignore FDR bit for PKE1_STAT -- simulator does not implement PKE->RAM transfers */
- case PKE_REG_CYCLE:
- case PKE_REG_MODE:
- case PKE_REG_NUM:
- case PKE_REG_MASK:
- case PKE_REG_CODE:
- case PKE_REG_ITOPS:
- case PKE_REG_ITOP:
- case PKE_REG_R0:
- case PKE_REG_R1:
- case PKE_REG_R2:
- case PKE_REG_R3:
- case PKE_REG_C0:
- case PKE_REG_C1:
- case PKE_REG_C2:
- case PKE_REG_C3:
- writeable = 0;
- break;
-
- default:
- ASSERT(0); /* test above should prevent this possibility */
- }
-
- /* perform return */
- if(! writeable)
- {
- ; /* error */
- }
-
+ write_pke_reg (me, reg_num, input);
return nr_bytes;
/* NOTREACHED */
}
else if(what == chk_path1) /* VU -> GPUIF */
{
+ ASSERT(me->pke_number == 1);
if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 1)
any_stall = 1;
}
else if(what == chk_path2) /* PKE -> GPUIF */
{
+ ASSERT(me->pke_number == 1);
if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 2)
any_stall = 1;
}
else if(what == chk_path3) /* DMA -> GPUIF */
{
+ ASSERT(me->pke_number == 1);
if(BIT_MASK_GET(gpuif_stat, GPUIF_REG_STAT_APATH_B, GPUIF_REG_STAT_APATH_E) == 3)
any_stall = 1;
}
/* set appropriate bit */
if(BIT_MASK_GET(imm, PKE_REG_MSKPATH3_B, PKE_REG_MSKPATH3_E) != 0)
- gif_mode = GIF_REG_MODE_M3R_MASK;
+ gif_mode = GIF_REG_STAT_M3P;
else
gif_mode = 0;
- /* write register; patrickm code will look at M3R bit only */
- PKE_MEM_WRITE(me, GIF_REG_MODE, & gif_mode, 4);
+ /* write register to "read-only" register; gpuif code will look at M3P bit only */
+ PKE_MEM_WRITE(me, GIF_REG_VIF_M3P, & gif_mode, 4);
/* done */
pke_pc_advance(me, 1);
switch(PKE_REG_MASK_GET(me, MODE, MDE))
{
case PKE_MODE_ADDROW: /* add row registers to output data */
+ case PKE_MODE_ACCROW: /* same .. later conditionally accumulate */
for(i=0; i<4; i++)
/* exploit R0..R3 contiguity */
unpacked_data[i] += me->regs[PKE_REG_R0 + i][0];
break;
- case PKE_MODE_ACCROW: /* add row registers to output data; accumulate */
- for(i=0; i<4; i++)
- {
- /* exploit R0..R3 contiguity */
- unpacked_data[i] += me->regs[PKE_REG_R0 + i][0];
- me->regs[PKE_REG_R0 + i][0] = unpacked_data[i];
- }
- break;
-
case PKE_MODE_INPUT: /* pass data through */
default: /* specified as undefined */
;
{
case PKE_MASKREG_INPUT:
masked_value = & unpacked_data[i];
+
+ /* conditionally accumulate */
+ if(PKE_REG_MASK_GET(me, MODE, MDE) == PKE_MODE_ACCROW)
+ me->regs[PKE_REG_R0 + i][0] = unpacked_data[i];
+
break;
case PKE_MASKREG_ROW: /* exploit R0..R3 contiguity */
{
/* no mask - just copy over entire unpacked quadword */
memcpy(vu_new_data, unpacked_data, sizeof(unpacked_data));
+
+ /* conditionally store accumulated row results */
+ if(PKE_REG_MASK_GET(me, MODE, MDE) == PKE_MODE_ACCROW)
+ for(i=0; i<4; i++)
+ me->regs[PKE_REG_R0 + i][0] = unpacked_data[i];
}
/* write new VU data word at address; reverse words if needed */