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:
113
ea32i.h
Normal file
113
ea32i.h
Normal 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
|
||||
}
|
||||
9
ea64v.h
9
ea64v.h
@@ -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
784
em.c
@@ -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
494
emdev.h
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user