Skip to content

Commit feb155f

Browse files
larsbrinkhoffpkoning2
authored andcommitted
H316: Convert IMP long leaders to short, and vice versa.
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.
1 parent 33d6b08 commit feb155f

File tree

2 files changed

+170
-8
lines changed

2 files changed

+170
-8
lines changed

H316/h316_hi.c

Lines changed: 167 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ void hi_rx_local (uint16 line, uint16 txnext, uint16 txcount);
105105
t_stat hi_reset (DEVICE *dptr);
106106
t_stat hi_attach (UNIT *uptr, CONST char *cptr);
107107
t_stat hi_detach (UNIT *uptr);
108+
t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
109+
t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
108110

109111

110112

@@ -115,7 +117,7 @@ t_stat hi_detach (UNIT *uptr);
115117
// Host interface data blocks ...
116118
// The HIDB is our own internal data structure for each host. It keeps data
117119
// about the TCP/IP connection, buffers, etc.
118-
#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS}
120+
#define HI_HIDB(N) {FALSE, FALSE, 0, {0}, 0, 0, 0, FALSE, 0, 0, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, HI_TXBPS}
119121
HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2);
120122
HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4);
121123

@@ -161,8 +163,9 @@ REG hi3_reg[] = HI_REG(3), hi4_reg[] = HI_REG(4);
161163

162164
// Host Device Modifiers ...
163165
// These are the modifiers simh uses for the "SET MIxn" and "SHOW MIx" commands.
164-
#define HI_MOD(N) { \
165-
{ 0 } \
166+
#define HI_MOD(N) { \
167+
{ MTAB_XTD|MTAB_VDV, 0, NULL, "CONVERT", &hi_set_convert, &hi_show_convert, NULL }, \
168+
{ MTAB_XTD|MTAB_VDV, 1, NULL, "NOCONVERT", &hi_set_convert, &hi_show_convert, NULL }, \
166169
}
167170
MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2);
168171
MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4);
@@ -196,6 +199,25 @@ UNIT *const hi_units [HI_NUM] = {&hi1_unit, &hi2_unit, &hi3_unit, &hi4_unit};
196199
DIB *const hi_dibs [HI_NUM] = {&hi1_dib, &hi2_dib, &hi3_dib, &hi4_dib };
197200
HIDB *const hi_hidbs [HI_NUM] = {&hi1_db, &hi2_db, &hi3_db, &hi4_db };
198201

202+
// Old message type field set to this to signal new format leader.
203+
#define NEW_FORMAT_FLAG (15 << 8)
204+
205+
// 1822 message types (or subtypes).
206+
#define LEADER_REGULAR 000
207+
#define LEADER_UNCONTROLLED 003
208+
#define LEADER_NOP 004
209+
210+
// 1822 new leader flags.
211+
#define NLEADER_TRACE 010
212+
#define NLEADER_OCTAL 004
213+
#define NLEADER_FOR_IMP 252
214+
#define NLEADER_PRIORITY 0200
215+
216+
// 1822 old leader flags.
217+
#define OLEADER_PRIORITY 010
218+
#define OLEADER_FOR_IMP 004
219+
#define OLEADER_TRACE 002
220+
#define OLEADER_OCTAL 001
199221

200222

201223
////////////////////////////////////////////////////////////////////////////////
@@ -235,6 +257,7 @@ void hi_reset_tx (uint16 host)
235257
{
236258
PHIDB(host)->iloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE;
237259
PHIDB(host)->txtotal = 0;
260+
PHIDB(host)->txfirst = TRUE;
238261
CLR_TX_IRQ(host); CLR_TX_IEN(host);
239262
}
240263

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

