root/src/dps8/dps8_prt.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. prt_init
  2. prt_reset
  3. gc
  4. parseID
  5. openPrtFile
  6. eoj
  7. print_buf
  8. loadImageBuffer
  9. readStatusRegister
  10. loadVFCImage
  11. print_cmd
  12. prt_cmd_202
  13. prt_cmd_300
  14. prt_cmd_300a
  15. prt_cmd_400
  16. prt_iom_cmd
  17. prt_show_nunits
  18. prt_set_nunits
  19. prt_show_device_name
  20. prt_set_device_model
  21. prt_show_device_model
  22. prt_set_device_name
  23. prt_show_path
  24. prt_set_path
  25. burst_printer
  26. signal_prt_ready
  27. prt_set_ready
  28. prt_set_config
  29. prt_show_config

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * SPDX-License-Identifier: Multics
   5  * scspell-id: cb56e6b9-f62e-11ec-8a20-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * Copyright (c) 2007-2013 Michael Mondy
  10  * Copyright (c) 2012-2016 Harry Reed
  11  * Copyright (c) 2013-2016 Charles Anthony
  12  * Copyright (c) 2020-2021 Dean Anderson
  13  * Copyright (c) 2021-2022 The DPS8M Development Team
  14  *
  15  * All rights reserved.
  16  *
  17  * This software is made available under the terms of the ICU
  18  * License, version 1.8.1 or later.  For more details, see the
  19  * LICENSE.md file at the top-level directory of this distribution.
  20  *
  21  * ---------------------------------------------------------------------------
  22  *
  23  * This source file may contain code comments that adapt, include, and/or
  24  * incorporate Multics program code and/or documentation distributed under
  25  * the Multics License.  In the event of any discrepancy between code
  26  * comments herein and the original Multics materials, the original Multics
  27  * materials should be considered authoritative unless otherwise noted.
  28  * For more details and historical background, see the LICENSE.md file at
  29  * the top-level directory of this distribution.
  30  *
  31  * ---------------------------------------------------------------------------
  32  */
  33 
  34 #include <stdio.h>
  35 #include <ctype.h>
  36 #include <unistd.h>
  37 
  38 #include "dps8.h"
  39 #include "dps8_iom.h"
  40 #include "dps8_prt.h"
  41 #include "dps8_sys.h"
  42 #include "dps8_faults.h"
  43 #include "dps8_scu.h"
  44 #include "dps8_cable.h"
  45 #include "dps8_cpu.h"
  46 #include "dps8_utils.h"
  47 #include "utfile.h"
  48 
  49 #define DBG_CTR 1
  50 
  51 //-- // XXX We use this where we assume there is only one unit
  52 //-- #define ASSUME0 0
  53 //--
  54 
  55 // printer_types.incl.pl1
  56 //
  57 // dcl  models (13) fixed bin /* table of printer model numbers */
  58 //     (202, 300, 301, 302, 303, 304, 401, 402, 901, 1000, 1200, 1201, 1600);
  59 //
  60 // dcl  types (13) fixed bin /* table of corresponding printer types */
  61 //    (  1,   2,   2,   2,   3,   3,   4,   4,   4,    4,    4,    4,    4);
  62 //
  63 // dcl  WRITE (4) bit (6) /* printer write edited commands */
  64 //     ("011000"b, "011000"b, "011100"b, "011100"b);
  65 //
  66 // dcl  WRITE_NE_SLEW (4) bit (6) /* printer write non-edited commands */
  67 //     ("001001"b, "001001"b, "001101"b, "001101"b);
  68 //
  69 // dcl  LOAD_IMAGE (4) bit (6) /* printer load image buffer commands */
  70 //     ("000000"b, "001100"b, "000001"b, "000001"b);
  71 //
  72 // dcl  LOAD_VFC (4) bit (6) /* printer load VFC image commands */
  73 //     ("000000"b, "000000"b, "000000"b, "000101"b);
  74 //
  75 // dcl  READ_STATUS (4) bit (6) /* printer read detailed status command */
  76 //     ("000000"b, "000000"b, "000000"b, "000011"b);
  77 
  78 // AN87 only defines commands for
  79 //   PRT203/303, PRU1200/1600
  80 // and
  81 //   PRT202/300
  82 
  83 #define N_PRT_UNITS 1 // default
  84 
  85 static t_stat prt_reset (DEVICE * dptr);
  86 static t_stat prt_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
  87 static t_stat prt_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
  88 static t_stat prt_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
  89 static t_stat prt_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
  90 static t_stat prt_set_config (UNUSED UNIT *  uptr, UNUSED int32 value,
  91                               const char * cptr, UNUSED void * desc);
  92 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
  93                                UNUSED int  val, UNUSED const void * desc);
  94 static t_stat prt_show_path (UNUSED FILE * st, UNIT * uptr,
  95                                        UNUSED int val, UNUSED const void * desc);
  96 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
  97                                     const UNUSED char * cptr, UNUSED void * desc);
  98 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
  99                              UNUSED const char * cptr,
 100                              UNUSED void * desc);
 101 
 102 static t_stat prt_show_device_model (FILE *st, UNIT *uptr, int val, const void *desc);
 103 static t_stat prt_set_device_model (UNIT * uptr, int32 value, const char * cptr, void * desc);
 104 
 105 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
 106                      UNIT_IDLE )
 107 UNIT prt_unit[N_PRT_UNITS_MAX] =
 108   {
 109     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 110     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 111     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 112     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 113     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 114     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 115     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 116     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 117     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 118     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 119     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 120     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 121     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 122     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 123     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 124     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 125     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 126     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 127     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 128     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 129     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 130     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 131     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 132     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 133     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 134     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 135     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 136     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 137     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 138     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 139     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 140     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 141     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
 142     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
 143   };
 144 
 145 #define PRT_UNIT_NUM(uptr) ((uptr) - prt_unit)
 146 
 147 static DEBTAB prt_dt[] =
 148   {
 149     { "NOTIFY", DBG_NOTIFY, NULL },
 150     { "INFO",   DBG_INFO,   NULL },
 151     { "ERR",    DBG_ERR,    NULL },
 152     { "WARN",   DBG_WARN,   NULL },
 153     { "DEBUG",  DBG_DEBUG,  NULL },
 154     { "ALL",    DBG_ALL,    NULL }, /* don't move as it messes up DBG message */
 155     { NULL,     0,          NULL }
 156   };
 157 
 158 #define UNIT_WATCH UNIT_V_UF
 159 
 160 static MTAB prt_mod[] =
 161   {
 162 #ifndef SPEED
 163     { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 164     { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 165 #endif
 166     {
 167       MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* mask               */
 168       0,                                          /* match              */
 169       "NUNITS",                                   /* print string       */
 170       "NUNITS",                                   /* match string       */
 171       prt_set_nunits,                             /* validation routine */
 172       prt_show_nunits,                            /* display routine    */
 173       "Number of PRT units in the system",        /* value descriptor   */
 174       NULL                                        /* help               */
 175     },
 176     {
 177       MTAB_XTD | MTAB_VDV  | MTAB_NMO | \
 178                  MTAB_VALR | MTAB_NC,             /* mask               */
 179       0,                                          /* match              */
 180       "PATH",                                     /* print string       */
 181       "PATH",                                     /* match string       */
 182       prt_set_path,                               /* validation routine */
 183       prt_show_path,                              /* display routine    */
 184       "Path to write PRT files",                  /* value descriptor   */
 185       NULL                                        /* help               */
 186     },
 187     {
 188       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* mask               */
 189       0,                                          /* match              */
 190       "NAME",                                     /* print string       */
 191       "NAME",                                     /* match string       */
 192       prt_set_device_name,                        /* validation routine */
 193       prt_show_device_name,                       /* display routine    */
 194       "Select the printer name",                  /* value descriptor   */
 195       NULL                                        /* help               */
 196     },
 197 
 198     {
 199       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* mask               */
 200       0,                                          /* match              */
 201       "MODEL",                                    /* print string       */
 202       "MODEL",                                    /* match string       */
 203       prt_set_device_model,                       /* validation routine */
 204       prt_show_device_model,                      /* display routine    */
 205       "Select the printer model",                 /* value descriptor   */
 206       NULL                                        /* help               */
 207     },
 208     {
 209       MTAB_XTD | MTAB_VUN,                        /* mask               */
 210       0,                                          /* match              */
 211       (char *) "CONFIG",                          /* print string       */
 212       (char *) "CONFIG",                          /* match string       */
 213       prt_set_config,                             /* validation routine */
 214       prt_show_config,                            /* display routine    */
 215       NULL,                                       /* value descriptor   */
 216       NULL,                                       /* help               */
 217     },
 218     {
 219       MTAB_XTD | MTAB_VUN | MTAB_NMO | MTAB_VALR, /* mask               */
 220       0,                                          /* match              */
 221       "READY",                                    /* print string       */
 222       "READY",                                    /* match string       */
 223       prt_set_ready,                              /* validation routine */
 224       NULL,                                       /* display routine    */
 225       NULL,                                       /* value descriptor   */
 226       NULL                                        /* help               */
 227     },
 228     { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
 229   };
 230 
 231 DEVICE prt_dev = {
 232     "PRT",        /* name                */
 233     prt_unit,     /* unit                */
 234     NULL,         /* registers           */
 235     prt_mod,      /* modifiers           */
 236     N_PRT_UNITS,  /* number of units     */
 237     10,           /* address radix       */
 238     24,           /* address width       */
 239     1,            /* address increment   */
 240     8,            /* data radix          */
 241     36,           /* data width          */
 242     NULL,         /* examine             */
 243     NULL,         /* deposit             */
 244     prt_reset,    /* reset               */
 245     NULL,         /* boot                */
 246     NULL,         /* attach              */
 247     NULL,         /* detach              */
 248     NULL,         /* context             */
 249     DEV_DEBUG,    /* flags               */
 250     0,            /* debug control flags */
 251     prt_dt,       /* debug flag names    */
 252     NULL,         /* memory size change  */
 253     NULL,         /* logical name        */
 254     NULL,         /* help                */
 255     NULL,         /* attach help         */
 256     NULL,         /* attach context      */
 257     NULL,         /* description         */
 258     NULL          /* end                 */
 259 };
 260 
 261 typedef struct
 262   {
 263     enum prt_mode
 264       {
 265          prtNoMode, prtPrt, prtLdImgBuf, prtRdStatReg, prtLdVFCImg
 266       }  ioMode;
 267     int  prtUnitNum;
 268     bool isBCD;
 269     bool isEdited;
 270     int  slew;
 271     char device_name[MAX_DEV_NAME_LEN];
 272     int  prtfile; // fd
 273     //bool last;
 274     bool cachedFF;
 275     bool split;
 276     int  model;
 277   } prt_state_t;
 278 
 279 static prt_state_t prt_state[N_PRT_UNITS_MAX];
 280 
 281 static char prt_path[1025];
 282 
 283 #define N_MODELS 13
 284 
 285 static const char * model_names[N_MODELS] =
 286   {
 287     "202", "300", "301",  "302",  "303",  "304",
 288     "401", "402", "901", "1000", "1200", "1201",
 289     "1600"
 290   };
 291 
 292 #define MODEL_1600 12
 293 
 294 static const int model_type[N_MODELS] =
 295   { 1, 2, 2, 2, 3, 3,
 296     4, 4, 4, 4, 4, 4,
 297     4
 298   };
 299 
 300 #ifdef NO_C_ELLIPSIS
 301 static const uint8 newlines[128] = {
 302   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 303   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 304   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 305   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 306   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 307   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 308   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 309   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 310   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 311   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 312   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 313   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 314   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 315   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 316   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
 317   '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'
 318 };
 319 
 320 static const uint8 spaces[128] = {
 321   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 322   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 323   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 324   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 325   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 326   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 327   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 328   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 329   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 330   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 331   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 332   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 333   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 334   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 335   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
 336   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
 337 };
 338 #else
 339 static const uint8 newlines[128] = { [0 ... 127] = '\n' };
 340 static const uint8   spaces[128] = { [0 ... 127] = ' ' };
 341 #endif
 342 static const uint8 formfeed[1] = { '\f' };
 343 static const uint8 crlf[4]     = { '\r', '\n', '\r', '\n' };
 344 static const uint8 cr[2]       = { '\r', '\n' };
 345 
 346 /*
 347  * prt_init()
 348  *
 349  */
 350 
 351 // Once-only initialization
 352 
 353 void prt_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 354   {
 355     memset (prt_path, 0, sizeof (prt_path));
 356     memset (prt_state, 0, sizeof (prt_state));
 357     for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
 358       {
 359         prt_state[i].prtfile = -1;
 360         prt_state[i].model = MODEL_1600;
 361       }
 362   }
 363 
 364 static t_stat prt_reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 365   {
 366 
 367 
 368 
 369 
 370 
 371 
 372 
 373     return SCPE_OK;
 374   }
 375 
 376 // Given an array of word36 and a 9bit char offset, return the char
 377 
 378 static word9 gc (word36 * b, uint os)
     /* [previous][next][first][last][top][bottom][index][help] */
 379   {
 380     uint wordno = os / 4;
 381     uint charno = os % 4;
 382     return (word9) getbits36_9 (b[wordno], charno * 9);
 383   }
 384 
 385 // Don't know what the longest user id is...
 386 #define LONGEST 128
 387 
 388 // looking for space/space/5 digit number/\037/\005/name/\037
 389 // qno will get 5 chars + null;
 390 
 391 //  040040061060 060060062037 005101156164 150157156171 056123171163 101144155151 156056141037 145061060060 060062013002
 392 // <  10002\037\005Anthony.SysAdmin.a\037e10002\013\002>
 393 //  01234567   8   9
 394 static int parseID (word36 * b, uint tally, char * qno, char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 395   {
 396     if (tally < 3)
 397       return 0;
 398     if (gc (b, 0) != 040)
 399       return 0;
 400     if (gc (b, 1) != 040)
 401       return 0;
 402     uint i;
 403     for (i = 0; i < 5; i ++)
 404       {
 405         word9 ch = gc (b, 2 + i);
 406         if (ch < '0' || ch > '9')
 407           return 0;
 408         qno[i] = (char) ch;
 409       }
 410     qno[5] = 0;
 411     if (gc (b, 7) != 037)
 412       return 0;
 413     //if (gc (b, 8) != 005)
 414       //return 0;
 415     for (i = 0; i < LONGEST; i ++)
 416       {
 417         word9 ch = gc (b, 9 + i);
 418         if (ch == 037)
 419           break;
 420         if (! isprint (ch))
 421           return 0;
 422         name[i] = (char) ch;
 423       }
 424     name[i] = 0;
 425     return -1;
 426   }
 427 
 428 // 0 ok
 429 // -1 unable to open print file
 430 // -2 unable to write to print file
 431 // -3 form feed cached, no i/o done.
 432 
 433 static int openPrtFile (int prt_unit_num, word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 434   {
 435     if (prt_state[prt_unit_num].prtfile != -1)
 436       return 0;
 437 
 438 // The first (spooled) write is a formfeed; special case it and delay opening
 439 //  until the next line
 440 
 441     if (tally == 1 && buffer[0] == 0014013000000llu) //-V536
 442       {
 443         prt_state[prt_unit_num].cachedFF = true;
 444         return -3;
 445       }
 446 
 447     char qno[6], name[LONGEST + 1];
 448     int rc = parseID (buffer, tally, qno, name);
 449     char template[1024 + 129 + LONGEST];
 450     char unit_designator = 'a' + (char) prt_unit_num;
 451     char split_prefix[6];
 452     split_prefix[0] = 0;
 453     if (prt_state [prt_unit_num] . split) {
 454       sprintf(split_prefix, "prt%c/", unit_designator);
 455     }
 456     if (rc == 0)
 457       sprintf (template, "%s%sprt%c.spool.XXXXXX.prt", prt_path, split_prefix, unit_designator);
 458     else
 459       sprintf (template, "%s%sprt%c.spool.%s.%s.XXXXXX.prt", prt_path, split_prefix, unit_designator, qno, name);
 460 
 461     prt_state[prt_unit_num].prtfile = utfile_mkstemps (template, 4);
 462     if (prt_state[prt_unit_num].prtfile == -1)
 463       {
 464         sim_warn ("Unable to open printer file '%s', errno %d\n", template, errno);
 465         return -1;
 466       }
 467     if (prt_state[prt_unit_num].cachedFF)
 468       {
 469         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, formfeed, 1);
 470         if (n_write != 1)
 471           {
 472             return -2;
 473           }
 474         prt_state[prt_unit_num].cachedFF = false;
 475       }
 476     return 0;
 477   }
 478 
 479 // looking for lines "\037\014%%%%%\037\005"
 480 static int eoj (word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 481   {
 482     if (tally < 3)
 483       return 0;
 484     if (getbits36_9 (buffer[0], 0) != 037)
 485       return 0;
 486     if (getbits36_9 (buffer[0], 9) != 014)
 487       return 0;
 488     word9 ch = getbits36_9 (buffer[0], 18);
 489     if (ch < '0' || ch > '9')
 490       return 0;
 491     ch = getbits36_9 (buffer[0], 27);
 492     if (ch < '0' || ch > '9')
 493       return 0;
 494     ch = getbits36_9 (buffer[1], 0);
 495     if (ch < '0' || ch > '9')
 496       return 0;
 497     ch = getbits36_9 (buffer[1], 9);
 498     if (ch < '0' || ch > '9')
 499       return 0;
 500     ch = getbits36_9 (buffer[1], 18);
 501     if (ch < '0' || ch > '9')
 502       return 0;
 503     if (getbits36_9 (buffer[1], 27) != 037)
 504       return 0;
 505     if (getbits36_9 (buffer[2], 0) != 005)
 506       return 0;
 507     return -1;
 508   }
 509 
 510 // Based on prt_status_table_.alm
 511 //  I think that "substat_entry a,b,c,d"
 512 //    a  character number (6 bit chars; 6/word))
 513 //    b  bit pattern
 514 // so
 515 //   substat_entry       1,000000,,(Normal)
 516 // means "a 0 in char 1" means normal.
 517 //
 518 
 519 
 520 
 521 
 522 
 523 
 524 
 525 
 526 
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534 
 535 
 536 
 537 
 538 
 539 
 540 
 541 
 542 
 543 
 544 
 545 
 546 
 547 
 548 
 549 
 550 
 551 
 552 
 553 
 554 
 555 
 556 
 557 
 558 
 559 
 560 
 561 
 562 
 563 
 564 
 565 
 566 
 567 
 568 
 569 
 570 
 571 
 572 
 573 
 574 
 575 
 576 
 577 
 578 
 579 
 580 
 581 
 582 
 583 
 584 
 585 
 586 
 587 
 588 
 589 
 590 
 591 
 592 
 593 
 594 
 595 
 596 
 597 
 598 
 599 
 600 
 601 
 602 
 603 
 604 
 605 
 606 
 607 
 608 
 609 
 610 
 611 
 612 
 613 
 614 
 615 // 0 OK
 616 // -1 Can't open print file
 617 // -2 Can't write to print file
 618 
 619 static int print_buf (int prt_unit_num, bool isBCD, bool is_edited, int slew, word36 * buffer, uint tally)
     /* [previous][next][first][last][top][bottom][index][help] */
 620   {
 621 // derived from pr2_conv_$lower_case_table
 622 //
 623 //        0    1    2    3    4    5    6    7
 624 // 000   '0'  '1'  '2'  '3'  '4'  '5'  '6'  '7'
 625 // 010   '8'  '9'  '{'  '#'  '?'  ':'  '>'
 626 // 020   ' '  'a'  'b'  'c'  'd'  'e'  'f'  'g'
 627 // 030   'h'  'i'  '|'  '.'  '}'  '('  '<'  '`'
 628 // 040   '^'  'j'  'k'  'l'  'm'  'm'  'o'  'p'
 629 // 050   'q'  'r'  '_'  '$'  '*'  ')'  ';'  '\''
 630 // 060   '+'  '/'  's'  't'  'u'  'v'  'w'  'x'
 631 // 070   'y'  'z'  '~'  ','  '!'  '='  '"'
 632 
 633     static char * bcd_lc =
 634       "01234567"
 635       "89{#?;>?"
 636       " abcdefg"
 637       "hi|.}(<\\"
 638       "^jklmnop"
 639       "qr_$*);'"
 640       "+/stuvwx"
 641       "yz~,!=\"!"; // '!' is actually the escape character, caught above
 642 
 643 // derived from pr2_conv_$upper_case_table
 644 //
 645 //        0    1    2    3    4    5    6    7
 646 // 000   '0'  '1'  '2'  '3'  '4'  '5'  '6'  '7'
 647 // 010   '8'  '9'  '['  '#'  '@'  ':'  '>'
 648 // 020   ' '  'A'  'B'  'C'  'D'  'E'  'F'  'G'
 649 // 030   'H'  'I'  '&'  '.'  ']'  '('  '<'  '`'
 650 // 040   '^'  'J'  'K'  'L'  'M'  'N'  'O'  'P'
 651 // 050   'Q'  'R'  '-'  '$'  '*'  ')'  ';'  '\''
 652 // 060   '+'  '/'  'S'  'T'  'U'  'V'  'W'  'X'
 653 // 070   'Y'  'Z'  '\\' ','  '%'  '='  '"'
 654     static char * bcd_uc =
 655       "01234567"
 656       "89[#@;>?"  // '?' is actually in the lower case table; pr2_conv_ never generates 017 in upper case mode
 657       " ABCDEFG"
 658       "HI&.](<\\"
 659       "^JKLMNOP"
 660       "QR-$*);'"
 661       "+/STUVWX"
 662       "YZ_,%=\"!"; // '!' is actually the escape character, caught above
 663 
 664 // Used for nonedited; has question mark.
 665     static char * bcd =
 666       "01234567"
 667       "89[#@;> "  // 'POLTS says that 17 is question mark for nonedited
 668       " ABCDEFG"
 669       "HI&.](<\\"
 670       "^JKLMNOP"
 671       "QR-$*);'"
 672       "+/STUVWX"
 673       "YZ_,%=\"!";
 674 
 675     if (prt_state[prt_unit_num].prtfile == -1)
 676       {
 677         int rc = openPrtFile (prt_unit_num, buffer, tally);
 678         if (rc < 0) // Can't open or can't write to print file; or ff cached
 679           {
 680             return rc == -3 ? 0 : rc;
 681           }
 682       }
 683 
 684 
 685 
 686 
 687 
 688 
 689 
 690 
 691 
 692 
 693 
 694 
 695 
 696 
 697 
 698 
 699 
 700 
 701 
 702 
 703 
 704 
 705 
 706 
 707 
 708 
 709 
 710 
 711 
 712 
 713     if (slew == -1)
 714       {
 715         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, formfeed, 1);
 716         if (n_write != 1)
 717           {
 718             return -2;
 719           }
 720       }
 721     else if (slew)
 722       {
 723         for (int i = 0; i < slew; i ++)
 724           {
 725             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, crlf, 2);
 726             if (n_write != 2)
 727               {
 728                 return -2;
 729               }
 730           }
 731       }
 732 // Not needed; always slew back to column 0 when done.
 733 //    else
 734 //      {
 735 //        write (prt_state[prt_unit_num].prtfile, cr, 1);
 736 //      }
 737 
 738     if (tally)
 739       {
 740             if (isBCD)
 741           {
 742             uint nchars = tally * 6;
 743 #define get_BCD_char(i) ((uint8_t) ((buffer[i / 6] >> ((5 - i % 6) * 6)) & 077))
 744 
 745             if (! is_edited)
 746               { // Easy case
 747                 uint8 bytes[nchars];
 748                 for (uint i = 0; i < nchars; i ++)
 749                   {
 750                     bytes[i] = (uint8_t) bcd_uc [get_BCD_char (i)];
 751                   }
 752                 ssize_t n_write = write (prt_state[prt_unit_num].prtfile, bytes, nchars);
 753                 if (n_write != nchars)
 754                   {
 755                     return -2;
 756                   }
 757               }
 758             else // edited BCD
 759               {
 760                 //bool BCD_case = false; // false is upper case
 761                 // POLTS implies 3 sets
 762                 // 0 - initial set, upper case, no question mark.
 763                 // 1  - first change: lower case, question mark.
 764                 // 2  - second change: upper case, question mark.
 765                 int BCD_cset = 0;
 766                 char * table[3] = { bcd, bcd_lc, bcd_uc };
 767 
 768                 for (uint i = 0; i < nchars; i ++)
 769                   {
 770                     uint8_t ch = get_BCD_char (i);
 771 // Looking at pr2_conv_.alm, it looks like the esc char is 77
 772 //  77 n  if n is
 773 //      0 - 017, slew n lines  (0 is just CR)
 774 //      020 generate slew to top of page,
 775 //      021 generate slew to top of inside page,
 776 //      022 generate slew to top of outside page,
 777 //      041 to 057, generate (n-040) *8 spaces
 778 
 779                     if (ch == 077)
 780                       {
 781                         i ++;
 782                         uint8_t n = get_BCD_char (i);
 783 
 784                         if (n == 077) // pr2_conv_ sez ESC ESC is case shift
 785                           {
 786                             //BCD_case = ! BCD_case;
 787                             switch (BCD_cset)
 788                               {
 789                                 case 0: BCD_cset = 1; break; // default to lower
 790                                 case 1: BCD_cset = 2; break; // lower to upper
 791                                 case 2: BCD_cset = 1; break; // upper to lower
 792                               }
 793                           }
 794                         else if (n >= 041 && n <= 057)
 795                           {
 796                             int nchars = (n - 040) * 8;
 797                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, spaces, (size_t)nchars);
 798                             if (n_write != nchars)
 799                               {
 800                                 return -2;
 801                               }
 802                           }
 803                         else if (n >= 020 && n <= 022)
 804                           {
 805                             // XXX not distinguishing between top of page, inside page, outside page
 806                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, formfeed, 1);
 807                             if (n_write != 1)
 808                               {
 809                                 return -2;
 810                               }
 811                           }
 812                         else if (n == 0) // slew 0 lines is just CR
 813                           {
 814                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, cr, 1);
 815                             if (n_write != 1)
 816                               {
 817                                 return -2;
 818                               }
 819                           }
 820                         else if (n <= 017)
 821                           {
 822                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, newlines, n);
 823                             if (n_write != n)
 824                               {
 825                                 return -2;
 826                               }
 827                           }
 828 #ifdef TESTING
 829                         else
 830                           {
 831                             sim_warn ("Printer BCD edited ESC %u. %o ignored\n", n, n);
 832                           }
 833 #endif
 834                       }
 835                     else // not escape
 836                       {
 837                         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, table[BCD_cset] + ch, 1);
 838                         if (n_write != 1)
 839                           {
 840                             return -2;
 841                           }
 842                       }
 843                   } // for i to nchars
 844               } // edited BCD
 845           } // BCD
 846         else // ASCII
 847           {
 848             uint nchars = tally * 4;
 849 #define get_ASCII_char(i) ((uint8_t) ((buffer[i / 4] >> ((3 - i % 4) * 9)) & 0377))
 850 
 851             if (! is_edited)
 852               { // Easy case
 853                 uint8 bytes[nchars];
 854                 uint nbytes = 0;
 855                 for (uint i = 0; i < nchars; i ++)
 856                   {
 857                     uint8_t ch = get_ASCII_char (i);
 858                     if (isprint (ch))
 859                       bytes[nbytes ++] = ch;
 860                   }
 861                 ssize_t n_write = write (prt_state[prt_unit_num].prtfile, bytes, nbytes);
 862                 if (n_write != nbytes)
 863                   {
 864                     return -2;
 865                   }
 866               }
 867             else // edited ASCII
 868               {
 869                 uint col = 0;
 870                 for (uint i = 0; i < tally * 4; i ++)
 871                   {
 872                     uint8_t ch = get_ASCII_char (i);
 873                     if (ch == 037) // insert n spaces
 874                       {
 875                         i ++;
 876                         uint8_t n = get_ASCII_char (i);
 877                         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, spaces, n);
 878                         if (n_write != n)
 879                           {
 880                             return -2;
 881                           }
 882                         col += n;
 883                       }
 884                     else if (ch == 013) // insert n new lines
 885                       {
 886                         i ++;
 887                         uint8_t n = get_ASCII_char (i);
 888                         if (n)
 889                            {
 890                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, newlines, n);
 891                             if (n_write != n)
 892                               {
 893                                 return -2;
 894                               }
 895                           }
 896                         else // 0 lines; just slew to beginning of line
 897                           {
 898                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, cr, 1);
 899                             if (n_write != 1)
 900                               {
 901                                 return -2;
 902                               }
 903                           }
 904                         col = 0;
 905                       }
 906                     else if (ch == 014) // slew page
 907                       {
 908                         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, formfeed, 1);
 909                         if (n_write != 1)
 910                           {
 911                             return -2;
 912                           }
 913                         col = 0;
 914                       }
 915                     else if (ch == 011) // horizontal tab
 916                       {
 917                         i ++;
 918                         uint8_t n = get_ASCII_char (i);
 919                         if (col < n)
 920                           {
 921                             ssize_t n_write = write (prt_state[prt_unit_num].prtfile, spaces, n - col);
 922                             if (n_write != n - col)
 923                               {
 924                                 return -2;
 925                               }
 926                             col += n;
 927                           }
 928                       }
 929                     else if (isprint (ch))
 930                       {
 931                         ssize_t n_write = write (prt_state[prt_unit_num].prtfile, & ch, 1);
 932                         if (n_write != 1)
 933                           {
 934                             return -2;
 935                           }
 936                         col ++;
 937                       }
 938                   } // for
 939               } // edited ASCII
 940           } // ASCII
 941       } // tally
 942 
 943 // Slew back to beginning of line
 944     ssize_t n_write = write (prt_state[prt_unit_num].prtfile, cr, 1);
 945     if (n_write != 1)
 946       {
 947         return -2;
 948       }
 949 
 950     if ((! isBCD) && eoj (buffer, tally))
 951       {
 952         close (prt_state[prt_unit_num].prtfile);
 953         prt_state[prt_unit_num].prtfile = -1;
 954       }
 955     return 0;
 956   }
 957 
 958 static int loadImageBuffer (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 959   {
 960     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 961     // We don't actually have a print chain, so just pretend we loaded the image data
 962     p->stati = 04000; //-V536
 963     return 0;
 964   }
 965 
 966 static int readStatusRegister (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 967   {
 968     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
 969 
 970     uint tally = p -> DDCW_TALLY;
 971 
 972     if (tally != 4)
 973       {
 974         sim_warn ("%s: expected tally of 4, is %d\n", __func__, tally);
 975       }
 976     if (tally == 0)
 977       {
 978         tally = 4096;
 979       }
 980 
 981 // system_library_tools/source/bound_io_tools_.s.archive/analyze_detail_stat_.pl1  anal_fips_disk_().
 982 
 983     word36 buffer[tally];
 984     memset (buffer, 0, sizeof (buffer));
 985     // word 1 char 1   0: normal
 986     // word 1 char 2   0: device not busy
 987     // word 1 char 3   0: no device attention bit set
 988     // word 1 char 4   0: no device data alert
 989     // word 1 char 5   0: unused
 990     // word 1 char 6   0: no command reject
 991     //buffer[0] = 0;
 992     // word 2 char 1 (7) 0: unused
 993     // word 2 char 2 (9) 0: unused
 994     // word 2 char 3 (10) 0: unused
 995     // word 2 char 4 (11) 0: no MPC attention
 996     // word 2 char 5 (12) 0: no MPC data alert
 997     // word 2 char 6 (13) 0: unused
 998     //buffer[2] = 0;
 999     // word 3 char 1 (14) 0: no MPC command reject
1000     // word 3 char 2 (15) 0: unused
1001     // word 3 char 3 (16) 0: unused
1002     // word 3 char 4 (17) 0: unused
1003     // word 3 char 5 (18) 0: unused
1004     // word 3 char 6 (19) 0: unused
1005     //buffer[3] = 0;
1006     uint wordsProcessed = tally;
1007     iom_indirect_data_service (iom_unit_idx, chan, buffer,
1008                             & wordsProcessed, true);
1009     p->charPos = 0;
1010     p->stati = 04000; //-V536
1011     return 0;
1012   }
1013 
1014 static int loadVFCImage (uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1015   {
1016     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1017     // We don't actually have a VFC, so just pretend we loaded the image data
1018     p->stati = 04000; //-V536
1019     return 0;
1020   }
1021 
1022 static iom_cmd_rc_t print_cmd (uint iom_unit_idx, uint chan, int prt_unit_num, bool isBCD, bool is_edited, int slew)
     /* [previous][next][first][last][top][bottom][index][help] */
1023   {
1024     iom_chan_data_t * p = & iom_chan_data[iom_unit_idx][chan];
1025     p->isRead = false;
1026 
1027 
1028 
1029 
1030 
1031 
1032 
1033 
1034 
1035 
1036 
1037 
1038 
1039 
1040 
1041 
1042 
1043 
1044 
1045 
1046 
1047 
1048 
1049 
1050 
1051 
1052 
1053 
1054 
1055 
1056 
1057 
1058 
1059 
1060 
1061         uint tally = p -> DDCW_TALLY;
1062         sim_debug (DBG_DEBUG, & prt_dev,
1063                    "%s: Tally %d (%o)\n", __func__, tally, tally);
1064 
1065         if (tally == 0)
1066           tally = 4096;
1067 
1068         // Copy from core to buffer
1069         word36 buffer[tally];
1070         uint wordsProcessed = 0;
1071         iom_indirect_data_service (iom_unit_idx, chan, buffer,
1072                                 & wordsProcessed, false);
1073         p -> initiate = false;
1074 
1075 
1076 
1077 
1078 
1079 
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 
1088 
1089 
1090 
1091 
1092 
1093 
1094         int rc = print_buf (prt_unit_num, isBCD, is_edited, slew, buffer, tally);
1095         if (rc == -1) // Can't open print file
1096           {
1097             p->stati = 04201; // Out of paper
1098             return IOM_CMD_ERROR;
1099           }
1100         if (rc == -2) // Can't write to print file
1101           {
1102             p->stati = 04210; // Check alert
1103             return IOM_CMD_ERROR;
1104           }
1105 
1106 
1107 
1108 
1109 
1110 
1111 
1112 
1113 
1114 
1115 
1116     p -> tallyResidue = 0;
1117     p -> stati = 04000;
1118     //return IOM_CMD_PROCEED;
1119     return IOM_CMD_RESIDUE;
1120   }
1121 
1122 iom_cmd_rc_t prt_cmd_202 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1123   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1124   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1125   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1126   UNIT * unitp         = & prt_unit[devUnitIdx];
1127   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1128   prt_state_t * statep = & prt_state[devUnitIdx];
1129 
1130   // IDCW?
1131   if (IS_IDCW (p)) {
1132     // IDCW
1133     statep->ioMode = prtNoMode;
1134 
1135     switch (p->IDCW_DEV_CMD) {
1136       case 000: // CMD 00 Request status
1137         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\n", __func__);
1138         p->stati = 04000;
1139         break;
1140 
1141       case 010: // CMD 010 -- print nonedited BCD, slew one line
1142         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\n", __func__);
1143         statep->ioMode     = prtPrt;
1144         statep->prtUnitNum = prt_unit_num;
1145         statep->isBCD      = true;
1146         statep->isEdited   = false;
1147         statep->slew       = 1;
1148         p->stati           = 04000;
1149         break;
1150 
1151       case 030: // CMD 030 -- print edited BCD, slew zero lines
1152         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\n", __func__);
1153         statep->ioMode     = prtPrt;
1154         statep->prtUnitNum = prt_unit_num;
1155         statep->isBCD      = true;
1156         statep->isEdited   = true;
1157         statep->slew       = 0;
1158         p->stati           = 04000;
1159         break;
1160 
1161       case 040: // CMD 40 Reset status
1162         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\n", __func__);
1163         p->stati  = 04000;
1164         p->isRead = false;
1165         break;
1166 
1167       default:
1168         p->stati      = 04501; // cmd reject, invalid opcode
1169         p->chanStatus = chanStatIncorrectDCW;
1170         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1171           sim_warn ("%s: PRT unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1172         return IOM_CMD_ERROR;
1173     } // switch IDCW_DEV_CMND
1174 
1175     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\n", __func__, p->stati);
1176     return IOM_CMD_PROCEED;
1177   } // if IDCW
1178 
1179   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1180   switch (statep->ioMode) {
1181     case prtNoMode:
1182       //sim_printf ("%s: Unexpected IOTx\n", __func__);
1183       //sim_warn ("%s: Unexpected IOTx\n", __func__);
1184       //return IOM_CMD_ERROR;
1185       break;
1186 
1187     case prtPrt: {
1188         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1189                 statep->isEdited, statep->slew);
1190         if (rc) //-V547
1191           return rc;
1192       }
1193       break;
1194 
1195     default:
1196       sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1197       return IOM_CMD_ERROR;
1198   }
1199 
1200   return IOM_CMD_PROCEED;
1201 }
1202 
1203 iom_cmd_rc_t prt_cmd_300 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1204   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1205   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1206   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1207   UNIT * unitp         = & prt_unit[devUnitIdx];
1208   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1209   prt_state_t * statep = & prt_state[devUnitIdx];
1210 
1211   // IDCW?
1212   if (IS_IDCW (p)) {
1213     // IDCW
1214     statep->ioMode = prtNoMode;
1215 
1216     switch (p->IDCW_DEV_CMD) {
1217 
1218       case 000: // CMD 00 Request status
1219         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\n", __func__);
1220         p->stati = 04000;
1221         break;
1222 
1223       case 011: // CMD 011 -- print nonedited ASCII, slew one line
1224         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\n", __func__);
1225         statep->ioMode     = prtPrt;
1226         statep->prtUnitNum = prt_unit_num;
1227         statep->isBCD      = false;
1228         statep->isEdited   = false;
1229         statep->slew       = 1;
1230         p->stati           = 04000;
1231         break;
1232 
1233       case 014: // CMD 014 -- Load Image Buffer
1234         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\n", __func__);
1235         statep->ioMode = prtLdImgBuf;
1236         p->stati       = 04000;
1237         break;
1238 
1239       case 030: // CMD 030 -- print edited ASCII, slew zero lines
1240         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\n", __func__);
1241         statep->ioMode     = prtPrt;
1242         statep->prtUnitNum = prt_unit_num;
1243         statep->isBCD      = false;
1244         statep->isEdited   = true;
1245         statep->slew       = 0;
1246         p->stati           = 04000;
1247         break;
1248 
1249       case 040: // CMD 40 Reset status
1250         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\n", __func__);
1251         p->stati  = 04000;
1252         p->isRead = false;
1253         break;
1254 
1255       default:
1256         p->stati      = 04501; // cmd reject, invalid opcode
1257         p->chanStatus = chanStatIncorrectDCW;
1258         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1259           sim_warn ("%s: PRT unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1260         return IOM_CMD_ERROR;
1261     } // switch IDCW_DEV_CMND
1262 
1263     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\n", __func__, p->stati);
1264     return IOM_CMD_PROCEED;
1265   } // if IDCW
1266 
1267   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1268   switch (statep->ioMode) {
1269     case prtNoMode:
1270       //sim_printf ("%s: Unexpected IOTx\n", __func__);
1271       //sim_warn ("%s: Unexpected IOTx\n", __func__);
1272       //return IOM_CMD_ERROR;
1273       break;
1274 
1275     case prtPrt: {
1276         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1277                 statep->isEdited, statep->slew);
1278         if (rc) //-V547
1279           return rc;
1280       }
1281       break;
1282 
1283     case prtLdImgBuf: {
1284         int rc = loadImageBuffer (iomUnitIdx, chan);
1285         if (rc) //-V547
1286           return IOM_CMD_ERROR;
1287       }
1288       break;
1289 
1290     default:
1291       sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1292       return IOM_CMD_ERROR;
1293   }
1294   return IOM_CMD_PROCEED;
1295 }
1296 
1297 iom_cmd_rc_t prt_cmd_300a (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1298   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1299   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1300   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1301   UNIT * unitp         = & prt_unit[devUnitIdx];
1302   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1303   prt_state_t * statep = & prt_state[devUnitIdx];
1304 
1305   // IDCW?
1306   if (IS_IDCW (p)) {
1307     // IDCW
1308     statep->ioMode = prtNoMode;
1309 
1310     switch (p->IDCW_DEV_CMD) {
1311       case 000: // CMD 00 Request status
1312         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\n", __func__);
1313         p->stati = 04000;
1314         break;
1315 
1316       case 001: // CMD 001 -- Load Image Buffer
1317         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\n", __func__);
1318         statep->ioMode = prtLdImgBuf;
1319         p->stati       = 04000;
1320         break;
1321 
1322       case 015: // CMD 015 -- print nonedited ASCII, slew one line
1323         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\n", __func__);
1324         statep->ioMode     = prtPrt;
1325         statep->prtUnitNum = prt_unit_num;
1326         statep->isBCD      = false;
1327         statep->isEdited   = false;
1328         statep->slew       = 1;
1329         p->stati           = 04000;
1330         break;
1331 
1332       case 034: // CMD 034 -- print edited ASCII, slew zero lines
1333         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\n", __func__);
1334         statep->ioMode     = prtPrt;
1335         statep->prtUnitNum = prt_unit_num;
1336         statep->isBCD      = false;
1337         statep->isEdited   = true;
1338         statep->slew       = 0;
1339         p->stati           = 04000;
1340         break;
1341 
1342       case 040: // CMD 40 Reset status
1343         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\n", __func__);
1344         p->stati  = 04000;
1345         p->isRead = false;
1346         break;
1347 
1348       default:
1349         p->stati      = 04501; // cmd reject, invalid opcode
1350         p->chanStatus = chanStatIncorrectDCW;
1351         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1352           sim_warn ("%s: PRT unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1353         return IOM_CMD_ERROR;
1354     } // switch IDCW_DEV_CMND
1355 
1356     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\n", __func__, p->stati);
1357     return IOM_CMD_PROCEED;
1358   } // if IDCW
1359 
1360   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1361   switch (statep->ioMode) {
1362     case prtNoMode:
1363       //sim_printf ("%s: Unexpected IOTx\n", __func__);
1364       //sim_warn ("%s: Unexpected IOTx\n", __func__);
1365       //return IOM_CMD_ERROR;
1366       break;
1367 
1368     case prtPrt: {
1369         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1370                 statep->isEdited, statep->slew);
1371         if (rc) //-V547
1372           return rc;
1373       }
1374       break;
1375 
1376     case prtLdImgBuf: {
1377         int rc = loadImageBuffer (iomUnitIdx, chan);
1378         if (rc) //-V547
1379           return IOM_CMD_ERROR;
1380       }
1381       break;
1382 
1383     default:
1384       sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1385       return IOM_CMD_ERROR;
1386   }
1387   return IOM_CMD_PROCEED;
1388 }
1389 
1390 iom_cmd_rc_t prt_cmd_400 (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1391   iom_chan_data_t * p  = & iom_chan_data[iomUnitIdx][chan];
1392   uint ctlr_unit_idx   = get_ctlr_idx (iomUnitIdx, chan);
1393   uint devUnitIdx      = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1394   UNIT * unitp         = & prt_unit[devUnitIdx];
1395   int prt_unit_num     = (int) PRT_UNIT_NUM (unitp);
1396   prt_state_t * statep = & prt_state[devUnitIdx];
1397 
1398   // IDCW?
1399   if (IS_IDCW (p)) {
1400     // IDCW
1401     statep->ioMode = prtNoMode;
1402 
1403     switch (p->IDCW_DEV_CMD) {
1404 
1405       case 000: // CMD 00 Request status
1406         sim_debug (DBG_DEBUG, & prt_dev, "%s: Request Status\n", __func__);
1407         p->stati = 04000;
1408         break;
1409 
1410       case 001: // CMD 001 -- Load Image Buffer
1411         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\n", __func__);
1412         statep->ioMode = prtLdImgBuf;
1413         p->stati       = 04000;
1414         break;
1415 
1416       case 003: // CMD 003 -- Read Status
1417         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load Image Buffer\n", __func__);
1418         statep->ioMode = prtRdStatReg;
1419         p->stati       = 04000;
1420         break;
1421 
1422       // load_vfc: entry (pip, pcip, iop, rcode);
1423       //
1424       // dcl 1 vfc_image aligned,                    /* print VFC image */
1425       //    (2 lpi fixed bin (8),                    /* lines per inch */
1426       //     2 image_length fixed bin (8),           /* number of lines represented by image */
1427       //     2 toip,                                 /* top of inside page info */
1428       //       3 line fixed bin (8),                 /* line number */
1429       //       3 pattern bit (9),                    /* VFC pattern */
1430       //     2 boip,                                 /* bottom of inside page info */
1431       //       3 line fixed bin (8),                 /* line number */
1432       //       3 pattern bit (9),                    /* VFC pattern */
1433       //     2 toop,                                 /* top of outside page info */
1434       //       3 line fixed bin (8),                 /* line number */
1435       //       3 pattern bit (9),                    /* VFC pattern */
1436       //     2 boop,                                 /* bottom of outside page info */
1437       //       3 line fixed bin (8),                 /* line number */
1438       //       3 pattern bit (9),                    /* VFC pattern */
1439       //     2 pad bit (18)) unal;                   /* fill out last word */
1440       //
1441       // dcl (toip_pattern init ("113"b3),           /* top of inside page pattern */
1442       //      toop_pattern init ("111"b3),           /* top of outside page pattern */
1443       //      bop_pattern init ("060"b3))            /* bottom of page pattern */
1444       //      bit (9) static options (constant);
1445 
1446       case 005: // CMD 005 -- Load VFC image
1447         sim_debug (DBG_DEBUG, & prt_dev, "%s: Load VFC Image\n", __func__);
1448         statep->ioMode = prtLdVFCImg;
1449         p->stati       = 04000;
1450         break;
1451 
1452       case 010: // CMD 010 -- print nonedited BCD, slew zero lines
1453         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Zero Lines\n", __func__);
1454         statep->ioMode     = prtPrt;
1455         statep->prtUnitNum = prt_unit_num;
1456         statep->isBCD      = true;
1457         statep->isEdited   = false;
1458         statep->slew       = 0;
1459         p->stati           = 04000;
1460         break;
1461 
1462       case 011: // CMD 011 -- print nonedited BCD, slew one line
1463         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew One Line\n", __func__);
1464         statep->ioMode     = prtPrt;
1465         statep->prtUnitNum = prt_unit_num;
1466         statep->isBCD      = true;
1467         statep->isEdited   = false;
1468         statep->slew       = 1;
1469         p->stati           = 04000;
1470         break;
1471 
1472       case 012: // CMD 012 -- print nonedited BCD, slew two lines
1473         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Two Lines\n", __func__);
1474         statep->ioMode     = prtPrt;
1475         statep->prtUnitNum = prt_unit_num;
1476         statep->isBCD      = true;
1477         statep->isEdited   = false;
1478         statep->slew       = 2;
1479         p->stati           = 04000;
1480         break;
1481 
1482       case 013: // CMD 013 -- print nonedited BCD, slew top of page
1483         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited BCD, Slew Top Of Page\n", __func__);
1484         statep->ioMode     = prtPrt;
1485         statep->prtUnitNum = prt_unit_num;
1486         statep->isBCD      = true;
1487         statep->isEdited   = false;
1488         statep->slew       = -1;
1489         p->stati           = 04000;
1490         break;
1491 
1492       case 014: // CMD 014 -- print nonedited ASCII, slew zero lines
1493         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Zero Lines\n", __func__);
1494         statep->ioMode     = prtPrt;
1495         statep->prtUnitNum = prt_unit_num;
1496         statep->isBCD      = false;
1497         statep->isEdited   = false;
1498         statep->slew       = 0;
1499         p->stati           = 04000;
1500         break;
1501 
1502       case 015: // CMD 015 -- print nonedited ASCII, slew one line
1503         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew One Line\n", __func__);
1504         statep->ioMode     = prtPrt;
1505         statep->prtUnitNum = prt_unit_num;
1506         statep->isBCD      = false;
1507         statep->isEdited   = false;
1508         statep->slew       = 1;
1509         p->stati           = 04000;
1510         break;
1511 
1512       case 016: // CMD 016 -- print nonedited ASCII, slew two lines
1513         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Two Lines\n", __func__);
1514         statep->ioMode     = prtPrt;
1515         statep->prtUnitNum = prt_unit_num;
1516         statep->isBCD      = false;
1517         statep->isEdited   = false;
1518         statep->slew       = 2;
1519         p->stati           = 04000;
1520         break;
1521 
1522       case 017: // CMD 017 -- print nonedited ASCII, slew top of page
1523         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Nonedited ASCII, Slew Top Of Page\n", __func__);
1524         statep->ioMode     = prtPrt;
1525         statep->prtUnitNum = prt_unit_num;
1526         statep->isBCD      = false;
1527         statep->isEdited   = false;
1528         statep->slew       = -1;
1529         p->stati           = 04000;
1530         break;
1531 
1532       case 030: // CMD 030 -- print edited BCD, slew zero lines
1533         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Zero Lines\n", __func__);
1534         statep->ioMode     = prtPrt;
1535         statep->prtUnitNum = prt_unit_num;
1536         statep->isBCD      = true;
1537         statep->isEdited   = true;
1538         statep->slew       = 0;
1539         p->stati           = 04000;
1540         break;
1541 
1542       case 031: // CMD 031 -- print edited BCD, slew one line
1543         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew One Line\n", __func__);
1544         statep->ioMode     = prtPrt;
1545         statep->prtUnitNum = prt_unit_num;
1546         statep->isBCD      = true;
1547         statep->isEdited   = true;
1548         statep->slew       = 1;
1549         p->stati           = 04000;
1550         break;
1551 
1552       case 032: // CMD 032 -- print edited BCD, slew two lines
1553         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Two Lines\n", __func__);
1554         statep->ioMode     = prtPrt;
1555         statep->prtUnitNum = prt_unit_num;
1556         statep->isBCD      = true;
1557         statep->isEdited   = true;
1558         statep->slew       = 2;
1559         p->stati           = 04000;
1560         break;
1561 
1562       case 033: // CMD 033 -- print edited BCD, slew top of page
1563         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited BCD, Slew Top Of Page\n", __func__);
1564         statep->ioMode     = prtPrt;
1565         statep->prtUnitNum = prt_unit_num;
1566         statep->isBCD      = true;
1567         statep->isEdited   = true;
1568         statep->slew       = -1;
1569         p->stati           = 04000;
1570         break;
1571 
1572       case 034: // CMD 034 -- print edited ASCII, slew zero lines
1573         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Zero Lines\n", __func__);
1574         statep->ioMode     = prtPrt;
1575         statep->prtUnitNum = prt_unit_num;
1576         statep->isBCD      = false;
1577         statep->isEdited   = true;
1578         statep->slew       = 0;
1579         p->stati           = 04000;
1580         break;
1581 
1582       case 035: // CMD 035 -- print edited ASCII, slew one line
1583         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew One Line\n", __func__);
1584         statep->ioMode     = prtPrt;
1585         statep->prtUnitNum = prt_unit_num;
1586         statep->isBCD      = false;
1587         statep->isEdited   = true;
1588         statep->slew       = 1;
1589         p->stati           = 04000;
1590         break;
1591 
1592       case 036: // CMD 036 -- print edited ASCII, slew two lines
1593         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Two Lines\n", __func__);
1594         statep->ioMode     = prtPrt;
1595         statep->prtUnitNum = prt_unit_num;
1596         statep->isBCD      = false;
1597         statep->isEdited   = true;
1598         statep->slew       = 2;
1599         p->stati           = 04000;
1600         break;
1601 
1602       case 037: // CMD 037 -- print edited ASCII, slew top of page
1603         sim_debug (DBG_DEBUG, & prt_dev, "%s: Print Edited ASCII, Slew Top Of Page\n", __func__);
1604         statep->ioMode     = prtPrt;
1605         statep->prtUnitNum = prt_unit_num;
1606         statep->isBCD      = false;
1607         statep->isEdited   = true;
1608         statep->slew       = -1;
1609         p->stati           = 04000;
1610         break;
1611 
1612       case 040: // CMD 40 Reset status
1613         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reset Status\n", __func__);
1614         p->stati  = 04000;
1615         p->isRead = false;
1616         break;
1617 
1618       case 061:  { // CMD 61 Slew one line
1619           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew One Line\n", __func__);
1620           int rc = print_buf (prt_unit_num, false, false, 1, NULL, 0);
1621           if (rc == -1) { // Can't open print file
1622             p->stati = 04201; // Out of paper
1623             return IOM_CMD_ERROR;
1624           }
1625           if (rc == -2) { // Can't write to print file
1626             p->stati = 04210; // Check alert
1627             return IOM_CMD_ERROR;
1628           }
1629           p->stati  = 04000;
1630           p->isRead = false;
1631         }
1632         break;
1633 
1634       case 062: { // CMD 62 Slew two lines
1635           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew Two Lines\n", __func__);
1636           int rc = print_buf (prt_unit_num, false, false, 2, NULL, 0);
1637           if (rc == -1) { // Can't open print file
1638             p->stati = 04201; // Out of paper
1639             return IOM_CMD_ERROR;
1640           }
1641           if (rc == -2) { // Can't write to print file
1642             p->stati = 04210; // Check alert
1643             return IOM_CMD_ERROR;
1644           }
1645           p->stati  = 04000;
1646           p->isRead = false;
1647         }
1648         break;
1649 
1650       case 063: { // CMD 63 Slew to top of page
1651           sim_debug (DBG_DEBUG, & prt_dev, "%s: Slew To Top Of Page\n", __func__);
1652           int rc = print_buf (prt_unit_num, false, false, -1, NULL, 0);
1653           if (rc == -1) { // Can't open print file
1654             p->stati = 04201; // Out of paper
1655             return IOM_CMD_ERROR;
1656           }
1657           if (rc == -2) { // Can't write to print file
1658             p->stati = 04210; // Check alert
1659             return IOM_CMD_ERROR;
1660           }
1661           p->stati  = 04000;
1662           p->isRead = false;
1663         }
1664         break;
1665 
1666       case 066: // CMD 66 Reserve device
1667         sim_debug (DBG_DEBUG, & prt_dev, "%s: Reserve Device\n", __func__);
1668         p->stati  = 04000;
1669         p->isRead = false;
1670         break;
1671 
1672       case 067: // CMD 67 Release device
1673         sim_debug (DBG_DEBUG, & prt_dev, "%s: Release Device\n", __func__);
1674         p->stati  = 04000;
1675         p->isRead = false;
1676         break;
1677 
1678       default:
1679         p->stati      = 04501; // cmd reject, invalid opcode
1680         p->chanStatus = chanStatIncorrectDCW;
1681         if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
1682         sim_warn ("%s: PRT unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1683         return IOM_CMD_ERROR;
1684     } // switch IDCW_DEV_CMND
1685 
1686     sim_debug (DBG_DEBUG, & prt_dev, "%s: stati %04o\n", __func__, p->stati);
1687     return IOM_CMD_PROCEED;
1688   } // if IDCW
1689 
1690   // Not IDCW; TDCW are captured in IOM, so must be IOTD, IOTP or IOTNP
1691   switch (statep->ioMode) {
1692     case prtNoMode:
1693       //sim_printf ("%s: Unexpected IOTx\n", __func__);
1694       //sim_warn ("%s: Unexpected IOTx\n", __func__);
1695       //return IOM_CMD_ERROR;
1696       break;
1697 
1698     case prtPrt: {
1699         iom_cmd_rc_t rc = print_cmd (iomUnitIdx, chan, statep->prtUnitNum, statep->isBCD,
1700                 statep->isEdited, statep->slew);
1701         if (rc) //-V547
1702           return rc;
1703       }
1704       break;
1705 
1706     case prtLdImgBuf: {
1707         int rc = loadImageBuffer (iomUnitIdx, chan);
1708         if (rc) //-V547
1709           return IOM_CMD_ERROR;
1710       }
1711       break;
1712 
1713     case prtRdStatReg: {
1714         int rc = readStatusRegister (iomUnitIdx, chan);
1715         if (rc) //-V547
1716           return IOM_CMD_ERROR;
1717       }
1718       break;
1719 
1720     case prtLdVFCImg: {
1721         int rc = loadVFCImage (iomUnitIdx, chan);
1722         if (rc) //-V547
1723           return IOM_CMD_ERROR;
1724       }
1725       break;
1726 
1727     default:
1728       sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1729       return IOM_CMD_ERROR;
1730   }
1731   return IOM_CMD_PROCEED;
1732 }
1733 
1734 iom_cmd_rc_t prt_iom_cmd (uint iomUnitIdx, uint chan) {
     /* [previous][next][first][last][top][bottom][index][help] */
1735   iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1736   uint ctlr_unit_idx  = get_ctlr_idx (iomUnitIdx, chan);
1737   uint devUnitIdx     = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1738   UNIT * unitp        = & prt_unit[devUnitIdx];
1739   int prt_unit_num    = (int) PRT_UNIT_NUM (unitp);
1740 
1741   switch (model_type [prt_state[prt_unit_num].model]) {
1742     case 1: // 202
1743       return prt_cmd_202 (iomUnitIdx, chan);
1744 
1745     case 2: // 300, 301, 302
1746       return prt_cmd_300 (iomUnitIdx, chan);
1747 
1748     case 3: // 303, 304
1749       return prt_cmd_300a (iomUnitIdx, chan);
1750       // switch type 3 cmd
1751 
1752     case 4: // 401, 402, 901, 1000, 1200, 1201, 1600
1753       return prt_cmd_400 (iomUnitIdx, chan);
1754   }
1755   p->stati = 04502; //-V536  // invalid device code
1756   return IOM_CMD_DISCONNECT;
1757 }
1758 
1759 static t_stat prt_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
1760                                UNUSED const void * desc)
1761   {
1762     sim_printf("Number of PRT units in system is %d\n", prt_dev.numunits);
1763     return SCPE_OK;
1764   }
1765 
1766 static t_stat prt_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1767                               UNUSED void * desc)
1768   {
1769     if (! cptr)
1770       return SCPE_ARG;
1771     int n = atoi (cptr);
1772     if (n < 1 || n > N_PRT_UNITS_MAX)
1773       return SCPE_ARG;
1774     prt_dev.numunits = (uint) n;
1775     return SCPE_OK;
1776   }
1777 
1778 static t_stat prt_show_device_name (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1779                                     UNUSED int val, UNUSED const void * desc)
1780   {
1781     int n = (int) PRT_UNIT_NUM (uptr);
1782     if (n < 0 || n >= N_PRT_UNITS_MAX)
1783       return SCPE_ARG;
1784     sim_printf("name     : %s", prt_state[n].device_name);
1785     return SCPE_OK;
1786   }
1787 
1788 static t_stat prt_set_device_model (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
1789                                     const UNUSED char * cptr, UNUSED void * desc)
1790   {
1791     int n = (int) PRT_UNIT_NUM (uptr);
1792     if (n < 0 || n >= N_PRT_UNITS_MAX)
1793       return SCPE_ARG;
1794     if (cptr)
1795       {
1796         for (int i = 0; i < N_MODELS; i ++)
1797            {
1798              if (strcmp (cptr, model_names[i]) == 0)
1799                {
1800                  prt_state[n].model = i;
1801                  return SCPE_OK;
1802                }
1803             }
1804         sim_printf ("Model '%s' not known (202 300 301 302 303 304 401 402 901 1000 1200 1201 1600)\n", cptr);
1805         return SCPE_ARG;
1806       }
1807     sim_printf ("Specify model from 202 300 301 302 303 304 401 402 901 1000 1200 1201 1600\n");
1808     return SCPE_ARG;
1809   }
1810 
1811 static t_stat prt_show_device_model (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1812                                      UNUSED int val, UNUSED const void * desc)
1813   {
1814     int n = (int) PRT_UNIT_NUM (uptr);
1815     if (n < 0 || n >= N_PRT_UNITS_MAX)
1816       return SCPE_ARG;
1817     sim_printf("model    : %s", model_names[prt_state[n].model]);
1818     return SCPE_OK;
1819   }
1820 
1821 static t_stat prt_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
1822                                    const UNUSED char * cptr, UNUSED void * desc)
1823   {
1824     int n = (int) PRT_UNIT_NUM (uptr);
1825     if (n < 0 || n >= N_PRT_UNITS_MAX)
1826       return SCPE_ARG;
1827     if (cptr)
1828       {
1829         strncpy (prt_state[n].device_name, cptr, MAX_DEV_NAME_LEN - 1);
1830         prt_state[n].device_name[MAX_DEV_NAME_LEN - 1] = 0;
1831       }
1832     else
1833       prt_state[n].device_name[0] = 0;
1834     return SCPE_OK;
1835   }
1836 
1837 static t_stat prt_show_path (UNUSED FILE * st, UNUSED UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
1838                              UNUSED int val, UNUSED const void * desc)
1839   {
1840     sim_printf("Path to PRT files is %s\n", prt_path);
1841     return SCPE_OK;
1842   }
1843 
1844 static t_stat prt_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
1845                             const UNUSED char * cptr, UNUSED void * desc)
1846   {
1847     if (! cptr)
1848       return SCPE_ARG;
1849 
1850     size_t len = strlen(cptr);
1851 
1852     if (len >= sizeof(prt_path))
1853       return SCPE_ARG;
1854     strncpy(prt_path, cptr, sizeof(prt_path));
1855     if (len > 0)
1856       {
1857         if (prt_path[len - 1] != '/')
1858           {
1859             if (len == sizeof(prt_path) - 1)
1860               return SCPE_ARG;
1861             prt_path[len++] = '/';
1862             prt_path[len] = 0;
1863           }
1864       }
1865     return SCPE_OK;
1866   }
1867 
1868 t_stat burst_printer (UNUSED int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
1869   {
1870     for (int i = 0; i < N_PRT_UNITS_MAX; i ++)
1871       {
1872         if (strcmp (buf, prt_state[i].device_name) == 0)
1873           {
1874             if (prt_state[i].prtfile != -1)
1875               {
1876                 close (prt_state[i].prtfile);
1877                 prt_state[i].prtfile = -1;
1878                 return SCPE_OK;
1879               }
1880             sim_printf ("burst sees nothing to burst\n");
1881             return SCPE_OK;
1882           }
1883       }
1884     sim_printf ("burst can't find printer named '%s'\n", buf);
1885     return SCPE_ARG;
1886   }
1887 
1888 static t_stat signal_prt_ready (uint prt_unit_idx) {
     /* [previous][next][first][last][top][bottom][index][help] */
1889   // Don't signal if the sim is not running....
1890   if (! sim_is_running)
1891     return SCPE_OK;
1892   uint ctlr_unit_idx = cables->prt_to_urp[prt_unit_idx].ctlr_unit_idx;
1893 
1894 
1895 
1896 
1897 
1898 
1899 
1900 
1901 
1902 
1903 
1904 
1905 
1906 
1907 
1908 
1909 
1910 
1911 
1912 
1913 
1914 
1915 
1916   // Which port should the controller send the interrupt to? All of them...
1917   for (uint ctlr_port_num = 0; ctlr_port_num < MAX_CTLR_PORTS; ctlr_port_num ++) {
1918     struct ctlr_to_iom_s * urp_to_iom = & cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num];
1919     if (urp_to_iom->in_use) {
1920       uint iom_unit_idx = urp_to_iom->iom_unit_idx;
1921       uint chan_num     = urp_to_iom->chan_num;
1922       uint dev_code     = cables->prt_to_urp[prt_unit_idx].dev_code;
1923 
1924       send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0x40, 01 /* disk pack ready */);
1925       return SCPE_OK;
1926     }
1927   }
1928   return SCPE_ARG;
1929 
1930 }
1931 
1932 static t_stat prt_set_ready (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
1933                              UNUSED const char * cptr,
1934                              UNUSED void * desc)
1935   {
1936     int n = (int) PRT_UNIT_NUM (uptr);
1937     if (n < 0 || n >= N_PRT_UNITS_MAX)
1938       {
1939         sim_debug (DBG_ERR, & prt_dev,
1940                    "Printer set ready: Invalid unit number %ld\n", (long) n);
1941         sim_printf ("error: Invalid unit number %ld\n", (long) n);
1942         return SCPE_ARG;
1943       }
1944     return signal_prt_ready ((uint) n);
1945   }
1946 
1947 static config_value_list_t cfg_on_off[] =
1948   {
1949     { "off",     0 },
1950     { "on",      1 },
1951     { "disable", 0 },
1952     { "enable",  1 },
1953     { NULL,      0 }
1954   };
1955 
1956 static config_list_t prt_config_list[] =
1957   {
1958    { "split", 0, 1, cfg_on_off },
1959    { NULL,    0, 0, NULL }
1960   };
1961 
1962 static t_stat prt_set_config (UNUSED UNIT *  uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
1963                               const char * cptr, UNUSED void * desc)
1964   {
1965     int devUnitIdx    = (int) PRT_UNIT_NUM (uptr);
1966     prt_state_t * psp = prt_state + devUnitIdx;
1967     // XXX Minor bug; this code doesn't check for trailing garbage
1968     config_state_t cfg_state = { NULL, NULL };
1969 
1970     for (;;)
1971       {
1972         int64_t v;
1973         int rc = cfg_parse (__func__, cptr, prt_config_list,
1974                            & cfg_state, & v);
1975         if (rc == -1) // done
1976           break;
1977 
1978         if (rc == -2) // error
1979           {
1980             cfg_parse_done (& cfg_state);
1981             return SCPE_ARG;
1982           }
1983         const char * p = prt_config_list[rc].name;
1984 
1985         if (strcmp (p, "split") == 0)
1986           {
1987             psp->split = v != 0;
1988             continue;
1989           }
1990 
1991         sim_warn ("error: prt_set_config: Invalid cfg_parse rc <%ld>\n",
1992                   (long) rc);
1993         cfg_parse_done (& cfg_state);
1994         return SCPE_ARG;
1995       } // process statements
1996     cfg_parse_done (& cfg_state);
1997     return SCPE_OK;
1998   }
1999 
2000 static t_stat prt_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
2001                                UNUSED int  val, UNUSED const void * desc)
2002   {
2003     int devUnitIdx    = (int) PRT_UNIT_NUM (uptr);
2004     prt_state_t * psp = prt_state + devUnitIdx;
2005     sim_msg ("split    : %d", psp->split);
2006     return SCPE_OK;
2007   }

/* [previous][next][first][last][top][bottom][index][help] */