| /* h316_hi.c- BBN ARPAnet IMP Host Interface | |
| 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. | |
| hi host interface | |
| 21-May-13 RLA New file | |
| The host interface is one of the BBN engineered devices unique to the | |
| ARPAnet IMP. This is the famous "1822" card which connected each IMP to a | |
| host computer - a DECSYSTEM-10, an SDS Sigma 7, an IBM 360/90, a CDC6600, | |
| or any one of many other ARPAnet hosts. The idea is to simulate this | |
| interface by using a TCP/UDP connection to another simh instance emulating | |
| the host machine and running the ARPAnet host software. | |
| Presently the details of the host interface card are not well known, and | |
| this implementation is simply a place holder. It's enough to allow the IMP | |
| software to run, but not actually to communicate with a host. The IMP simply | |
| believes that all the attached hosts are down at the moment. | |
| Host interface state is maintained in a set of position and state variables: | |
| Host state is maintained in the following variables - | |
| TBA TBA | |
| TODO | |
| IMPLEMENT THIS MODULE!!! | |
| */ | |
| #ifdef VM_IMPTIP | |
| #include "h316_defs.h" // H316 emulator definitions | |
| #include "h316_imp.h" // ARPAnet IMP/TIP definitions | |
| // 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() | |
| extern uint16 M[]; // main memory (for DMC access) | |
| // Forward declarations ... | |
| int32 hi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev); | |
| int32 hi1_io (int32 inst, int32 fnc, int32 dat, int32 dev); | |
| int32 hi2_io (int32 inst, int32 fnc, int32 dat, int32 dev); | |
| int32 hi3_io (int32 inst, int32 fnc, int32 dat, int32 dev); | |
| int32 hi4_io (int32 inst, int32 fnc, int32 dat, int32 dev); | |
| t_stat hi_service (UNIT *uptr); | |
| t_stat hi_reset (DEVICE *dptr); | |
| t_stat hi_attach (UNIT *uptr, char *cptr); | |
| t_stat hi_detach (UNIT *uptr); | |
| //////////////////////////////////////////////////////////////////////////////// | |
| ////////////////////// D A T A S T R U C T U R E S ////////////////////// | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Host interface data blocks ... | |
| // The HIDB is our own internal data structure for each host. It keeps data | |
| // about the TCP/IP connection, buffers, etc. | |
| #define HI_HIDB(N) {0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE} | |
| HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2); | |
| HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4); | |
| // Host Device Information Blocks ... | |
| // The DIB is the structure simh uses to keep track of the device IO address | |
| // and IO service routine. It can also hold the DMC channel, but we don't use | |
| // that because it's unit specific. | |
| #define HI_DIB(N) {HI##N, 1, HI##N##_RX_DMC, HI##N##_TX_DMC, \ | |
| INT_V_HI##N##RX, INT_V_HI##N##TX, &hi##N##_io, N} | |
| DIB hi1_dib = HI_DIB(1), hi2_dib = HI_DIB(2); | |
| DIB hi3_dib = HI_DIB(3), hi4_dib = HI_DIB(4); | |
| // Host Device Unit data ... | |
| // simh uses the unit data block primarily to schedule device service events. | |
| // The UNIT data also contains four "user" fields which devices can reuse for | |
| // any purpose and we take advantage of that to store the line number. | |
| #define hline u3 // our host line number is stored in user data 3 | |
| #define HI_UNIT(N) {UDATA (&hi_service, UNIT_ATTABLE, 0), HI_POLL_DELAY, N, 0, 0, 0} | |
| UNIT hi1_unit = HI_UNIT(1), hi2_unit = HI_UNIT(2); | |
| UNIT hi3_unit = HI_UNIT(3), hi4_unit = HI_UNIT(4); | |
| // Host Device Registers ... | |
| // These are the simh device "registers" - they c can be viewed with the | |
| // "EXAMINE HIxn STATE" command and modified by "DEPOSIT HIxn ..." | |
| #define HI_REG(N) { \ | |
| { DRDATA (POLL, hi##N##_unit.wait, 24), REG_NZ + PV_LEFT }, \ | |
| { FLDATA (RXIRQ, dev_ext_int, INT_V_HI##N##RX-INT_V_EXTD) }, \ | |
| { FLDATA (RXIEN, dev_ext_enb, INT_V_HI##N##RX-INT_V_EXTD) }, \ | |
| { DRDATA (RXTOT, hi##N##_db.rxtotal,32), REG_RO + PV_LEFT }, \ | |
| { FLDATA (TXIRQ, dev_ext_int, INT_V_HI##N##TX-INT_V_EXTD) }, \ | |
| { FLDATA (TXIEN, dev_ext_enb, INT_V_HI##N##TX-INT_V_EXTD) }, \ | |
| { DRDATA (TXTOT, hi##N##_db.txtotal,32), REG_RO + PV_LEFT }, \ | |
| { FLDATA (LLOOP, hi##N##_db.lloop, 0), PV_RZRO }, \ | |
| { FLDATA (ERROR, hi##N##_db.error, 0), PV_RZRO }, \ | |
| { FLDATA (READY, hi##N##_db.ready, 0), PV_RZRO }, \ | |
| { FLDATA (FULL, hi##N##_db.full , 0), PV_RZRO }, \ | |
| { NULL } \ | |
| } | |
| REG hi1_reg[] = HI_REG(1), hi2_reg[] = HI_REG(2); | |
| REG hi3_reg[] = HI_REG(3), hi4_reg[] = HI_REG(4); | |
| // Host Device Modifiers ... | |
| // These are the modifiers simh uses for the "SET MIxn" and "SHOW MIx" commands. | |
| #define HI_MOD(N) { \ | |
| { 0 } \ | |
| } | |
| MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2); | |
| MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4); | |
| // Debug modifiers for "SET HIn DEBUG = xxx" ... | |
| DEBTAB hi_debug[] = { | |
| {"WARN", IMP_DBG_WARN}, // print warnings that would otherwise be suppressed | |
| {"UDP", IMP_DBG_UDP}, // print all UDP messages sent and received | |
| {"IO", IMP_DBG_IOT}, // print all program I/O instructions | |
| {0} | |
| }; | |
| // Host Device data ... | |
| // This is the primary simh structure that defines each device - it gives the | |
| // plain text name, the addresses of the unit, register and modifier tables, and | |
| // the addresses of all action routines (e.g. attach, reset, etc). | |
| #define HI_DEV(HI,N,F) { \ | |
| #HI, &hi##N##_unit, hi##N##_reg, hi##N##_mod, \ | |
| 1, 10, 31, 1, 8, 8, \ | |
| NULL, NULL, &hi_reset, NULL, &hi_attach, &hi_detach, \ | |
| &hi##N##_dib, DEV_DISABLE|DEV_DEBUG|(F), 0, hi_debug, NULL, NULL \ | |
| } | |
| DEVICE hi1_dev = HI_DEV(HI1,1,DEV_DIS), hi2_dev = HI_DEV(HI2,2,DEV_DIS); | |
| DEVICE hi3_dev = HI_DEV(HI3,3,DEV_DIS), hi4_dev = HI_DEV(HI4,4,DEV_DIS); | |
| // Host Tables ... | |
| // These tables make it easy to locate the data associated with any host. | |
| DEVICE *const hi_devices[HI_NUM] = {&hi1_dev, &hi2_dev, &hi3_dev, &hi4_dev }; | |
| UNIT *const hi_units [HI_NUM] = {&hi1_unit, &hi2_unit, &hi3_unit, &hi4_unit}; | |
| DIB *const hi_dibs [HI_NUM] = {&hi1_dib, &hi2_dib, &hi3_dib, &hi4_dib }; | |
| HIDB *const hi_hidbs [HI_NUM] = {&hi1_db, &hi2_db, &hi3_db, &hi4_db }; | |
| //////////////////////////////////////////////////////////////////////////////// | |
| ////////////////// L O W L E V E L F U N C T I O N S /////////////////// | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Find a pointer to the DEVICE, UNIT, DIB or HIDB given the host number ... | |
| #define PDEVICE(h) hi_devices[(h)-1] | |
| #define PUNIT(h) hi_units[(h)-1] | |
| #define PDIB(h) hi_dibs[(h)-1] | |
| #define PHIDB(h) hi_hidbs[(h)-1] | |
| // These macros set and clear the interrupt request and enable flags ... | |
| #define SET_RX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) | |
| #define SET_TX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) | |
| #define CLR_RX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) | |
| #define CLR_TX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) | |
| #define CLR_RX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->rxint - INT_V_EXTD))) | |
| #define CLR_TX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->txint - INT_V_EXTD))) | |
| // TRUE if the host has the specified debugging output enabled ... | |
| #define ISHDBG(l,f) ((PDEVICE(l)->dctrl & (f)) != 0) | |
| // Reset receiver (clear flags AND initialize all data) ... | |
| void hi_reset_rx (uint16 host) | |
| { | |
| PHIDB(host)->lloop = PHIDB(host)->error = PHIDB(host)->enabled = FALSE; | |
| PHIDB(host)->ready = PHIDB(host)->eom = FALSE; | |
| PHIDB(host)->rxtotal = 0; | |
| CLR_RX_IRQ(host); CLR_RX_IEN(host); | |
| } | |
| // Reset transmitter (clear flags AND initialize all data) ... | |
| void hi_reset_tx (uint16 host) | |
| { | |
| PHIDB(host)->lloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE; | |
| PHIDB(host)->txtotal = 0; | |
| CLR_TX_IRQ(host); CLR_TX_IEN(host); | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| //////////// I / O I N S T R U C T I O N E M U L A T I O N ///////////// | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Host specific I/O routines ... | |
| int32 hi1_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(1, inst, fnc, dat, dev);} | |
| int32 hi2_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(2, inst, fnc, dat, dev);} | |
| int32 hi3_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(3, inst, fnc, dat, dev);} | |
| int32 hi4_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(4, inst, fnc, dat, dev);} | |
| // Common I/O simulation routine ... | |
| int32 hi_io (uint16 host, int32 inst, int32 fnc, int32 dat, int32 dev) | |
| { | |
| // This routine is invoked by the CPU module whenever the code executes any | |
| // I/O instruction (OCP, SKS, INA or OTA) with one of our modem's device | |
| // address. | |
| // OCP (output control pulse) initiates various modem operations ... | |
| if (inst == ioOCP) { | |
| switch (fnc) { | |
| case 000: | |
| // HnROUT - start regular host output ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "start regular output (PC=%06o)\n", PC-1); | |
| return dat; | |
| case 001: | |
| // HnIN - start host input ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "start input (PC=%06o)\n", PC-1); | |
| return dat; | |
| case 002: | |
| // HnFOUT - start final host output ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "start final output (PC=%06o)\n", PC-1); | |
| return dat; | |
| case 003: | |
| // HnXP - cross patch ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable cross patch (PC=%06o)\n", PC-1); | |
| return dat; | |
| case 004: | |
| // HnUNXP - un-cross patch ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "disable cross patch (PC=%06o)\n", PC-1); | |
| return dat; | |
| case 005: | |
| // HnENAB - enable ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable host (PC=%06o)\n", PC-1); | |
| return dat; | |
| } | |
| // SKS (skip) tests various modem conditions ... | |
| } else if (inst == ioSKS) { | |
| switch (fnc) { | |
| case 000: | |
| // HnERR - skip on host error ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on error (PC=%06o %s)\n", PC-1, "NOSKIP"); | |
| return dat; | |
| case 001: | |
| // HnRDY - skip on host ready ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on ready (PC=%06o %s)\n", PC-1, "NOSKIP"); | |
| return dat; | |
| case 002: | |
| // HnEOM - skip on end of message ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on end of message (PC=%06o %s)\n", PC-1, "NOSKIP"); | |
| return dat; | |
| case 005: | |
| // HnFULL - skip on host buffer full ... | |
| sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on buffer full (PC=%06o %s)\n", PC-1, "NOSKIP"); | |
| return dat; | |
| } | |
| } | |
| // Anything else is an error... | |
| sim_debug(IMP_DBG_WARN, PDEVICE(host), "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); | |
| return IOBADFNC(dat); | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| /////////////////// H O S T E V E N T S E R V I C E //////////////////// | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Unit service ... | |
| t_stat hi_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 hi_reset (DEVICE *dptr) | |
| { | |
| // simh calls this routine for the RESET command ... | |
| UNIT *uptr = dptr->units; | |
| uint16 host= uptr->hline; | |
| hi_reset_rx(host); hi_reset_tx(host); | |
| return SCPE_OK; | |
| } | |
| // Attach (connect) ... | |
| t_stat hi_attach (UNIT *uptr, char *cptr) | |
| { | |
| // simh calls this routine for (what else?) the ATTACH command. | |
| uint16 host = uptr->hline; | |
| fprintf(stderr,"HI%d - host interface not yet implemented\n", host); | |
| return SCPE_IERR; | |
| } | |
| // Detach (connect) ... | |
| t_stat hi_detach (UNIT *uptr) | |
| { | |
| // simh calls this routine for (you guessed it!) the DETACH command. | |
| uint16 host = uptr->hline; | |
| fprintf(stderr,"HI%d - host interface not yet implemented\n", host); | |
| return SCPE_IERR; | |
| } | |
| #endif // #ifdef VM_IMPTIP from the very top |