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

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