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