Echnego Status

To get echo negotiation working, we need to:

  • Understand how the parameters are being passed to the FNP in the mailbox.

As an example, in dps8_fnp.c, search for " set_framing_chars". It takes 2 parameters (the characters). which are stored in the low eight bits of of command_data0 and command_data1, which are located in the FNP mailbox.

The handler extracts the two parameters, and formats a message to the FNP, and calls tellFNP to pass the message.

So, by reading the MTB we should be able to get the general format of the parameters, and by examining the Multics source, we can get the exact locations of the parameters in the mailbox.

bound_355_wired.s.archive/dn355.pl1 looks promising:

send_echo_table:
     procedure (mbx_num, table_bits);
  • Define the messages.

It looks like the are four messages:

set_echnego_break_table

start_negotiated_echo

stop_negotiated_echo

init_echo_negotiation

The messages to the fnp are of the general format "verb <parameters>"; eg.

set_framing_chars 10 11

If there is a large amount of data, there is a protocol for passing a block of memory: (see "wtx" and pack()).
foo data:<len>:<hex data>

So suppose the set_echnego_break_table takes a 256 bit string. 256 bits takes 8 words. So the message might be:
set_echnego_break_table data:8:6affd…3a

But I just realized that pack() packs 9 bit characters and discards the high bit. Hmmm.Need to revisit that… we probably need "data8" and "data36" protocols…

Anyway, once the arguments are understood, adding the messages to dps8_fnp are relatively straight forward. I haven't done it because I haven't had time to decipher the MTB and the Multics source. (We also have the FNP source code, it might make sense to see if there is usable information in there.)

  • Receive the messages. and store the parameters

In fnp_cmds.c, the message is parsed, and passed to a overly long if/eleeif. Search for set_framing_chars; it uses sscanf to pick out the parameters, validates them, and stores them in Mstate.

  • Run the protocol.

In fnp_2.c, processInputCharacter() handles incoming traffic from the terminal.

If has the echo and line break logic, and is incorrect. When I was using dialup back in 197<mumble>, "half duplex" and "full duplex"referred to the local echoing of characters on the terminal, and I coded processInputCharacter that way. For Multics, "half_duplex" (correctly) means that the terminal needs to be switched between input and output modes (like the operator console and its ATTN key); and "echoplex" refers to local echoing.

So, the "half duplex" code in processInputCharacter is bogus and needs revisiting.

In processInputCharacter, near the top, is

if (MState . line [hsla_line_num] .echoPlex)

The code needs to read
if (negotiated echo)

else if (echoplex)

else

There is also "breakAll" code mingled in there. In this context "line break" means that the input character causes the accumulated input to be transmitted to Multics. In not "breakAll" mode, that would CR or LF, etc. In "breakAll", each character is sent.

The added code needs to consult the various parameters and the input character to make decisions about echoing and line break.
processInputCharacter() needs a complete rewrite anyway. It looks a lot like whoever wrote it (that would be me) didn't understand how it was supposed to work.

Understanding the echnego table in the mailbox

Patch hardcore to print the table contents.

bound_355_wired.s.archive/fnp_multiplexer.pl1

dcl  1 echnego_break_table aligned,
       2 words (0:15) unaligned,
         3 bits bit (16) unaligned,
         3 pad bit (2) unaligned;
          else if order = "set_echnego_break_table"
          then do;
               mbx_data_len = length (unspec (echnego_break_table));
               unspec (echnego_break_table) = ""b;          /* Get pads */
               do i = 0 to hbound (echnego_break_table.words, 1);
                    echnego_break_table.bits (i) = substr (data_ptr -> based_echo_table_bits, 1 + 16 * i, 16);
               end;
               mbx_data_long = unspec (echnego_break_table);
               opcode = set_echnego_break_table;
cp >ldd>sl1>s>bound_355_wired.s.archive
ac x bound_355_wired.s.archive fnp_multiplexer.pl1

               mbx_data_len = length (unspec (echnego_break_table));
call syserr (0, "mbx_data_len ^d", mbx_data_len);
               unspec (echnego_break_table) = ""b;          /* Get pads */
               do i = 0 to hbound (echnego_break_table.words, 1);
call syserr (0, "  ^w", substr (data_ptr -> based_echo_table_bits, 1 + 16 * i
, 16));
                    echnego_break_table.bits (i) = substr (data_ptr -> based_ec
\cho_table_bits, 1 + 16 * i, 16);
               end;

pl1 fnp_multiplexer
cp >ldd>sl1>o>bound_355_wired.archive
ac u bound_355_wired fnp_multiplexer
bind bound_355_wired

Generate tape, reboot, emacs….

0852.5  mbx_data_len 288
0852.5    777774000000
0852.5  =
0852.5    040000000000
0852.5    000000000000
0852.5    400000000000
0852.5    000040000000
0852.5    000000000000
0852.5    000004000000
0852.5    777774000000
0852.5  =
0852.5  =
0852.5  =
0852.5  =
0852.5  =
0852.5  =
0852.5  =

