1
0
mirror of https://github.com/prirun/p50em.git synced 2026-02-27 00:39:52 +00:00

added ea32i.h include file, ea64v, devamlc, PNC

ea64v never needs to return a bit offset
added devamlc feature to set room available in user's input buffer
misc PNC changes (not working yet)
This commit is contained in:
Jim
2007-04-19 00:00:00 -04:00
parent 5bc7332b1f
commit 319b868345
5 changed files with 1003 additions and 404 deletions

113
ea32i.h Normal file
View File

@@ -0,0 +1,113 @@
#define IMM_EA 0x80000000
inline ea_t ea32i (ea_t earp, unsigned short inst, unsigned long *immu32, unsigned long long *immu64) {
#ifdef OSX
int tm, sr, br, ring;
unsigned short d;
int temp32;
ea_t ea, ip;
*immu32 = 0xAAAAAAAA;
*immu64 = 0xAAAAAAAAAAAAAAAALL;
tm = (inst >> 5) & 3;
sr = (inst >> 2) & 7;
br = inst & 3;
ring = RP & RINGMASK32;
TRACE(T_EAI, " tm=%d, sr=%d, dr=%d, br=%d\n", tm, sr, (inst >> 7) & 7, br);
switch (tm) {
case 0:
switch (br) {
case 0: /* reg-reg */
*immu32 = crsl[sr];
return IMM_EA;
case 1:
d = iget16(RP);
RPL++;
if (sr == 0) /* imm type 1 */
*immu32 = d << 16;
else /* imm type 2 */
*(int *)immu32 = *(short *)&d;
return IMM_EA;
case 2:
switch (sr) {
case 0: /* imm type 3 */
d = iget16(RP);
RPL++;
*immu64 = (((long long)(d & 0xFF00)) << 48) | (d & 0xFF);
return IMM_EA;
case 1: /* FAC0 source */
*immu64 = *(unsigned long long *)(crsl+FAC0);
return IMM_EA;
case 3: /* FAC1 source */
*immu64 = *(unsigned long long *)(crsl+FAC1);
return IMM_EA;
case 2:
case 4:
case 5:
case 6:
case 7:
fault(UIIFAULT, RPL, RP);
fatal("ea32i: return from UII fault!");
default:
fatal("ea32i: sr < 0 or > 7?");
}
fatal("ea32i: case tm=0 br=2 fall-through");
case 3: /* GR relative */
d = iget16(RP);
RPL++;
ea = (crsl[sr] & 0xFFFF0000) | ((crsl[sr] + d) & 0xFFFF);
if (ea & 0x80000000)
fault(POINTERFAULT, ea>>16, ea);
return ea | ring;
default:
fatal("ea32i: tm=0, br < 0 or > 3?");
}
fatal("ea32i: tm=0 fall-through");
case 1: /* TM=1: Direct and Indexed */
d = iget16(RP);
RPL++;
if (sr == 0)
ea = (crsl[BR+br] & 0xFFFF0000) | ((crsl[BR+br] + d) & 0xFFFF);
else
ea = (crsl[BR+br] & 0xFFFF0000) | ((crsl[BR+br] + d + crs[sr*2]) & 0xFFFF);
return ea | ring;
case 2: /* TM=2: Indirect and Indirect Preindexed */
d = iget16(RP);
RPL++;
if (sr == 0)
ea = (crsl[BR+br] & 0xFFFF0000) | ((crsl[BR+br] + d) & 0xFFFF);
else
ea = (crsl[BR+br] & 0xFFFF0000) | ((crsl[BR+br] + d + crs[sr*2]) & 0xFFFF);
ip = get32(ea | ring);
if (ip & 0x80000000)
fault(POINTERFAULT, ip>>16, ea);
return ip | ring;
case 3: /* TM=3: Indirect and Indirect Postindexed */
d = iget16(RP);
RPL++;
ea = (crsl[BR+br] & 0xFFFF0000) | ((crsl[BR+br] + d) & 0xFFFF);
ip = get32(ea | ring);
if (ip & 0x80000000)
fault(POINTERFAULT, ip>>16, ea);
if (sr > 0)
ip = (ip & 0xFFFF0000) | ((ip + crs[sr*2]) & 0xFFFF);
return ip | ring;
default:
fatal("ea32i: tm out of range!");
}
fatal("ea32i: main switch fall through");
#else
fatal("ea32i: not implemented");
#endif
}

View File

