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

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