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