This summer a group of us worked together to resurrect the original ARPAnet IMP software, and I’m now happy to say that the IMP lives again in simulation. It’s possible to run the original IMP software on a modified version of the H316 simh and to set up a virtual network of simulated IMPs talking to each other. IMP to IMP connections, which would have originally been carried over leased telephone lines, are tunneled over IP. As far as we can tell, everything works pretty much as it did in the early 1970s. IMPs are able to exchange routing information, console to console communications, network statistics, and they would carry host traffic if there were hosts on the network. The hooks are in there to allow simh to support the IMP side of the 1822 host interface, and the next step would be to recover the OS for an ARPAnet era host and then extend the corresponding simulator to talk to the IMP simulation.
192 lines
7.3 KiB
C
192 lines
7.3 KiB
C
/* h316_imp.c- BBN ARPAnet IMP/TIP Specific Hardware
|
|
Based on the SIMH simulator package written by Robert M Supnik.
|
|
|
|
Copyright (c) 2013 Robert Armstrong, bob@jfcl.com.
|
|
|
|
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
|
|
ROBERT ARMSTRONG 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 Robert Armstrong shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Robert Armstrong.
|
|
|
|
tks task switch device
|
|
mlc multiline controller (aka TIP)
|
|
|
|
21-May-13 RLA New file
|
|
|
|
OVERVIEW
|
|
|
|
This module implements the IMP pseudo device - this hack takes care of two
|
|
custom devices in the IMP hardware - device 041, which implements task
|
|
switching and the RDIMPN instruction, and device 42, which implements the
|
|
AMIMLC ("am I a multiline controller") instruction. This module also contains
|
|
a few miscellaneous routines which are used by the IMP support in general.
|
|
|
|
IMP state is maintained in a set of state variables:
|
|
|
|
MLC always zero (TIP flag)
|
|
IEN task interrupt enabled
|
|
IRQ task interrupt pending
|
|
|
|
TODO
|
|
*/
|
|
#ifdef VM_IMPTIP
|
|
#include "h316_defs.h" // H316 emulator definitions
|
|
#include "h316_imp.h" // ARPAnet IMP/TIP definitions
|
|
|
|
// Locals ...
|
|
uint16 imp_station = IMP_STATION; // IMP number (or address)
|
|
uint16 imp_ismlc = 0; // 1 for MLC (not yet implemented!)
|
|
|
|
// Externals from other parts of simh ...
|
|
extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors
|
|
extern int32 PC; // current PC (for debug messages)
|
|
extern int32 stop_inst; // needed by IOBADFNC()
|
|
|
|
// Forward declarations ...
|
|
int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev);
|
|
t_stat imp_service (UNIT *uptr);
|
|
t_stat imp_reset (DEVICE *dptr);
|
|
t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *dp);
|
|
t_stat io_show_int (FILE *st, UNIT *uptr, int32 val, void *dp);
|
|
t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp);
|
|
t_stat io_set_int (UNIT *uptr, int32 val, char *cptr, void *dp);
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////// D A T A S T R U C T U R E S //////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// IMP device information block ...
|
|
DIB imp_dib = { IMP, 2, IOBUS, IOBUS, INT_V_TASK, INT_V_NONE, &imp_io, 0 };
|
|
|
|
// IMP unit data (we have only one!) ...
|
|
UNIT imp_unit = { UDATA (&imp_service, 0, 0) };
|
|
|
|
// IMP device registers (for "EXAMINE IMP STATE") ...
|
|
REG imp_reg[] = {
|
|
{ FLDATA (MLC, imp_ismlc, 0), REG_RO },
|
|
{ FLDATA (IEN, dev_ext_enb, INT_V_TASK-INT_V_EXTD) },
|
|
{ FLDATA (IRQ, dev_ext_int, INT_V_TASK-INT_V_EXTD) },
|
|
{ NULL }
|
|
};
|
|
|
|
// IMP device modifiers (for "SET/SHOW IMP xxx") ...
|
|
MTAB imp_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 0, "NUM", "NUM", &imp_set_station, &imp_show_station, NULL },
|
|
{ 0 }
|
|
};
|
|
|
|
// IMP debugging flags (for "SET IMP DEBUG=xxx") ...
|
|
DEBTAB imp_debug[] = {
|
|
{"WARN", IMP_DBG_WARN},
|
|
{"IO", IMP_DBG_IOT},
|
|
{0}
|
|
};
|
|
|
|
// And finally tie it all together ...
|
|
DEVICE imp_dev = {
|
|
"IMP", &imp_unit, imp_reg, imp_mod,
|
|
1, 0, 0, 0, 0, 0,
|
|
NULL, NULL, &imp_reset, NULL, NULL, NULL,
|
|
&imp_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, imp_debug, NULL, NULL
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////// I M P I / O A N D S E R V I C E R O U T I N E S //////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Set and clear the TASK IRQ and IEN ...
|
|
#define SET_TASK_IRQ() SET_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD)))
|
|
#define CLR_TASK_IRQ() CLR_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD)))
|
|
#define CLR_TASK_IEN() CLR_EXT_ENB((1u << (imp_dib.inum - INT_V_EXTD)))
|
|
|
|
// IMP I/O routine ...
|
|
int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev)
|
|
{
|
|
if (dev == IMP) {
|
|
if ((inst == ioOCP) && (fnc == 000)) {
|
|
// TASK - just set the task interrupt request bit ...
|
|
sim_debug(IMP_DBG_IOT, &imp_dev, "request task interrupt (PC=%06o)\n", PC-1);
|
|
SET_TASK_IRQ(); return dat;
|
|
} else if ((inst == ioINA) && ((fnc == 010) || (fnc == 000))) {
|
|
// RDIMPN - return the IMP address and always skip ...
|
|
sim_debug(IMP_DBG_IOT, &imp_dev, "read address (PC=%06o)\n", PC-1);
|
|
return IOSKIP(imp_station);
|
|
}
|
|
} else if (dev == IMP+1) {
|
|
if ((inst == ioSKS) && (fnc == 000)) {
|
|
// AMIMLC - skip if this machine is an MLC ...
|
|
sim_debug(IMP_DBG_IOT, &imp_dev, "skip on MLC (PC=%06o %s)\n", PC-1, imp_ismlc ? "SKIP" : "NOSKIP");
|
|
if (imp_ismlc != 0) return IOSKIP(dat); else return dat;
|
|
}
|
|
}
|
|
|
|
// Anything else is an error...
|
|
sim_debug(IMP_DBG_WARN, &imp_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc);
|
|
return IOBADFNC(dat);
|
|
}
|
|
|
|
// Unit service ...
|
|
t_stat imp_service (UNIT *uptr)
|
|
{
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/////////////// D E V I C E A C T I O N C O M M A N D S ////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Reset routine ...
|
|
t_stat imp_reset (DEVICE *dptr)
|
|
{
|
|
// The simh RESET command clears both the interrupt request and enable...
|
|
CLR_TASK_IRQ(); CLR_TASK_IEN();
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
///////// D E V I C E S E T A N D S H O W C O M M A N D S //////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Show the station number ...
|
|
t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *desc)
|
|
{
|
|
fprintf(st,"station=%d", imp_station);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
// Set the station number ...
|
|
t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp)
|
|
{
|
|
uint32 newnum; t_stat sts;
|
|
if (cptr == NULL) return SCPE_ARG;
|
|
newnum = get_uint (cptr, 10, 9999, &sts);
|
|
if (newnum == 0) return SCPE_ARG;
|
|
imp_station = newnum;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
#endif // #ifdef VM_IMPTIP from the very top
|