3378 lines
84 KiB
C
Executable File
3378 lines
84 KiB
C
Executable File
/*******************************************************************************
|
|
' Author: Dave Hein
|
|
' Version 0.21
|
|
' Copyright (c) 2010, 2011
|
|
' See end of file for terms of use.
|
|
'******************************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "interp.h"
|
|
#include "spinsim.h"
|
|
|
|
#define IGNORE_WZ_WC
|
|
#define PRINT_RAM_ACCESS
|
|
|
|
#define AUX_SIZE 256
|
|
#define AUX_MASK (AUX_SIZE - 1)
|
|
|
|
#define REG_INDA 0x1f2
|
|
#define REG_INDB 0x1f3
|
|
#define REG_PINA 0x1f4
|
|
#define REG_PINB 0x1f5
|
|
#define REG_PINC 0x1f6
|
|
#define REG_PIND 0x1f7
|
|
#define REG_OUTA 0x1f8
|
|
#define REG_OUTB 0x1f9
|
|
#define REG_OUTC 0x1fa
|
|
#define REG_OUTD 0x1fb
|
|
#define REG_DIRA 0x1fc
|
|
#define REG_DIRB 0x1fd
|
|
#define REG_DIRC 0x1fe
|
|
#define REG_DIRD 0x1ff
|
|
|
|
extern char *hubram;
|
|
extern int32_t memsize;
|
|
extern char lockstate[8];
|
|
extern char lockalloc[8];
|
|
extern PasmVarsT PasmVars[8];
|
|
extern int32_t pasmspin;
|
|
extern int32_t cycleaccurate;
|
|
extern int32_t loopcount;
|
|
extern int32_t proptwo;
|
|
extern int32_t pin_val;
|
|
|
|
extern FILE *tracefile;
|
|
|
|
char *GetOpname2(unsigned int, int *);
|
|
|
|
void NotImplemented(int instruction)
|
|
{
|
|
int dummy;
|
|
char *opname = GetOpname2(instruction, &dummy);
|
|
printf("\n%s not implemented - %8.8x\n", opname, instruction);
|
|
spinsim_exit(1);
|
|
}
|
|
|
|
static int32_t parity(int32_t val)
|
|
{
|
|
val ^= val >> 16;
|
|
val ^= val >> 8;
|
|
val ^= val >> 4;
|
|
val ^= val >> 2;
|
|
val ^= val >> 1;
|
|
return val & 1;
|
|
}
|
|
|
|
static int32_t _abs(int32_t val)
|
|
{
|
|
return val < 0 ? -val : val;
|
|
}
|
|
|
|
static int32_t seuss(int32_t value, int32_t forward)
|
|
{
|
|
uint32_t a, c, x, y;
|
|
|
|
x = value;
|
|
if (!x) x = 1;
|
|
y = 32;
|
|
a = 0x17;
|
|
if (!forward) a = (a >> 1) | (a << 31);
|
|
while (y--)
|
|
{
|
|
c = x & a;
|
|
while (c & 0xfffffffe) c = (c >> 1) ^ (c & 1);
|
|
if (forward)
|
|
x = (x >> 1) | (c << 31);
|
|
else
|
|
x = (x << 1) | c;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
uint32_t sqrt32(uint32_t y)
|
|
{
|
|
uint32_t x, t1;
|
|
|
|
x = 0;
|
|
t1 = 1 << 30;
|
|
while (t1)
|
|
{
|
|
x |= t1;
|
|
if (x <= y)
|
|
{
|
|
y -= x;
|
|
x += t1;
|
|
}
|
|
else
|
|
x -= t1;
|
|
x >>= 1;
|
|
t1 >>= 2;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
uint32_t sqrt64(uint64_t y)
|
|
{
|
|
uint64_t x, t1;
|
|
|
|
x = 0;
|
|
t1 = 1;
|
|
t1 <<= 60;
|
|
while (t1)
|
|
{
|
|
x |= t1;
|
|
if (x <= y)
|
|
{
|
|
y -= x;
|
|
x += t1;
|
|
}
|
|
else
|
|
x -= t1;
|
|
x >>= 1;
|
|
t1 >>= 2;
|
|
}
|
|
return (uint32_t)x;
|
|
}
|
|
|
|
int32_t CheckWaitPin(PasmVarsT *pasmvars, int32_t instruct, int32_t value1, int32_t value2)
|
|
{
|
|
int32_t match, pin_values;
|
|
int32_t portnum = (instruct >> 24) & 3;
|
|
|
|
if (portnum == 0)
|
|
pin_values = pin_val;
|
|
else
|
|
pin_values = 0xffffffff;
|
|
|
|
if (instruct & 0x04000000)
|
|
match = ((pin_values & value2) != value1); // waitpne
|
|
else
|
|
match = ((pin_values & value2) == value1); // waitpne
|
|
|
|
return match;
|
|
}
|
|
|
|
int wait1[128] = {
|
|
7, 3, 7, 3, 7, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
|
|
0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
|
|
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0,16,16,16,16, 1,10, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,13, 0};
|
|
|
|
int wait2[0x120] = {
|
|
6, 0, 6, 0, 0, 0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0,
|
|
12,12,12,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 1, 5, 5, 1, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0,11, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 14,14,14,14, 0, 0, 0, 0,
|
|
15,15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
static int32_t CheckWaitFlag2(PasmVarsT *pasmvars, int instruct, int value1, int value2)
|
|
{
|
|
int32_t hubcycles;
|
|
int32_t waitmode = 0;
|
|
int32_t srcaddr = instruct & 511;
|
|
int32_t waitflag = pasmvars->waitflag;
|
|
int32_t opcode = (instruct >> (32 - 7)) & 127;
|
|
int32_t hubop = 0;
|
|
|
|
if (waitflag)
|
|
{
|
|
waitflag--;
|
|
if ((instruct & 0xf8000000) == 0xc8000000)
|
|
{
|
|
if (CheckWaitPin(pasmvars, instruct, value1, value2))
|
|
waitflag = 0;
|
|
}
|
|
pasmvars->waitflag = waitflag;
|
|
if (waitflag == 0) pasmvars->waitmode = 0;
|
|
return waitflag;
|
|
}
|
|
|
|
if (opcode != 127)
|
|
waitflag = wait1[opcode];
|
|
else if (srcaddr < 0x120)
|
|
waitflag = wait2[srcaddr];
|
|
else
|
|
waitflag = 0;
|
|
|
|
// if (waitflag) printf("CheckWaitFlag2: %8.8x %d\n", instruct, waitflag);
|
|
|
|
hubcycles = (pasmvars->cogid - loopcount) & 7;
|
|
|
|
switch (waitflag)
|
|
{
|
|
case 0: // 1
|
|
break;
|
|
|
|
case 1: // 1 - 8
|
|
hubop = 1;
|
|
waitflag = hubcycles;
|
|
waitmode = WAIT_HUB;
|
|
break;
|
|
|
|
case 2: // 2
|
|
waitflag = 1;
|
|
waitmode = WAIT_MULT;
|
|
break;
|
|
|
|
case 3: // 1 or 3 - 10 rdxxxxc
|
|
//printf("\nvalue2 = %8.8x, dcachehubaddr = %8.8x\n", value2&0xffffffe0, pasmvars->dcachehubaddr);
|
|
if ((value2 & 0xfffffe0) == pasmvars->dcachehubaddr)
|
|
waitflag = 0;
|
|
else
|
|
{
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles + 2;
|
|
}
|
|
break;
|
|
|
|
case 4: // 1 or 1 - 8
|
|
if ((value2 & 0xfffffe0) == pasmvars->dcachehubaddr)
|
|
waitflag = 0;
|
|
else
|
|
{
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
}
|
|
break;
|
|
|
|
case 5: // 1 - 9 for lockset and lockclr
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
if (instruct & 0x00800000)
|
|
waitflag++;
|
|
break;
|
|
|
|
case 6: // 2 - 9
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles + 1;
|
|
break;
|
|
|
|
case 7: // 3 - 10 rdxxxx
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles + 2;
|
|
break;
|
|
|
|
case 8: // mac
|
|
waitflag = 0;
|
|
break;
|
|
|
|
case 9: // 1 - 9 for cognew or N for waitcnt
|
|
if (instruct & 0x01000000)
|
|
{
|
|
waitmode = WAIT_CNT;
|
|
waitflag = value1 - GetCnt();
|
|
}
|
|
else
|
|
{
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
if (instruct & 0x00800000)
|
|
waitflag++;
|
|
}
|
|
break;
|
|
|
|
case 10: // 1 - 8 for wrlong or 1 for frac
|
|
if (instruct & 0x01000000)
|
|
waitflag = 0;
|
|
else
|
|
{
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
}
|
|
break;
|
|
|
|
case 11: // N for wait
|
|
if (!value1)
|
|
waitflag = 0;
|
|
else
|
|
{
|
|
waitmode = WAIT_CNT;
|
|
waitflag = value1 - 1;
|
|
}
|
|
break;
|
|
|
|
case 12: // mulcount
|
|
waitmode = WAIT_MULT;
|
|
waitflag = pasmvars->mulcount;
|
|
break;
|
|
|
|
case 13: // 1 - 8 for callax, callbx
|
|
if ((instruct & 0x01800000) == 0x01000000)
|
|
{
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
}
|
|
else
|
|
waitflag = 0;
|
|
break;
|
|
|
|
case 14: // 1 - 8 for callax, callbx
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles;
|
|
break;
|
|
|
|
case 15: // 2 - 9 for retax, retbx
|
|
hubop = 1;
|
|
waitmode = WAIT_HUB;
|
|
waitflag = hubcycles + 1;
|
|
break;
|
|
|
|
case 16: // N for waitpxx
|
|
waitmode = WAIT_PIN;
|
|
waitflag = pasmvars->lastd - GetCnt();
|
|
break;
|
|
}
|
|
|
|
pasmvars->waitflag = waitflag;
|
|
pasmvars->waitmode = waitmode;
|
|
|
|
return hubop;
|
|
}
|
|
|
|
// Compute the hub RAM address from the pointer instruction - SUPIIIIII
|
|
int32_t GetPointer(PasmVarsT *pasmvars, int32_t ptrinst, int32_t size)
|
|
{
|
|
int32_t address = 0; // Set to zero to avoid compiler warning
|
|
int32_t offset = (ptrinst << 26) >> (26 - size);
|
|
|
|
switch ((ptrinst >> 6) & 7)
|
|
{
|
|
case 0: // ptra[offset]
|
|
address = (pasmvars->ptra + offset) & 0x3ffff;
|
|
break;
|
|
|
|
case 1: // ptra
|
|
address = pasmvars->ptra;
|
|
break;
|
|
|
|
case 2: // ptra[++offset]
|
|
address = (pasmvars->ptra + offset) & 0x3ffff;
|
|
//pasmvars->ptra = address;
|
|
pasmvars->ptra0 = address;
|
|
break;
|
|
|
|
case 3: // ptra[offset++]
|
|
address = pasmvars->ptra;
|
|
//pasmvars->ptra = (pasmvars->ptra + offset) & 0x3ffff;
|
|
pasmvars->ptra0 = (pasmvars->ptra + offset) & 0x3ffff;
|
|
break;
|
|
|
|
case 4: // ptrb[offset]
|
|
address = (pasmvars->ptrb + offset) & 0x3ffff;
|
|
break;
|
|
|
|
case 5: // ptrb
|
|
address = pasmvars->ptrb;
|
|
break;
|
|
|
|
case 6: // ptrb[++offset]
|
|
address = (pasmvars->ptrb + offset) & 0x3ffff;
|
|
//pasmvars->ptrb = address;
|
|
pasmvars->ptrb0 = address;
|
|
break;
|
|
|
|
case 7: // ptrb[offset++]
|
|
address = pasmvars->ptrb;
|
|
//pasmvars->ptrb = (pasmvars->ptrb + offset) & 0x3ffff;
|
|
pasmvars->ptrb0 = (pasmvars->ptrb + offset) & 0x3ffff;
|
|
break;
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
// Compute the aux RAM pointer from the pointer instruction - 1SUPIIIII
|
|
int32_t GetAuxPointer(PasmVarsT *pasmvars, int32_t ptrinst)
|
|
{
|
|
int32_t address = 0; // Set to zero to avoid compiler warning
|
|
int32_t offset = (ptrinst << 27) >> 27;
|
|
|
|
switch ((ptrinst >> 5) & 7)
|
|
{
|
|
case 0: // ptrx[offset]
|
|
address = (pasmvars->ptrx + offset) & 255;
|
|
break;
|
|
|
|
case 1: // ptrx
|
|
address = pasmvars->ptrx;
|
|
break;
|
|
|
|
case 2: // ptrx[++offset]
|
|
address = (pasmvars->ptrx + offset) & 255;
|
|
pasmvars->ptrx = address;
|
|
break;
|
|
|
|
case 3: // ptrx[offset++]
|
|
address = pasmvars->ptrx;
|
|
pasmvars->ptrx = (pasmvars->ptrx + offset) & 255;
|
|
break;
|
|
|
|
case 4: // ptry[offset]
|
|
address = (pasmvars->ptry + offset) & 255;
|
|
break;
|
|
|
|
case 5: // ptry
|
|
address = pasmvars->ptry;
|
|
break;
|
|
|
|
case 6: // ptry[++offset]
|
|
address = (pasmvars->ptry + offset) & 255;
|
|
pasmvars->ptry = address;
|
|
break;
|
|
|
|
case 7: // ptry[offset++]
|
|
address = pasmvars->ptry;
|
|
pasmvars->ptry = (pasmvars->ptry + offset) & 255;
|
|
break;
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
void UpdatePins2(void)
|
|
{
|
|
int32_t i;
|
|
int32_t mask1;
|
|
int32_t val = 0;
|
|
int32_t mask = 0;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (PasmVars[i].state)
|
|
{
|
|
mask1 = PasmVars[i].mem[REG_DIRA]; // dira
|
|
val |= mask1 & PasmVars[i].mem[REG_OUTA]; // outa
|
|
mask |= mask1;
|
|
}
|
|
}
|
|
pin_val = (~mask) | val;
|
|
//printf("UpdatePins2: %8.8x\n", pin_val);
|
|
}
|
|
|
|
void CheckIndRegs(PasmVarsT *pasmvars, int32_t instruct, int32_t sflag, int32_t dflag, int32_t *pdstaddr, int32_t *psrcaddr)
|
|
{
|
|
int32_t dstaddr = *pdstaddr;
|
|
int32_t srcaddr = *psrcaddr;
|
|
int32_t cond = (instruct >> 18) & 15;
|
|
int32_t opcode_zci = (instruct >> 22) & 0x3ff;
|
|
int32_t indirects = (!sflag && (srcaddr & 0x1fe) == 0x1f2);
|
|
int32_t indirectd = (!dflag && (dstaddr & 0x1fe) == 0x1f2);
|
|
int32_t pre_indexs = cond & 3;
|
|
int32_t pre_indexd = cond >> 2;
|
|
int32_t post_indexs = pre_indexs;
|
|
int32_t post_indexd = pre_indexd;
|
|
static int32_t postincrtab[4] = {0, 1, -1, 1};
|
|
int32_t incra = 0;
|
|
int32_t incrb = 0;
|
|
|
|
// Don't handle fixindx or setindx here
|
|
if (opcode_zci == 0x3f0) return;
|
|
|
|
// Return if neither source or destination is indirect
|
|
if (!indirects && !indirectd) return;
|
|
|
|
// Or post-increment indices if source and destination use same register
|
|
if (indirects && indirectd && srcaddr == dstaddr)
|
|
post_indexs = post_indexd = (pre_indexs | pre_indexd);
|
|
|
|
if (indirectd)
|
|
{
|
|
if (dstaddr == REG_INDA)
|
|
{
|
|
incra = postincrtab[post_indexd];
|
|
dstaddr = pasmvars->inda + (pre_indexd == 3);
|
|
if (dstaddr > pasmvars->indatop) dstaddr = pasmvars->indabot;
|
|
}
|
|
else
|
|
{
|
|
incrb = postincrtab[post_indexd];
|
|
dstaddr = pasmvars->indb + (pre_indexd == 3);
|
|
if (dstaddr > pasmvars->indbtop) dstaddr = pasmvars->indbbot;
|
|
}
|
|
}
|
|
|
|
if (indirects)
|
|
{
|
|
if (srcaddr == REG_INDA)
|
|
{
|
|
incra = postincrtab[post_indexd];
|
|
srcaddr = pasmvars->inda + (pre_indexd == 3);
|
|
if (srcaddr > pasmvars->indatop) srcaddr = pasmvars->indabot;
|
|
}
|
|
else
|
|
{
|
|
incrb = postincrtab[post_indexd];
|
|
srcaddr = pasmvars->indb + (pre_indexd == 3);
|
|
if (srcaddr > pasmvars->indbtop) srcaddr = pasmvars->indbbot;
|
|
}
|
|
}
|
|
|
|
if (incra == 1)
|
|
{
|
|
if (pasmvars->inda < pasmvars->indatop)
|
|
pasmvars->inda0 = pasmvars->inda + 1;
|
|
else
|
|
pasmvars->inda0 = pasmvars->indabot;
|
|
}
|
|
else if (incra == -1)
|
|
{
|
|
if (pasmvars->inda > pasmvars->indabot)
|
|
pasmvars->inda0 = pasmvars->inda - 1;
|
|
else
|
|
pasmvars->inda0 = pasmvars->indatop;
|
|
}
|
|
|
|
if (incrb == 1)
|
|
{
|
|
if (pasmvars->indb < pasmvars->indbtop)
|
|
pasmvars->indb0 = pasmvars->indb + 1;
|
|
else
|
|
pasmvars->indb0 = pasmvars->indbbot;
|
|
}
|
|
else if (incrb == -1)
|
|
{
|
|
if (pasmvars->indb > pasmvars->indbbot)
|
|
pasmvars->indb0 = pasmvars->indb - 1;
|
|
else
|
|
pasmvars->indb0 = pasmvars->indbtop;
|
|
}
|
|
|
|
// Update values of srcaddr and dstaddr
|
|
*psrcaddr = srcaddr;
|
|
*pdstaddr = dstaddr;
|
|
}
|
|
|
|
#if 0
|
|
void IncrementIndRegs(PasmVarsT *pasmvars)
|
|
{
|
|
pasmvars->inda += pasmvars->indaincr;
|
|
if (pasmvars->inda > pasmvars->indatop)
|
|
pasmvars->inda = pasmvars->indabot;
|
|
else if (pasmvars->inda < pasmvars->indabot)
|
|
pasmvars->inda = pasmvars->indatop;
|
|
|
|
pasmvars->indb += pasmvars->indbincr;
|
|
if (pasmvars->indb > pasmvars->indbtop)
|
|
pasmvars->indb = pasmvars->indbbot;
|
|
else if (pasmvars->indb < pasmvars->indbbot)
|
|
pasmvars->indb = pasmvars->indbtop;
|
|
}
|
|
#endif
|
|
|
|
void SaveRegisters(PasmVarsT *pasmvars)
|
|
{
|
|
pasmvars->inda0 = pasmvars->inda;
|
|
pasmvars->indb0 = pasmvars->indb;
|
|
pasmvars->ptra0 = pasmvars->ptra;
|
|
pasmvars->ptrb0 = pasmvars->ptrb;
|
|
}
|
|
|
|
void UpdateRegisters(PasmVarsT *pasmvars)
|
|
{
|
|
pasmvars->inda = pasmvars->inda0;
|
|
pasmvars->indb = pasmvars->indb0;
|
|
pasmvars->ptra = pasmvars->ptra0;
|
|
pasmvars->ptrb = pasmvars->ptrb0;
|
|
}
|
|
|
|
int32_t FetchHubInstruction(PasmVarsT *pasmvars, int32_t prefetch)
|
|
{
|
|
int32_t i, j, pc, lineaddr, maxnotused;
|
|
|
|
if (prefetch)
|
|
pc = (pasmvars->pc1 + 8) & 0xffff;
|
|
else
|
|
pc = pasmvars->pc & 0xffff;
|
|
lineaddr = (pc << 2) & 0x3ffe0;
|
|
|
|
// Check if already cached
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (lineaddr == pasmvars->icachehubaddr[i]) break;
|
|
}
|
|
|
|
// Update usage if not prefetch
|
|
if (!prefetch)
|
|
{
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
if (j == i)
|
|
pasmvars->icachenotused[j] = 0;
|
|
else
|
|
{
|
|
pasmvars->icachenotused[j]++;
|
|
if (pasmvars->icachenotused[j] > 255)
|
|
pasmvars->icachenotused[j] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return if cached
|
|
if (i < 4)
|
|
return pasmvars->icache[i][pc&7];
|
|
|
|
// Find the least used cache buffer
|
|
j = 0;
|
|
maxnotused = pasmvars->icachenotused[0];
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
if (pasmvars->icachenotused[i] > maxnotused)
|
|
{
|
|
j = i;
|
|
maxnotused = pasmvars->icachenotused[i];
|
|
}
|
|
}
|
|
|
|
// Fill selected cache buffer and return
|
|
#if 0
|
|
if (!prefetch)
|
|
printf("FetchHubInstruction: Fetch into cache %d, pc = %4.4x\n", j, pc);
|
|
else
|
|
printf("FetchHubInstruction: Prefetch into cache %d, pc = %4.4x\n", j, pc);
|
|
#endif
|
|
if (!prefetch)
|
|
{
|
|
pasmvars->waitmode = WAIT_CACHE;
|
|
pasmvars->waitflag = ((pasmvars->cogid - loopcount) & 7) + 2;
|
|
}
|
|
pasmvars->icache[j][0] = LONG(lineaddr);
|
|
pasmvars->icache[j][1] = LONG(lineaddr + 4);
|
|
pasmvars->icache[j][2] = LONG(lineaddr + 8);
|
|
pasmvars->icache[j][3] = LONG(lineaddr + 12);
|
|
pasmvars->icache[j][4] = LONG(lineaddr + 16);
|
|
pasmvars->icache[j][5] = LONG(lineaddr + 20);
|
|
pasmvars->icache[j][6] = LONG(lineaddr + 24);
|
|
pasmvars->icache[j][7] = LONG(lineaddr + 28);
|
|
pasmvars->icachehubaddr[j] = lineaddr;
|
|
pasmvars->icachenotused[j] = 0;
|
|
return pasmvars->icache[j][pc&7];
|
|
}
|
|
|
|
void CheckPrefetch(PasmVarsT *pasmvars)
|
|
{
|
|
if (!pasmvars->prefetch) return;
|
|
if (pasmvars->cogid != (loopcount & 7)) return;
|
|
if (pasmvars->waitmode & WAIT_HUB) return;
|
|
if (pasmvars->pc < 0x200) return;
|
|
FetchHubInstruction(pasmvars, 1);
|
|
}
|
|
|
|
int32_t ExecutePasmInstruction2(PasmVarsT *pasmvars)
|
|
{
|
|
int32_t cflag = pasmvars->cflag;
|
|
int32_t zflag = pasmvars->zflag;
|
|
int32_t instruct, pc, cond;
|
|
int32_t opcode, value2, value1, zci;
|
|
int32_t srcaddr, dstaddr;
|
|
int32_t result = 0;
|
|
int32_t temp, write_zcr, sflag, dflag, psflag, pdflag;
|
|
int32_t opcode_zci, indirect, rflag, aflag;
|
|
int32_t returnflag = 0;
|
|
int32_t breakflag = 0;
|
|
int32_t hubop = 0;
|
|
|
|
// Check if multiplier working
|
|
if (pasmvars->mulcount)
|
|
pasmvars->mulcount--;
|
|
|
|
// Check if we can skip further processing if not printing, not waiting
|
|
// for a pin state and wait flag is greater than 1.
|
|
if (pasmvars->waitflag > 1 && !pasmvars->printflag && pasmvars->waitmode != WAIT_PIN)
|
|
{
|
|
CheckPrefetch(pasmvars);
|
|
pasmvars->waitflag--;
|
|
return 0;
|
|
}
|
|
|
|
// Fetch a new instruction and update the pipeline
|
|
if (!pasmvars->waitflag)
|
|
{
|
|
// Update instruction pipeline and fetch new instruction
|
|
pasmvars->instruct4 = pasmvars->instruct3;
|
|
pasmvars->instruct3 = pasmvars->instruct2;
|
|
pasmvars->instruct2 = pasmvars->instruct1;
|
|
if ((pasmvars->pc & 0xfff8) == pasmvars->dcachecogaddr)
|
|
pasmvars->instruct1 = pasmvars->dcache[pasmvars->pc & 7];
|
|
else if (pasmvars->pc < 0x200)
|
|
pasmvars->instruct1 = pasmvars->mem[pasmvars->pc];
|
|
else if (pasmvars->pc)
|
|
pasmvars->instruct1 = FetchHubInstruction(pasmvars, 0);
|
|
// Update PC pipeline and increment PC
|
|
pasmvars->pc4 = pasmvars->pc3;
|
|
pasmvars->pc3 = pasmvars->pc2;
|
|
pasmvars->pc2 = pasmvars->pc1;
|
|
pasmvars->pc1 = pasmvars->pc;
|
|
if (pasmvars->repcnt && pasmvars->pc >= pasmvars->reptop)
|
|
{
|
|
if (!pasmvars->repforever) pasmvars->repcnt--;
|
|
pasmvars->pc = pasmvars->repbot;
|
|
}
|
|
else
|
|
pasmvars->pc = (pasmvars->pc + 1) & 0xffff;
|
|
// Check for REPS instruction in the second stage of the pipeline
|
|
if ((pasmvars->instruct2 & 0xffc00000) == 0xfac00000 && !(pasmvars->pc2 & INVALIDATE_INSTR))
|
|
{
|
|
pasmvars->repcnt = (pasmvars->instruct2 >> 6) & 0xffff;
|
|
pasmvars->repbot = pasmvars->pc;
|
|
pasmvars->reptop = (pasmvars->pc + (pasmvars->instruct2 & 63)) & 0xffff;
|
|
}
|
|
}
|
|
|
|
// Check for cache wait
|
|
if (pasmvars->waitflag && pasmvars->waitmode == WAIT_CACHE)
|
|
{
|
|
if (--pasmvars->waitflag == 0)
|
|
pasmvars->waitmode = 0;
|
|
else
|
|
{
|
|
if (pasmvars->printflag) DebugPasmInstruction2(pasmvars);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Get the instruction and pc at the end of the pipeline
|
|
instruct = pasmvars->instruct4;
|
|
pc = pasmvars->pc4;
|
|
|
|
// Return if instruction has been invalidated and not printing
|
|
if (pc & INVALIDATE_INSTR)
|
|
{
|
|
if (!pasmvars->printflag)
|
|
{
|
|
CheckPrefetch(pasmvars);
|
|
#if 0
|
|
if (pasmvars->waitflag)
|
|
{
|
|
pasmvars->waitflag--;
|
|
if (!pasmvars->waitflag) pasmvars->waitmode = 0;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
returnflag = 1;
|
|
}
|
|
|
|
// Extract bit fields from the instruction
|
|
opcode = (instruct >> 25) & 127;
|
|
zci = (instruct >> 22) & 7;
|
|
cond = (instruct >> 18) & 15;
|
|
dstaddr = (instruct >> 9) & 511;
|
|
srcaddr = instruct & 511;
|
|
opcode_zci = (opcode << 3) | zci;
|
|
|
|
// Decode the immediate flags for the source and destination fields
|
|
sflag = (opcode_zci >= 0x3ea) | (zci & 1);
|
|
|
|
dflag = (opcode >= 0x68 && opcode <= 0x7a && (zci & 2)) |
|
|
((opcode_zci & 0x3e2) == 0x302 && opcode_zci < 0x31e) |
|
|
(opcode != 0x7f && opcode_zci >= 0x3eb) |
|
|
(opcode == 0x7f && srcaddr >= 0x40 && srcaddr <= 0xdc && (zci & 1)) |
|
|
(opcode == 0x7f && srcaddr >= 0x100);
|
|
|
|
// Determine if indirect registers are used
|
|
indirect = (!sflag && (srcaddr & 0x1fe) == 0x1f2) |
|
|
(!dflag && (dstaddr & 0x1fe) == 0x1f2) |
|
|
(opcode_zci == 0x3f0);
|
|
|
|
// Determine if ptra or ptrb are referenced
|
|
psflag = ((opcode < 6) | (opcode_zci >= 0x340 && opcode_zci <= 0x34b)) & sflag;
|
|
pdflag = (opcode == 0x7f && srcaddr >= 0x085 && srcaddr <= 0x087 && dflag);
|
|
|
|
// Determine if instruction uses relative address
|
|
rflag = (((opcode >= 0x54 && opcode <= 0x57) |
|
|
(opcode >= 0x76 && opcode <= 0x77) |
|
|
(opcode_zci >= 0x3d8 && opcode_zci <= 0x3e8)) & sflag) |
|
|
(opcode_zci == 0x3ea);
|
|
|
|
// Determine if instruction is AUGS or AUGD
|
|
aflag = (opcode_zci >= 0x3ec && opcode_zci <= 0x3ef);
|
|
|
|
// Save ptra, ptrb, inda and indb
|
|
SaveRegisters(pasmvars);
|
|
|
|
// Handle the indirect registers
|
|
if (indirect) CheckIndRegs(pasmvars, instruct, sflag, dflag, &dstaddr, &srcaddr);
|
|
|
|
// else return if condition code is not met and
|
|
// not using indirect registers and not augx instruction
|
|
else if (!((cond >> ((cflag << 1) | zflag)) & 1) && !aflag)
|
|
{
|
|
if (!pasmvars->printflag)
|
|
{
|
|
CheckPrefetch(pasmvars);
|
|
#if 0
|
|
if (pasmvars->waitflag)
|
|
{
|
|
pasmvars->waitflag--;
|
|
if (!pasmvars->waitflag) pasmvars->waitmode = 0;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
returnflag = 1;
|
|
}
|
|
|
|
// Set the flag that controls writing the result, zero flag and carry flag
|
|
write_zcr = zci | 1; // Assume writing result
|
|
|
|
// Get value1 from the destination field
|
|
if (pdflag)
|
|
value1 = GetPointer(pasmvars, dstaddr, 5);
|
|
else if (dflag)
|
|
{
|
|
if (pasmvars->augdflag)
|
|
value1 = (pasmvars->augdvalue << 9) | dstaddr;
|
|
else
|
|
value1 = dstaddr;
|
|
}
|
|
else if ((dstaddr & 0x1f8) == pasmvars->dcachecogaddr)
|
|
value1 = pasmvars->dcache[dstaddr & 7];
|
|
else
|
|
value1 = pasmvars->mem[dstaddr];
|
|
|
|
// Get value2 from the source field
|
|
if (psflag)
|
|
{
|
|
if (opcode < 6)
|
|
value2 = GetPointer(pasmvars, srcaddr, opcode >> 1);
|
|
else
|
|
value2 = GetPointer(pasmvars, srcaddr, (opcode_zci >> 2) & 3);
|
|
}
|
|
else if (sflag)
|
|
{
|
|
if (pasmvars->augsflag)
|
|
value2 = (pasmvars->augsvalue << 9) | srcaddr;
|
|
else if (rflag)
|
|
value2 = (srcaddr << 23) >> 23;
|
|
else
|
|
value2 = srcaddr;
|
|
}
|
|
else if (srcaddr == REG_PINA)
|
|
value2 = pin_val;
|
|
else if ((srcaddr & 0x1f8) == pasmvars->dcachecogaddr)
|
|
value2 = pasmvars->dcache[srcaddr & 7];
|
|
else
|
|
value2 = pasmvars->mem[srcaddr];
|
|
|
|
// Check sflag and dflag and reset augsflag and augdflag if needed
|
|
if (sflag) pasmvars->augsflag = 0;
|
|
if (dflag) pasmvars->augdflag = 0;
|
|
|
|
// Check the wait flag if the return flag is not set
|
|
if (returnflag)
|
|
{
|
|
if (pasmvars->waitflag)
|
|
{
|
|
pasmvars->waitflag--;
|
|
if (!pasmvars->waitflag) pasmvars->waitmode = 0;
|
|
}
|
|
}
|
|
else
|
|
hubop = CheckWaitFlag2(pasmvars, instruct, value1, value2);
|
|
|
|
if (!hubop)
|
|
CheckPrefetch(pasmvars);
|
|
|
|
// Print instruction if printflag set
|
|
if (pasmvars->printflag) DebugPasmInstruction2(pasmvars);
|
|
|
|
// Return if returnflag or waitflag is set
|
|
if (returnflag || pasmvars->waitflag) return 0;
|
|
|
|
// Check for breakpoint
|
|
if (pc == pasmvars->breakpnt)
|
|
{
|
|
if (!pasmvars->printflag) pasmvars->printflag = 15;
|
|
DebugPasmInstruction2(pasmvars);
|
|
breakflag = 1;
|
|
}
|
|
|
|
// Update ptra, ptrb, inda and indb
|
|
UpdateRegisters(pasmvars);
|
|
|
|
// Decode the opcode and execute the instruction
|
|
// Set the variables result, zflag and cflag.
|
|
// Clear bits within write_zcr to prevent writing variables.
|
|
switch(opcode >> 3) // Decode the four most significant bits
|
|
{
|
|
case 0: // rdxxxx, rdxxxc, rdaux, rdauxr
|
|
if (opcode < 6)
|
|
{
|
|
#if 0
|
|
// Check if using a ptr register
|
|
if (sflag) value2 = GetPointer(pasmvars, srcaddr, opcode >> 1);
|
|
|
|
#endif
|
|
if (opcode & 1) // cache read
|
|
{
|
|
int32_t hubaddr = value2 & 0xffffffe0;
|
|
if (hubaddr != pasmvars->dcachehubaddr)
|
|
{
|
|
pasmvars->dcache[0] = LONG(hubaddr);
|
|
pasmvars->dcache[1] = LONG(hubaddr+4);
|
|
pasmvars->dcache[2] = LONG(hubaddr+8);
|
|
pasmvars->dcache[3] = LONG(hubaddr+12);
|
|
pasmvars->dcache[4] = LONG(hubaddr+16);
|
|
pasmvars->dcache[5] = LONG(hubaddr+20);
|
|
pasmvars->dcache[6] = LONG(hubaddr+24);
|
|
pasmvars->dcache[7] = LONG(hubaddr+28);
|
|
pasmvars->dcachehubaddr = hubaddr;
|
|
}
|
|
}
|
|
}
|
|
switch(opcode)
|
|
{
|
|
uint8_t *bptr;
|
|
uint16_t *wptr;
|
|
|
|
case 0: // rdbyte
|
|
result = BYTE(value2);
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdb[%x]", value2);
|
|
break;
|
|
|
|
case 1: // rdbytec
|
|
bptr = (uint8_t *)pasmvars->dcache;
|
|
result = bptr[value2 & 31];
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdb[%x]", value2);
|
|
break;
|
|
|
|
case 2: // rdword
|
|
result = WORD(value2);
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdw[%x]", value2);
|
|
break;
|
|
|
|
case 3: // rdwordc
|
|
wptr = (uint16_t *)pasmvars->dcache;
|
|
result = wptr[(value2 >> 1) & 15];
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdw[%x]", value2);
|
|
break;
|
|
|
|
case 4: // rdlong
|
|
result = LONG(value2);
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdl[%x]", value2);
|
|
break;
|
|
|
|
case 5: // rdlongc
|
|
result = pasmvars->dcache[(value2 >> 2) & 7];
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", rdl[%x]", value2);
|
|
break;
|
|
|
|
case 6: // rdaux
|
|
case 7: // rdauxr
|
|
if ((zci & 1) && (srcaddr & 0x100))
|
|
temp = GetAuxPointer(pasmvars, srcaddr);
|
|
else
|
|
temp = value2 & 0xff;
|
|
if (opcode & 1)
|
|
temp ^= 0xff;
|
|
result = pasmvars->auxram[temp];
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 1: // isob, notb, clrb, setbxx
|
|
value2 = (value2 & 0x1f);
|
|
cflag = (value1 >> value2) & 1;
|
|
switch ((value2 >> 5) & 7)
|
|
{
|
|
case 0: // isob
|
|
result = (value1 >> value2) & 1;
|
|
break;
|
|
|
|
case 1: // notb
|
|
result = value1 ^ (1 << value2);
|
|
break;
|
|
|
|
case 2: // clrb
|
|
result = value1 & (~(1 << value2));
|
|
break;
|
|
|
|
case 3: // setb
|
|
result = value1 | (1 << value2);
|
|
break;
|
|
|
|
case 4: // setbc
|
|
result = value1 & (~(1 << value2));
|
|
result |= cflag << value2;
|
|
break;
|
|
|
|
case 5: // setbnc
|
|
result = value1 & (~(1 << value2));
|
|
result |= (cflag ^ 1) << value2;
|
|
break;
|
|
|
|
case 6: // setbz
|
|
result = value1 & (~(1 << value2));
|
|
result |= zflag << value2;
|
|
break;
|
|
|
|
case 7: // setbnz
|
|
result = value1 & (~(1 << value2));
|
|
result |= (zflag ^ 1) << value2;
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 2: // andn, and, or, xor, muxxx
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // andn
|
|
result = value1 & (~value2);
|
|
break;
|
|
|
|
case 1: // and
|
|
result = value1 & value2;
|
|
break;
|
|
|
|
case 2: // or
|
|
result = value1 | value2;
|
|
break;
|
|
|
|
case 3: // xor
|
|
result = value1 ^ value2;
|
|
break;
|
|
|
|
case 4: // muxc
|
|
result = (value1 & (~value2)) | (value2 & (-cflag));
|
|
break;
|
|
|
|
case 5: // muxnc
|
|
result = (value1 & (~value2)) | (value2 & (~(-cflag)));
|
|
break;
|
|
|
|
case 6: // muxz
|
|
result = (value1 & (~value2)) | (value2 & (-zflag));
|
|
break;
|
|
|
|
case 7: // muxnz
|
|
result = (value1 & (~value2)) | (value2 & (~(-zflag)));
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
cflag = parity(result);
|
|
break;
|
|
|
|
case 3: // rotate and shift
|
|
value2 &= 0x1f; // Get five LSB's
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // ror
|
|
result = (((uint32_t)value1) >> value2) | (value1 << (32 - value2));
|
|
cflag = value1 & 1;
|
|
break;
|
|
|
|
case 1: // rol
|
|
result = (((uint32_t)value1) >> (32 - value2)) | (value1 << value2);
|
|
cflag = (value1 >> 31) & 1;
|
|
break;
|
|
|
|
case 2: // shr
|
|
result = (((uint32_t)value1) >> value2);
|
|
cflag = value1 & 1;
|
|
break;
|
|
|
|
case 3: // shl
|
|
result = (value1 << value2);
|
|
cflag = (value1 >> 31) & 1;
|
|
break;
|
|
|
|
case 4: // rcr
|
|
if (value2)
|
|
{
|
|
result = (cflag << 31) | (((uint32_t)value1) >> 1);
|
|
result >>= (value2 - 1);
|
|
}
|
|
else
|
|
result = value1;
|
|
cflag = value1 & 1;
|
|
break;
|
|
|
|
case 5: // rcl
|
|
result = cflag ? (1 << value2) - 1 : 0;
|
|
result |= (value1 << value2);
|
|
cflag = (value1 >> 31) & 1;
|
|
break;
|
|
|
|
case 6: // sar
|
|
result = value1 >> value2;
|
|
cflag = value1 & 1;
|
|
break;
|
|
|
|
case 7: // rev
|
|
cflag = value1 & 1;
|
|
value2 = 32 - value2;
|
|
result = 0;
|
|
while (value2-- > 0)
|
|
{
|
|
result = (result << 1) | (value1 & 1);
|
|
value1 >>= 1;
|
|
}
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 4: // mov, not abs, negxx
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // mov
|
|
result = value2;
|
|
cflag = (value2 >> 31) & 1;
|
|
break;
|
|
|
|
case 1: // not
|
|
cflag = value2 < 0;
|
|
result = ~value2;
|
|
break;
|
|
|
|
case 2: // abs
|
|
cflag = (value2 >> 31) & 1;
|
|
result = _abs(value2);
|
|
break;
|
|
|
|
case 3: // neg
|
|
cflag = (value2 >> 31) & 1;
|
|
result = -value2;
|
|
break;
|
|
|
|
case 4: // negc
|
|
result = cflag ? -value2 : value2;
|
|
cflag = (value2 >> 31) & 1;
|
|
break;
|
|
|
|
case 5: // negnc
|
|
result = cflag ? value2 : -value2;
|
|
cflag = (value2 >> 31) & 1;
|
|
break;
|
|
|
|
case 6: // negz
|
|
result = zflag ? -value2 : value2;
|
|
cflag = (value2 >> 31) & 1;
|
|
break;
|
|
|
|
case 7: // negnz
|
|
result = zflag ? value2 : -value2;
|
|
cflag = (value2 >> 31) & 1;
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 5: // addxx, subxx
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // add
|
|
result = value1 + value2;
|
|
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
|
|
break;
|
|
|
|
case 1: // sub
|
|
result = value1 - value2;
|
|
cflag = ((uint32_t)value1) < ((uint32_t)value2);
|
|
break;
|
|
|
|
case 2: // addx
|
|
result = value1 + value2 + cflag;
|
|
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
|
|
case 3: // subx
|
|
result = value1 - value2 - cflag;
|
|
if (value2 != 0xffffffff || !cflag)
|
|
cflag = ((uint32_t)value1) < ((uint32_t)(value2 + cflag));
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
|
|
case 4: // adds
|
|
result = value1 + value2;
|
|
cflag = (((~(value1 ^ value2)) & (value1 ^ result)) >> 31) & 1;
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 5: // subs
|
|
result = value1 - value2;
|
|
zflag = (result == 0);
|
|
cflag = (((value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
break;
|
|
|
|
case 6: // addsx
|
|
result = value1 + value2 + cflag;
|
|
cflag = (((~(value1 ^ value2)) & (value1 ^ result)) >> 31) & 1;
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
|
|
case 7: // subsx
|
|
result = value1 - value2 - cflag;
|
|
cflag = (((value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
|
|
case 6: // sumxx, min, max, mins, maxs
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // sumc
|
|
result = cflag ? value1 - value2 : value1 + value2;
|
|
cflag = (~cflag) << 31;
|
|
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
break;
|
|
|
|
case 1: // sumnc
|
|
result = cflag ? value1 + value2 : value1 - value2;
|
|
cflag = cflag << 31;
|
|
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
break;
|
|
|
|
case 2: // sumz
|
|
result = zflag ? value1 - value2 : value1 + value2;
|
|
cflag = (~zflag) << 31;
|
|
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
break;
|
|
|
|
case 3: // sumnz
|
|
result = zflag ? value1 + value2 : value1 - value2;
|
|
cflag = zflag << 31;
|
|
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
break;
|
|
|
|
case 4: // min
|
|
cflag = (((uint32_t)value1) < ((uint32_t)value2));
|
|
zflag = (value2 == 0);
|
|
result = cflag ? value2 : value1;
|
|
break;
|
|
|
|
case 5: // max
|
|
cflag = (((uint32_t)value1) < ((uint32_t)value2));
|
|
zflag = (value2 == 0);
|
|
result = cflag ? value1 : value2;
|
|
break;
|
|
|
|
case 6: // mins
|
|
cflag = (value1 < value2);
|
|
zflag = (value2 == 0);
|
|
result = cflag ? value2 : value1;
|
|
break;
|
|
|
|
case 7: // maxs
|
|
cflag = (value1 < value2);
|
|
zflag = (value2 == 0);
|
|
result = cflag ? value1 : value2;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 7: // addabs, subabs, incmod, decmod, cmpsub, subr, mul, scl
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // addabs
|
|
cflag = (value2 >> 31) & 1;
|
|
value2 = _abs(value2);
|
|
result = value1 + value2;
|
|
cflag ^= (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
|
|
break;
|
|
|
|
case 1: // subabs
|
|
result = _abs(value2);
|
|
cflag = ((value2 >> 31) & 1) ^
|
|
(((uint32_t)value1) < ((uint32_t)result));
|
|
result = value1 - result;
|
|
break;
|
|
|
|
case 2: // incmod
|
|
cflag = (value1 == value2);
|
|
if (cflag)
|
|
result = 0;
|
|
else
|
|
result = value1 + 1;
|
|
break;
|
|
|
|
case 3: // decmod
|
|
cflag = (value1 == 0);
|
|
if (cflag)
|
|
result = value2;
|
|
else
|
|
result = value1 - 1;
|
|
break;
|
|
|
|
case 4: // cmpsub
|
|
cflag = (((uint32_t)value1) >= ((uint32_t)value2));
|
|
result = cflag ? value1 - value2 : value1;
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 5: // subr
|
|
result = value2 - value1;
|
|
cflag = ((uint32_t)value2) < ((uint32_t)value1);
|
|
break;
|
|
|
|
case 6: // mul
|
|
value1 = (value1 << 12) >> 12;
|
|
value2 = (value2 << 12) >> 12;
|
|
result = value1 * value2;
|
|
break;
|
|
|
|
case 7: // scl
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 8: // decodex, encod, blmask, onecnt, zercnt, incpar, decpar, splitx, mergex
|
|
switch(opcode&7)
|
|
{
|
|
case 0: // decod2
|
|
result = 1 << (value1 & 3);
|
|
result |= result << 4;
|
|
result |= result << 8;
|
|
result |= result << 16;
|
|
break;
|
|
|
|
case 1: // decod3
|
|
result = 1 << (value1 & 7);
|
|
result |= result << 8;
|
|
result |= result << 16;
|
|
break;
|
|
|
|
case 2: // decod4
|
|
result = 1 << (value1 & 0xf);
|
|
result |= result << 16;
|
|
break;
|
|
|
|
case 3: // decod5
|
|
result = 1 << (value1 & 0x1f);
|
|
break;
|
|
|
|
case 4: // encod, blmask
|
|
if (!(zci & 2)) // encod
|
|
{
|
|
for (result = 32; result > 0; result--)
|
|
{
|
|
if (value2 & 0x80000000) break;
|
|
value2 <<= 1;
|
|
}
|
|
}
|
|
else // blmask
|
|
{
|
|
value1 = (value1 & 0x1f) + 1;
|
|
if (value1 == 32)
|
|
result = 0xffffffff;
|
|
else
|
|
result = (1 << value1) - 1;
|
|
}
|
|
break;
|
|
|
|
case 5: // onecnt, zercnt
|
|
if (!(zci & 2)) // onecnt
|
|
{
|
|
for (result = 0; value1; value1 <<= 1)
|
|
{
|
|
if (value1 & 0x80000000) result++;
|
|
}
|
|
}
|
|
else // zercnt
|
|
{
|
|
for (result = 32; value1; value1 <<= 1)
|
|
{
|
|
if (value1 & 0x80000000) result--;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6: // incpat, decpat
|
|
if (!(zci & 4)) // incpat
|
|
{
|
|
NotImplemented(instruct);
|
|
}
|
|
else // decpat
|
|
{
|
|
NotImplemented(instruct);
|
|
}
|
|
break;
|
|
|
|
case 7: //splitb, mergeb, splitw, mergew
|
|
switch (zci >> 1)
|
|
{
|
|
int i;
|
|
case 0: // splitb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 1: // mergeb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 2: // splitw
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
result = (result << 1) |
|
|
((value1 >> 15)&0x10000) | ((value1 >> 30)&1);
|
|
value1 <<= 1;
|
|
}
|
|
break;
|
|
|
|
case 3: // mergew
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
result = (result << 2) |
|
|
((value1 >> 30) & 2) | ((value1 >> 15) & 1);
|
|
value1 <<= 1;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case 9: // getnib, setbin, getword, setword, setwrds, rolnib, ...
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // getnib, setnib
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
temp = (instruct >> 22) & 0x1c;
|
|
if (!(zci&2)) // getnib
|
|
{
|
|
result = (value1 >> temp) & 15;
|
|
}
|
|
else // setnib
|
|
{
|
|
result = (value2 & 15) << temp;
|
|
temp = ~(15 << temp);
|
|
result |= (value1 & temp);
|
|
}
|
|
break;
|
|
|
|
case 4: // getword, setword
|
|
temp = (instruct >> 20) & 16;
|
|
if (!(zci&2)) // getword
|
|
{
|
|
result = (value1 >> temp) & 0xffff;
|
|
}
|
|
else // setword
|
|
{
|
|
result = (value2 & 0xffff) << temp;
|
|
temp = ~(0xffff << temp);
|
|
result |= (value1 & temp);
|
|
}
|
|
break;
|
|
|
|
case 5: // setwrds, rolnib, rolbyte, rolword
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 6: // sets, setd, setx, seti
|
|
switch (zci >> 1)
|
|
{
|
|
case 0: // sets
|
|
result = (value1 & 0xfffffe00) | (value2 &0x1ff);
|
|
break;
|
|
|
|
case 1: // setd
|
|
result = (value1 & 0xfffc01ff) | ((value2 &0x1ff) << 9);
|
|
break;
|
|
|
|
case 2: // setx
|
|
result = (value1 & 0xff83ffff) | ((value2 &0x1f) << 18);
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 3: // seti
|
|
result = (value1 & 0x007fffff) | ((value2 &0x1ff) << 23);
|
|
break;
|
|
}
|
|
write_zcr &= 1;
|
|
break;
|
|
|
|
case 7:
|
|
write_zcr &= 3;
|
|
if (!(zci & 4)) // cognew
|
|
{
|
|
// Look for next available cog
|
|
for (result = 0; result < 8; result++)
|
|
{
|
|
if (!PasmVars[result].state) break;
|
|
}
|
|
if (result == 8) // None available
|
|
{
|
|
cflag = 1;
|
|
result = 7;
|
|
}
|
|
else // Start cog
|
|
{
|
|
cflag = 0;
|
|
StartPasmCog2(&PasmVars[result], (value2 & 0x3ffff), (value1 & 0x3fffc), result);
|
|
}
|
|
}
|
|
else // waitcnt
|
|
{
|
|
if (value1 != GetCnt())
|
|
{
|
|
printf("ERROR: waitcnt value1 = %8.8x, cnt = %8.8x\n", value1, GetCnt());
|
|
spinsim_exit(1);
|
|
}
|
|
result = value1 + value2;
|
|
zflag = (result == 0);
|
|
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 10: // getbyte, setbyte, movbyts, xxxxrgb, xxxpix, jmpxx, xjxx
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // getbyte, setbyte
|
|
case 1:
|
|
temp = (instruct >> 21) & 0x18;
|
|
if (!(zci&2)) // getbyte
|
|
{
|
|
result = (value1 >> temp) & 255;
|
|
}
|
|
else // setbyte
|
|
{
|
|
result = (value2 & 255) << temp;
|
|
temp = ~(255 << temp);
|
|
result |= (value1 & temp);
|
|
}
|
|
break;
|
|
|
|
case 2: // setbyts, movbyts, packrgb, unpkrgb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 3: // addpix, mulpix, blnpix, mixpix
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 4: // jmpsw
|
|
case 5: // jmpswd
|
|
if (zci&1)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
pc += 4;
|
|
result = pc;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 6: // ijz, ijzd, ijnz, ijnzd
|
|
result = value1 + 1;
|
|
zflag = (result == 0);
|
|
cflag = (result == 0);
|
|
// Determine if we should jump
|
|
if (zflag != (zci >> 2))
|
|
{
|
|
if (instruct & 0x00400000)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed jump
|
|
if (!(zci & 2))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
}
|
|
write_zcr &= 1;
|
|
break;
|
|
|
|
case 7: // djz, djzd, djnz, djnzd
|
|
result = value1 - 1;
|
|
zflag = (result == 0);
|
|
cflag = (result == -1);
|
|
// Determine if we should jump
|
|
if (zflag != (zci >> 2))
|
|
{
|
|
if (instruct & 0x00400000)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed jump
|
|
if (!(zci & 2))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
}
|
|
write_zcr &= 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 11: // testxx, cmpxx
|
|
write_zcr &= 6;
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // testb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 1: // testn
|
|
result = value1 & (~value2);
|
|
zflag = (result == 0);
|
|
cflag = parity(result);
|
|
break;
|
|
|
|
case 2: // test
|
|
result = value1 & value2;
|
|
zflag = (result == 0);
|
|
cflag = parity(result);
|
|
break;
|
|
|
|
case 3: // cmp
|
|
//printf("\ncmp $%x $%x\n", value1, value2);
|
|
result = value1 - value2;
|
|
zflag = (result == 0);
|
|
cflag = ((uint32_t)value1) < ((uint32_t)value2);
|
|
break;
|
|
|
|
case 4: // cmpx
|
|
result = value1 - value2 - cflag;
|
|
if (value2 != 0xffffffff || !cflag)
|
|
cflag = ((uint32_t)value1) < ((uint32_t)(value2 + cflag));
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
|
|
case 5: // cmps
|
|
//printf("\ncmps $%x $%x\n", value1, value2);
|
|
result = value1 - value2;
|
|
zflag = (result == 0);
|
|
cflag = value1 < value2;
|
|
break;
|
|
|
|
case 6: // cmpsx
|
|
result = value1 - value2 - cflag;
|
|
cflag = (((value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
|
|
zflag = (result == 0) & zflag;
|
|
break;
|
|
|
|
case 7: // cmpr
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 12: // coginit, waitvid, waitpeq, waitpne
|
|
switch (opcode & 7)
|
|
{
|
|
case 0: // coginit, waitvid
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
if (!(zci&2)) // coginit
|
|
{
|
|
result = (instruct >> 24) & 7;
|
|
//printf("\ncoginit: cog = %d, value1 = %8.8x, dflag = %d\n", result, value1, dflag);
|
|
StartPasmCog2(&PasmVars[result], (value2 & 0x3ffff), (value1 & 0x3fffc), result);
|
|
UpdatePins2();
|
|
// Return without saving if we restarted this cog
|
|
if (result == pasmvars->cogid) return breakflag;
|
|
}
|
|
else // waitvid
|
|
{
|
|
NotImplemented(instruct);
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 4: // waitpeq
|
|
case 5:
|
|
case 6: // waitpne
|
|
case 7:
|
|
write_zcr &= 2;
|
|
cflag = !CheckWaitPin(pasmvars, instruct, value1, value2);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 13: // wrxxx, frac, setaccx, macx, mul32x, div32x, div64x
|
|
temp = ((opcode & 7) << 1) | (zci >> 2);
|
|
|
|
#if 0
|
|
if (temp <= 2)
|
|
{
|
|
// Check if using a ptr register
|
|
if (sflag) value2 = GetPointer(pasmvars, srcaddr, temp & 3);
|
|
}
|
|
|
|
#endif
|
|
switch (temp)
|
|
{
|
|
case 0: // wrbyte
|
|
BYTE(value2) = value1;
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", wrb[%x] = %x", value2, value1);
|
|
break;
|
|
|
|
case 1: // wrword
|
|
WORD(value2) = value1;
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", wrw[%x] = %x", value2, value1);
|
|
break;
|
|
|
|
case 2: // wrlong
|
|
LONG(value2) = value1;
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", wrl[%x] = %x", value2, value1);
|
|
break;
|
|
|
|
case 3: // frac
|
|
if (value2)
|
|
{
|
|
pasmvars->divq = ((uint64_t)value1 << 32) / (uint64_t)value2;
|
|
pasmvars->divr = ((uint64_t)value1 << 32) % (uint64_t)value2;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->divq = 0;
|
|
pasmvars->divr = 0;
|
|
}
|
|
break;
|
|
|
|
case 4: // wraux
|
|
case 5: // wrauxr
|
|
if ((zci & 1) && (srcaddr & 0x100))
|
|
temp = GetAuxPointer(pasmvars, srcaddr);
|
|
else
|
|
temp = value2 & 0xff;
|
|
if (opcode & 1)
|
|
temp ^= 0xff;
|
|
pasmvars->auxram[temp] = value1;
|
|
break;
|
|
|
|
case 6: // setacca
|
|
pasmvars->acca = (((int64_t)value1) << 32) | (uint64_t)value2;
|
|
break;
|
|
|
|
case 7: // setaccb
|
|
pasmvars->accb = (((int64_t)value1) << 32) | (uint64_t)value2;
|
|
break;
|
|
|
|
case 8: // maca
|
|
value1 = (value1 << 12) >> 12;
|
|
value2 = (value2 << 12) >> 12;
|
|
pasmvars->acca += (int64_t)value1 * (int64_t)value2;
|
|
break;
|
|
|
|
case 9: // macb
|
|
value1 = (value1 << 12) >> 12;
|
|
value2 = (value2 << 12) >> 12;
|
|
pasmvars->accb += (int64_t)value1 * (int64_t)value2;
|
|
break;
|
|
|
|
case 10: // mul32
|
|
pasmvars->mulcount = 17;
|
|
pasmvars->mul = (int64_t)value1 * (int64_t)value2;
|
|
break;
|
|
|
|
case 11: // mul32u
|
|
pasmvars->mulcount = 17;
|
|
pasmvars->mul = (uint64_t)value1 * (uint64_t)value2;
|
|
break;
|
|
|
|
case 12: // div32
|
|
pasmvars->mulcount = 17;
|
|
if (value2)
|
|
{
|
|
pasmvars->divq = value1 / value2;
|
|
pasmvars->divr = value1 % value2;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->divq = 0;
|
|
pasmvars->divr = 0;
|
|
}
|
|
break;
|
|
|
|
case 13: // div32u
|
|
pasmvars->mulcount = 17;
|
|
if (value2)
|
|
{
|
|
pasmvars->divq = (uint32_t)value1 / (uint32_t)value2;
|
|
pasmvars->divr = (uint32_t)value1 % (uint32_t)value2;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->divq = 0;
|
|
pasmvars->divr = 0;
|
|
}
|
|
break;
|
|
|
|
case 14: // div64
|
|
pasmvars->mulcount = 17;
|
|
if (pasmvars->divisor)
|
|
{
|
|
pasmvars->divq = ((((int64_t)value1) << 32) | (uint64_t)value2) / (int64_t)pasmvars->divisor;
|
|
pasmvars->divr = ((((int64_t)value1) << 32) | (uint64_t)value2) % (int64_t)pasmvars->divisor;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->divq = 0;
|
|
pasmvars->divr = 0;
|
|
}
|
|
break;
|
|
|
|
case 15: // div64u
|
|
pasmvars->mulcount = 17;
|
|
if (pasmvars->divisor)
|
|
{
|
|
pasmvars->divq = ((((uint64_t)value1) << 32) | (uint64_t)value2) / (uint64_t)pasmvars->divisor;
|
|
pasmvars->divr = ((((uint64_t)value1) << 32) | (uint64_t)value2) % (uint64_t)pasmvars->divisor;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->divq = 0;
|
|
pasmvars->divr = 0;
|
|
}
|
|
break;
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 14: // sqrt64, qsincos, qarctan, qrotate, setserx, setctrs, ...
|
|
temp = ((opcode & 7) << 1) | (zci >> 2);
|
|
switch (temp)
|
|
{
|
|
case 0: // sqrt64
|
|
write_zcr = 0;
|
|
pasmvars->mulcount = 32;
|
|
pasmvars->sqrt = sqrt64(((uint64_t)value1<<32) | (uint32_t)value2);
|
|
break;
|
|
|
|
case 1: // qsincos
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 2: // qartan
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 3: // qrotate
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 4: // setsera
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 5: // setserb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 6: // setctrs
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 7: // setwavs
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 8: // setfrqs
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 9: // setphss
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 10: // addphss
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 11: // subphss
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 12: // jp
|
|
case 13: // jpd
|
|
if (value1 < 32 && ((pin_val >> value1) & 1))
|
|
{
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 14: // jnp
|
|
case 15: // jnpd
|
|
if (value1 < 32 && !((pin_val >> value1) & 1))
|
|
{
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 15:
|
|
switch(opcode & 7)
|
|
{
|
|
case 0: // cfgpins
|
|
case 1: // cfgpins, jmptask
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 2: // setxft, setmix
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 3: // jz, jzd, jnz, jnzd
|
|
if ((value1 == 0) != (zci >> 2))
|
|
{
|
|
if (instruct & 0x00400000)
|
|
pasmvars->pc = (pc + value2) & 0xffff;
|
|
else
|
|
pasmvars->pc = value2 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed jump
|
|
if (!(zci & 2))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 4: // locbase, locbyte, locword, loclong
|
|
if (sflag)
|
|
result = (pc + value2) << 2;
|
|
else
|
|
result = value2 << 2;
|
|
switch (zci >> 1)
|
|
{
|
|
case 0: // locbase
|
|
result &= 0x3ffff;
|
|
break;
|
|
|
|
case 1: // locbyte
|
|
result = (result + value1) & 0x3ffff;
|
|
break;
|
|
|
|
case 2: // locword
|
|
result = (result + (value1 << 1)) & 0x3ffff;
|
|
break;
|
|
|
|
case 3: // loclong
|
|
result = (result + (value1 << 2)) & 0x3ffff;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 5: // jmplist, locinst, reps, augs, augd
|
|
switch (zci)
|
|
{
|
|
case 0: // jmplist
|
|
case 1:
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 2: // locinst
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 3: // reps
|
|
break;
|
|
|
|
case 4: // augs
|
|
case 5:
|
|
pasmvars->augsflag = 1;
|
|
pasmvars->augsvalue = instruct & 0x007fffff;
|
|
break;
|
|
|
|
case 6: // augd
|
|
case 7:
|
|
pasmvars->augdflag = 1;
|
|
pasmvars->augdvalue = instruct & 0x007fffff;
|
|
break;
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 6: // fixindx, setindx, locptrx, jmpx, callx, callax, callbx, callxx, callyx
|
|
switch (zci)
|
|
{
|
|
case 0: // fixindx, setindx
|
|
switch (cond & 3) // Handle inda
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case 1: // fixinda
|
|
pasmvars->inda = srcaddr;
|
|
if (srcaddr < dstaddr)
|
|
{
|
|
pasmvars->indabot = srcaddr;
|
|
pasmvars->indatop = dstaddr;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->indabot = dstaddr;
|
|
pasmvars->indatop = srcaddr;
|
|
}
|
|
break;
|
|
|
|
case 2: // setindb #addr
|
|
pasmvars->inda = srcaddr;
|
|
pasmvars->indabot = 0;
|
|
pasmvars->indatop = 511;
|
|
break;
|
|
|
|
case 3: // setindb ++/--delt
|
|
pasmvars->inda = (pasmvars->inda + ((srcaddr << 23) >> 23)) & 511;
|
|
pasmvars->indabot = 0;
|
|
pasmvars->indatop = 511;
|
|
break;
|
|
}
|
|
switch (cond >> 2) // Handle indb
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case 1: // fixindb
|
|
pasmvars->indb = srcaddr;
|
|
if (srcaddr < dstaddr)
|
|
{
|
|
pasmvars->indbbot = srcaddr;
|
|
pasmvars->indbtop = dstaddr;
|
|
}
|
|
else
|
|
{
|
|
pasmvars->indbbot = dstaddr;
|
|
pasmvars->indbtop = srcaddr;
|
|
}
|
|
break;
|
|
|
|
case 2: // setindb #addr
|
|
pasmvars->indb = dstaddr;
|
|
pasmvars->indbbot = 0;
|
|
pasmvars->indbtop = 511;
|
|
break;
|
|
|
|
case 3: // setindb ++/--delt
|
|
pasmvars->indb = (pasmvars->indb + ((dstaddr << 23) >> 23)) & 511;
|
|
pasmvars->indbbot = 0;
|
|
pasmvars->indbtop = 511;
|
|
}
|
|
break;
|
|
|
|
case 1: // locptra, locptrb
|
|
switch ((instruct >> 16) & 3)
|
|
{
|
|
case 0: // locptra #abs
|
|
pasmvars->ptra = (instruct & 0xffff) << 2;
|
|
break;
|
|
|
|
case 1: // locptra @rel
|
|
pasmvars->ptra = ((pc + instruct) & 0xffff) << 2;
|
|
break;
|
|
|
|
case 2: // locptrb #abs
|
|
pasmvars->ptrb = (instruct & 0xffff) << 2;
|
|
break;
|
|
|
|
case 3: // locptrb @rel
|
|
pasmvars->ptrb = ((pc + instruct) & 0xffff) << 2;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 2: // jmp, jmpd
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 3: // call, calld
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
pc += 4;
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
pasmvars->retstack[pasmvars->retptr] = pc;
|
|
pasmvars->retptr = (pasmvars->retptr + 1) & 3;
|
|
if (pasmvars->retptr == 0)
|
|
printf("return stack overflow\n");
|
|
break;
|
|
|
|
case 4: // calla, callad
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
{
|
|
pc += 4;
|
|
}
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
LONG(pasmvars->ptra) = pc;
|
|
pasmvars->ptra = (pasmvars->ptra + 4) & 0x3ffff;
|
|
break;
|
|
|
|
case 5: // callb, callbd
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
{
|
|
pc += 4;
|
|
}
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
LONG(pasmvars->ptrb) = pc;
|
|
pasmvars->ptrb = (pasmvars->ptrb + 4) & 0x3ffff;
|
|
break;
|
|
|
|
case 6: // callx, callxd
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
pc += 4;
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
pasmvars->auxram[pasmvars->ptrx] = pc;
|
|
pasmvars->ptrx = (pasmvars->ptrx + 1) & AUX_MASK;
|
|
break;
|
|
|
|
case 7: // cally, callyd
|
|
if (instruct & 0x10000)
|
|
pasmvars->pc = (pc + instruct) & 0xffff;
|
|
else
|
|
pasmvars->pc = instruct & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct & 0x20000))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
pc += 4;
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
pasmvars->auxram[pasmvars->ptry^255] = pc;
|
|
pasmvars->ptry = (pasmvars->ptry + 1) & AUX_MASK;
|
|
break;
|
|
}
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 7:
|
|
if ((instruct&511) >= 0x40 && (instruct&511) <= 0xdc)
|
|
{
|
|
write_zcr &= 6;
|
|
if (zci & 1)
|
|
value1 = (instruct >> 9) & 511;
|
|
}
|
|
|
|
switch ((instruct >> 6) & 7)
|
|
{
|
|
case 0:
|
|
switch (instruct & 511)
|
|
{
|
|
case 0x000: // cogid
|
|
result = pasmvars->cogid;
|
|
break;
|
|
|
|
case 0x001: // taskid
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x002: // locknew
|
|
for (result = 0; result < 8; result++)
|
|
{
|
|
if (!lockalloc[result]) break;
|
|
}
|
|
if (result == 8)
|
|
{
|
|
cflag = 1;
|
|
result = 7;
|
|
}
|
|
else
|
|
{
|
|
cflag = 0;
|
|
lockalloc[result] = 1;
|
|
}
|
|
zflag = (result == 0);
|
|
break;
|
|
|
|
case 0x003: // getlfsr
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x004: // getcnt
|
|
result = GetCnt();
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x005: // getcntx
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x006: // getacal
|
|
result = pasmvars->acca & 0xffffffff;
|
|
break;
|
|
|
|
case 0x007: // getacah
|
|
result = pasmvars->acca >> 32;
|
|
break;
|
|
|
|
case 0x008: // getacbl
|
|
result = pasmvars->accb & 0xffffffff;
|
|
break;
|
|
|
|
case 0x009: // getacbh
|
|
result = pasmvars->accb >> 32;
|
|
break;
|
|
|
|
case 0x00a: // getptra
|
|
result = pasmvars->ptra;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x00b: // getptrb
|
|
result = pasmvars->ptrb;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x00c: // getptrx
|
|
result = pasmvars->ptrx;
|
|
break;
|
|
|
|
case 0x00d: // getptry
|
|
result = pasmvars->ptry;
|
|
break;
|
|
|
|
case 0x00e: // serina
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x00f: // serinb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x010: // getmull
|
|
result = pasmvars->mul & 0xffffffff;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x011: // getmulh
|
|
result = (pasmvars->mul >> 32) & 0xffffffff;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x012: // getdivq
|
|
result = pasmvars->divq;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x013: // getdivr
|
|
result = pasmvars->divr;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x014: // getsqrt
|
|
result = pasmvars->sqrt;
|
|
zflag = (result == 0);
|
|
cflag = 0;
|
|
break;
|
|
|
|
case 0x015: // getqx
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x016: // getqy
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x017: // getqz
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x018: // getphsa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x019: // getphza
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01a: // getcosa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01b: // getsina
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01c: // getphsb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01d: // getphzb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01e: // getcosb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x01f: // getsinb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x020: // pushzc
|
|
result = (value1 << 2) | (zflag << 1) | cflag;
|
|
zflag = (value1 >> 31) & 1;
|
|
cflag = (value1 >> 30) & 1;
|
|
break;
|
|
|
|
case 0x021: // popzc
|
|
result = ((value1 >> 2) & 0x3fffffff) | (zflag << 31) | (cflag << 30);
|
|
zflag = (value1 >> 1) & 1;
|
|
cflag = value1 & 1;
|
|
break;
|
|
|
|
case 0x022: // subcnt
|
|
result = GetCnt() - value1;
|
|
cflag = (result >> 31) & 1;
|
|
zflag = (result == 0);
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x023: // getpix
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x024: // binbcd
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x025: // bcdbin
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x026: // bingry
|
|
result = value1 ^ ((value1 >> 1) & 0x7fffffff);
|
|
break;
|
|
|
|
case 0x027: // grybin
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x028: // eswap4
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x029: // eswap8
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x02a: // seussf
|
|
result = seuss(value1, 1);
|
|
break;
|
|
|
|
case 0x02b: // seussr
|
|
result = seuss(value1, 0);
|
|
break;
|
|
|
|
case 0x02c: // incd
|
|
result = value1 + 0x200;
|
|
zflag = (result == 0);
|
|
write_zcr &= 5;
|
|
break;
|
|
|
|
case 0x02d: // decd
|
|
result = value1 - 0x200;
|
|
zflag = (result == 0);
|
|
write_zcr &= 5;
|
|
break;
|
|
|
|
case 0x02e: // incds
|
|
result = value1 + 0x201;
|
|
zflag = (result == 0);
|
|
write_zcr &= 5;
|
|
break;
|
|
|
|
case 0x02f: // decds
|
|
result = value1 - 0x201;
|
|
zflag = (result == 0);
|
|
write_zcr &= 5;
|
|
break;
|
|
|
|
case 0x030: // pop
|
|
pasmvars->retptr = (pasmvars->retptr - 1) & 3;
|
|
pasmvars->retstack[pasmvars->retptr] = value1;
|
|
if (pasmvars->retptr == 3)
|
|
printf("return stack underflow\n");
|
|
break;
|
|
|
|
default:
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 1: // repd
|
|
if ((instruct & 0xffc3fe00) == 0xfe03fe00)
|
|
{
|
|
pasmvars->repcnt = 1;
|
|
pasmvars->repforever = 1;
|
|
}
|
|
else
|
|
pasmvars->repcnt = value1;
|
|
pasmvars->repbot = (pasmvars->pc) & 0xffff;
|
|
pasmvars->reptop = (pasmvars->pc + (srcaddr & 63)) & 0xffff;
|
|
break;
|
|
|
|
case 2:
|
|
write_zcr = 0;
|
|
switch (instruct & 511)
|
|
{
|
|
case 0x080: // clkset
|
|
result = value1 & 0x1ff;
|
|
if (result & 0x100)
|
|
{
|
|
RebootProp();
|
|
return breakflag;
|
|
}
|
|
break;
|
|
|
|
case 0x081: // cogstop
|
|
PasmVars[value1&7].state = 0;
|
|
UpdatePins2();
|
|
break;
|
|
|
|
case 0x082: // lockset
|
|
result = value1 & 7;
|
|
cflag = lockstate[result] & 1;
|
|
lockstate[result] = -1;
|
|
write_zcr = (zci & 2);
|
|
break;
|
|
|
|
case 0x083: // lockclr
|
|
result = value1 & 7;
|
|
cflag = lockstate[result] & 1;
|
|
lockstate[result] = 0;
|
|
write_zcr = (zci & 2);
|
|
break;
|
|
|
|
case 0x084: // lockret
|
|
for (result = 0; result < 8; result++)
|
|
{
|
|
if (!lockalloc[result]) break;
|
|
}
|
|
cflag = (result == 8);
|
|
result = value1 & 7;
|
|
zflag = (result == 0);
|
|
lockalloc[result] = 0;
|
|
break;
|
|
|
|
case 0x085: // rdwidec
|
|
case 0x086: // rdwide
|
|
#if 0
|
|
// Check if using a ptr register
|
|
if (zci & 1) value1 = GetPointer(pasmvars, dstaddr, 5);
|
|
#endif
|
|
value1 &= 0xffffffe0;
|
|
if (!(instruct & 1) || value1 != pasmvars->dcachehubaddr)
|
|
{
|
|
pasmvars->dcache[0] = LONG(value1);
|
|
pasmvars->dcache[1] = LONG(value1+4);
|
|
pasmvars->dcache[2] = LONG(value1+8);
|
|
pasmvars->dcache[3] = LONG(value1+12);
|
|
pasmvars->dcache[4] = LONG(value1+16);
|
|
pasmvars->dcache[5] = LONG(value1+20);
|
|
pasmvars->dcache[6] = LONG(value1+24);
|
|
pasmvars->dcache[7] = LONG(value1+28);
|
|
pasmvars->dcachehubaddr = value1;
|
|
}
|
|
#if 0
|
|
fprintf(tracefile, "rdwide(%8.8x) %8.8x %8.8x %8.8x %8.8x\n",
|
|
value1, pasmvars->dcache[0], pasmvars->dcache[1],
|
|
pasmvars->dcache[2], pasmvars->dcache[3]);
|
|
#endif
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x087: // wrwide
|
|
#if 0
|
|
// Check if using a ptr register
|
|
if (zci & 1) value1 = GetPointer(pasmvars, dstaddr, 5);
|
|
#endif
|
|
value1 &= 0xffffffe0;
|
|
LONG(value1) = pasmvars->dcache[0];
|
|
LONG(value1+4) = pasmvars->dcache[1];
|
|
LONG(value1+8) = pasmvars->dcache[2];
|
|
LONG(value1+12) = pasmvars->dcache[3];
|
|
LONG(value1+16) = pasmvars->dcache[4];
|
|
LONG(value1+20) = pasmvars->dcache[5];
|
|
LONG(value1+24) = pasmvars->dcache[6];
|
|
LONG(value1+28) = pasmvars->dcache[7];
|
|
#if 0
|
|
fprintf(tracefile, "wrwide(%8.8x) %8.8x %8.8x %8.8x %8.8x\n",
|
|
value1, pasmvars->dcache[0], pasmvars->dcache[1],
|
|
pasmvars->dcache[2], pasmvars->dcache[3]);
|
|
#endif
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x088: // getp
|
|
if (value1 < 32)
|
|
cflag = (pin_val >> value1) & 1;
|
|
else
|
|
cflag = 1;
|
|
zflag = cflag ^ 1;
|
|
write_zcr = (zci & 6);
|
|
break;
|
|
|
|
case 0x089: // getnp
|
|
if (value1 < 32)
|
|
zflag = (pin_val >> value1) & 1;
|
|
else
|
|
zflag = 1;
|
|
cflag = zflag ^ 1;
|
|
write_zcr = (zci & 6);
|
|
break;
|
|
|
|
case 0x08a: // serouta
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x08b: // seroutb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x08c: // cmpcnt
|
|
result = GetCnt() - value1;
|
|
cflag = (result >> 31) & 1;
|
|
zflag = (result == 0);
|
|
write_zcr = (zci & 6);
|
|
break;
|
|
|
|
case 0x08d: // waitpx
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x08e: // waitpr
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x08f: // waitpf
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x090: // setzc
|
|
zflag = (value1 >> 1) & 1;
|
|
cflag = value1 & 1;
|
|
write_zcr = (zci & 6);
|
|
break;
|
|
|
|
case 0x091: // setmap
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x092: // setxch
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x093: // settask
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x094: // setrace
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x095: // saracca
|
|
pasmvars->acca >>= (value1 & 63);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x096: // saraccb
|
|
pasmvars->accb >>= (value1 & 63);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x097: // saraccs
|
|
pasmvars->acca >>= (value1 & 63);
|
|
pasmvars->accb >>= (value1 & 63);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x098: // setptra
|
|
pasmvars->ptra = value1 & 0x3ffff;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x099: // setptrb
|
|
pasmvars->ptrb = value1 & 0x3ffff;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x09a: // addptra
|
|
pasmvars->ptra = (pasmvars->ptra + value1) & 0x3ffff;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x09b: // addptrb
|
|
pasmvars->ptrb = (pasmvars->ptrb + value1) & 0x3ffff;
|
|
break;
|
|
|
|
case 0x09c: // subptra
|
|
pasmvars->ptra = (pasmvars->ptra - value1) & 0x3ffff;
|
|
break;
|
|
|
|
case 0x09d: // subptrb
|
|
pasmvars->ptrb = (pasmvars->ptrb - value1) & 0x3ffff;
|
|
break;
|
|
|
|
case 0x09e: // setwide
|
|
pasmvars->dcachecogaddr = value1 & 0x1f8;
|
|
break;
|
|
|
|
case 0x09f: // setwidz
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0a0: // setptrx
|
|
pasmvars->ptrx = value1 & 255;
|
|
break;
|
|
|
|
case 0x0a1: // setptry
|
|
pasmvars->ptry = value1 & 255;
|
|
break;
|
|
|
|
case 0x0a2: // addptrx
|
|
pasmvars->ptrx = (pasmvars->ptrx + value1) & 255;
|
|
break;
|
|
|
|
case 0x0a3: // addptry
|
|
pasmvars->ptry = (pasmvars->ptry + value1) & 255;
|
|
break;
|
|
|
|
case 0x0a4: // subptrx
|
|
pasmvars->ptrx = (pasmvars->ptrx - value1) & 255;
|
|
break;
|
|
|
|
case 0x0a5: // subptry
|
|
pasmvars->ptry = (pasmvars->ptry - value1) & 255;
|
|
break;
|
|
|
|
case 0x0a6: // passcnt
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0a7: // wait
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x0a8: // offp
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] &= ~(1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0a9: // notp
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
result = pasmvars->mem[dstaddr] ^ (1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0aa: // clrp
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0ab: // setp
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
result = pasmvars->mem[dstaddr] | (1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0ac: // setpc
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
if (pasmvars->cflag)
|
|
result = pasmvars->mem[dstaddr] | (1 << (value1 & 31));
|
|
else
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0ad: // setpnc
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
if (!pasmvars->cflag)
|
|
result = pasmvars->mem[dstaddr] | (1 << (value1 & 31));
|
|
else
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0ae: // setpz
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
if (pasmvars->zflag)
|
|
result = pasmvars->mem[dstaddr] | (1 << (value1 & 31));
|
|
else
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0af: // setpnz
|
|
write_zcr = 1;
|
|
dstaddr = ((value1 & 127) >> 5) + REG_DIRA;
|
|
pasmvars->mem[dstaddr] |= (1 << (value1 & 31));
|
|
dstaddr = ((value1 & 127) >> 5) + REG_OUTA;
|
|
if (!pasmvars->zflag)
|
|
result = pasmvars->mem[dstaddr] | (1 << (value1 & 31));
|
|
else
|
|
result = pasmvars->mem[dstaddr] & ~(1 << (value1 & 31));
|
|
break;
|
|
|
|
case 0x0b0: // div64d
|
|
write_zcr = 0;
|
|
pasmvars->divisor = value1;
|
|
break;
|
|
|
|
case 0x0b1: // sqrt32
|
|
write_zcr = 0;
|
|
pasmvars->mulcount = 16;
|
|
pasmvars->sqrt = sqrt32(value1);
|
|
break;
|
|
|
|
case 0x0b2: // qlog
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b3: // qexp
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b4: // setqi
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b5: // setqz
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b6: // cfgdacs
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b7: // setdacs
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b8: // cfgdac0
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0b9: // cfgdac1
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0ba: // cfgdac2
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0bb: // cfgdac3
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0bc: // setdac0
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0bd: // setdac1
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0be: // setdac2
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0bf: // setdac3
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
default:
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
write_zcr = 0;
|
|
switch (instruct & 511)
|
|
{
|
|
case 0x0c0: // setctra
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c1: // setwava
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c2: // setfrqa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c3: // setphsa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c4: // addphsa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c5: // subphsa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c6: // setvid
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c7: // setvidy
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c8: // setctrb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0c9: // setwavb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0ca: // setfrqb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0cb: // setphsb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0cc: // addphsb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0cd: // subphsb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0ce: // setvidi
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0cf: // setvidq
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d0: // setpix
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d1: // setpixz
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d2: // setpixu
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d3: // setpixv
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d4: // setpixa
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d5: // setpixr
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d6: // setpixg
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d7: // setpixb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d8: // setpora
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0d9: // setporb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0da: // setporc
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0db: // setpord
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0dc: // push
|
|
pasmvars->retstack[pasmvars->retptr] = value1;
|
|
pasmvars->retptr = (pasmvars->retptr + 1) & 3;
|
|
if (pasmvars->retptr == 0)
|
|
printf("return stack overflow\n");
|
|
break;
|
|
|
|
case 0x0f4: // jmp
|
|
case 0x0f5: // jmpd
|
|
pasmvars->pc = value1 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x0f6: // call
|
|
case 0x0f7: // calld
|
|
pasmvars->pc = value1 & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
pc++;
|
|
}
|
|
else
|
|
pc += 4;
|
|
pc |= (pasmvars->zflag << 17) | (pasmvars->cflag << 16);
|
|
pasmvars->retstack[pasmvars->retptr] = pc;
|
|
pasmvars->retptr = (pasmvars->retptr + 1) & 3;
|
|
if (pasmvars->retptr == 0)
|
|
printf("return stack overflow\n");
|
|
break;
|
|
|
|
case 0x0f8: // calla
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0f9: // callad
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0fa: // callb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0fb: // callbd
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0fc: // callx
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0fd: // callxd
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0fe: // cally
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x0ff: // callyd
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
default:
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
write_zcr &= 6;
|
|
switch (instruct & 511)
|
|
{
|
|
case 0x100: // reta
|
|
case 0x101: // retad
|
|
pasmvars->ptra = (pasmvars->ptra - 4) & 0x3ffff;
|
|
result = LONG(pasmvars->ptra);
|
|
cflag = (result >> 16) & 1;
|
|
zflag = (result >> 17) & 1;
|
|
pasmvars->pc = result & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x102: // retb
|
|
case 0x103: // retbd
|
|
pasmvars->ptrb = (pasmvars->ptrb - 4) & 0x3ffff;
|
|
result = LONG(pasmvars->ptrb);
|
|
cflag = (result >> 16) & 1;
|
|
zflag = (result >> 17) & 1;
|
|
pasmvars->pc = result & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x104: // retx
|
|
case 0x105: // retxd
|
|
pasmvars->ptrx = (pasmvars->ptrx - 1) & AUX_MASK;
|
|
result = pasmvars->auxram[pasmvars->ptrx];
|
|
cflag = (result >> 16) & 1;
|
|
zflag = (result >> 17) & 1;
|
|
pasmvars->pc = result & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x106: // rety
|
|
case 0x107: // retyd
|
|
pasmvars->ptry = (pasmvars->ptry - 1) & AUX_MASK;
|
|
result = pasmvars->auxram[pasmvars->ptry^255];
|
|
cflag = (result >> 16) & 1;
|
|
zflag = (result >> 17) & 1;
|
|
pasmvars->pc = result & 0xffff;
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x108: // ret
|
|
case 0x109: // retd
|
|
pasmvars->retptr = (pasmvars->retptr - 1) & 3;
|
|
result = pasmvars->retstack[pasmvars->retptr];
|
|
cflag = (result >> 16) & 1;
|
|
zflag = (result >> 17) & 1;
|
|
pasmvars->pc = result & 0xffff;
|
|
if (pasmvars->retptr == 3)
|
|
printf("return stack underflow\n");
|
|
// Invalidate the instruction pipeline if non-delayed
|
|
if (!(instruct&1))
|
|
{
|
|
pasmvars->pc1 |= INVALIDATE_INSTR;
|
|
pasmvars->pc2 |= INVALIDATE_INSTR;
|
|
pasmvars->pc3 |= INVALIDATE_INSTR;
|
|
}
|
|
break;
|
|
|
|
case 0x10a: // polctra
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x10b: // polctrb
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x10c: // polvid
|
|
NotImplemented(instruct);
|
|
break;
|
|
|
|
case 0x10d: // capctra
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x10e: // capctrb
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x10f: // capctrs
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x110: // setpixw
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x111: // clracca
|
|
pasmvars->acca = 0;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x112: // clraccb
|
|
pasmvars->accb = 0;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x113: // clraccs
|
|
pasmvars->acca = 0;
|
|
pasmvars->accb = 0;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x114: // chkptrx
|
|
zflag = (pasmvars->ptrx == 0);
|
|
cflag = (pasmvars->ptrx >> 7) & 1;
|
|
break;
|
|
|
|
case 0x115: // chkptry
|
|
zflag = (pasmvars->ptry == 0);
|
|
cflag = (pasmvars->ptry >> 7) & 1;
|
|
break;
|
|
|
|
case 0x116: // synctra
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x117: // synctrb
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x118: // dcachex
|
|
pasmvars->dcachehubaddr = 0xffffffff;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x119: // icachex
|
|
pasmvars->icachehubaddr[0] = 0xffffffff;
|
|
pasmvars->icachehubaddr[1] = 0xffffffff;
|
|
pasmvars->icachehubaddr[2] = 0xffffffff;
|
|
pasmvars->icachehubaddr[3] = 0xffffffff;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x11a: // icachep
|
|
pasmvars->prefetch = 1;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
case 0x11b: // icachen
|
|
pasmvars->prefetch = 0;
|
|
write_zcr = 0;
|
|
break;
|
|
|
|
default:
|
|
NotImplemented(instruct);
|
|
write_zcr = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
NotImplemented(instruct);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Conditionally update flags and write result
|
|
if (write_zcr & 4)
|
|
{
|
|
pasmvars->zflag = zflag;
|
|
if (pasmvars->printflag > 1) fprintf(tracefile, ", z = %d", zflag);
|
|
}
|
|
if (write_zcr & 2)
|
|
{
|
|
pasmvars->cflag = cflag;
|
|
if (pasmvars->printflag > 1) fprintf(tracefile, ", c = %d", cflag);
|
|
}
|
|
if (write_zcr & 1)
|
|
{
|
|
pasmvars->lastd = result;
|
|
if ((dstaddr & 0x1f8) == pasmvars->dcachecogaddr)
|
|
{
|
|
pasmvars->dcache[dstaddr & 7] = result;
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", dcache[%d] = %x", dstaddr & 7, result);
|
|
}
|
|
else
|
|
{
|
|
pasmvars->mem[dstaddr] = result;
|
|
if (pasmvars->printflag > 1)
|
|
fprintf(tracefile, ", cram[%x] = %x", dstaddr, result);
|
|
}
|
|
// Check if we need to update the pins
|
|
if (dstaddr >= REG_OUTA && dstaddr <= REG_DIRD) UpdatePins2();
|
|
}
|
|
if (pasmvars->waitflag)
|
|
{
|
|
fprintf(tracefile, "XXXXXXXXXX BAD XXXXXXXXXXXXXXX\n");
|
|
pasmvars->waitflag--;
|
|
if (!pasmvars->waitflag) pasmvars->waitmode = 0;
|
|
}
|
|
return breakflag;
|
|
}
|
|
/*
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
| TERMS OF USE: MIT License |
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
|Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
|
|
|files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
|
|
|modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
|
|
|is furnished to do so, subject to the following conditions: |
|
|
| |
|
|
|The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
|
|
| |
|
|
|THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
|
|WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
|
|COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|
|
|ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
*/
|