3b2: NI 10Base5 Ethernet Device

- Implements an Ethernet device ("NI", for "Network Interface")
    for the 3B2 simulator.
This commit is contained in:
Seth Morabito 2019-03-09 10:44:52 -08:00
parent 4b82a90c43
commit b0a4fb443c
12 changed files with 1859 additions and 122 deletions

View file

@ -170,9 +170,10 @@ static DEBTAB cpu_deb_tab[] = {
{ "INIT", INIT_MSG, "Initialization" }, { "INIT", INIT_MSG, "Initialization" },
{ "IRQ", IRQ_MSG, "Interrupt Handling" }, { "IRQ", IRQ_MSG, "Interrupt Handling" },
{ "IO", IO_DBG, "I/O Dispatch" }, { "IO", IO_DBG, "I/O Dispatch" },
{ "CIO", CIO_DBG, "Common I/O Interface" },
{ "TRACE", TRACE_DBG, "Call Trace" }, { "TRACE", TRACE_DBG, "Call Trace" },
{ "ERROR", ERR_MSG, "Error" }, { "ERROR", ERR_MSG, "Error" },
{ NULL, 0 } { NULL, 0, NULL }
}; };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK|UNIT_IDLE, MAXMEMSIZE) }; UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK|UNIT_IDLE, MAXMEMSIZE) };
@ -180,9 +181,13 @@ UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK|UNIT_IDLE, MAXMEMSIZE) };
#define UNIT_V_EXHALT (UNIT_V_UF + 0) /* halt to console */ #define UNIT_V_EXHALT (UNIT_V_UF + 0) /* halt to console */
#define UNIT_EXHALT (1u << UNIT_V_EXHALT) #define UNIT_EXHALT (1u << UNIT_V_EXHALT)
/*
* TODO: This works fine for now, but the moment we want to emulate
* SCSI (0x0100) or EPORTS (0x0102) we're in trouble!
*/
const char *cio_names[8] = { const char *cio_names[8] = {
"", "*VOID*", "*VOID*", "PORTS", "", "SBD", "NI", "PORTS",
"*VOID*", "CTC", "*VOID*", "*VOID*" "*VOID*", "CTC", "NAU", "*VOID*"
}; };
MTAB cpu_mod[] = { MTAB cpu_mod[] = {
@ -1821,9 +1826,9 @@ t_stat sim_instr(void)
if (cio[i].intr && if (cio[i].intr &&
cio[i].ipl == cpu_int_ipl && cio[i].ipl == cpu_int_ipl &&
cio[i].ivec == cpu_int_vec) { cio[i].ivec == cpu_int_vec) {
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[%08x] [IRQ] Handling CIO interrupt for card %d\n", "[%08x] [IRQ] Handling CIO interrupt for card %d ivec=%02x\n",
R[NUM_PC], i); R[NUM_PC], i, cpu_int_vec);
cio[i].intr = FALSE; cio[i].intr = FALSE;
} }

View file