335+
// Convert 1822 long header from host, to short leader for IMP.
336+
static int16 hi_convert_long_to_short(uint16 line, int16 count)
337+
{
338+
uint16 nflags, mtype, htype, host, imp, id, stype, length;
339+
uint16 oflags;
340+
uint16 *data = PHIDB(line)->rxdata;
341+
342+
if (count == 0)
343+
return 0;
344+
345+
if (count < 7 || (data[1] & 0x0F00) != NEW_FORMAT_FLAG)
346+
return count; // This is not a long leader message.
347+
348+
nflags = (data[2] & 0x0F00) >> 8;
349+
mtype = data[2] & 0xFF;
350+
htype = (data[3] & 0xFF00) >> 8;
351+
host = data[3] & 0xFF;
352+
imp = data[4];
353+
id = (data[5] & 0xFFF0) >> 4;
354+
stype = data[5] & 0x000F;
355+
length = data[6];
356+
357+
// Keep track of padding.
358+
if (mtype == LEADER_NOP)
359+
PHIDB(line)->padding = stype;
360+
361+
// Sorry, can't handle these addresses.
362+
if (host > 3)
363+
return 0;
364+
if (imp > 63)
365+
return 0;
366+
367+
if (mtype == LEADER_REGULAR && stype == LEADER_UNCONTROLLED)
368+
mtype = LEADER_UNCONTROLLED, stype = 0;
369+
else if (mtype == LEADER_NOP)
370+
stype = 0;
371+
372+
oflags = 0;
373+
if (nflags & NLEADER_TRACE)
374+
oflags |= OLEADER_TRACE;
375+
if (nflags & NLEADER_OCTAL)
376+
oflags |= OLEADER_OCTAL;
377+
if (host >= NLEADER_FOR_IMP) {
378+
oflags |= OLEADER_FOR_IMP;
379+
host -= NLEADER_FOR_IMP;
380+
}
381+
if (htype & NLEADER_PRIORITY)
382+
oflags |= OLEADER_PRIORITY;
383+
384+
oflags <<= 12;
385+
mtype <<= 8;
386+
host <<= 6;
387+
id <<= 4;
388+
data[1] = oflags | mtype | host | imp;
389+
data[2] = id | stype;
390+
391+
if (mtype == LEADER_REGULAR) {
392+
count -= 4 + PHIDB(line)->padding;
393+
memmove(&data[3], &data[7 + PHIDB(line)->padding], 2 * count);
394+
} else {
395+
count = 3;
396+
}
397+
398+
return count;
399+
}
400+
401+
// Convert 1822 short header from IMP, to long leader for host.
402+
static uint16 hi_convert_short_to_long(uint16 line, uint16 *data, uint16 count)
403+
{
404+
uint16 oflags, mtype, host, imp, id, stype;
405+
uint16 nflags = 0, htype = 0, length = 0;
406+
407+
oflags = (data[1] & 0xF000) >> 12;
408+
mtype = (data[1] & 0x0F00) >> 8;
409+
host = (data[1] & 0x00C0) >> 6;
410+
imp = data[1] & 0x003F;
411+
id = (data[2] & 0xFFF0) >> 4;
412+
stype = data[2] & 0x000F;
413+
414+
if (mtype == LEADER_REGULAR) {
415+
memmove(&data[7 + PHIDB(line)->padding], &data[3], 2 * (count - 3));
416+
memset(&data[7], 0, 2 * PHIDB(line)->padding);
417+
length = 16 * (count - 3);
418+
count += PHIDB(line)->padding;
419+
}
420+
count += 4;
421+
422+
if (oflags & OLEADER_PRIORITY)
423+
htype |= NLEADER_PRIORITY;
424+
htype |= 7;
425+
if (oflags & OLEADER_FOR_IMP)
426+
host += NLEADER_FOR_IMP;
427+
if (oflags & OLEADER_TRACE)
428+
nflags |= NLEADER_TRACE;
429+
if (oflags & OLEADER_OCTAL)
430+
nflags |= OLEADER_OCTAL;
431+
432+
if (mtype == LEADER_REGULAR)
433+
stype = 0;
434+
else if (mtype == LEADER_UNCONTROLLED)
435+
mtype = LEADER_REGULAR, stype = LEADER_UNCONTROLLED;
436+
else if (mtype == LEADER_NOP)
437+
stype = 0;
438+
439+
nflags <<= 8;
440+
htype <<= 8;
441+
id <<= 4;
442+
data[1] = NEW_FORMAT_FLAG;
443+
data[2] = nflags | mtype;
444+
data[3] = htype | host;
445+
data[4] = imp;
446+
data[5] = id | stype;
447+
data[6] = length;
448+
449+
return count;
450+
}
451+
312452
// Start the transmitter ...
313453
void hi_start_tx (uint16 line, uint16 flags)
314454
{
@@ -337,16 +477,19 @@ void hi_start_tx (uint16 line, uint16 flags)
337477
// uint16 flags;
338478
// uint16 data [MAXDATA - 1];
339479
// Put the packet into a temp buffer for assembly.
340-
uint16 *tmp = (uint16 *)malloc ((count + 1) * sizeof (*tmp));
480+
static uint16 tmp[1500];
341481
uint16 i;
342482

343483
tmp [0] = flags;
344484
if (PHIDB(line)->enabled)
345485
tmp [0] |= PFLG_READY;
346486
for (i = 0; i < count; i ++)
347487
tmp [i + 1] = M [next+i];
348-
ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count + 1);
349-
free (tmp);
488+
count++;
489+
if (PHIDB(line)->convert && PHIDB(line)->txfirst)
490+
count = hi_convert_short_to_long(line, tmp, count);
491+
PHIDB(line)->txfirst = !!(flags & PFLG_FINAL);
492+
ret = udp_send(PDEVICE(line), PHIDB(line)->link, tmp, count);
350493
if (ret != SCPE_OK && ret != 66) hi_link_error(line);
351494
}
352495

