Skip to content

Commit

Permalink
H316: Convert IMP long leaders to short, and vice versa.
Browse files Browse the repository at this point in the history
This adds the modifiers CONVERT and NOCOVERT to the HI units.  When
enabled for a unit, 1822 messages will transparently be converted.
IMP-to-host messages are converted from the old, short (32-bit) format
to the new, long (96-bit) format.  Host-to-IMP messages are converted
in the other direction.

The motivation for this feature, is that the currently running IMP
software is from 1974 and only supports short leaders.  Some operating
systems are from a later era, and only support long leaders.
  • Loading branch information
larsbrinkhoff authored and pkoning2 committed Jan 17, 2025
1 parent 33d6b08 commit feb155f
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 8 deletions.
175 changes: 167 additions & 8 deletions H316/h316_hi.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ void hi_rx_local (uint16 line, uint16 txnext, uint16 txcount);
t_stat hi_reset (DEVICE *dptr);
t_stat hi_attach (UNIT *uptr, CONST char *cptr);
t_stat hi_detach (UNIT *uptr);
t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc);



Expand All @@ -115,7 +117,7 @@ t_stat hi_detach (UNIT *uptr);
// 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) {FALSE, FALSE, 0, {0}, 0, 0, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS}
#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, FALSE, 0, 0, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS}
HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2);
HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4);

Expand Down Expand Up @@ -161,8 +163,9 @@ 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 } \
#define HI_MOD(N) { \
{ MTAB_XTD|MTAB_VDV, 0, NULL, "CONVERT", &hi_set_convert, &hi_show_convert, NULL }, \
{ MTAB_XTD|MTAB_VDV, 1, NULL, "NOCONVERT", &hi_set_convert, &hi_show_convert, NULL }, \
}
MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2);
MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4);
Expand Down Expand Up @@ -196,6 +199,25 @@ 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 };

// Old message type field set to this to signal new format leader.
#define NEW_FORMAT_FLAG (15 << 8)

// 1822 message types (or subtypes).
#define LEADER_REGULAR 000
#define LEADER_UNCONTROLLED 003
#define LEADER_NOP 004

// 1822 new leader flags.
#define NLEADER_TRACE 010
#define NLEADER_OCTAL 004
#define NLEADER_FOR_IMP 252
#define NLEADER_PRIORITY 0200

// 1822 old leader flags.
#define OLEADER_PRIORITY 010
#define OLEADER_FOR_IMP 004
#define OLEADER_TRACE 002
#define OLEADER_OCTAL 001


////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -235,6 +257,7 @@ void hi_reset_tx (uint16 host)
{
PHIDB(host)->iloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE;
PHIDB(host)->txtotal = 0;
PHIDB(host)->txfirst = TRUE;
CLR_TX_IRQ(host); CLR_TX_IEN(host);
}

Expand Down Expand Up @@ -309,6 +332,123 @@ void hi_debug_msg (uint16 line, uint16 next, uint16 count, const char *ptext)
///////////////// T R A N S M I T A N D R E C E I V E //////////////////
////////////////////////////////////////////////////////////////////////////////

// Convert 1822 long header from host, to short leader for IMP.
static int16 hi_convert_long_to_short(uint16 line, int16 count)
{
uint16 nflags, mtype, htype, host, imp, id, stype, length;
uint16 oflags;
uint16 *data = PHIDB(line)->rxdata;

if (count == 0)
return 0;

if (count < 7 || (data[1] & 0x0F00) != NEW_FORMAT_FLAG)
return count; // This is not a long leader message.

nflags = (data[2] & 0x0F00) >> 8;
mtype = data[2] & 0xFF;
htype = (data[3] & 0xFF00) >> 8;
host = data[3] & 0xFF;
imp = data[4];
id = (data[5] & 0xFFF0) >> 4;
stype = data[5] & 0x000F;
length = data[6];

// Keep track of padding.
if (mtype == LEADER_NOP)
PHIDB(line)->padding = stype;

// Sorry, can't handle these addresses.
if (host > 3)
return 0;
if (imp > 63)
return 0;

if (mtype == LEADER_REGULAR && stype == LEADER_UNCONTROLLED)
mtype = LEADER_UNCONTROLLED, stype = 0;
else if (mtype == LEADER_NOP)
stype = 0;

oflags = 0;
if (nflags & NLEADER_TRACE)
oflags |= OLEADER_TRACE;
if (nflags & NLEADER_OCTAL)
oflags |= OLEADER_OCTAL;
if (host >= NLEADER_FOR_IMP) {
oflags |= OLEADER_FOR_IMP;
host -= NLEADER_FOR_IMP;
}
if (htype & NLEADER_PRIORITY)
oflags |= OLEADER_PRIORITY;

oflags <<= 12;
mtype <<= 8;
host <<= 6;
id <<= 4;
data[1] = oflags | mtype | host | imp;
data[2] = id | stype;

if (mtype == LEADER_REGULAR) {
count -= 4 + PHIDB(line)->padding;
memmove(&data[3], &data[7 + PHIDB(line)->padding], 2 * count);
} else {
count = 3;
}

return count;
}