@ -77,6 +77,12 @@ noret __libc_longjmp (jmp_buf buf, int val);
#define HALF_MASK 0xffffu #define HALF_MASK 0xffffu
#define BYTE_MASK 0xff #define BYTE_MASK 0xff
/*
* Custom t_stat
*/
#define SCPE_PEND (SCPE_OK + 1) /* CIO job already pending */
#define SCPE_NOJOB (SCPE_OK + 2) /* No CIO job on the request queue */
/* /*
* *
* Physical memory in the 3B2 is arranged as follows: * Physical memory in the 3B2 is arranged as follows:
@ -141,15 +147,19 @@ noret __libc_longjmp (jmp_buf buf, int val);
#define C_STACK_FAULT 9 #define C_STACK_FAULT 9
/* Debug flags */ /* Debug flags */
#define READ_MSG 0x001 #define READ_MSG 0x0001
#define WRITE_MSG 0x002 #define WRITE_MSG 0x0002
#define DECODE_MSG 0x004 #define DECODE_MSG 0x0004
#define EXECUTE_MSG 0x008 #define EXECUTE_MSG 0x0008
#define INIT_MSG 0x010 #define INIT_MSG 0x0010
#define IRQ_MSG 0x020 #define IRQ_MSG 0x0020
#define IO_DBG 0x040 #define IO_DBG 0x0040
#define TRACE_DBG 0x080 #define CIO_DBG 0x0080
#define ERR_MSG 0x100 #define TRACE_DBG 0x0100
#define CALL_DBG 0x0200
#define PKT_DBG 0x0400
#define ERR_MSG 0x0800
#define CACHE_DBG 0x1000
/* Data types operated on by instructions. NB: These integer values /* Data types operated on by instructions. NB: These integer values
have meaning when decoding instructions, so this is not just an have meaning when decoding instructions, so this is not just an

View file

@ -171,12 +171,10 @@ t_stat if_detach(UNIT *uptr)
uint32 if_read(uint32 pa, size_t size) { uint32 if_read(uint32 pa, size_t size) {
uint8 reg, data; uint8 reg, data;
uint32 pc;
UNIT *uptr; UNIT *uptr;
uptr = &(if_dev.units[0]); uptr = &(if_dev.units[0]);
reg = (uint8)(pa - IFBASE); reg = (uint8)(pa - IFBASE);
pc = R[NUM_PC];
switch (reg) { switch (reg) {
case IF_STATUS_REG: case IF_STATUS_REG:

View file

@ -56,6 +56,7 @@ void cio_clear(uint8 cid)
cio[cid].id = 0; cio[cid].id = 0;
cio[cid].exp_handler = NULL; cio[cid].exp_handler = NULL;
cio[cid].full_handler = NULL; cio[cid].full_handler = NULL;
cio[cid].reset_handler = NULL;
cio[cid].sysgen = NULL; cio[cid].sysgen = NULL;
cio[cid].rqp = 0; cio[cid].rqp = 0;
cio[cid].cqp = 0; cio[cid].cqp = 0;
@ -101,7 +102,7 @@ void cio_sysgen(uint8 cid)
sysgen_p = pread_w(SYSGEN_PTR); sysgen_p = pread_w(SYSGEN_PTR);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[%08x] [SYSGEN] Starting sysgen for card %d. sysgen_p=%08x\n", "[%08x] [SYSGEN] Starting sysgen for card %d. sysgen_p=%08x\n",
R[NUM_PC], cid, sysgen_p); R[NUM_PC], cid, sysgen_p);
@ -115,22 +116,22 @@ void cio_sysgen(uint8 cid)
cio[cid].ivec = pread_b(sysgen_p + 10); cio[cid].ivec = pread_b(sysgen_p + 10);
cio[cid].no_rque = pread_b(sysgen_p + 11); cio[cid].no_rque = pread_b(sysgen_p + 11);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen rqp = %08x\n", "[SYSGEN] sysgen rqp = %08x\n",
cio[cid].rqp); cio[cid].rqp);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen cqp = %08x\n", "[SYSGEN] sysgen cqp = %08x\n",
cio[cid].cqp); cio[cid].cqp);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen rqs = %02x\n", "[SYSGEN] sysgen rqs = %02x\n",
cio[cid].rqs); cio[cid].rqs);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen cqs = %02x\n", "[SYSGEN] sysgen cqs = %02x\n",
cio[cid].cqs); cio[cid].cqs);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen ivec = %02x\n", "[SYSGEN] sysgen ivec = %02x\n",
cio[cid].ivec); cio[cid].ivec);
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[SYSGEN] sysgen no_rque = %02x\n", "[SYSGEN] sysgen no_rque = %02x\n",
cio[cid].no_rque); cio[cid].no_rque);
@ -138,20 +139,19 @@ void cio_sysgen(uint8 cid)
if (cio[cid].sysgen != NULL) { if (cio[cid].sysgen != NULL) {
cio[cid].sysgen(cid); cio[cid].sysgen(cid);
} else { } else {
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[%08x] [cio_sysgen] Not running custom sysgen.\n", "[%08x] [cio_sysgen] Not running custom sysgen.\n",
R[NUM_PC]); R[NUM_PC]);
} }
} }
void cio_cexpress(uint8 cid, uint16 esize, cio_entry *cqe, uint8 *app_data) void cio_cexpress(uint8 cid, uint32 esize, cio_entry *cqe, uint8 *app_data)
{ {
int32 i; uint32 i, cqp;
uint32 cqp;
cqp = cio[cid].cqp; cqp = cio[cid].cqp;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[%08x] [cio_cexpress] cqp = %08x seqbit = %d\n", "[%08x] [cio_cexpress] cqp = %08x seqbit = %d\n",
R[NUM_PC], cqp, cio[cid].seqbit); R[NUM_PC], cqp, cio[cid].seqbit);
@ -170,12 +170,11 @@ void cio_cexpress(uint8 cid, uint16 esize, cio_entry *cqe, uint8 *app_data)
} }
} }
void cio_cqueue(uint8 cid, uint8 cmd_stat, uint16 esize, void cio_cqueue(uint8 cid, uint8 cmd_stat, uint32 esize,
cio_entry *cqe, uint8 *app_data) cio_entry *cqe, uint8 *app_data)
{ {
int32 i; uint32 i, cqp, top;
uint32 cqp, top; uint16 lp;
uint16 lp, ulp;
/* Apply the CMD/STAT bit */ /* Apply the CMD/STAT bit */
cqe->subdevice |= (cmd_stat << 7); cqe->subdevice |= (cmd_stat << 7);
@ -191,7 +190,6 @@ void cio_cqueue(uint8 cid, uint8 cmd_stat, uint16 esize,
/* Get the load pointer. This is a 16-bit absolute offset /* Get the load pointer. This is a 16-bit absolute offset
* from the top of the queue to the start of the entry. */ * from the top of the queue to the start of the entry. */
lp = pread_h(cqp + esize); lp = pread_h(cqp + esize);
ulp = pread_h(cqp + esize + 2);
/* Load the entry at the supplied address */ /* Load the entry at the supplied address */
pwrite_h(top + lp, cqe->byte_count); pwrite_h(top + lp, cqe->byte_count);
@ -209,22 +207,17 @@ void cio_cqueue(uint8 cid, uint8 cmd_stat, uint16 esize,
* start of the queue */ * start of the queue */
if (cio[cid].cqs > 0) { if (cio[cid].cqs > 0) {
lp = (lp + esize) % (esize * cio[cid].cqs); lp = (lp + esize) % (esize * cio[cid].cqs);
/* Store it back to the correct location */ /* Store it back to the correct location */
pwrite_h(cqp + esize, lp); pwrite_h(cqp + esize, lp);
} else {
sim_debug(IO_DBG, &cpu_dev,
"[%08x] [cio_cqueue] ERROR! Completion Queue Size is 0!",
R[NUM_PC]);
} }
} }
/* /*
* Retrieve the Express Entry from the Request Queue * Retrieve the Express Entry from the Request Queue
*/ */
void cio_rexpress(uint8 cid, uint16 esize, cio_entry *rqe, uint8 *app_data) void cio_rexpress(uint8 cid, uint32 esize, cio_entry *rqe, uint8 *app_data)
{ {
int32 i; uint32 i;
uint32 rqp; uint32 rqp;
rqp = cio[cid].rqp; rqp = cio[cid].rqp;
@ -247,12 +240,12 @@ void cio_rexpress(uint8 cid, uint16 esize, cio_entry *rqe, uint8 *app_data)
* be serviced. * be serviced.
* *
* Returns SCPE_OK on success, or SCPE_NXM if no entry was found. * Returns SCPE_OK on success, or SCPE_NXM if no entry was found.
*
*/ */
t_stat cio_rqueue(uint8 cid, uint8 qnum, uint16 esize, t_stat cio_rqueue(uint8 cid, uint32 qnum, uint32 esize,
cio_entry *rqe, uint8 *app_data) cio_entry *rqe, uint8 *app_data)
{ {
int32 i; uint32 i, rqp, top;
uint32 rqp, top;
uint16 lp, ulp; uint16 lp, ulp;
/* Get the physical address of the request queue in main memory */ /* Get the physical address of the request queue in main memory */
@ -263,6 +256,8 @@ t_stat cio_rqueue(uint8 cid, uint8 qnum, uint16 esize,
lp = pread_h(rqp); lp = pread_h(rqp);
ulp = pread_h(rqp + 2); ulp = pread_h(rqp + 2);
/* Check to see if the request queue is empty. If it is, there's
* nothing to take. */
if (lp == ulp) { if (lp == ulp) {
return SCPE_NXM; return SCPE_NXM;
} }
@ -294,7 +289,7 @@ t_stat cio_rqueue(uint8 cid, uint8 qnum, uint16 esize,
/* /*
* Return the Load Pointer for the given request queue * Return the Load Pointer for the given request queue
*/ */
uint16 cio_r_lp(uint8 cid, uint8 qnum, uint16 esize) uint16 cio_r_lp(uint8 cid, uint32 qnum, uint32 esize)
{ {
uint32 rqp; uint32 rqp;
@ -308,7 +303,7 @@ uint16 cio_r_lp(uint8 cid, uint8 qnum, uint16 esize)
/* /*
* Return the Unload Pointer for the given request queue * Return the Unload Pointer for the given request queue
*/ */
uint16 cio_r_ulp(uint8 cid, uint8 qnum, uint16 esize) uint16 cio_r_ulp(uint8 cid, uint32 qnum, uint32 esize)
{ {
uint32 rqp; uint32 rqp;
@ -319,14 +314,14 @@ uint16 cio_r_ulp(uint8 cid, uint8 qnum, uint16 esize)
return pread_h(rqp + 2); return pread_h(rqp + 2);
} }
uint16 cio_c_lp(uint8 cid, uint16 esize) uint16 cio_c_lp(uint8 cid, uint32 esize)
{ {
uint32 cqp; uint32 cqp;
cqp = cio[cid].cqp + esize; cqp = cio[cid].cqp + esize;
return pread_h(cqp); return pread_h(cqp);
} }
uint16 cio_c_ulp(uint8 cid, uint16 esize) uint16 cio_c_ulp(uint8 cid, uint32 esize)
{ {
uint32 cqp; uint32 cqp;
cqp = cio[cid].cqp + esize; cqp = cio[cid].cqp + esize;
@ -337,7 +332,7 @@ uint16 cio_c_ulp(uint8 cid, uint16 esize)
* Returns true if there is room in the completion queue * Returns true if there is room in the completion queue
* for a new entry. * for a new entry.
*/ */
t_bool cio_cqueue_avail(uint8 cid, uint16 esize) t_bool cio_cqueue_avail(uint8 cid, uint32 esize)
{ {
uint32 lp, ulp; uint32 lp, ulp;
@ -347,6 +342,21 @@ t_bool cio_cqueue_avail(uint8 cid, uint16 esize)
return(((lp + esize) % (cio[cid].cqs * esize)) != ulp); return(((lp + esize) % (cio[cid].cqs * esize)) != ulp);
} }
t_bool cio_rqueue_avail(uint8 cid, uint32 qnum, uint32 esize)
{
uint32 rqp, lp, ulp;
/* Get the physical address of the request queue in main memory */
rqp = cio[cid].rqp +
esize +
(qnum * (LUSIZE + (esize * cio[cid].rqs)));
lp = pread_h(rqp);
ulp = pread_h(rqp + 2);
return(lp != ulp);
}
uint32 io_read(uint32 pa, size_t size) uint32 io_read(uint32 pa, size_t size)
{ {
struct iolink *p; struct iolink *p;
@ -403,7 +413,7 @@ uint32 io_read(uint32 pa, size_t size)
case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */ case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */
case CIO_INT0: /* We've seen an INT0 but not an INT1. */ case CIO_INT0: /* We've seen an INT0 but not an INT1. */
cio[cid].sysgen_s |= CIO_INT0; cio[cid].sysgen_s |= CIO_INT0;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT0) ID\n", "[READ] [%08x] (%d INT0) ID\n",
R[NUM_PC], cid); R[NUM_PC], cid);
/* Return the correct byte of our board ID */ /* Return the correct byte of our board ID */
@ -415,7 +425,7 @@ uint32 io_read(uint32 pa, size_t size)
break; break;
case CIO_INT1: /* We've seen an INT1 but not an INT0. Time to sysgen */ case CIO_INT1: /* We've seen an INT1 but not an INT0. Time to sysgen */
cio[cid].sysgen_s |= CIO_INT0; cio[cid].sysgen_s |= CIO_INT0;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT0) SYSGEN\n", "[READ] [%08x] (%d INT0) SYSGEN\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio_sysgen(cid); cio_sysgen(cid);
@ -423,7 +433,7 @@ uint32 io_read(uint32 pa, size_t size)
break; break;
case CIO_SYSGEN: /* We've already sysgen'ed */ case CIO_SYSGEN: /* We've already sysgen'ed */
cio[cid].sysgen_s |= CIO_INT0; /* This must come BEFORE the exp_handler */ cio[cid].sysgen_s |= CIO_INT0; /* This must come BEFORE the exp_handler */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT0) EXPRESS JOB\n", "[READ] [%08x] (%d INT0) EXPRESS JOB\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].exp_handler(cid); cio[cid].exp_handler(cid);
@ -432,7 +442,7 @@ uint32 io_read(uint32 pa, size_t size)
default: default:
/* This should never happen */ /* This should never happen */
stop_reason = STOP_ERR; stop_reason = STOP_ERR;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT0) ERROR IN STATE MACHINE sysgen_s=%02x\n", "[READ] [%08x] (%d INT0) ERROR IN STATE MACHINE sysgen_s=%02x\n",
R[NUM_PC], cid, cio[cid].sysgen_s); R[NUM_PC], cid, cio[cid].sysgen_s);
data = 0; data = 0;
@ -445,20 +455,20 @@ uint32 io_read(uint32 pa, size_t size)
case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */ case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */
case CIO_INT1: /* We've seen an INT1 but not an INT0 */ case CIO_INT1: /* We've seen an INT1 but not an INT0 */
/* There's nothing to do in this instance */ /* There's nothing to do in this instance */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT1) IGNORED\n", "[READ] [%08x] (%d INT1) IGNORED\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; cio[cid].sysgen_s |= CIO_INT1;
break; break;
case CIO_INT0: /* We've seen an INT0 but not an INT1. Time to sysgen */ case CIO_INT0: /* We've seen an INT0 but not an INT1. Time to sysgen */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT1) SYSGEN\n", "[READ] [%08x] (%d INT1) SYSGEN\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; cio[cid].sysgen_s |= CIO_INT1;
cio_sysgen(cid); cio_sysgen(cid);
break; break;
case CIO_SYSGEN: /* We've already sysgen'ed */ case CIO_SYSGEN: /* We've already sysgen'ed */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT1) FULL\n", "[READ] [%08x] (%d INT1) FULL\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; /* This must come BEFORE the full handler */ cio[cid].sysgen_s |= CIO_INT1; /* This must come BEFORE the full handler */
@ -467,7 +477,7 @@ uint32 io_read(uint32 pa, size_t size)
default: default:
/* This should never happen */ /* This should never happen */
stop_reason = STOP_ERR; stop_reason = STOP_ERR;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d INT1) ERROR IN STATE MACHINE sysgen_s=%02x\n", "[READ] [%08x] (%d INT1) ERROR IN STATE MACHINE sysgen_s=%02x\n",
R[NUM_PC], cid, cio[cid].sysgen_s); R[NUM_PC], cid, cio[cid].sysgen_s);
break; break;
@ -475,15 +485,18 @@ uint32 io_read(uint32 pa, size_t size)
return 0; /* Data returned is arbitrary */ return 0; /* Data returned is arbitrary */
case IOF_STAT: case IOF_STAT:
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] (%d RESET)\n", "[READ] [%08x] (%d RESET)\n",
R[NUM_PC], cid); R[NUM_PC], cid);
if (cio[cid].reset_handler) {
cio[cid].reset_handler(cid);
}
cio[cid].sysgen_s = 0; cio[cid].sysgen_s = 0;
return 0; /* Data returned is arbitrary */ return 0; /* Data returned is arbitrary */
default: default:
/* We should never reach here, but if we do, there's /* We should never reach here, but if we do, there's
* nothing listening. */ * nothing listening. */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[READ] [%08x] No card at cid=%d reg=%d\n", "[READ] [%08x] No card at cid=%d reg=%d\n",
R[NUM_PC], cid, reg); R[NUM_PC], cid, reg);
csr_data |= CSRTIMO; csr_data |= CSRTIMO;
@ -520,7 +533,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
if (cio[cid].id == 0) { if (cio[cid].id == 0) {
/* Nothing lives here */ /* Nothing lives here */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] No card at cid=%d reg=%d\n", "[WRITE] [%08x] No card at cid=%d reg=%d\n",
R[NUM_PC], cid, reg); R[NUM_PC], cid, reg);
csr_data |= CSRTIMO; csr_data |= CSRTIMO;
@ -540,20 +553,20 @@ void io_write(uint32 pa, uint32 val, size_t size)
switch(cio[cid].sysgen_s) { switch(cio[cid].sysgen_s) {
case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */ case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */
case CIO_INT0: /* We've seen an INT0 but not an INT1. */ case CIO_INT0: /* We've seen an INT0 but not an INT1. */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT0) ID\n", "[WRITE] [%08x] (%d INT0) ID\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT0; cio[cid].sysgen_s |= CIO_INT0;
break; break;
case CIO_INT1: /* We've seen an INT1 but not an INT0. Time to sysgen */ case CIO_INT1: /* We've seen an INT1 but not an INT0. Time to sysgen */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT0) SYSGEN\n", "[WRITE] [%08x] (%d INT0) SYSGEN\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT0; cio[cid].sysgen_s |= CIO_INT0;
cio_sysgen(cid); cio_sysgen(cid);
break; break;
case CIO_SYSGEN: /* We've already sysgen'ed */ case CIO_SYSGEN: /* We've already sysgen'ed */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT0) EXPRESS JOB\n", "[WRITE] [%08x] (%d INT0) EXPRESS JOB\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT0; cio[cid].sysgen_s |= CIO_INT0;
@ -562,7 +575,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
default: default:
/* This should never happen */ /* This should never happen */
stop_reason = STOP_ERR; stop_reason = STOP_ERR;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT0) ERROR IN STATE MACHINE sysgen_s=%02x\n", "[WRITE] [%08x] (%d INT0) ERROR IN STATE MACHINE sysgen_s=%02x\n",
R[NUM_PC], cid, cio[cid].sysgen_s); R[NUM_PC], cid, cio[cid].sysgen_s);
break; break;
@ -574,20 +587,20 @@ void io_write(uint32 pa, uint32 val, size_t size)
case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */ case CIO_INT_NONE: /* We've never seen an INT0 or INT1 */
case CIO_INT1: /* We've seen an INT1 but not an INT0 */ case CIO_INT1: /* We've seen an INT1 but not an INT0 */
/* There's nothing to do in this instance */ /* There's nothing to do in this instance */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT1) IGNORED\n", "[WRITE] [%08x] (%d INT1) IGNORED\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; cio[cid].sysgen_s |= CIO_INT1;
break; break;
case CIO_INT0: /* We've seen an INT0 but not an INT1. Time to sysgen */ case CIO_INT0: /* We've seen an INT0 but not an INT1. Time to sysgen */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT1) SYSGEN\n", "[WRITE] [%08x] (%d INT1) SYSGEN\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; cio[cid].sysgen_s |= CIO_INT1;
cio_sysgen(cid); cio_sysgen(cid);
break; break;
case CIO_SYSGEN: /* We've already sysgen'ed */ case CIO_SYSGEN: /* We've already sysgen'ed */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT1) FULL\n", "[WRITE] [%08x] (%d INT1) FULL\n",
R[NUM_PC], cid); R[NUM_PC], cid);
cio[cid].sysgen_s |= CIO_INT1; cio[cid].sysgen_s |= CIO_INT1;
@ -596,7 +609,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
default: default:
/* This should never happen */ /* This should never happen */
stop_reason = STOP_ERR; stop_reason = STOP_ERR;
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d INT1) ERROR IN STATE MACHINE sysgen_s=%02x\n", "[WRITE] [%08x] (%d INT1) ERROR IN STATE MACHINE sysgen_s=%02x\n",
R[NUM_PC], cid, cio[cid].sysgen_s); R[NUM_PC], cid, cio[cid].sysgen_s);
break; break;
@ -604,15 +617,18 @@ void io_write(uint32 pa, uint32 val, size_t size)
return; return;
case IOF_STAT: case IOF_STAT:
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] (%d RESET)\n", "[WRITE] [%08x] (%d RESET)\n",
R[NUM_PC], cid); R[NUM_PC], cid);
if (cio[cid].reset_handler) {
cio[cid].reset_handler(cid);
}
cio[cid].sysgen_s = 0; cio[cid].sysgen_s = 0;
return; return;
default: default:
/* We should never reach here, but if we do, there's /* We should never reach here, but if we do, there's
* nothing listening. */ * nothing listening. */
sim_debug(IO_DBG, &cpu_dev, sim_debug(CIO_DBG, &cpu_dev,
"[WRITE] [%08x] No card at cid=%d reg=%d\n", "[WRITE] [%08x] No card at cid=%d reg=%d\n",
R[NUM_PC], cid, reg); R[NUM_PC], cid, reg);
csr_data |= CSRTIMO; csr_data |= CSRTIMO;
@ -640,10 +656,18 @@ void io_write(uint32 pa, uint32 val, size_t size)
/* For debugging only */ /* For debugging only */
void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type, void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type,
uint16 esize, cio_entry *entry, uint8 *app_data) uint32 esize, cio_entry *entry, uint8 *app_data)
{ {
char appl[64];
uint32 i, c_offset;
for (i = 0, c_offset=0; i < (esize - QESIZE); i++) {
snprintf(appl + c_offset, 3, "%02x", app_data[i]);
c_offset += 2;
}
sim_debug(dbits, dev, sim_debug(dbits, dev,
"*** %s ENTRY: byte_count=%04x, subdevice=%02x, opcode=%d, address=%08x\n", "*** %s ENTRY: byte_count=%04x, subdevice=%02x, opcode=%d, address=%08x, app_data=%s\n",
type, entry->byte_count, entry->subdevice, type, entry->byte_count, entry->subdevice,
entry->opcode, entry->address); entry->opcode, entry->address, appl);
} }