@@ -1,7 +1,7 @@
/* this version is derived from the flowchart in the preliminary P400
release notes */
inline ea_t ea64v (ea_t earp, unsigned short inst, short x, unsigned short *opcode, unsigned short *bit) {
inline ea_t ea64v (ea_t earp, unsigned short inst, short x, unsigned short *opcode) {
ea_t ea; /* full seg/word va */
unsigned short ea_s; /* eff address segno */
@@ -17,7 +17,6 @@ inline ea_t ea64v (ea_t earp, unsigned short inst, short x, unsigned short *opco
unsigned short m;
unsigned short rph,rpl;
*bit = 0;
i = inst & 0100000; /* indirect is bit 1 (left/MS bit) */
/* rph/rpl (and earp) are usually = RPH/RPL in the register file,
@@ -131,9 +130,11 @@ labB:
fault(POINTERFAULT, m, ea);
ea_s = m | (ea_s & RINGMASK16);
ea_w = get16(INCVA(ea,1));
#if 0
if (ea_s & EXTMASK16)
*bit = get16(INCVA(ea,2)) >> 12;
TRACE(T_EAV, " After indirect, ea_s=%o, ea_w=%o, bit=%d\n", ea_s, ea_w, *bit);
warn("em: extension bit set in ea64v");
#endif
TRACE(T_EAV, " After indirect, ea_s=%o, ea_w=%o\n", ea_s, ea_w);
}
if (xok)
if (ixy == 5)

784
em.c
View File

@@ -1390,11 +1390,7 @@ special:
}
#include "ea64v.h"
unsigned int ea32i (ea_t earp, unsigned short inst, short x) {
TRACE(T_EAI, "Mode 32I not implemented\n");
}
#include "ea32i.h"
ea_t apea(unsigned short *bitarg) {
unsigned short ibr, ea_s, ea_w, bit, br, a;
@@ -2857,11 +2853,9 @@ main (int argc, char **argv) {
double tempd,tempd1,tempd2;
unsigned short tempda[4],tempda1[4];
ea_t tempea;
unsigned int ea32; /* full V/I mode eff address */
ea_t ea; /* final MR effective address */
ea_t eanext; /* ea of lower 16 bits in instl */
unsigned long instl;
ea_t earp; /* RP to use for eff address calcs */
int dr;
unsigned short eabit;
unsigned short opcode;
short i,j,x;
@@ -2878,6 +2872,8 @@ main (int argc, char **argv) {
ea_t trapaddr;
unsigned short stpm[8];
unsigned short access;
unsigned long immu32;
unsigned long long immu64;
unsigned short zresult, zclen1, zclen2, zaccess;
unsigned int zlen1, zlen2;
@@ -2886,7 +2882,6 @@ main (int argc, char **argv) {
struct timeval boot_tv;
struct timezone tz;
float mips;
/* open trace log */
@@ -5232,216 +5227,234 @@ a1a:
if (class == 1) {
TRACE(T_INST, " shift group\n");
scount = -inst & 077;
if (scount == 0)
scount = 0100;
switch (inst & 01700) {
if ((crs[KEYS] & 0016000) == 0010000) { /* I-mode Generic */
switch (inst) {
case 00000: /* LRL */
TRACE(T_FLOW, " LRL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 32) {
case 0040300: /* DRN */
break;
case 0040301: /* DRNP */
break;
case 0040302: /* DRNZ */
break;
case 0040310: /* SSSN */
break;
default:
TRACE(T_INST, " unrecognized I-mode generic class 1 instruction!\n");
printf(" unrecognized I-mode generic class 1 instruction %o!\n", inst);
fatal(NULL);
}
} else {
TRACE(T_INST, " shift group\n");
scount = -inst & 077;
if (scount == 0)
scount = 0100;
switch (inst & 01700) {
case 00000: /* LRL */
TRACE(T_FLOW, " LRL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 32) {
utempl = *(unsigned int *)(crs+L);
EXPCL(utempl & bitmask32[33-scount]);
*(unsigned int *)(crs+L) = utempl >> scount;
} else {
*(unsigned int *)(crs+L) = 0;
}
break;
case 00100: /* LRS (different in R & V modes) */
TRACE(T_FLOW, " LRS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (crs[KEYS] & 010000) { /* V/I mode */
if (scount <= 32) {
templ = *(int *)(crs+L);
EXPCL(templ & bitmask32[33-scount]);
templ = templ >> scount;
*(int *)(crs+L) = templ;
} else if (crs[A] & 0x8000) {
*(int *)(crs+L) = 0xFFFFFFFF;
SETCL;
} else {
*(int *)(crs+L) = 0;
}
} else {
utempa = crs[B] & 0x8000; /* save B bit 1 */
if (scount <= 31) {
templ = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
EXPCL(templ & bitmask32[32-scount]);
templ = templ >> (scount+1);
crs[A] = templ >> 15;
crs[B] = (templ & 0x7FFF) | utempa;
} else if (crs[A] & 0x8000) {
*(int *)(crs+A) = 0xFFFF7FFF | utempa;
SETCL;
} else {
*(int *)(crs+A) = utempa;
}
}
break;
case 00200: /* LRR */
TRACE(T_FLOW, " LRR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount > 32)
scount = scount - 32;
utempl = *(unsigned int *)(crs+L);
EXPCL(utempl & bitmask32[33-scount]);
*(unsigned int *)(crs+L) = utempl >> scount;
} else {
*(unsigned int *)(crs+L) = 0;
}
break;
case 00100: /* LRS (different in R & V modes) */
TRACE(T_FLOW, " LRS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (crs[KEYS] & 010000) { /* V/I mode */
if (scount <= 32) {
templ = *(int *)(crs+L);
EXPCL(templ & bitmask32[33-scount]);
templ = templ >> scount;
*(int *)(crs+L) = templ;
} else if (crs[A] & 0x8000) {
*(int *)(crs+L) = 0xFFFFFFFF;
SETCL;
} else {
*(int *)(crs+L) = 0;
}
} else {
utempa = crs[B] & 0x8000; /* save B bit 1 */
if (scount <= 31) {
templ = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
EXPCL(templ & bitmask32[32-scount]);
templ = templ >> (scount+1);
crs[A] = templ >> 15;
crs[B] = (templ & 0x7FFF) | utempa;
} else if (crs[A] & 0x8000) {
*(int *)(crs+A) = 0xFFFF7FFF | utempa;
SETCL;
} else {
*(int *)(crs+A) = utempa;
}
}
break;
case 00200: /* LRR */
TRACE(T_FLOW, " LRR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount > 32)
scount = scount - 32;
utempl = *(unsigned int *)(crs+L);
EXPCL(utempl & bitmask32[33-scount]);
utempl = (utempl >> scount) | (utempl << (32-scount));
*(unsigned int *)(crs+L) = utempl;
break;
case 00300:
if (inst == 040310) {
printf("SSSN @ %o/%o\n", RPH, RPL);
TRACE(T_FLOW, " SSSN\n", inst);
fault(UIIFAULT, RPL, RP);
utempl = (utempl >> scount) | (utempl << (32-scount));
*(unsigned int *)(crs+L) = utempl;
break;
}
goto badshift;
case 00400: /* ARL */
TRACE(T_FLOW, " ARL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
case 00300:
if (inst == 040310) {
printf("SSSN @ %o/%o\n", RPH, RPL);
TRACE(T_FLOW, " SSSN\n", inst);
fault(UIIFAULT, RPL, RP);
break;
}
goto badshift;
case 00400: /* ARL */
TRACE(T_FLOW, " ARL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
EXPCL(crs[A] & bitmask16[17-scount]);
crs[A] = crs[A] >> scount;
} else {
crs[A] = 0;
}
break;
case 00500: /* ARS */
TRACE(T_FLOW, " ARS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
tempa = *(short *)(crs+A);
EXPCL(tempa & bitmask16[17-scount]);
tempa = tempa >> scount;
*(short *)(crs+A) = tempa;
} else if (crs[A] & 0x8000) {
*(short *)(crs+A) = 0xFFFF;
SETCL;
} else {
*(short *)(crs+A) = 0;
}
break;
case 00600: /* ARR */
TRACE(T_FLOW, " ARR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
scount = ((scount-1)%16)+1; /* make scount 1-16 */
EXPCL(crs[A] & bitmask16[17-scount]);
crs[A] = crs[A] >> scount;
} else {
crs[A] = 0;
}
break;
crs[A] = (crs[A] >> scount) | (crs[A] << (16-scount));
break;
case 00500: /* ARS */
TRACE(T_FLOW, " ARS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
tempa = *(short *)(crs+A);
EXPCL(tempa & bitmask16[17-scount]);
tempa = tempa >> scount;
*(short *)(crs+A) = tempa;
} else if (crs[A] & 0x8000) {
*(short *)(crs+A) = 0xFFFF;
SETCL;
} else {
*(short *)(crs+A) = 0;
}
break;
case 01000: /* LLL */
TRACE(T_FLOW, " LLL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 32) {
utempl = *(unsigned int *)(crs+A);
EXPCL(utempl & bitmask32[scount]);
utempl = utempl << scount;
*(unsigned int *)(crs+A) = utempl;
} else {
*(unsigned int *)(crs+A) = 0;
}
break;
case 00600: /* ARR */
TRACE(T_FLOW, " ARR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
scount = ((scount-1)%16)+1; /* make scount 1-16 */
EXPCL(crs[A] & bitmask16[17-scount]);
crs[A] = (crs[A] >> scount) | (crs[A] << (16-scount));
break;
case 01100: /* LLS (different in R/V modes) */
TRACE(T_FLOW, " LLS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (crs[KEYS] & 010000) { /* V/I mode */
if (scount < 32) {
templ = 0x80000000;
templ = templ >> scount; /* create mask */
templ = templ & *(int *)(crs+A); /* grab bits */
templ = templ >> (31-scount); /* extend them */
EXPCL(!(templ == -1 || templ == 0));
*(int *)(crs+A) = *(int *)(crs+A) << scount;
} else {
EXPCL(*(int *)(crs+A) != 0);
*(int *)(crs+A) = 0;
}
} else {
utempa = crs[B] & 0x8000; /* save B bit 1 */
if (scount < 31) {
utempl = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
templ2 = 0x80000000;
templ2 = templ2 >> scount; /* create mask */
templ2 = templ2 & utempl; /* grab bits */
templ2 = templ2 >> (31-scount); /* sign extend them */
EXPCL(!(templ2 == -1 || templ2 == 0));
//printf(" before: A=%x, B=%x, utempl=%x, ", crs[A], crs[B], utempl);
utempl = utempl << scount;
crs[A] = utempl >> 16;
crs[B] = ((utempl >> 1) & 0x7FFF) | utempa;
//printf(" after: A=%x, B=%x, utempl=%x\n", crs[A], crs[B], utempl);
} else {
EXPCL(*(unsigned int *)(crs+A) != 0);
*(unsigned int *)(crs+A) = utempa;
}
}
if (crs[KEYS] & 0100000)
mathexception('i', FC_INT_OFLOW, 0);
break;
case 01000: /* LLL */
TRACE(T_FLOW, " LLL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 32) {
case 01200: /* LLR */
TRACE(T_FLOW, " LLR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount > 32)
scount = scount - 32;
utempl = *(unsigned int *)(crs+A);
EXPCL(utempl & bitmask32[scount]);
utempl = utempl << scount;
utempl = (utempl << scount) | (utempl >> (32-scount));
*(unsigned int *)(crs+A) = utempl;
} else {
*(unsigned int *)(crs+A) = 0;
}
break;
break;
case 01100: /* LLS (different in R/V modes) */
TRACE(T_FLOW, " LLS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (crs[KEYS] & 010000) { /* V/I mode */
if (scount < 32) {
templ = 0x80000000;
templ = templ >> scount; /* create mask */
templ = templ & *(int *)(crs+A); /* grab bits */
templ = templ >> (31-scount); /* extend them */
EXPCL(!(templ == -1 || templ == 0));
*(int *)(crs+A) = *(int *)(crs+A) << scount;
case 01400: /* ALL */
TRACE(T_FLOW, " ALL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
EXPCL(crs[A] & bitmask16[scount]);
crs[A] = crs[A] << scount;
} else {
EXPCL(*(int *)(crs+A) != 0);
*(int *)(crs+A) = 0;
crs[A] = 0;
}
} else {
utempa = crs[B] & 0x8000; /* save B bit 1 */
if (scount < 31) {
utempl = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1);
templ2 = 0x80000000;
templ2 = templ2 >> scount; /* create mask */
templ2 = templ2 & utempl; /* grab bits */
templ2 = templ2 >> (31-scount); /* sign extend them */
EXPCL(!(templ2 == -1 || templ2 == 0));
//printf(" before: A=%x, B=%x, utempl=%x, ", crs[A], crs[B], utempl);
utempl = utempl << scount;
crs[A] = utempl >> 16;
crs[B] = ((utempl >> 1) & 0x7FFF) | utempa;
//printf(" after: A=%x, B=%x, utempl=%x\n", crs[A], crs[B], utempl);
} else {
EXPCL(*(unsigned int *)(crs+A) != 0);
*(unsigned int *)(crs+A) = utempa;
break;
case 01500: /* ALS */
TRACE(T_FLOW, " ALS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 15) {
tempa = 0100000;
tempa = tempa >> scount; /* create mask */
tempa = tempa & crs[A]; /* grab bits */
tempa = tempa >> (15-scount); /* extend them */
crs[A] = crs[A] << scount;
EXPCL(!(tempa == -1 || tempa == 0));
} else if (crs[A] != 0) {
crs[A] = 0;
SETCL;
}
}
if (crs[KEYS] & 0100000)
mathexception('i', FC_INT_OFLOW, 0);
break;
if (crs[KEYS] & 0100000)
mathexception('i', FC_INT_OFLOW, 0);
break;
case 01200: /* LLR */
TRACE(T_FLOW, " LLR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount > 32)
scount = scount - 32;
utempl = *(unsigned int *)(crs+A);
EXPCL(utempl & bitmask32[scount]);
utempl = (utempl << scount) | (utempl >> (32-scount));
*(unsigned int *)(crs+A) = utempl;
break;
case 01400: /* ALL */
TRACE(T_FLOW, " ALL %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 16) {
case 01600: /* ALR */
TRACE(T_FLOW, " ALR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
scount = ((scount-1)%16)+1; /* make scount 1-16 */
EXPCL(crs[A] & bitmask16[scount]);
crs[A] = crs[A] << scount;
} else {
crs[A] = 0;
crs[A] = (crs[A] << scount) | (crs[A] >> (16-scount));
break;
default:
badshift:
printf("emulator warning: unrecognized shift instruction %o at %o/%o\n", inst, RPH, RPL);
TRACE(T_INST, " unrecognized shift instruction!: %o\n", inst);
}
break;
case 01500: /* ALS */
TRACE(T_FLOW, " ALS %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
if (scount <= 15) {
tempa = 0100000;
tempa = tempa >> scount; /* create mask */
tempa = tempa & crs[A]; /* grab bits */
tempa = tempa >> (15-scount); /* extend them */
crs[A] = crs[A] << scount;
EXPCL(!(tempa == -1 || tempa == 0));
} else if (crs[A] != 0) {
crs[A] = 0;
SETCL;
}
if (crs[KEYS] & 0100000)
mathexception('i', FC_INT_OFLOW, 0);
break;
case 01600: /* ALR */
TRACE(T_FLOW, " ALR %d\n", scount);
crs[KEYS] &= ~0120000; /* clear C,L */
scount = ((scount-1)%16)+1; /* make scount 1-16 */
EXPCL(crs[A] & bitmask16[scount]);
crs[A] = (crs[A] << scount) | (crs[A] >> (16-scount));
break;
default:
badshift:
printf("emulator warning: unrecognized shift instruction %o at %o/%o\n", inst, RPH, RPL);
TRACE(T_INST, " unrecognized shift instruction!: %o\n", inst);
continue;
}
continue;
}
if (class == 2) {
@@ -5599,6 +5612,372 @@ keys = 14200, modals=100177
fatal("Coding error: bad generic class");
}
if ((crs[KEYS] & 0016000) != 0010000) goto nonimode;
#ifndef OSX
RESTRICT();
#endif
ea = ea32i(earp, inst, &immu32, &immu64);
dr = (inst >> 7) & 7;
switch (inst >> 10) {
case 000:
fatal("I-mode generic class 0?");
case 001:
TRACE(T_INST, " L\n");
if (*(int *)&ea < 0)
crsl[dr] = immu32;
else
crsl[dr] = get32(ea);
continue;
case 002:
TRACE(T_INST, " A\n");
if (*(int *)&ea < 0)
utempl2 = immu32;
else
utempl2 = get32(ea);
crs[KEYS] &= ~0120300; /* clear C, L, LT, EQ */
utempl = crsl[dr]; /* save orig L for sign check */
utempll = utempl; /* expand to 64 bits */
utempll += utempl2; /* 64-bit add */
crsl[dr] = utempll; /* truncate results */
if (utempll & 0x100000000LL) /* set L-bit if carry */
crs[KEYS] |= 020000;
if (crsl[dr] == 0) /* set EQ? */
crs[KEYS] |= 0100;
if ((~utempl ^ utempl2) & (utempl ^ crsl[dr]) & 0x80000000) {
if (*(int *)(crsl+dr) >= 0)
crs[KEYS] |= 0200;
mathexception('i', FC_INT_OFLOW, 0);
} else if (*(int *)(crsl+dr) < 0)
crs[KEYS] |= 0200;
continue;
case 003:
TRACE(T_INST, " N\n");
if (*(int *)&ea < 0)
crsl[dr] &= immu32;
else
crsl[dr] &= get32(ea);
continue;
case 004:
TRACE(T_INST, " LHL1\n");
if (*(int *)&ea < 0)
crs[dr*2] = immu32 << 1;
else
crs[dr*2] = get16(ea) << 1;
continue;
case 005:
TRACE(T_INST, " SHL\n");
fatal("SHL not implemented");
continue;
case 006: /* Special MR FP format */
/* DFC, DFL, FC, FL */
continue;
case 007:
fatal("I-mode opcode 007");
case 010:
/* register generic branch */
continue;
case 011:
TRACE(T_INST, " LH\n");
if (*(int *)&ea < 0)
crs[dr*2] = immu32;
else
crs[dr*2] = get16(ea);
continue;
case 012:
TRACE(T_INST, " AH\n");
continue;
case 013:
TRACE(T_INST, " NH\n");
if (*(int *)&ea < 0)
crs[dr*2] &= immu32;
else
crs[dr*2] &= get16(ea);
continue;
case 014:
TRACE(T_INST, " LHL2\n");
if (*(int *)&ea < 0)
crs[dr*2] = immu32 << 2;
else
crs[dr*2] = get16(ea) << 2;
continue;
case 015:
TRACE(T_INST, " SHA\n");
fatal("SHA not impl");
continue;
case 016: /* Special MR FP format */
/* DFA, DFST, FA, FST, PCL */
continue;
case 017:
fatal("I-mode opcode 017");
case 020:
fatal("I-mode generic class 1?");
case 021:
TRACE(T_INST, " ST\n");
if (*(int *)&ea < 0)
fatal("ST imm");
put32(crsl[dr],ea);
continue;
case 022:
TRACE(T_INST, " S\n");
fatal("S not impl");
continue;
case 023:
TRACE(T_INST, " O\n");
if (*(int *)&ea < 0)
crsl[dr] |= immu32;
else
crsl[dr] |= get32(ea);
continue;
case 024:
TRACE(T_INST, " ROT\n");
fatal("ROT not impl");
continue;
case 025:
fatal("I-mode opcode 025");
case 026: /* Special MR FP format */
/* DFM, DFS, FM, FS */
continue;
case 027:
fatal("I-mode opcode 027");
case 030: /* register generic */
switch (inst) {
}
continue;
case 031:
fatal("I-mode opcode 031");
case 032:
TRACE(T_INST, " SH\n");
continue;
case 033:
TRACE(T_INST, " OH\n");
if (*(int *)&ea < 0)
crs[dr*2] |= immu32;
else
crs[dr*2] |= get16(ea);
continue;
case 034:
TRACE(T_INST, " EIO\n");
pio(ea & 0xFFFF);
continue;
case 035:
TRACE(T_INST, " LHL3\n");
if (*(int *)&ea < 0)
crs[dr*2] = immu32 << 3;
else
crs[dr*2] = get16(ea) << 3;
continue;
case 036: /* Special MR FP format */
/* DFD, FD, QFAD, QFLD, QFSB, QFST */
continue;
case 037:
fatal("I-mode opcode 031");
case 040: /* generic class 2, overlays skip group */
fatal("I-mode generic class 2?");
case 041:
TRACE(T_INST, " I\n");
utempl = crsl[dr];
if (*(int *)&ea < 0) {
crsl[dr] = immu32;
crsl[(inst >> 2) & 7] = utempl;
} else {
crsl[dr] = get32(ea);
put32(utempl, ea);
}
continue;
case 042:
TRACE(T_INST, " M\n");
continue;
case 043:
TRACE(T_INST, " X\n");
if (*(int *)&ea < 0)
crsl[dr] ^= immu32;
else
crsl[dr] ^= get32(ea);
continue;
case 044:
TRACE(T_INST, " LDAR\n");
utempa = ea; /* word number portion only */
if (utempa & 040000) { /* absolute RF addressing */
RESTRICT();
utempa &= 0377;
if (utempa == 020)
crsl[dr] = 1;
else if (utempa == 024)
crsl[dr] = -1;
else
crsl[dr] = regs.u32[utempa];
} else {
utempa &= 037;
if (utempa > 017) RESTRICT();
crsl[dr] = *(((unsigned int *)crs)+utempa);
}
continue;
case 045:
TRACE(T_INST, " CCP/LCP\n");
continue;
case 046: /* I-mode special MR, GR format */
/* EALB, IM, QFC, QFDV, QFMP, TM */
continue;
case 047:
fatal("I-mode opcode 047");
case 050:
fatal("I-mode opcode 050");
case 051:
/* IH, STH */
continue;
case 052:
TRACE(T_INST, " MH\n");
continue;
case 053:
TRACE(T_INST, " XH\n");
if (*(int *)&ea < 0)
crs[dr*2] ^= immu32;
else
crs[dr*2] ^= get16(ea);
continue;
case 054:
TRACE(T_INST, " STAR\n");
utempa = ea; /* word number portion only */
if (utempa & 040000) { /* absolute RF addressing */
RESTRICT();
regs.u32[utempa & 0377] = crsl[dr];
} else {
utempa &= 037;
if (utempa > 017) RESTRICT();
*(((unsigned int *)crs)+utempa) = crsl[dr];
}
continue;
case 055:
/* ACP, SCC */
continue;
case 056: /* I-mode special MR, GR format */
/* EAXB, IMH, JMP, TMH */
continue;
case 057:
fatal("I-mode opcode 057");
case 060:
fatal("I-mode generic class 3?");
case 061:
TRACE(T_INST, " C\n");
continue;
case 062:
TRACE(T_INST, " D\n");
continue;
case 063:
TRACE(T_INST, " EAR\n");
crsl[dr] = ea;
continue;
case 064:
fatal("I-mode opcode 064");
case 065:
TRACE(T_INST, " LIP\n");
crsl[dr] = get32(ea);
if (crsl[dr] & 0x80000000)
fault(POINTERFAULT, crsl[dr]>>16, ea);
continue;
case 066: /* I-mode special MR */
/* DM, JSXB */
continue;
case 067:
fatal("I-mode opcode 067");
case 070:
fatal("I-mode opcode 067");
case 071:
TRACE(T_INST, " CH\n");
continue;
case 072:
TRACE(T_INST, " DH\n");
continue;
case 073:
TRACE(T_INST, " JSR\n");
crs[dr*2] = RPH;
RPH = ea;
continue;
case 074:
fatal("I-mode opcode 074");
case 075:
TRACE(T_INST, " AIP\n");
crsl[dr] += get32(ea);
if (crsl[dr] & 0x80000000)
fault(POINTERFAULT, crsl[dr]>>16, ea);
/* NOTE: ISG says C & L need to be set, ring needs to be weakened */
continue;
case 076:
/* DMH, TCNP */
continue;
case 077:
fatal("I-mode opcode 077");
}
fatal("I-mode fall-through?");
nonimode:
/* here for non-generic instructions: memory references or pio */
/* pio can only occur in S/R modes */
@@ -5657,12 +6036,9 @@ keys = 14200, modals=100177
ea = ea32r64r(earp, inst, x, &opcode);
break;
case 4<<10: /* 32I */
ea = ea32i(earp, inst, x);
warn("32I mode not supported");
fault(RESTRICTFAULT, 0, 0);
break;
fatal("32I mode invalid here");
case 6<<10: /* 64V */
ea = ea64v(earp, inst, x, &opcode, &eabit);
ea = ea64v(earp, inst, x, &opcode);
break;
default:
printf("Bad CPU mode in EA calculation, keys = %o\n", crs[KEYS]);

494
emdev.h
View File

@@ -2015,6 +2015,7 @@ int devamlc (int class, int func, int device) {
unsigned short dss; /* 1 bit per line */
unsigned short sockfd[16]; /* Unix socket fd, 1 per line */
unsigned short tstate[16]; /* terminal state (telnet) */
unsigned short room[16]; /* room (chars) left in input buffer */
} dc[64];
int lx;
@@ -2029,7 +2030,7 @@ int devamlc (int class, int func, int device) {
int fd;
unsigned int addrlen;
unsigned char buf[1024]; /* max size of DMQ buffer */
int i, n, nw, newdevice;
int i, n, n2, nw, newdevice;
fd_set fds;
struct timeval timeout;
unsigned char ch;
@@ -2217,11 +2218,25 @@ int devamlc (int class, int func, int device) {
devpoll[device] = AMLCPOLL*instpermsec; /* setup another poll */
IOSKIP;
} else if (func == 03) { /* set room in input buffer */
lx = (crs[A]>>12);
dc[device].room[lx] = crs[A] & 0xFFF;
//printf("OTA '03%02o: AMLC line %d, room=%d, A=0x%04x\n", device, lx, dc[device].room[lx], crs[A]);
IOSKIP;
} else if (func == 014) { /* set DMA/C channel (for input) */
dc[device].dmcchan = crs[A] & 0x7ff;
//printf("OTA '14%02o: AMLC chan = %o\n", device, dc[device].dmcchan);
if (!(crs[A] & 0x800))
fatal("Can't run AMLC in DMA mode!");
#if 0
dmcea = dc[device].dmcchan;
dmcpair = get32r0(dmcea);
dmcbufbegea = dmcpair>>16;
dmcbufendea = dmcpair & 0xffff;
dmcnw = dmcbufendea - dmcbufbegea + 1;
printf("AMLC: dmcnw=%d\n", dmcnw);
#endif
IOSKIP;
} else if (func == 015) { /* set DMT/DMQ base address (for output) */
@@ -2269,6 +2284,7 @@ int devamlc (int class, int func, int device) {
dc[newdevice].dss |= bitmask16[lx+1];
dc[newdevice].sockfd[lx] = fd;
dc[newdevice].tstate[lx] = TS_DATA;
dc[newdevice].room[lx] = 64;
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, newdevice, lx);
break;
}
@@ -2302,16 +2318,18 @@ int devamlc (int class, int func, int device) {
buf[4] = 251; /* will */
buf[5] = 3; /* supress go ahead */
buf[6] = 255; /* IAC */
buf[7] = 251; /* will */
buf[7] = 253; /* do */
buf[8] = 0; /* binary mode */
write(fd, buf, 9);
strcpy((void *)buf,"\
\r\n\
Welcome to the Prime Computer 50-series emulator, running Primos rev 19.2!\r\n\
After logging in, use the Prime HELP command for assistance.\r\n\
You are welcome to create a directory under GUEST for your files.\r\n\
To report bugs or contact the author, send email to prirun@gmail.com\r\n\
Enjoy your time travels! -Jim Wilcoxson\r\n\
\n\
After logging in, use the Prime HELP command for assistance.\r\n\
You are welcome to create a directory under GUEST for your files.\r\n\
To report bugs or contact the author, send email to prirun@gmail.com\r\n\
\n\
Enjoy your time travels! -Jim Wilcoxson aka JIMMY\r\n\
\r\n\
Login please.\r\n\
OK, ");
@@ -2319,27 +2337,27 @@ OK, ");
}
}
/* do a receive/transmit scan loop for every line. This loop is
fairly efficient because Primos turns off xmitenable on DMQ
lines after a short time w/o any output. */
/* do a transmit scan loop for every line. This loop is fairly
efficient because Primos turns off xmitenable on DMQ lines
after a short time w/o any output.
if (dc[device].xmitenabled != 0 || dc[device].dss != 0) {
NOTE: it's important to do xmit processing even if a line is
not currently connected, to drain the tty output buffer.
Otherwise, the DMQ buffer fills, this stalls the tty output
buffer, and when the next connection occurs on this line, the
output buffer from the previous terminal session will then be
displayed to the new user. */
if (dc[device].dss || dc[device].xmitenabled) {
for (lx = 0; lx < 16; lx++) {
/* Transmit is first. Lots of opportunity to optimize this:
rather than using the rtq instruction, do a mapva call to
access the qcb directly, pack the queue data to a buffer,
attempt to write the buffer to the socket, and then update
the qcb to reflect how many bytes were actually written.
This would avoid lots of get16/mapva calls and the write
select could be removed.
NOTE: it's important to do xmit processing even if a line
is not currently connected, to drain the tty output buffer.
Otherwise, the DMQ buffer fills, this stalls the tty output
buffer, and when the next connection occurs on this line,
the output buffer from the previous terminal session will
then be displayed to the new user. */
/* Lots of opportunity to optimize transmits: rather than
using the rtq instruction, do a mapva call to access the
qcb directly, pack the queue data to a buffer, attempt to
write the buffer to the socket, and then update the qcb to
reflect how many bytes were actually written. This would
avoid lots of get16/mapva calls and the write select could
be removed. */
if (dc[device].xmitenabled & bitmask16[lx+1]) {
n = 0;
@@ -2383,10 +2401,10 @@ OK, ");
the AMLC device is configured as a QAMLC */
}
/* NOTE: on a partial write, terminal data is lost. The best
option would be to find out how much room is left in the
socket buffer and only remove that many characters from the
queue in the loop above.
/* NOTE: on a partial write, data sent to the terminal is
lost. The best option would be to find out how much room
is left in the socket buffer and only remove that many
characters from the queue in the loop above.
Mac OSX write selects on sockets will only return true if
there are SO_SNDLOWAT (defaults to 1024) bytes available in
@@ -2402,112 +2420,132 @@ OK, ");
fprintf(stderr," %d bytes written, but %d bytes sent\n", n, nw);
}
}
}
}
/* process input, but only as much as will fit into the DMC buffer.
NOTE: because the size of the AMLC tumble tables is limited, this
could pose a denial of service issue. Input should probably be
processed in a round to be more fair with this limited resource.
/* process input, but only as much as will fit into the DMC
buffer. NOTE: because the size of the AMLC tumble tables is
limited, this could pose a denial of service issue. Input
should probably be processed in a round to be more fair with
this limited resource, or the tumble table space could be
apportioned for each connected line or each line with data
waiting to be read.
The AMLC tumble tables should never overflow, because we only
read as many characters from the socket buffers as will fit in
the tumble tables. */
The AMLC tumble tables should never overflow, because we only
read as many characters from the socket buffers as will fit in
the tumble tables. However, the tty line buffers may overflow,
causing data from the terminal to be dropped. To help avoid
this, a new OTA "set room left" has been implemented. If there
is no room left in the tty input buffer, don't read any more
characters from the socket for that line. */
if ((dc[device].dss & dc[device].recvenabled & bitmask16[lx+1]) && !dc[device].eor) {
if (dc[device].bufnum)
dmcea = dc[device].dmcchan ^ 2;
else
dmcea = dc[device].dmcchan;
dmcpair = get32r0(dmcea);
dmcbufbegea = dmcpair>>16;
dmcbufendea = dmcpair & 0xffff;
dmcnw = dmcbufendea - dmcbufbegea + 1;
if (dmcnw <= 0)
continue;
if (dmcnw > sizeof(buf))
dmcnw = sizeof(buf);
while ((n = read(dc[device].sockfd[lx], buf, dmcnw)) == -1 && errno == EINTR)
if (!dc[device].eor) {
if (dc[device].bufnum)
dmcea = dc[device].dmcchan ^ 2;
else
dmcea = dc[device].dmcchan;
dmcpair = get32r0(dmcea);
dmcbufbegea = dmcpair>>16;
dmcbufendea = dmcpair & 0xffff;
dmcnw = dmcbufendea - dmcbufbegea + 1;
for (lx = 0; lx < 16 && dmcnw > 0; lx++) {
if (!(dc[device].dss & dc[device].recvenabled & bitmask16[lx+1])
|| dc[device].room[lx] < 8)
continue;
/* dmcnw is the # of characters left in the dmc buffer, but
there may be further size/space restrictions for this line */
n2 = dmcnw;
if (n2 > sizeof(buf))
n2 = sizeof(buf);
if (n2 > dc[device].room[lx])
n2 = dc[device].room[lx];
while ((n = read(dc[device].sockfd[lx], buf, n2)) == -1 && errno == EINTR)
;
//printf("processing recv on device %o, line %d, b#=%d, n2=%d, n=%d\n", device, lx, dc[device].bufnum, n2, n);
/* zero length read means the socket has been closed */
if (n == 0) {
n = -1;
errno = EPIPE;
}
if (n == -1) {
n = 0;
if (errno == EAGAIN || errno == EWOULDBLOCK)
;
//printf("processing recv on device %o, line %d, b#=%d, dmcnw=%d, n=%d\n", device, lx, dc[device].bufnum, dmcnw, n);
else if (errno == EPIPE || errno == ECONNRESET) {
/* zero length read means the socket has been closed */
if (n == 0) {
n = -1;
errno = EPIPE;
}
if (n == -1) {
n = 0;
if (errno == EAGAIN || errno == EWOULDBLOCK)
;
else if (errno == EPIPE || errno == ECONNRESET) {
/* see similar code above */
close(dc[device].sockfd[lx]);
dc[device].dss &= ~bitmask16[lx+1];
//printf("em: closing AMLC line %d on device '%o\n", lx, device);
} else {
perror("Reading AMLC");
}
}
/* very primitive support here for telnet - only enough to
ignore commands sent by the telnet client. Telnet
commands could be split across reads and AMLC interrupts,
so a small state machine is used for each line */
if (n > 0) {
state = dc[device].tstate[lx];
for (i=0; i<n; i++) {
ch = buf[i];
switch (state) {
case TS_DATA:
if (ch == 255)
state = TS_IAC;
else if (ch != 0) {
storech:
utempa = lx<<12 | 0x0200 | ch;
put16r0(utempa, dmcbufbegea);
//printf("******* stored character %o (%c) at %o\n", utempa, utempa&0x7f, dmcbufbegea);
dmcbufbegea = INCVA(dmcbufbegea, 1);
}
break;
case TS_IAC:
switch (ch) {
case 255:
state = TS_DATA;
goto storech;
case 251: /* will */
case 252: /* won't */
case 253: /* do */
case 254: /* don't */
state = TS_OPTION;
break;
case 250: /* begin suboption */
state = TS_SUBOPT;
break;
default: /* ignore other chars after IAC */
state = TS_DATA;
}
break;
case TS_SUBOPT:
if (ch == 255)
state = TS_IAC;
break;
case TS_OPTION:
default:
state = TS_DATA;
}
}
dc[device].tstate[lx] = state;
if (dmcbufbegea-1 > dmcbufendea)
fatal("AMLC tumble table overflowed?");
put16r0(dmcbufbegea, dmcea);
if (dmcbufbegea > dmcbufendea) { /* end of range has occurred */
dc[device].bufnum = 1-dc[device].bufnum;
dc[device].eor = 1;
}
/* see similar code above */
close(dc[device].sockfd[lx]);
dc[device].dss &= ~bitmask16[lx+1];
//printf("em: closing AMLC line %d on device '%o\n", lx, device);
} else {
perror("Reading AMLC");
}
}
/* very primitive support here for telnet - only enough to
ignore commands sent by the telnet client. Telnet
commands could be split across reads and AMLC interrupts,
so a small state machine is used for each line */
if (n > 0) {
state = dc[device].tstate[lx];
for (i=0; i<n; i++) {
ch = buf[i];
switch (state) {
case TS_DATA:
if (ch == 255)
state = TS_IAC;
else {
storech:
utempa = lx<<12 | 0x0200 | ch;
put16r0(utempa, dmcbufbegea);
//printf("******* stored character %o (%c) at %o\n", utempa, utempa&0x7f, dmcbufbegea);
dmcbufbegea = INCVA(dmcbufbegea, 1);
dmcnw--;
}
break;
case TS_IAC:
switch (ch) {
case 255:
state = TS_DATA;
goto storech;
case 251: /* will */
case 252: /* won't */
case 253: /* do */
case 254: /* don't */
state = TS_OPTION;
break;
case 250: /* begin suboption */
state = TS_SUBOPT;
break;
default: /* ignore other chars after IAC */
state = TS_DATA;
}
break;
case TS_SUBOPT:
if (ch == 255)
state = TS_IAC;
break;
case TS_OPTION:
default:
state = TS_DATA;
}
}
dc[device].tstate[lx] = state;
}
}
if (dmcbufbegea-1 > dmcbufendea)
fatal("AMLC tumble table overflowed?");
put16r0(dmcbufbegea, dmcea);
if (dmcbufbegea > dmcbufendea) { /* end of range has occurred */
dc[device].bufnum = 1-dc[device].bufnum;
dc[device].eor = 1;
}
}
@@ -2529,7 +2567,7 @@ storech:
NOTE: there is always at least one board with ctinterrupt set
(the last board), so it will always be polling and checking
for new incoming connections */
for new incoming connections and incoming data */
if ((dc[device].ctinterrupt || dc[device].xmitenabled || (dc[device].recvenabled & dc[device].dss)) && devpoll[device] == 0)
devpoll[device] = AMLCPOLL*instpermsec; /* setup another poll */
@@ -2695,6 +2733,8 @@ storech:
int devpnc (int class, int func, int device) {
#if 0
#define PNCPOLL 100
/* PNC controller status bits */
@@ -2706,6 +2746,15 @@ int devpnc (int class, int func, int device) {
#define PNCTWOTOKENS 0x200 /* bit 7, only set after xmit EOR */
#define PNCTOKDETECT 0x100 /* bit 8, only set after xmit EOR */
/* xmit/recv states */
#define XR_IDLE 0 /* initial state: no xmit or recv */
#define XR_READY 1 /* ready to recv or xmit */
#define XR_XFER 3 /* transferring data over socket */
#define MINCONNTIME 30 /* wait 30 seconds between connect attempts */
#define MAXPKTBYTES 2048 /* max of 2048 byte packets */
static short configured = 0; /* true if PNC configured */
static unsigned short pncstat; /* controller status word */
static unsigned short recvstat; /* receive status word */
@@ -2725,6 +2774,7 @@ int devpnc (int class, int func, int device) {
short port; /* emulator network port on the remote node */
short myremid; /* my node ID on the remote node's ring network */
short yourremid; /* remote node's id on its own network */
time_t conntime; /* time of last connect request */
} ni[256];
/* array to map socket fd's to local node id's for accessing the ni
@@ -2735,14 +2785,18 @@ int devpnc (int class, int func, int device) {
static short fdnimap[FDMAPSIZE];
typedef struct {
short state, offset;
unsigned short dmachan, dmareg, dmaaddr;
short dmanw, toid, fromid, remtoid, remfromid;
unsigned short *iobufp;
short dmanw, dmabytesleft, toid, fromid, remtoid, remfromid;
unsigned char iobuf[MAXPKTBYTES+2];
} t_dma;
static t_dma recv, xmit;
short i;
unsigned short access, dmaword, dmaword1, dmaword2;
unsigned short access, dmaword;
unsigned short *iobufp;
time_t timenow;
struct hostent* server;
struct sockaddr_in addr;
int fd, optval, fdflags;
@@ -2779,6 +2833,8 @@ int devpnc (int class, int func, int device) {
ni[i].myremid = 0;
ni[i].yourremid = 0;
}
xmit.state = XR_IDLE;
recv.state = XR_IDLE;
myid = 0; /* set an invalid node id */
/* read the ring.cfg config file. Each line contains:
@@ -2896,6 +2952,8 @@ int devpnc (int class, int func, int device) {
ni[i].fd = -1;
}
}
xmit.state = XR_IDLE;
recv.state = XR_IDLE;
pncstat &= ~PNCCONNECTED;
/* OCP '0701 - connect
@@ -2951,6 +3009,7 @@ int devpnc (int class, int func, int device) {
pncstat &= ~PNCXMITINT; /* clear "xmit interrupting" */
pncstat &= ~PNCTOKDETECT; /* clear "token detected" */
xmitstat = 0;
xmit.state = XR_IDLE;
} else if (func == 05) { /* set PNC into "delay" mode */
TRACE(T_INST|T_RIO, " OCP '%02o%02o - set delay mode\n", func, device);
@@ -2958,6 +3017,7 @@ int devpnc (int class, int func, int device) {
} else if (func == 010) { /* stop xmit in progress */
TRACE(T_INST|T_RIO, " OCP '%02o%02o - stop xmit\n", func, device);
xmitstat = 0;
xmit.state = XR_IDLE;
} else if (func == 011) { /* dunno what this is - rev 20 startup */
TRACE(T_INST|T_RIO, " OCP '%02o%02o - unknown\n", func, device);
@@ -2975,6 +3035,7 @@ int devpnc (int class, int func, int device) {
TRACE(T_INST|T_RIO, " OCP '%02o%02o - ack recv int\n", func, device);
pncstat &= ~PNCRCVINT;
recvstat = 0;
recv.active = 0;
} else if (func == 015) { /* set interrupt mask (enable int) */
TRACE(T_INST|T_RIO, " OCP '%02o%02o - enable interrupts\n", func, device);
@@ -2991,6 +3052,8 @@ int devpnc (int class, int func, int device) {
xmitstat = 0;
pncvec = 0;
enabled = 0;
xmit.state = XR_IDLE;
recv.state = XR_IDLE;
} else {
printf("Unimplemented OCP device '%02o function '%02o\n", device, func);
@@ -3055,11 +3118,17 @@ int devpnc (int class, int func, int device) {
recv.dmanw = -((recv.dmanw>>4) ^ 0xF000);
recv.dmaaddr = regs.sym.regdmx[recv.dmareg+1];
recv.iobufp = mem + mapva(recv.dmaaddr, WACC, &access, 0);
recv.state = XR_READY;
recv.offset = -1; /* initialize for new packet */
TRACE(T_INST|T_RIO, " recv: dmachan=%o, dmareg=%o, dmaaddr=%o, dmanw=%d\n", recv.dmachan, recv.dmareg, recv.dmaaddr, recv.dmanw);
devpoll[device] = 10;
IOSKIP;
} else if (func == 015) { /* initiate xmit, dma chan in A */
if (xmitstat & 0x0040) { /* already busy? */
warn("pnc: xmit when already busy!");
return; /* yes, return and don't skip */
}
xmitstat = 0x0040; /* set xmit busy */
xmit.dmachan = crs[A];
xmit.dmareg = xmit.dmachan<<1;
@@ -3071,41 +3140,53 @@ int devpnc (int class, int func, int device) {
xmit.dmaaddr = regs.sym.regdmx[xmit.dmareg+1];
TRACE(T_INST|T_RIO, " xmit: dmachan=%o, dmareg=%o, dmaaddr=%o, dmanw=%d\n", xmit.dmachan, xmit.dmareg, xmit.dmaaddr, xmit.dmanw);
/* PNC transmit:
NOTE: most of this stuff needs to be moved to poll, because
it may not be possible to start/complete a transmit here!
get a physical pointer to the xmit buffer, which can't cross
a page boundary, then xmit the buffer. Since PNC packets
have a specific size of either 512, 1024, or 2048 bytes, and
we're using a byte-stream for communication, 2 extra header
bytes are sent with the packet length (in words), to let the
other end know how big the packet is.
*/
xmit.iobufp = mem + mapva(xmit.dmaaddr, RACC, &access, 0);
/* read the first word, the to and from node id's, and map them
to the remote hosts' expected to and from node id's */
xmit.iobufp = mem + mapva(xmit.dmaaddr, RACC, &access, 0);
dmaword = *xmit.iobufp++;
xmit.toid = dmaword >> 8;
xmit.fromid = dmaword & 0xFF;
TRACE(T_INST|T_RIO, " xmit: dmaword = '%o/%d [%03o %03o]\n", dmaword, *(short *)&dmaword, dmaword>>8, dmaword&0xff);
TRACE(T_INST|T_RIO, " xmit: toid=%d, fromid=%d\n", xmit.toid, xmit.fromid);
/* broadcast packets are "I am up" msgs and are simply "eaten"
here, as this is handled later in the devpnc poll code.
XXX: should check that this really is the "I am up" msg */
/* broadcast packets are "I am up" msgs and are simply discarded
here, with a succesful transmit status. Node up/down is
handled in the devpnc poll code.
XXX: should check that this really is the "I am up" msg */
if (xmit.toid == 255) {
regs.sym.regdmx[xmit.dmareg+1] += xmit.dmanw; /* bump xmit address */
regs.sym.regdmx[xmit.dmareg] += xmit.dmanw; /* and count */
goto xmitdone;
goto xmitdone1;
}
/* check for errors, then map to and from node id to remote to
and from node id */
/* if this xmit is to me and there is a new receive pending and
there is room left in the receive buffer, put the packet
directly in my receive buffer. If we can't receive it now,
set NACK xmit and receive status. If the packet is not to
me, copy it to the xmit.iobuf and add the header */
if (xmit.toid == myid) {
if (recv.state == XR_READY && recv.dmanw >= xmit.dmanw) {
memcpy(recv.iobufp, xmit.iobufp, xmit.dmanw*2);
regs.sym.regdmx[recv.dmareg] += xmit.dmanw; /* bump recv count */
regs.sym.regdmx[recv.dmareg+1] += xmit.dmanw; /* and address */
pncstat |= 0x8000; /* set recv interrupt too */
recv.state = XR_IDLE; /* no longer ready to recv */
xmitdone1:
regs.sym.regdmx[xmit.dmareg] += xmit.dmanw; /* and xmit count */
regs.sym.regdmx[xmit.dmareg+1] += xmit.dmanw; /* and address */
pncstat |= 0x4100; /* set xmit interrupt + token */
xmitstat |= 0x8000; /* set ACK xmit status */
goto xmitdone;
} else {
xmitstat |= 0x1000; /* set xmit NACK status */
recvstat |= 0x20; /* set recv premature EOR */
}
}
/* check for unreasonable situations */
if (xmit.toid == 0)
fatal("PNC: xmit.toid is zero");
@@ -3116,49 +3197,18 @@ int devpnc (int class, int func, int device) {
fatal(NULL);
}
/* map local to and from node id to remote to and from node id */
if (ni[xmit.fromid].myremid > 0)
xmit.remfromid = ni[xmit.fromid].myremid;
else
xmit.remfromid = myid;
xmit.remtoid = ni[xmit.toid].yourremid;
dmaword1 = (xmit.remtoid << 8) | xmit.remfromid;
for (i=0; i < xmit.dmanw; i++) {
if (i == 0)
dmaword = dmaword1;
else
dmaword = *xmit.iobufp++;
TRACE(T_INST|T_RIO, " xmit: word %d = '%o/%d [%03o %03o]\n", i, dmaword, *(short *)&dmaword, dmaword>>8, dmaword&0xff);
/* if this xmit is local and there is a receive pending and there is
room left in the receive buffer, put the word directly in my
receive buffer. If it's local but we can't receive it, set
NACK xmit and receive status */
if (xmit.toid == myid) {
if ((recvstat & 0x0040) && regs.sym.regdmx[recv.dmareg]) {
*recv.iobufp++ = dmaword;
regs.sym.regdmx[recv.dmareg]++; /* bump count */
regs.sym.regdmx[recv.dmareg+1]++; /* bump address */
} else {
xmitstat |= 0x1000; /* set xmit NACK status */
recvstat |= 0x20; /* set recv premature EOR */
}
} else {
/* send remote over sockets */
}
regs.sym.regdmx[xmit.dmareg+1]++; /* bump xmit address */
regs.sym.regdmx[xmit.dmareg]++; /* and count */
}
xmit.state = XR_READY; /* xmit pending */
xmit.offset = -1; /* initialize for new xmit */
devpoll[device] = 10;
xmitdone:
pncstat |= 0x4100; /* set xmit interrupt + token */
if (xmit.toid == myid)
pncstat |= 0x8000; /* set recv interrupt too */
if (xmitstat == 0x0040) /* complete w/o errors? */
xmitstat |= 0x8000; /* yes, set ACK xmit status */
devpoll[device] = PNCPOLL*instpermsec;
if (enabled && (pncstat & 0xC000))
if (intvec == -1)
intvec = pncvec;
@@ -3192,6 +3242,52 @@ xmitdone:
case 4:
TRACE(T_INST|T_RIO, " POLL '%02o%02o\n", func, device);
/* if a transmit is pending, start/continue it until completes */
if (xmit.state > XR_IDLE) {
if (ni[xmit.toid].fd == -1) { /* not connected yet */
if (time(&timenow) - ni[xmit.toid].conntime < MINCONNTIME) {
printf("em: waiting for connection timeout to node %d\n", xmit.toid);
goto xmiterr;
}
if ((ni[xmit.toid].fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror ("Unable to create socket");
exit(1);
}
server = gethostbyname(ni[xmit.toid].ip);
if (server == NULL) {
fprintf(stderr,"pnc: cannot resolve %s\n", ni[xmit.toid].ip);
close(ni[xmit.toid].fd);
ni[xmit.toid].fd = -1;
goto xmiterr;
}
ni[xmit.toid].conntime = timenow;
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&addr.sin_addr.s_addr, server->h_length);
addr.sin_port = htons(ni[xmit.toid].port);
if (connect(ni[xmit.toid].fd, (void *) &addr,(socklen_t) sizeof(addr)) < 0) {
perror("pnc: error connecting to server\n");
close(ni[xmit.toid].fd);
ni[xmit.toid].fd = -1;
goto xmiterr;
}
xmit.state = XR_XFER;
}
/* start/continue the transfer */
if (xmit.state == XR_XFER) {
if ((n=write(ni[xmit.toid].fd, xmit.iobuf[offset], xmit.dmabytes-xmit.offset)) < 0) {
perror("pnc: write error");
} else {
xmit.offset += n;
xmit.dmabytesleft -= n;
if (xmit.dmabytesleft == 0)
xmit.state = XR_IDLE;
}
}
#if 0
while ((fd = accept(pncfd, (struct sockaddr *)&addr, &addrlen)) == -1 && errno == EINTR)
;
@@ -3202,6 +3298,13 @@ xmitdone:
} else {
if (fd >= MAXFD)
fatal("New connection fd is too big");
printf("New PNC connection:\n");
/*
- new connect request came in
- scan host table to find matching IP
- how to figure out when one IP has multiple emulators? port?
- if already connected, display warning error and ignore
newdevice = 0;
for (i=0; devices[i] && !newdevice && i<MAXBOARDS; i++)
for (lx=0; lx<16; lx++)
@@ -3219,6 +3322,11 @@ xmitdone:
write(fd, "\rAll AMLC lines are in use!\r\n", 29);
close(fd);
}
xmitdone:
if (xmitstat == 0x0040) { /* complete w/o errors? */
pncstat |= 0x4100; /* set xmit interrupt + token */
xmitstat |= 0x8000; /* yes, set ACK xmit status */
}
#endif
devpoll[device] = PNCPOLL*instpermsec;
@@ -3226,5 +3334,7 @@ xmitdone:
default:
fatal("Bad func in devpcn");
}
#else
return -1;
#endif
}

7
regs.h
View File

@@ -80,10 +80,9 @@
#define FLR0 9
#define FAR1 10
#define FLR1 11
#define FAC0H 8
#define FAC0L 9
#define FAC1H 10
#define FAC1L 11
#define FAC0 8
#define FAC1 10
#define BR 12
union {
int rs[REGSETS][32];