@@ -426,14 +569,15 @@ void hi_poll_rx (uint16 line)
426569
} else {
427570
// Get a new UDP packet.
428571
count = udp_receive(PDEVICE(line), PHIDB(line)->link, PHIDB(line)->rxdata, MAXDATA);
572+
if (PHIDB(line)->convert) count = hi_convert_long_to_short(line, count);
429573
PHIDB(line)->eom = FALSE;
430574
PHIDB(line)->rxsize = count;
431575
if (count == 0) { return; }
432576
if (count < 0) { hi_link_error(line); return; }
433577
// Make note of the host ready bit.
434578
PHIDB(line)->ready = !! (PHIDB(line)->rxdata[0] & PFLG_READY);
435579
// Exclude the flags from the count.
436-
PHIDB(line)->rxnext = 1; count--;
580+
PHIDB(line)->rxnext = 1; count--;
437581
if (count == 0) return;
438582
PHIDB(line)->rxtotal++;
439583
}
@@ -445,10 +589,10 @@ void hi_poll_rx (uint16 line)
445589
count = maxbuf;
446590
}
447591
hi_update_dmc(PDIB(line)->rxdmc, count);
448-
hi_debug_msg (line, next, count, "received");
449592

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

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

684828

829+
t_stat hi_set_convert (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
830+
{
831+
PHIDB(uptr->hline)->convert = !val;
832+
return SCPE_OK;
833+
}
834+
835+
t_stat hi_show_convert (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
836+
{
837+
if (PHIDB(uptr->hline)->convert)
838+
fprintf (st, "Convert short leaders");
839+
else
840+
fprintf (st, "Do not convert short leaders");
841+
return SCPE_OK;
842+
}
843+
685844
#endif // #ifdef VM_IMPTIP from the very top

H316/h316_imp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,12 @@ struct _HIDB {
176176
uint16 rxdata[MAXDATA]; // UDP packet received.
177177
uint16 rxnext; // Index to next word in UDP packet.
178178
uint16 rxsize; // Size of UDP packet.
179+
uint16 padding; // Padding for long leaders.
180+
t_bool convert; // Convert between 1822 short/long messages.
179181
// Transmitter (IMP -> HOST) data ...
180182
uint32 txdelay; // RTC ticks until TX done interrupt
181183
uint32 txtotal; // total host messages sent
184+
t_bool txfirst; // First packet in a series
182185
// Other data ...
183186
t_bool iloop; // local loop back enabled
184187
t_bool enabled; // TRUE if the host is enabled

0 commit comments

Comments
 (0)