View file

@ -134,6 +134,11 @@
#define CIO_DOS 4 #define CIO_DOS 4
#define CIO_DSD 5 #define CIO_DSD 5
/* Response */
#define CIO_SUCCESS 0
#define CIO_FAILURE 2
#define CIO_SYSGEN_OK 3
/* Map a physical address to a card ID */ /* Map a physical address to a card ID */
#define CID(pa) (((((pa) >> 0x14) & 0x1f) / 2) - 1) #define CID(pa) (((((pa) >> 0x14) & 0x1f) / 2) - 1)
/* Map a card ID to a base address */ /* Map a card ID to a base address */
@ -154,21 +159,22 @@
typedef struct { typedef struct {
uint16 id; /* Card ID */ uint16 id; /* Card ID */
void (*exp_handler)(uint8 cid); /* Handler for express jobs */ void (*exp_handler)(uint8 cid); /* Handler for express jobs */
void (*full_handler)(uint8 cid); /* Handler for full jobs */ void (*full_handler)(uint8 cid); /* Handler for full jobs */
void (*sysgen)(uint8 cid); /* Sysgen routine (optional) */ void (*sysgen)(uint8 cid); /* Sysgen routine (optional) */
uint32 rqp; /* Request Queue Pointer */ void (*reset_handler)(uint8 cid); /* RESET request handler (optional) */
uint32 cqp; /* Completion Queue Pointer */ uint32 rqp; /* Request Queue Pointer */
uint8 rqs; /* Request queue size */ uint32 cqp; /* Completion Queue Pointer */
uint8 cqs; /* Completion queue size */ uint8 rqs; /* Request queue size */
uint8 ivec; /* Interrupt Vector */ uint8 cqs; /* Completion queue size */
uint8 no_rque; /* Number of request queues */ uint8 ivec; /* Interrupt Vector */
uint8 ipl; /* IPL that this card uses */ uint8 no_rque; /* Number of request queues */
t_bool intr; /* Card needs to interrupt */ uint8 ipl; /* IPL that this card uses */
uint8 sysgen_s; /* Sysgen state */ t_bool intr; /* Card needs to interrupt */
uint8 seqbit; /* Squence Bit */ uint8 sysgen_s; /* Sysgen state */
uint8 op; /* Last received opcode */ uint8 seqbit; /* Squence Bit */
uint8 op; /* Last received opcode */
} CIO_STATE; } CIO_STATE;
typedef struct { typedef struct {
@ -213,6 +219,7 @@ typedef struct {
uint32 retcode; uint32 retcode;
} pump; } pump;
extern t_bool cio_skip_seqbit;
extern uint16 cio_ints; extern uint16 cio_ints;
extern CIO_STATE cio[CIO_SLOTS]; extern CIO_STATE cio[CIO_SLOTS];
@ -221,18 +228,19 @@ t_stat cio_svc(UNIT *uptr);
void cio_clear(uint8 cid); void cio_clear(uint8 cid);
uint32 cio_crc32_shift(uint32 crc, uint8 data); uint32 cio_crc32_shift(uint32 crc, uint8 data);
void cio_cexpress(uint8 cid, uint16 esize, cio_entry *cqe, uint8 *app_data); void cio_cexpress(uint8 cid, uint32 esize, cio_entry *cqe, uint8 *app_data);
void cio_cqueue(uint8 cid, uint8 cmd_stat, uint16 esize, cio_entry *cqe, uint8 *app_data); void cio_cqueue(uint8 cid, uint8 cmd_stat, uint32 esize, cio_entry *cqe, uint8 *app_data);
void cio_rexpress(uint8 cid, uint16 esize, cio_entry *rqe, uint8 *app_data); t_bool cio_cqueue_avail(uint8 cid, uint32 esize);
t_stat cio_rqueue(uint8 cid, uint8 qnum, uint16 esize, cio_entry *rqe, uint8 *app_data); void cio_rexpress(uint8 cid, uint32 esize, cio_entry *rqe, uint8 *app_data);
t_bool cio_cqueue_avail(uint8 cid, uint16 esize); t_stat cio_rqueue(uint8 cid, uint32 qnum, uint32 esize, cio_entry *rqe, uint8 *app_data);
uint16 cio_r_lp(uint8 cid, uint8 qnum, uint16 esize); t_bool cio_rqueue_avail(uint8 cid, uint32 qnum, uint32 esize);
uint16 cio_r_ulp(uint8 cid, uint8 qnum, uint16 esize); uint16 cio_r_lp(uint8 cid, uint32 qnum, uint32 esize);
uint16 cio_c_lp(uint8 cid, uint16 esize); uint16 cio_r_ulp(uint8 cid, uint32 qnum, uint32 esize);
uint16 cio_c_ulp(uint8 cid, uint16 esize); uint16 cio_c_lp(uint8 cid, uint32 esize);
uint16 cio_c_ulp(uint8 cid, uint32 esize);
void cio_sysgen(uint8 cid); void cio_sysgen(uint8 cid);
void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type, void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type,
uint16 esize, cio_entry *entry, uint8 *app_data); uint32 esize, cio_entry *entry, uint8 *app_data);
#endif #endif