And what does the DIA see?

fnp set_echnego_break_table
set_echnego_break_table 0 addr 203340 len 8

dataAddrPhys 1005340
   777774777774
   040000000000
   400000000040
   000000000004
   777774777774
   777774777774
   777774777774
   777774777774

Okay; 16 words, not 8, but correct.

The FNP sees:

set: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 35 64 92 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

Next up:

          else if order = "start_negotiated_echo"
          then do;
               mbx_data_len = 36;
               mbx_data =
                    bit (fixed (data_ptr -> echo_start_data.ctr, 18), 18)
                    || bit (fixed (data_ptr -> echo_start_data.screenleft, 18), 18);
               opcode = start_negotiated_echo;
          end;
          else if order = "set_echnego_break_table"
          then do;
               mbx_data_len = length (unspec (echnego_break_table));
               unspec (echnego_break_table) = ""b;          /* Get pads */
               do i = 0 to hbound (echnego_break_table.words, 1);
                    echnego_break_table.bits (i) = substr (data_ptr -> based_echo_table_bits, 1 + 16 * i, 16);
               end;
               mbx_data_long = unspec (echnego_break_table);
               opcode = set_echnego_break_table;
          end;
          else if order = "init_echo_negotiation"
          then do;
               mbx_data_len = 0;
               mbx_data = ""b;
               opcode = init_echo_negotiation;
          end;
          else if order = "stop_negotiated_echo"
          then do;
               mbx_data_len = 0;
               mbx_data = ""b;
               opcode = stop_negotiated_echo;
          end;

start_negotiated_echo, init_echo_negotiation, stop_negotiated_echo: No data, easy enough

ack_echnego_init
ack_echnego_stop
dcl  1 echo_start_data aligned based (data_ptr),            /* Echo starting data */
       2 ctr fixed bin (35),                                /* Synchronization counter */
       2 screenleft fixed bin (35);                         /* Length left on screen */
/* BEGIN INCLUDE FILE mcs_echo_neg_sys.incl.pl1   Bernard Greenberg 1/20/79 */

/* Modified 6/29/79 by BSG for FNP echo negotiation */

/****^  HISTORY COMMENTS:
  1) change(86-04-23,Coren), approve(86-04-23,MCR7300),
     audit(86-05-19,Beattie), install(86-07-08,MR12.0-1089):
     To increase size of break table and to add named constants for the size.
                                                   END HISTORY COMMENTS */

/* This include file defines the wired structure for MCS echo negotiation */

dcl echo_datap ptr;                                         /* Wired echo data ptr */
dcl WIRED_ECHO_BREAK_SIZE fixed bin internal static options (constant) init (255);
dcl WORDS_IN_ECHO_BREAK_TABLE fixed bin internal static options (constant) init (8);

dcl 1 echo_data based (echo_datap) aligned,                 /* Wired echo data */
    2 break (0: 255) bit (1) unaligned,                     /* 1 = break on this character */
    2 synchronized bit (1) unal,                            /* Mux echo negotiation is synchronized */
    2 mux_will_echnego bit (1) unal,                        /* Multiplexer accepted start_neg_echnego */
    2 echo_start_pending_sndopt bit (1) unal,               /* Send start_n_e when SEND_OUTPUT comes */
    2 awaiting_start_sync bit (1) unal,                     /* Awaiting mux reply ACK for start */
    2 awaiting_stop_sync bit (1) unal,                      /* Awaiting mux reply ACK for stop */
    2 pad bit (27) unaligned,
    2 sync_ctr fixed bin (35),                              /* Protocol ctr for MUX echo neg */
    2 chars_echoed fixed bin (9) unsigned unaligned,        /* Count of chars echoed */
    2 horiz_room_left fixed bin (9) unsigned unaligned,     /* Room left on line */
    2 rubout_trigger_chars (2) unaligned,                   /* Characters that cause rubout action */
      3 char char (1) unaligned,
    2 rubout_sequence_length fixed bin (4) unsigned unaligned, /* Length of rubout sequence, output */
    2 rubout_pad_count fixed bin (4) unsigned unaligned,    /* Count of pads needed */
    2 buffer_rubouts bit (1) unaligned,                     /* 1 = put rubouts and rubbed out in buffer */
    2 rubout_sequence char (12) unaligned;                  /* Actual rubout sequence */

/* END INCLUDE FILE mcs_echo_neg_sys.incl.pl1 */

According to the MTB…

Ring 0 MCS sends set_echnego_breaktable.

Then when appropriate, sends "start negotiated echo", specifying the number of characters left in the line.

My reading of page 13 last paragraph through page 14 second paragraph says that if in negotiated mode, never set the break bit on the returned buffer,.

The first full paragraph on 15 dicuess the sync. counter.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License