// Convert 1822 short header from IMP, to long leader for host.
static uint16 hi_convert_short_to_long(uint16 line, uint16 *data, uint16 count)
{
uint16 oflags, mtype, host, imp, id, stype;
uint16 nflags = 0, htype = 0, length = 0;

oflags = (data[1] & 0xF000) >> 12;
mtype = (data[1] & 0x0F00) >> 8;
host = (data[1] & 0x00C0) >> 6;
imp = data[1] & 0x003F;
id = (data[2] & 0xFFF0) >> 4;
stype = data[2] & 0x000F;

if (mtype == LEADER_REGULAR) {
memmove(&data[7 + PHIDB(line)->padding], &data[3], 2 * (count - 3));
memset(&data[7], 0, 2 * PHIDB(line)->padding);
length = 16 * (count - 3);
count += PHIDB(line)->padding;
}
count += 4;

if (oflags & OLEADER_PRIORITY)
htype |= NLEADER_PRIORITY;
htype |= 7;
if (oflags & OLEADER_FOR_IMP)
host += NLEADER_FOR_IMP;
if (oflags & OLEADER_TRACE)
nflags |= NLEADER_TRACE;
if (oflags & OLEADER_OCTAL)
nflags |= OLEADER_OCTAL;

if (mtype == LEADER_REGULAR)
stype = 0;
else if (mtype == LEADER_UNCONTROLLED)
mtype = LEADER_REGULAR, stype = LEADER_UNCONTROLLED;
else if (mtype == LEADER_NOP)
stype = 0;

nflags <<= 8;
htype <<= 8;
id <<= 4;
data[1] = NEW_FORMAT_FLAG;
data[2] = nflags | mtype;
data[3] = htype | host;
data[4] = imp;
data[5] = id | stype;
data[6] = length;

return count;
}

// Start the transmitter ...
void hi_start_tx (uint16 line, uint16 flags)
{
Expand Down Expand Up @@ -337,16 +477,19 @@ void hi_start_tx (uint16 line, uint16 flags)
// uint16 flags;
// uint16 data [MAXDATA - 1];
// Put the packet into a temp buffer for assembly.
uint16 *tmp = (uint16 *)malloc ((count + 1) * sizeof (*tmp));
static uint16 tmp[1500];
uint16 i;

tmp [0] = flags;
if (PHIDB(line)->enabled)
tmp [0] |= PFLG_READY;
for (i = 0; i < count; i ++)
tmp [i + 1] = M [next+i];
ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count + 1);
free (tmp);
count++;
if (PHIDB(line)->convert && PHIDB(line)->txfirst)
count = hi_convert_short_to_long(line, tmp, count);
PHIDB(line)->txfirst = !!(flags & PFLG_FINAL);
ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count);
if (ret != SCPE_OK && ret != 66) hi_link_error(line);
}

Expand Down Expand Up @@ -426,14 +569,15 @@ void hi_poll_rx (uint16 line)
} else {
// Get a new UDP packet.
count = udp_receive(PDEVICE(line), PHIDB(line)->link, PHIDB(line)->rxdata, MAXDATA);
if (PHIDB(line)->convert) count = hi_convert_long_to_short(line, count);
PHIDB(line)->eom = FALSE;
PHIDB(line)->rxsize = count;
if (count == 0) { return; }
if (count < 0) { hi_link_error(line); return; }
// Make note of the host ready bit.
PHIDB(line)->ready = !! (PHIDB(line)->rxdata[0] & PFLG_READY);
// Exclude the flags from the count.
PHIDB(line)->rxnext = 1; count--;
PHIDB(line)->rxnext = 1; count--;
if (count == 0) return;
PHIDB(line)->rxtotal++;
}
Expand All @@ -445,10 +589,10 @@ void hi_poll_rx (uint16 line)
count = maxbuf;
}
hi_update_dmc(PDIB(line)->rxdmc, count);
hi_debug_msg (line, next, count, "received");

for (i = 0; i < count; i ++)
* (pdata + i) = PHIDB(line)->rxdata[PHIDB(line)->rxnext++];
hi_debug_msg (line, next, count, "received");

// Now would be a good time to worry about whether a receive is pending!
if (!PHIDB(line)->rxpending) {
Expand Down Expand Up @@ -682,4 +826,19 @@ t_stat hi_detach (UNIT *uptr)
}


t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
PHIDB(uptr->hline)->convert = !val;
return SCPE_OK;
}

t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (PHIDB(uptr->hline)->convert)
fprintf (st, "Convert short leaders");
else
fprintf (st, "Do not convert short leaders");
return SCPE_OK;
}

#endif // #ifdef VM_IMPTIP from the very top
3 changes: 3 additions & 0 deletions H316/h316_imp.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,12 @@ struct _HIDB {
uint16 rxdata[MAXDATA]; // UDP packet received.
uint16 rxnext; // Index to next word in UDP packet.
uint16 rxsize; // Size of UDP packet.
uint16 padding; // Padding for long leaders.
t_bool convert; // Convert between 1822 short/long messages.
// Transmitter (IMP -> HOST) data ...
uint32 txdelay; // RTC ticks until TX done interrupt
uint32 txtotal; // total host messages sent
t_bool txfirst; // First packet in a series
// Other data ...
t_bool iloop; // local loop back enabled
t_bool enabled; // TRUE if the host is enabled
Expand Down

0 comments on commit feb155f

Please sign in to comment.