View file

@ -332,6 +332,9 @@ void pwrite_b(uint32 pa, uint8 val);
void pwrite_h(uint32 pa, uint16 val); void pwrite_h(uint32 pa, uint16 val);
void pwrite_w(uint32 pa, uint32 val); void pwrite_w(uint32 pa, uint32 val);
/* TODO: REMOVE AFTER DEBUGGING */
uint32 safe_read_w(uint32 va);
/* Virtual memory translation */ /* Virtual memory translation */
uint32 mmu_xlate_addr(uint32 va, uint8 r_acc); uint32 mmu_xlate_addr(uint32 va, uint8 r_acc);
t_stat mmu_decode_vaddr(uint32 vaddr, uint8 r_acc, t_stat mmu_decode_vaddr(uint32 vaddr, uint8 r_acc,

1270
3B2/3b2_ni.c Normal file

File diff suppressed because it is too large Load diff

219
3B2/3b2_ni.h Normal file
View file

@ -0,0 +1,219 @@
/* 3b2_ni.h: AT&T 3B2 Model 400 "NI" feature card
Copyright (c) 2018, Seth J. Morabito
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Except as contained in this notice, the name of the author shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the author.
*/
#ifndef _3B2_NI_H_
#define _3B2_NI_H_
#include "3b2_defs.h"
#include "3b2_io.h"
#include "sim_ether.h"
#define NI_ID 0x0002
#define NI_IPL 12
/* Opcodes for NI card */
#define NI_SETID 6
#define NI_TURNOFF 7
#define NI_TURNON 8
#define NI_SEND 11
#define NI_RECV 12
#define NI_STATS 13
#define NI_SANITY 15
#define NI_SEND_A 22
#define MAC_SIZE_BYTES 6
#define MAC_SIZE_CHARS 20
#define NIQESIZE 12
#define NI_QUE_MAX 1024
#define NI_TMR_WAIT_DEFAULT 3000
#define NI_RCV_POLL_US 8000
#define NI_XMIT_DELAY_US 60000
#define NI_INT_DELAY_US 500
#define NI_SANITY_INTERVAL_US 5000000
/* Maximum allowed number of multicast addresses */
#define NI_MULTI_MAX 64
/* At least two filter addresses are always configured:
* 1. The host MAC
* 2. The broadcast address */
#define NI_FILTER_MIN 2
/* Maximum total allowed number of filter addresses, including the
* host's MAC and the broadcast address. */
#define NI_FILTER_MAX NI_MULTI_MAX + NI_FILTER_MIN
/* Indexes in the internal filter address table of the
* host's MAC and the broadcast address */
#define NI_NIC_MAC 0
#define NI_BCST_MAC 1
/*
* For performance reasons, there are two modes of polling the receive
* queues. Initially, polling is VERY aggressive as we race the
* filling of the receive queues. Once we've taken three jobs from
* each of the two receive queues, we switch to slow polling,
* which uses coscheduling.
*/
#define NI_QPOLL_FAST 100
#define NI_QPOLL_SLOW 50000
#define NI_DIAG_CRC1 0x795268a4
#define NI_DIAG_CRC2 0xfab1057c
#define NI_DIAG_CRC3 0x10ca00cd
#define NI_PUMP_CRC1 0xfab1057c
#define NI_PUMP_CRC2 0xf6744bed
#define EIG_TABLE_SIZE 40
#define PKT_HEADER_LEN_OFFSET EIG_TABLE_SIZE
#define PKT_START_OFFSET (PKT_HEADER_LEN_OFFSET + 4)
/*
* The NI card has two request queues for packet receive: One for
* small packets, and one for large packets. The small queue is meant
* for packets smaller than 128 bytes. The large queue is meant for
* packets up to 1500 bytes (no jumbo frames allowed)
*/
#define GE_QUEUE 0 /* General request queue */
#define SM_QUEUE 1 /* Small packet receive queue */
#define LG_QUEUE 2 /* Large packet receive queue */
#define SM_PKT_MAX 106 /* Max size of small packets (excluding CRC) */
#define LG_PKT_MAX 1514 /* Max size of large packets (excluding CRC) */
/*
* NI-specific debugging flags
*/
#define DBG_TRACE 0x01
#define DBG_IO 0x02
#define DBG_CACHE 0x04
#define DBG_DAT 0x08
#define DBG_ERR 0x10
#define DBG_ETH 0x20
#define NI_CACHE_HAS_SPACE(i) (((ni.job_cache[(i)].wp + 1) % NI_CACHE_LEN) != ni.job_cache[(i)].rp)
/*
* The NI card caches up to three jobs taken from each of the two
* packet receive queues so that they are available immediately after
* receipt of a packet. These jobs are kept in small circular buffers.
* Each job is represented by an ni_rec_job structure, containing a
* buffer pointer and a slot number. The slot number is used by both
* the driver and the firmware to correlate a packet receive buffer
* with a completion queue event.
*/
typedef struct {
uint32 addr; /* address of job's buffer */
uint8 slot; /* slot number of the job */
} ni_rec_job;
#define NI_CACHE_LEN 4
typedef struct {
ni_rec_job req[NI_CACHE_LEN]; /* the cache */
int wp; /* write pointer */
int rp; /* read pointer */
} ni_job_cache;
/*
* When the NI driver submits a packet send request to the general
* request queue, it constructs one or more ni_prot_info structs in
* main memory that point to the protocol-specific byte data of the
* packet (minus the Ethernet frame). These structs are packed one
* after the other following the Ethernet frame header in the job's
* request buffer. The last entry has its "last" bit set to non-zero.
*/
typedef struct {
uint32 addr; /* Physical address of the buffer in system RAM */
uint16 size; /* Length of the buffer */
uint16 last; /* Is this the last entry in the list? */
} ni_prot_info;
typedef struct {
uint32 rq_taken;
uint32 tx_fail;
uint32 rx_dropped;
uint32 rx_pkt;
uint32 tx_pkt;
uint32 rx_bytes;
uint32 tx_bytes;
} ni_stat_info;
typedef struct {
uint8 cid;
t_bool initialized;
t_bool enabled;
uint32 crc;
uint32 poll_rate;
char mac_str[MAC_SIZE_CHARS];
uint8 mac_bytes[MAC_SIZE_BYTES];
ni_job_cache job_cache[2];
ni_prot_info prot;
ni_stat_info stats;
uint8 fcf_seq;
ETH_DEV* eth;
ETH_PACK rd_buf;
ETH_PACK wr_buf;
ETH_QUE readq;
ETH_MAC macs[NI_FILTER_MAX]; /* List of all filter addresses */
int filter_count; /* Number of filters available */
ETH_PCALLBACK callback;
} NI_STATE;
extern DEVICE ni_dev;
void ni_recv_callback(int status);
t_stat ni_reset(DEVICE *dptr);
t_stat ni_rcv_svc(UNIT *uptr);
t_stat ni_sanity_svc(UNIT *uptr);
t_stat ni_rq_svc(UNIT *uptr);
t_stat ni_cio_svc(UNIT *uptr);
t_stat ni_attach(UNIT *uptr, CONST char *cptr);
t_stat ni_detach(UNIT *uptr);
t_stat ni_setmac(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat ni_showmac(FILE* st, UNIT *uptr, int32 val, CONST void *desc);
t_stat ni_try_job(uint8 cid);
t_stat ni_show_stats(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat ni_set_stats(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat ni_show_poll(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat ni_show_filters(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
const char *ni_description(DEVICE *dptr);
t_stat ni_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
void ni_cio_reset(uint8 cid);
void ni_process_packet();
void ni_int_ack(uint8 cid);
void ni_sysgen(uint8 cid);
void ni_express(uint8 cid);
void ni_full(uint8 cid);
#endif /* _3B2_NI_H_ */

View file

@ -93,14 +93,14 @@ extern UNIT cio_unit;
#define PORTS_DIAG_CRC2 0x77a1ea56 #define PORTS_DIAG_CRC2 0x77a1ea56
#define PORTS_DIAG_CRC3 0x84cf938b #define PORTS_DIAG_CRC3 0x84cf938b
#define LN(cid,port) ((PORTS_LINES * ((cid) - base_cid)) + (port)) #define LN(cid,port) ((PORTS_LINES * ((cid) - ports_base_cid)) + (port))
#define LCID(ln) (((ln) / PORTS_LINES) + base_cid) #define LCID(ln) (((ln) / PORTS_LINES) + ports_base_cid)
#define LPORT(ln) ((ln) % PORTS_LINES) #define LPORT(ln) ((ln) % PORTS_LINES)
int8 ports_base_cid; /* First cid in our contiguous block */
uint8 ports_int_cid; /* Interrupting card ID */
uint8 ports_int_subdev; /* Interrupting subdevice */
t_bool ports_conf = FALSE; /* Have PORTS cards been configured? */ t_bool ports_conf = FALSE; /* Have PORTS cards been configured? */
int8 base_cid; /* First cid in our contiguous block */
uint8 int_cid; /* Interrupting card ID */
uint8 int_subdev; /* Interrupting subdevice */
uint32 ports_crc; /* CRC32 of downloaded memory */ uint32 ports_crc; /* CRC32 of downloaded memory */
/* PORTS-specific state for each slot */ /* PORTS-specific state for each slot */
@ -184,8 +184,8 @@ DEVICE ports_dev = {
static void cio_irq(uint8 cid, uint8 dev, int32 delay) static void cio_irq(uint8 cid, uint8 dev, int32 delay)
{ {
int_cid = cid; ports_int_cid = cid;
int_subdev = dev & 0xf; ports_int_subdev = dev & 0xf;
sim_activate(&ports_unit[2], delay); sim_activate(&ports_unit[2], delay);
} }
@ -268,13 +268,15 @@ static void ports_cmd(uint8 cid, cio_entry *rentry, uint8 *rapp_data)
for (i = 0; i < rentry->byte_count; i++) { for (i = 0; i < rentry->byte_count; i++) {
ports_crc = cio_crc32_shift(ports_crc, pread_b(rentry->address + i)); ports_crc = cio_crc32_shift(ports_crc, pread_b(rentry->address + i));
} }
centry.address = rentry->address + rentry->byte_count;
sim_debug(TRACE_DBG, &ports_dev, sim_debug(TRACE_DBG, &ports_dev,
"[%08x] [ports_cmd] CIO Download Memory: bytecnt=%04x " "[%08x] [ports_cmd] CIO Download Memory: bytecnt=%04x "
"addr=%08x return_addr=%08x subdev=%02x (CRC=%08x)\n", "addr=%08x return_addr=%08x subdev=%02x (CRC=%08x)\n",
R[NUM_PC], R[NUM_PC],
rentry->byte_count, rentry->address, rentry->byte_count, rentry->address,
centry.address, centry.subdevice, ports_crc); centry.address, centry.subdevice, ports_crc);
centry.address = rentry->address + rentry->byte_count; /* We intentionally do not set the subdevice in
* the completion entry */
cio_cexpress(cid, PPQESIZE, &centry, app_data); cio_cexpress(cid, PPQESIZE, &centry, app_data);
cio_irq(cid, rentry->subdevice, DELAY_DLM); cio_irq(cid, rentry->subdevice, DELAY_DLM);
break; break;
@ -523,7 +525,7 @@ void ports_sysgen(uint8 cid)
cio_cexpress(cid, PPQESIZE, &cqe, app_data); cio_cexpress(cid, PPQESIZE, &cqe, app_data);
cio_cqueue(cid, CIO_STAT, PPQESIZE, &cqe, app_data); cio_cqueue(cid, CIO_STAT, PPQESIZE, &cqe, app_data);
int_cid = cid; ports_int_cid = cid;
sim_activate(&ports_unit[2], DELAY_STD); sim_activate(&ports_unit[2], DELAY_STD);
} }
@ -599,7 +601,7 @@ t_stat ports_reset(DEVICE *dptr)
} }
/* Remember the base card slot */ /* Remember the base card slot */
base_cid = cid; ports_base_cid = cid;
end_slot = (cid + (ports_desc.lines/PORTS_LINES)); end_slot = (cid + (ports_desc.lines/PORTS_LINES));
@ -669,20 +671,20 @@ t_stat ports_cio_svc(UNIT *uptr)
{ {
sim_debug(TRACE_DBG, &ports_dev, sim_debug(TRACE_DBG, &ports_dev,
"[ports_cio_svc] IRQ for board %d device %d\n", "[ports_cio_svc] IRQ for board %d device %d\n",
int_cid, int_subdev); ports_int_cid, ports_int_subdev);
if (cio[int_cid].ivec > 0) { if (cio[ports_int_cid].ivec > 0) {
cio[int_cid].intr = TRUE; cio[ports_int_cid].intr = TRUE;
} }
switch (cio[int_cid].op) { switch (cio[ports_int_cid].op) {
case PPC_CONN: case PPC_CONN:
cio[int_cid].op = PPC_ASYNC; cio[ports_int_cid].op = PPC_ASYNC;
ports_ldsc[LN(int_cid, int_subdev)].rcve = 1; ports_ldsc[LN(ports_int_cid, ports_int_subdev)].rcve = 1;
sim_activate(&ports_unit[2], DELAY_ASYNC); sim_activate(&ports_unit[2], DELAY_ASYNC);
break; break;
case PPC_ASYNC: case PPC_ASYNC:
ports_update_conn(LN(int_cid, int_subdev)); ports_update_conn(LN(ports_int_cid, ports_int_subdev));
break; break;
default: default:
break; break;

View file

@ -37,6 +37,7 @@
#include "3b2_mmu.h" #include "3b2_mmu.h"
#include "3b2_ctc.h" #include "3b2_ctc.h"
#include "3b2_ports.h" #include "3b2_ports.h"
#include "3b2_ni.h"
#include "3b2_sysdev.h" #include "3b2_sysdev.h"
char sim_name[] = "AT&T 3B2 Model 400"; char sim_name[] = "AT&T 3B2 Model 400";
@ -65,6 +66,7 @@ DEVICE *sim_devices[] = {
&id_dev, &id_dev,
&ports_dev, &ports_dev,
&ctc_dev, &ctc_dev,
&ni_dev,
NULL NULL
}; };
@ -93,6 +95,7 @@ void full_reset()
csr_reset(&csr_dev); csr_reset(&csr_dev);
ports_reset(&ports_dev); ports_reset(&ports_dev);
ctc_reset(&ctc_dev); ctc_reset(&ctc_dev);
ni_reset(&ni_dev);
} }
t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)

View file

@ -40,8 +40,8 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="../3B2/;../../windows-build/libSDL/SDL2-2.0.5/include;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/winpcap/Wpdpack/Include;../../windows-build/PCRE/include/;../../windows-build/pthreads;../../windows-build/libSDL/SDL2-2.0.8/include;../../windows-build/libpng-1.6.18" AdditionalIncludeDirectories="../3B2/;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/winpcap/Wpdpack/Include;../../windows-build/PCRE/include/;../../windows-build/pthreads;../../windows-build/libSDL/SDL2-2.0.8/include;../../windows-build/libpng-1.6.18"
PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC;USE_INT64;USE_ADDR64" PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC;USE_INT64;USE_ADDR64;USE_SHARED;PTW32_STATIC_LIB;SIM_ASYNCH_IO;USE_READER_THREAD;HAVE_SLIRP_NETWORK;USE_SIMH_SLIRP_DEBUG"
KeepComments="false" KeepComments="false"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="0" BasicRuntimeChecks="0"
@ -125,8 +125,8 @@
InlineFunctionExpansion="1" InlineFunctionExpansion="1"
OmitFramePointers="true" OmitFramePointers="true"
WholeProgramOptimization="true" WholeProgramOptimization="true"
AdditionalIncludeDirectories="../3B2/;../../windows-build/libSDL/SDL2-2.0.5/include;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/winpcap/Wpdpack/Include;../../windows-build/PCRE/include/;../../windows-build/pthreads;../../windows-build/libSDL/SDL2-2.0.8/include;../../windows-build/libpng-1.6.18" AdditionalIncludeDirectories="../3B2/;./;../;../slirp;../slirp_glue;../slirp_glue/qemu;../slirp_glue/qemu/win32/include;../../windows-build/winpcap/Wpdpack/Include;../../windows-build/PCRE/include/;../../windows-build/pthreads;../../windows-build/libSDL/SDL2-2.0.8/include;../../windows-build/libpng-1.6.18"
PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC;USE_INT64;USE_ADDR64" PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC;USE_INT64;USE_ADDR64;USE_SHARED;PTW32_STATIC_LIB;SIM_ASYNCH_IO;USE_READER_THREAD;HAVE_SLIRP_NETWORK;USE_SIMH_SLIRP_DEBUG"
StringPooling="true" StringPooling="true"
RuntimeLibrary="0" RuntimeLibrary="0"
EnableFunctionLevelLinking="true" EnableFunctionLevelLinking="true"
@ -224,6 +224,10 @@
RelativePath="..\3B2\3b2_mmu.c" RelativePath="..\3B2\3b2_mmu.c"
> >
</File> </File>
<File
RelativePath="..\3B2\3b2_ni.c"
>
</File>
<File <File
RelativePath="..\3B2\3b2_ports.c" RelativePath="..\3B2\3b2_ports.c"
> >
@ -236,6 +240,29 @@
RelativePath="..\3B2\3b2_sysdev.c" RelativePath="..\3B2\3b2_sysdev.c"
> >
</File> </File>
<File
RelativePath="..\..\windows-build\pthreads\pthread.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="HAVE_CONFIG_H;PTW32_BUILD_INLINED;PTW32_STATIC_LIB;__CLEANUP_C;$(NOINHERIT)"
CompileAs="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
WholeProgramOptimization="false"
PreprocessorDefinitions="HAVE_CONFIG_H;PTW32_BUILD_INLINED;PTW32_STATIC_LIB;__CLEANUP_C;$(NOINHERIT)"
CompileAs="1"
/>
</FileConfiguration>
</File>
<File <File
RelativePath="..\scp.c" RelativePath="..\scp.c"
> >
@ -280,6 +307,170 @@
RelativePath="..\sim_video.c" RelativePath="..\sim_video.c"
> >
</File> </File>
<Filter
Name="slirp"
>
<File
RelativePath="..\slirp\arp_table.c"
>
</File>
<File
RelativePath="..\slirp\bootp.c"
>
</File>
<File
RelativePath="..\slirp\bootp.h"
>
</File>
<File
RelativePath="..\slirp\cksum.c"
>
</File>
<File
RelativePath="..\slirp\debug.h"
>
</File>
<File
RelativePath="..\slirp\dnssearch.c"
>
</File>
<File
RelativePath="..\slirp_glue\glib_qemu_stubs.c"
>
</File>
<File
RelativePath="..\slirp\if.c"
>
</File>
<File
RelativePath="..\slirp\if.h"
>
</File>
<File
RelativePath="..\slirp\ip.h"
>
</File>
<File
RelativePath="..\slirp\ip_icmp.c"
>
</File>
<File
RelativePath="..\slirp\ip_icmp.h"
>
</File>
<File
RelativePath="..\slirp\ip_input.c"
>
</File>
<File
RelativePath="..\slirp\ip_output.c"
>
</File>
<File
RelativePath="..\slirp\libslirp.h"
>
</File>
<File
RelativePath="..\slirp\main.h"
>
</File>
<File
RelativePath="..\slirp\mbuf.c"
>
</File>
<File
RelativePath="..\slirp\mbuf.h"
>
</File>
<File
RelativePath="..\slirp\misc.c"
>
</File>
<File
RelativePath="..\slirp\misc.h"
>
</File>
<File
RelativePath="..\slirp\sbuf.c"
>
</File>
<File
RelativePath="..\slirp\sbuf.h"
>
</File>
<File
RelativePath="..\slirp_glue\sim_slirp.c"
>
</File>
<File
RelativePath="..\slirp\slirp.c"
>
</File>
<File
RelativePath="..\slirp\slirp.h"
>
</File>
<File
RelativePath="..\slirp\slirp_config.h"
>
</File>
<File
RelativePath="..\slirp\socket.c"
>
</File>
<File
RelativePath="..\slirp\socket.h"
>
</File>
<File
RelativePath="..\slirp\tcp.h"
>
</File>
<File
RelativePath="..\slirp\tcp_input.c"
>
</File>
<File
RelativePath="..\slirp\tcp_output.c"
>
</File>
<File
RelativePath="..\slirp\tcp_subr.c"
>
</File>
<File
RelativePath="..\slirp\tcp_timer.c"
>
</File>
<File
RelativePath="..\slirp\tcp_timer.h"
>
</File>
<File
RelativePath="..\slirp\tcp_var.h"
>
</File>
<File
RelativePath="..\slirp\tcpip.h"
>
</File>
<File
RelativePath="..\slirp\tftp.c"
>
</File>
<File
RelativePath="..\slirp\tftp.h"
>
</File>
<File
RelativePath="..\slirp\udp.c"
>
</File>
<File
RelativePath="..\slirp\udp.h"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="Header Files" Name="Header Files"
@ -321,6 +512,10 @@
RelativePath="..\3B2\3b2_mmu.h" RelativePath="..\3B2\3b2_mmu.h"
> >
</File> </File>
<File
RelativePath="..\3B2\3b2_ni.h"
>
</File>
<File <File
RelativePath="..\3B2\3b2_ports.h" RelativePath="..\3B2\3b2_ports.h"
> >

View file

@ -108,7 +108,7 @@ ifneq (,$(findstring besm6,$(MAKECMDGOALS)))
BESM6_BUILD = true BESM6_BUILD = true
endif endif
# building the pdp11, pdp10, or any vax simulator could use networking support # building the pdp11, pdp10, or any vax simulator could use networking support
ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring pdp10,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring pdp10,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring 3b2,$(MAKECMDGOALS))$(findstring all,$(MAKECMDGOALS))))
NETWORK_USEFUL = true NETWORK_USEFUL = true
ifneq (,$(findstring all,$(MAKECMDGOALS))) ifneq (,$(findstring all,$(MAKECMDGOALS)))
BUILD_MULTIPLE = s BUILD_MULTIPLE = s
@ -1842,8 +1842,8 @@ ATT3B2 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_mmu.c \
${ATT3B2D}/3b2_id.c ${ATT3B2D}/3b2_dmac.c \ ${ATT3B2D}/3b2_id.c ${ATT3B2D}/3b2_dmac.c \
${ATT3B2D}/3b2_sys.c ${ATT3B2D}/3b2_io.c \ ${ATT3B2D}/3b2_sys.c ${ATT3B2D}/3b2_io.c \
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \ ${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \
${ATT3B2D}/3b2_sysdev.c ${ATT3B2D}/3b2_ni.c ${ATT3B2D}/3b2_sysdev.c
ATT3B2_OPT = -I ${ATT3B2D} -DUSE_INT64 -DUSE_ADDR64 ATT3B2_OPT = -DUSE_INT64 -DUSE_ADDR64 -I ${ATT3B2D} ${NETWORK_OPT}
# #
# Build everything (not the unsupported/incomplete or experimental simulators) # Build everything (not the unsupported/incomplete or experimental simulators)
# #