This source file includes following definitions.
- pun_init
- pun_reset
- remove_spaces
- log_char_matrix_pattern
- search_glyph_patterns
- get_lace_char
- scan_card_for_glyphs
- create_punch_file
- write_punch_files
- log_card
- print_event
- print_state
- print_transition
- clear_card_cache
- save_card_in_cache
- transition_state
- do_state_idle
- do_state_starting_job
- do_state_scan_card_for_glyphs
- do_state_end_of_header
- do_state_cache_card
- do_state_end_of_deck
- do_state_end_of_job
- unexpected_event
- parse_card
- punWriteRecord
- pun_iom_cmd
- pun_show_nunits
- pun_set_nunits
- pun_show_device_name
- pun_set_device_name
- pun_set_path
- pun_show_path
- pun_set_config
- pun_show_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <signal.h>
36 #include <unistd.h>
37
38 #include "dps8.h"
39 #include "dps8_iom.h"
40 #include "dps8_crdpun.h"
41 #include "dps8_sys.h"
42 #include "dps8_cable.h"
43 #include "dps8_cpu.h"
44 #include "dps8_scu.h"
45 #include "dps8_faults.h"
46 #include "dps8_utils.h"
47 #include "utfile.h"
48
49 #define DBG_CTR 1
50
51 #if defined(FREE)
52 # undef FREE
53 #endif
54 #define FREE(p) do \
55 { \
56 free((p)); \
57 (p) = NULL; \
58 } while(0)
59
60
61
62
63
64 #define N_PUN_UNITS 1
65
66 static t_stat pun_reset (DEVICE * dptr);
67 static t_stat pun_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
68 static t_stat pun_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
69 static t_stat pun_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
70 static t_stat pun_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
71 static t_stat pun_show_path (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
72 UNUSED const void * desc);
73 static t_stat pun_set_path (UNUSED UNIT * uptr, UNUSED int32 value, const UNUSED char * cptr,
74 UNUSED void * desc);
75 static t_stat pun_set_config (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
76 UNUSED void * desc);
77 static t_stat pun_show_config (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
78 UNUSED const void * desc);
79
80 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
81 UNIT_IDLE )
82 UNIT pun_unit [N_PUN_UNITS_MAX] =
83 {
84 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
85 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
86 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
87 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
88 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
89 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
90 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
91 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
92 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
93 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
94 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
95 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
96 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
97 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
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 };
101
102 #define PUN_UNIT_NUM(uptr) ((uptr) - pun_unit)
103
104 static DEBTAB pun_dt [] =
105 {
106 { "NOTIFY", DBG_NOTIFY, NULL },
107 { "INFO", DBG_INFO, NULL },
108 { "ERR", DBG_ERR, NULL },
109 { "WARN", DBG_WARN, NULL },
110 { "DEBUG", DBG_DEBUG, NULL },
111 { "ALL", DBG_ALL, NULL },
112 { NULL, 0, NULL }
113 };
114
115 #define UNIT_WATCH UNIT_V_UF
116
117 static MTAB pun_mod [] =
118 {
119 #if !defined(SPEED)
120 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
121 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
122 #endif
123 {
124 MTAB_XTD | MTAB_VDV | \
125 MTAB_NMO | MTAB_VALR,
126 0,
127 "NUNITS",
128 "NUNITS",
129 pun_set_nunits,
130 pun_show_nunits,
131 "Number of PUN units in the system",
132 NULL
133 },
134 {
135 MTAB_XTD | MTAB_VUN | \
136 MTAB_VALR | MTAB_NC,
137 0,
138 "NAME",
139 "NAME",
140 pun_set_device_name,
141 pun_show_device_name,
142 "Set the punch device name",
143 NULL
144 },
145 {
146 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
147 MTAB_VALR | MTAB_NC,
148 0,
149 "PATH",
150 "PATH",
151 pun_set_path,
152 pun_show_path,
153 "Path to card punch directories",
154 NULL
155 },
156 {
157 MTAB_XTD | MTAB_VUN,
158 0,
159 (char *) "CONFIG",
160 (char *) "CONFIG",
161 pun_set_config,
162 pun_show_config,
163 NULL,
164 NULL,
165 },
166
167 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
168 };
169
170 DEVICE pun_dev = {
171 "PUN",
172 pun_unit,
173 NULL,
174 pun_mod,
175 N_PUN_UNITS,
176 10,
177 24,
178 1,
179 8,
180 36,
181 NULL,
182 NULL,
183 pun_reset,
184 NULL,
185 NULL,
186 NULL,
187 NULL,
188 DEV_DEBUG,
189 0,
190 pun_dt,
191 NULL,
192 NULL,
193 NULL,
194 NULL,
195 NULL,
196 NULL,
197 NULL
198 };
199
200 static config_value_list_t cfg_on_off[] =
201 {
202 { "off", 0 },
203 { "on", 1 },
204 { "disable", 0 },
205 { "enable", 1 },
206 { NULL, 0 }
207 };
208
209 static config_list_t pun_config_list[] =
210 {
211 { "logcards", 0, 1, cfg_on_off },
212 { NULL, 0, 0, NULL }
213 };
214
215 #define WORDS_PER_CARD 27
216 #define MAX_GLYPH_BUFFER_LEN 1024
217 #define CARD_COL_COUNT 80
218 #define NIBBLES_PER_COL 3
219 #define GLYPHS_PER_CARD 22
220 #define CHAR_MATRIX_BYTES 5
221
222 enum parse_state {
223 Idle, StartingJob, PunchGlyphLookup, EndOfHeader, CacheCard, EndOfDeck, EndOfJob
224 };
225
226 enum parse_event {
227 NoEvent, BannerCard, EndOfDeckCard, Card, Done
228 };
229
230 typedef struct card_cache_node CARD_CACHE_ENTRY;
231
232 struct card_cache_node
233 {
234 word12 tally;
235 word36 card_data[WORDS_PER_CARD];
236 CARD_CACHE_ENTRY *next_entry;
237 };
238
239 typedef struct
240 {
241 char device_name[MAX_DEV_NAME_LEN];
242 int punfile_raw;
243 bool log_cards;
244 enum parse_state current_state;
245 char raw_file_name [PATH_MAX + 1];
246 char glyph_buffer[MAX_GLYPH_BUFFER_LEN];
247 CARD_CACHE_ENTRY *first_cached_card;
248 CARD_CACHE_ENTRY *last_cached_card;
249 enum pun_mode { punNoMode, punWrBin } ioMode;
250 } pun_state_t ;
251
252 static pun_state_t pun_state[N_PUN_UNITS_MAX];
253 static char pun_path_prefix[PATH_MAX-63];
254
255
256
257
258
259
260
261 void pun_init (void)
262 {
263 (void)memset (pun_path_prefix, 0, sizeof (pun_path_prefix));
264 (void)memset (pun_state, 0, sizeof (pun_state));
265 for (int i = 0; i < N_PUN_UNITS_MAX; i ++)
266 {
267 pun_state [i] . punfile_raw = -1;
268 pun_state [i] . current_state = Idle;
269 }
270 }
271
272 static t_stat pun_reset (UNUSED DEVICE * dptr)
273 {
274 return SCPE_OK;
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288
289 static word36 eodCard [WORDS_PER_CARD] =
290 {
291 0000500000000llu,
292 0000000000000llu,
293 0000000000000llu,
294 0000000000000llu,
295 0000000000000llu,
296 0000000002000llu,
297 0240024002400llu,
298 0370000000000llu,
299 0372121122104llu,
300 0210437370000llu,
301 0000000210021llu,
302 0002100210037llu,
303 0000000001621llu,
304 0212521252125llu,
305 0373700000000llu,
306 0371602210421llu,
307 0102137370000llu,
308 0000021002500llu,
309 0250025003700llu,
310 0000000000000llu,
311 0000000000000llu,
312 0000000000000llu,
313 0000000000000llu,
314 0000000000000llu,
315 0000000000000llu,
316 0000000000000llu,
317 0000000050000llu
318 };
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 static word36 bannerCard [WORDS_PER_CARD] =
334 {
335 0000500000000llu,
336 0770077047704llu,
337 0770477000000llu,
338 0000000770477llu,
339 0047704770077llu,
340 0000000007700llu,
341 0770477047704llu,
342 0770000000000llu,
343 0007704770477llu,
344 0047700770000llu,
345 0000077007704llu,
346 0770477047700llu,
347 0000000000077llu,
348 0047704770477llu,
349 0007700000000llu,
350 0770077047704llu,
351 0770477000000llu,
352 0000000770477llu,
353 0047704770077llu,
354 0000000007700llu,
355 0770477047704llu,
356 0770000000000llu,
357 0007704770477llu,
358 0047700770000llu,
359 0000077007704llu,
360 0770477047700llu,
361 0000000050000llu
362 };
363
364
365
366
367
368
369
370
371 #define NUM_GLYPH_CHAR_PATTERNS 45
372
373 static uint8 glyph_char_patterns [NUM_GLYPH_CHAR_PATTERNS][CHAR_MATRIX_BYTES] =
374 {
375
376 { 037, 037, 037, 037, 037 },
377
378 { 000, 000, 000, 000, 000 },
379
380 { 000, 003, 003, 003, 000 },
381
382 { 021, 000, 012, 000, 004 },
383
384 { 037, 024, 024, 024, 037 },
385
386 { 037, 025, 025, 025, 012 },
387
388 { 037, 021, 021, 021, 021 },
389
390 { 037, 021, 021, 021, 016 },
391
392 { 037, 025, 025, 025, 021 },
393
394 { 037, 024, 024, 024, 020 },
395
396 { 037, 021, 021, 025, 027 },
397
398 { 037, 004, 004, 004, 037 },
399
400 { 021, 021, 037, 021, 021 },
401
402 { 003, 001, 001, 001, 037 },
403
404 { 037, 004, 004, 012, 021 },
405
406 { 037, 001, 001, 001, 001 },
407
408 { 037, 010, 004, 010, 037 },
409
410 { 037, 010, 004, 002, 037 },
411
412 { 037, 021, 021, 021, 037 },
413
414 { 037, 024, 024, 024, 034 },
415
416 { 037, 021, 025, 023, 037 },
417
418 { 037, 024, 024, 026, 035 },
419
420 { 035, 025, 025, 025, 027 },
421
422 { 020, 020, 037, 020, 020 },
423
424 { 037, 001, 001, 001, 037 },
425
426 { 030, 006, 001, 006, 030 },
427
428 { 037, 002, 004, 002, 037 },
429
430 { 021, 012, 004, 012, 021 },
431
432 { 020, 010, 007, 010, 020 },
433
434 { 021, 027, 025, 035, 021 },
435
436 { 016, 021, 021, 021, 016 },
437
438 { 000, 010, 000, 037, 000 },
439
440 { 023, 025, 025, 025, 035 },
441
442 { 021, 025, 025, 025, 037 },
443
444 { 034, 004, 004, 004, 037 },
445
446 { 035, 025, 025, 025, 022 },
447
448 { 037, 005, 005, 005, 007 },
449
450 { 020, 021, 022, 024, 030 },
451
452 { 012, 025, 025, 025, 012 },
453
454 { 034, 024, 024, 024, 037 },
455
456 { 001, 001, 001, 001, 001 },
457
458 { 000, 004, 004, 004, 000 },
459
460 { 000, 004, 012, 021, 000 },
461
462 { 000, 021, 012, 004, 000 },
463
464 { 001, 002, 004, 010, 020 }
465 };
466
467 static char glyph_chars [NUM_GLYPH_CHAR_PATTERNS] =
468 {
469 '*', ' ', '.', '>', 'A', 'B', 'C', 'D', 'E', 'F',
470 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
471 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
472 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
473 '_', '-', '(', ')', '/'
474 };
475
476 static uint8 glyph_char_word_offset [11] =
477 {
478 24, 22, 19, 17, 15, 12, 10, 8, 5, 3, 1
479 };
480
481 static uint8 glyph_nibble_offset [11] =
482 {
483 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2
484 };
485
486 static void remove_spaces(char *str)
487 {
488 int src = 0;
489 int dest = 0;
490 while (str[src])
491 {
492 if (str[src] != ' ')
493 {
494 str[dest++] = str[src];
495 }
496 src++;
497 }
498 str[dest] = 0;
499 }
500
501 static void log_char_matrix_pattern(uint8* char_matrix)
502 {
503 sim_print("\nChar Matrix\n");
504 for (uint col_offset = 0; col_offset < CHAR_MATRIX_BYTES; col_offset++)
505 {
506 sim_printf(" %03o\n", char_matrix[col_offset]);
507 }
508
509 sim_print("\r\n");
510 for (uint row = 0; row < 5; row++)
511 {
512 for (uint col = 0; col < CHAR_MATRIX_BYTES; col++)
513 {
514 if ((char_matrix[col] >> (4 - row)) & 0x1)
515 {
516 sim_print("*");
517 }
518 else
519 {
520 sim_print(" ");
521 }
522 }
523 sim_print("\r\n");
524 }
525 sim_print("\r\n");
526
527 }
528
529 static char search_glyph_patterns(uint8* matrix)
530 {
531 for (int pattern = 0; pattern < NUM_GLYPH_CHAR_PATTERNS; pattern++)
532 {
533 if (memcmp(matrix, &glyph_char_patterns[pattern], CHAR_MATRIX_BYTES) == 0)
534 {
535 return glyph_chars[pattern];
536 }
537 }
538
539 sim_warn("*** Warning: Punch found unknown block character pattern\n");
540 log_char_matrix_pattern(matrix);
541
542 return ' ';
543 }
544
545 static char get_lace_char(word36* buffer, uint char_pos)
546 {
547 if (char_pos >= GLYPHS_PER_CARD)
548 {
549 sim_warn("*** Error: Attempt to read punch block character out of range (%u)\n", char_pos);
550 return 0;
551 }
552
553 bool top = char_pos < 11;
554 uint char_offset = (char_pos < 11) ? char_pos : char_pos - 11;
555 uint word_offset = glyph_char_word_offset[char_offset];
556 uint nibble_offset = glyph_nibble_offset[char_offset];
557 word12 col_buffer[5];
558
559
560
561
562 for (uint col_offset = 0; col_offset < 5; col_offset++)
563 {
564 col_buffer[4 - col_offset] = (buffer[word_offset] >> (nibble_offset * 12)) & 0xFFF;
565 if (nibble_offset == 0)
566 {
567 nibble_offset = 2;
568 word_offset++;
569 }
570 else
571 {
572 nibble_offset--;
573 }
574 }
575
576
577 uint8 char_matrix[CHAR_MATRIX_BYTES];
578
579 for (uint col_offset = 0; col_offset < CHAR_MATRIX_BYTES; col_offset++)
580 {
581 char_matrix[col_offset] = (col_buffer[col_offset] >> (top ? 6 : 0)) & 0x1F;
582 }
583
584 char c = search_glyph_patterns(char_matrix);
585
586 return c;
587 }
588
589 static void scan_card_for_glyphs(pun_state_t * state, word36* buffer)
590 {
591 for (uint c_pos = 0; c_pos < 22; c_pos++)
592 {
593 char c = get_lace_char(buffer, c_pos);
594 uint current_length = (uint)strlen(state -> glyph_buffer);
595 if (current_length < (sizeof(state -> glyph_buffer) - 1))
596 {
597 state -> glyph_buffer[current_length++] = c;
598 state -> glyph_buffer[current_length] = 0;
599 }
600 }
601 }
602
603 static void create_punch_file(pun_state_t * state)
604 {
605 char template [4 * PATH_MAX+1];
606
607 if (state -> punfile_raw != -1)
608 {
609 sim_warn \
610 ("*** Error: Punch file already open when attempting to create new file, closing old file!\n");
611 close(state -> punfile_raw);
612 state -> punfile_raw = -1;
613 }
614
615 if (pun_path_prefix [0])
616 {
617 (void)sprintf (template, "%s%s/%s.spool.%s.XXXXXX.pun",
618 pun_path_prefix, state -> device_name,
619 state -> device_name,
620 state -> raw_file_name);
621 }
622 else
623 {
624 (void)sprintf (template, "%s.spool.%s.XXXXXX.pun",
625 state -> device_name,
626 state -> raw_file_name);
627 }
628
629 state -> punfile_raw = utfile_mkstemps(template, 4);
630 if (state -> punfile_raw < 0)
631 {
632 perror("creating punch '.pun' file\n");
633 }
634
635 }
636
637 static void write_punch_files (pun_state_t * state, word36* in_buffer, int word_count,
638 bool banner_card)
639 {
640 if (word_count != WORDS_PER_CARD)
641 {
642 sim_warn ("Unable to interpret punch buffer due to wrong length, not writing output!\n");
643 return;
644 }
645
646 uint8 byte_buffer[120];
647 (void)memset(&byte_buffer, 0, sizeof(byte_buffer));
648
649 word12 word12_buffer[80];
650 (void)memset(&word12_buffer, 0, sizeof(word12_buffer));
651
652 for (int nibble_index = 0; nibble_index < (CARD_COL_COUNT * NIBBLES_PER_COL); nibble_index++)
653 {
654 int byte_offset = nibble_index / 2;
655 int word36_offset = nibble_index / 9;
656 int nibble_offset = nibble_index % 9;
657 uint8 nibble = (in_buffer[word36_offset] >> ((8 - nibble_offset) * 4)) & 0xF;
658
659 if (nibble_index & 0x1)
660 {
661
662 byte_buffer[byte_offset] |= nibble;
663 }
664 else
665 {
666
667 byte_buffer[byte_offset] |= (nibble << 4);
668 }
669
670 int word12_offset = nibble_index / 3;
671 int word12_nibble_offset = 2 - (nibble_index % 3);
672
673 word12_buffer[word12_offset] |= nibble << (word12_nibble_offset * 4);
674 }
675
676 if (state->log_cards)
677 {
678 sim_printf("word12_buffer:\n");
679 for (uint i = 0; i < 80; i++)
680 {
681 sim_printf(" %04o\n", word12_buffer[i]);
682 }
683 sim_printf("\r\n");
684 }
685
686 if (state -> punfile_raw >= 0)
687 {
688 if (write(state -> punfile_raw, byte_buffer, sizeof(byte_buffer)) \
689 != sizeof(byte_buffer)) {
690 sim_warn ("Failed to write to .raw card punch file!\n");
691 perror("Writing .raw punch file\n");
692 }
693 }
694
695 }
696
697 static void log_card(word12 tally, word36 * buffer)
698 {
699 sim_printf ("tally %d\n", tally);
700
701 for (uint i = 0; i < tally; i ++)
702 {
703 sim_printf (" %012llo\n", (unsigned long long)buffer [i]);
704 }
705 sim_printf ("\r\n");
706
707 if (tally != WORDS_PER_CARD)
708 {
709 sim_warn("Unable to log punch card, tally is not 27 (%d)\n", tally);
710 return;
711 }
712
713 for (uint row = 0; row < 12; row ++)
714 {
715 for (uint col = 0; col < 80; col ++)
716 {
717
718 uint wordno = col / 3;
719 uint fieldno = col % 3;
720 word1 bit = getbits36_1 (buffer [wordno], fieldno * 12 + row);
721 if (bit)
722 sim_printf ("*");
723 else
724 sim_printf (" ");
725 }
726 sim_printf ("\r\n");
727 }
728 sim_printf ("\r\n");
729
730 for (uint row = 0; row < 12; row ++)
731 {
732
733 for (int col = 79; col >= 0; col --)
734 {
735
736 uint wordno = (uint) col / 3;
737 uint fieldno = (uint) col % 3;
738 word1 bit = getbits36_1 (buffer [wordno], fieldno * 12 + row);
739 if (bit)
740 sim_printf ("*");
741 else
742 sim_printf (" ");
743 }
744 sim_printf ("\r\n");
745 }
746 sim_printf ("\r\n");
747 }
748
749 static void print_event(enum parse_event event)
750 {
751 switch (event)
752 {
753 case NoEvent:
754 sim_warn("[No Event]");
755 break;
756 case BannerCard:
757 sim_warn("[Banner Card]");
758 break;
759 case EndOfDeckCard:
760 sim_warn("[End Of Deck Card]");
761 break;
762 case Card:
763 sim_warn("[Card]");
764 break;
765 case Done:
766 sim_warn("[Done]");
767 break;
768 default:
769 sim_warn("[unknown event %d]", event);
770 break;
771 }
772 }
773
774 static void print_state(enum parse_state state)
775 {
776 switch (state)
777 {
778 case Idle:
779 sim_warn("[Idle]");
780 break;
781 case StartingJob:
782 sim_warn("[Starting Job]");
783 break;
784 case PunchGlyphLookup:
785 sim_warn("[Punch Glyph Lookup]");
786 break;
787 case EndOfHeader:
788 sim_warn("[End Of Header]");
789 break;
790 case CacheCard:
791 sim_warn("[Cache Card]");
792 break;
793 case EndOfDeck:
794 sim_warn("[End Of Deck]");
795 break;
796 case EndOfJob:
797 sim_warn("[End Of Job]");
798 break;
799 default:
800 sim_warn("[unknown state %d]", state);
801 break;
802 }
803 }
804
805 static void print_transition(enum parse_state old_state, enum parse_event event,
806 enum parse_state new_state)
807 {
808 sim_warn(">>> Punch Transition: ");
809 print_event(event);
810 sim_warn(" = ");
811 print_state(old_state);
812 sim_warn(" -> ");
813 print_state(new_state);
814 sim_warn("\r\n");
815 }
816
817 static void clear_card_cache(pun_state_t * state)
818 {
819 CARD_CACHE_ENTRY *current_entry = state -> first_cached_card;
820 while (current_entry != NULL)
821 {
822 CARD_CACHE_ENTRY *old_entry = current_entry;
823 current_entry = current_entry->next_entry;
824 FREE(old_entry);
825 }
826
827 state -> first_cached_card = NULL;
828 state -> last_cached_card = NULL;
829 }
830
831 static void save_card_in_cache(pun_state_t * state, word12 tally, word36 * card_buffer)
832 {
833 CARD_CACHE_ENTRY *new_entry = malloc(sizeof(CARD_CACHE_ENTRY));
834 if (!new_entry)
835 {
836 (void)fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
837 __func__, __FILE__, __LINE__);
838 #if defined(USE_BACKTRACE)
839 # if defined(SIGUSR2)
840 (void)raise(SIGUSR2);
841
842 # endif
843 #endif
844 abort();
845 }
846
847 new_entry -> tally = tally;
848 memcpy(&new_entry -> card_data, card_buffer, sizeof(word36) * tally);
849 new_entry -> next_entry = NULL;
850
851 if (state -> first_cached_card == NULL)
852 {
853 state -> first_cached_card = new_entry;
854 state -> last_cached_card = new_entry;
855 }
856 else
857 {
858 state -> last_cached_card -> next_entry = new_entry;
859 state -> last_cached_card = new_entry;
860 }
861 }
862
863 static void transition_state(enum parse_event event, pun_state_t * state,
864 enum parse_state new_state)
865 {
866 if (state -> log_cards)
867 {
868 print_transition(state -> current_state, event, new_state);
869 }
870
871 state -> current_state = new_state;
872 }
873
874 static enum parse_event do_state_idle(enum parse_event event, pun_state_t * state)
875 {
876 transition_state(event, state, Idle);
877
878
879
880 return NoEvent;
881 }
882
883 static enum parse_event do_state_starting_job(enum parse_event event,
884 pun_state_t * state, word12 tally,
885 word36 * card_buffer)
886 {
887 transition_state(event, state, StartingJob);
888
889 clear_card_cache(state);
890 state -> glyph_buffer[0] = 0;
891 save_card_in_cache(state, tally, card_buffer);
892
893 return NoEvent;
894 }
895
896 static enum parse_event do_state_scan_card_for_glyphs(enum parse_event event,
897 pun_state_t * state,
898 word12 tally,
899 word36 * card_buffer)
900 {
901 transition_state(event, state, PunchGlyphLookup);
902
903 scan_card_for_glyphs(state, card_buffer);
904
905 save_card_in_cache(state, tally, card_buffer);
906
907 return NoEvent;
908 }
909
910 static enum parse_event do_state_end_of_header(enum parse_event event,
911 pun_state_t * state,
912 word12 tally,
913 word36 * card_buffer)
914 {
915 transition_state(event, state, EndOfHeader);
916
917 save_card_in_cache(state, tally, card_buffer);
918
919 if (state -> log_cards)
920 {
921 sim_printf("\n++++ Glyph Buffer ++++\n'%s'\n", state -> glyph_buffer);
922 }
923
924 char punch_file_name[PATH_MAX+1];
925 if (strlen(state -> glyph_buffer) < 86)
926 {
927 sim_warn \
928 ("*** Punch: glyph buffer too short, unable to parse file name '%s'\n",
929 state -> glyph_buffer);
930 punch_file_name[0] = 0;
931 }
932 else
933 {
934 (void)sprintf (punch_file_name, "%5.5s.%22.22s",
935 &state -> glyph_buffer[14],
936 &state -> glyph_buffer[88]
937 );
938 remove_spaces(punch_file_name);
939 }
940
941 strncpy(state -> raw_file_name, punch_file_name, sizeof(state -> raw_file_name));
942
943 create_punch_file(state);
944
945
946 CARD_CACHE_ENTRY *current_entry = state -> first_cached_card;
947 while (current_entry != NULL)
948 {
949 write_punch_files (state, current_entry -> card_data, WORDS_PER_CARD, true);
950 current_entry = current_entry->next_entry;
951 }
952
953 clear_card_cache(state);
954
955 return NoEvent;
956 }
957
958 static enum parse_event do_state_cache_card(enum parse_event event,
959 pun_state_t * state,
960 word12 tally,
961 word36 * card_buffer)
962 {
963 transition_state(event, state, CacheCard);
964
965 save_card_in_cache(state, tally, card_buffer);
966
967 return NoEvent;
968 }
969
970 static enum parse_event do_state_end_of_deck(enum parse_event event,
971 pun_state_t * state,
972 word12 tally,
973 word36 * card_buffer)
974 {
975 transition_state(event, state, EndOfDeck);
976
977 save_card_in_cache(state, tally, card_buffer);
978
979 return NoEvent;
980 }
981
982 static enum parse_event do_state_end_of_job(enum parse_event event,
983 pun_state_t * state,
984 word12 tally,
985 word36 * card_buffer)
986 {
987 transition_state(event, state, EndOfJob);
988
989
990 CARD_CACHE_ENTRY *current_entry = state -> first_cached_card;
991 while (current_entry != NULL)
992 {
993 write_punch_files (state, current_entry -> card_data, WORDS_PER_CARD,
994 (current_entry -> next_entry == NULL));
995 current_entry = current_entry->next_entry;
996 }
997
998 clear_card_cache(state);
999
1000 write_punch_files (state, card_buffer, tally, true);
1001
1002
1003 if (state -> punfile_raw >= 0)
1004 {
1005 close (state -> punfile_raw);
1006 state -> punfile_raw = -1;
1007 }
1008
1009 return Done;
1010 }
1011
1012 static void unexpected_event(enum parse_event event, pun_state_t * state)
1013 {
1014 sim_warn("*** Punch: Unexpected event ");
1015 print_event(event);
1016
1017 sim_warn(" in state ");
1018 print_state(state -> current_state);
1019
1020 sim_warn("***\n");
1021 }
1022
1023 static void parse_card(pun_state_t * state, word12 tally, word36 * card_buffer)
1024 {
1025 enum parse_event event = Card;
1026
1027 if (tally == WORDS_PER_CARD && memcmp (card_buffer, eodCard, sizeof (eodCard)) == 0)
1028 {
1029 event = EndOfDeckCard;
1030 }
1031
1032 if (tally == WORDS_PER_CARD && memcmp (card_buffer, bannerCard, sizeof (bannerCard)) == 0)
1033 {
1034 event = BannerCard;
1035 }
1036
1037 while (event != NoEvent)
1038 {
1039 enum parse_event current_event = event;
1040 event = NoEvent;
1041
1042 switch (current_event)
1043 {
1044 case BannerCard:
1045 switch (state -> current_state)
1046 {
1047 case Idle:
1048 event = do_state_starting_job(current_event, state, tally, card_buffer);
1049 break;
1050
1051 case PunchGlyphLookup:
1052 event = do_state_end_of_header(current_event, state, tally, card_buffer);
1053 break;
1054
1055 case EndOfDeck:
1056 event = do_state_end_of_job(current_event, state, tally, card_buffer);
1057 break;
1058
1059 default:
1060 unexpected_event(current_event, state);
1061 break;
1062 }
1063 break;
1064
1065 case EndOfDeckCard:
1066 switch (state -> current_state)
1067 {
1068 case StartingJob:
1069 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1070 break;
1071
1072 case PunchGlyphLookup:
1073 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1074 break;
1075
1076 case EndOfHeader:
1077 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1078 break;
1079
1080 case CacheCard:
1081 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1082 break;
1083
1084 case EndOfDeck:
1085 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1086 break;
1087
1088 default:
1089 unexpected_event(current_event, state);
1090 break;
1091 }
1092 break;
1093
1094 case Card:
1095 switch (state -> current_state)
1096 {
1097 case StartingJob:
1098 event = do_state_scan_card_for_glyphs(current_event, state, tally, card_buffer);
1099 break;
1100
1101 case PunchGlyphLookup:
1102 event = do_state_scan_card_for_glyphs(current_event, state, tally, card_buffer);
1103 break;
1104
1105 case EndOfHeader:
1106 event = do_state_cache_card(current_event, state, tally, card_buffer);
1107 break;
1108
1109 case CacheCard:
1110 event = do_state_cache_card(current_event, state, tally, card_buffer);
1111 break;
1112
1113 case EndOfDeck:
1114 event = do_state_cache_card(current_event, state, tally, card_buffer);
1115 break;
1116
1117 default:
1118 unexpected_event(current_event, state);
1119 break;
1120 }
1121 break;
1122
1123 case Done:
1124 switch (state -> current_state)
1125 {
1126 case EndOfJob:
1127 event = do_state_idle(current_event, state);
1128 break;
1129
1130 default:
1131 unexpected_event(current_event, state);
1132 break;
1133 }
1134 break;
1135
1136 default:
1137 sim_warn("*** Error: Punch received unknown event!\n");
1138 break;
1139 }
1140 }
1141
1142 }
1143
1144 static int punWriteRecord (uint iomUnitIdx, uint chan)
1145 {
1146 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1147 uint dev_code = p->IDCW_DEV_CODE;
1148 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1149 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][dev_code].unit_idx;
1150 UNIT * unitp = & pun_unit [devUnitIdx];
1151 long pun_unit_num = PUN_UNIT_NUM (unitp);
1152
1153 p -> isRead = false;
1154 if (p -> DDCW_TALLY != WORDS_PER_CARD)
1155 {
1156 sim_warn ("%s expected tally of 27\n", __func__);
1157 p -> chanStatus = chanStatIncorrectDCW;
1158 p -> stati = 05001;
1159 return -1;
1160 }
1161
1162
1163
1164
1165
1166
1167 word36 buffer [p -> DDCW_TALLY];
1168 uint wordsProcessed = 0;
1169 iom_indirect_data_service (iomUnitIdx, chan, buffer, & wordsProcessed, false);
1170 p->initiate = false;
1171
1172 if (pun_state [pun_unit_num] . log_cards)
1173 {
1174 log_card(p -> DDCW_TALLY, buffer);
1175 }
1176
1177 parse_card( &pun_state [pun_unit_num], p -> DDCW_TALLY, buffer);
1178
1179 p -> stati = 04000;
1180 return 0;
1181 }
1182
1183 iom_cmd_rc_t pun_iom_cmd (uint iomUnitIdx, uint chan) {
1184 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1185 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1186 uint dev_code = p->IDCW_DEV_CODE;
1187 #if defined(TESTING)
1188 cpu_state_t * cpup = _cpup;
1189
1190 sim_debug (DBG_TRACE, & pun_dev, "%s: PUN %c%02o_%02o\n",
1191 __func__, iomChar (iomUnitIdx), chan, dev_code);
1192 #endif
1193
1194 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1195 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][dev_code].unit_idx;
1196 pun_state_t * statep = & pun_state[devUnitIdx];
1197
1198
1199 if (IS_IDCW (p)) {
1200
1201 statep->ioMode = punNoMode;
1202 switch (p->IDCW_DEV_CMD) {
1203 case 011:
1204 sim_debug (DBG_DEBUG, & pun_dev, "%s: Punch Binary\n", __func__);
1205 statep->ioMode = punWrBin;
1206 p->stati = 04000;
1207 break;
1208
1209 case 031:
1210 sim_debug (DBG_DEBUG, & pun_dev, "%s: Set Diagnostic Mode\n", __func__);
1211 p->stati = 04000;
1212 break;
1213
1214 case 040:
1215 sim_debug (DBG_DEBUG, & pun_dev, "%s: Reset Status\n", __func__);
1216 p->stati = 04000;
1217 p->isRead = false;
1218 break;
1219
1220 default:
1221 if (p->IDCW_DEV_CMD != 051)
1222 sim_warn ("%s: PUN unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1223 p->stati = 04501;
1224 p->chanStatus = chanStatIncorrectDCW;
1225 return IOM_CMD_ERROR;
1226 }
1227 sim_debug (DBG_DEBUG, & pun_dev, "%s: stati %04o\n", __func__, p->stati);
1228 return IOM_CMD_PROCEED;
1229 }
1230
1231
1232 switch (statep->ioMode) {
1233 case punNoMode:
1234
1235
1236
1237 break;
1238
1239 case punWrBin: {
1240 int rc = punWriteRecord (iomUnitIdx, chan);
1241 if (rc)
1242 return IOM_CMD_ERROR;
1243 }
1244 break;
1245
1246 default:
1247 sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1248 return IOM_CMD_ERROR;
1249 }
1250 return rc;
1251 }
1252
1253 static t_stat pun_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1254 UNUSED const void * desc)
1255 {
1256 sim_printf("Number of PUN units in system is %d\n", pun_dev . numunits);
1257 return SCPE_OK;
1258 }
1259
1260 static t_stat pun_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1261 UNUSED void * desc)
1262 {
1263 if (! cptr)
1264 return SCPE_ARG;
1265 int n = atoi (cptr);
1266 if (n < 1 || n > N_PUN_UNITS_MAX)
1267 return SCPE_ARG;
1268 pun_dev . numunits = (uint32) n;
1269 return SCPE_OK;
1270 }
1271
1272 static t_stat pun_show_device_name (UNUSED FILE * st, UNIT * uptr,
1273 UNUSED int val, UNUSED const void * desc)
1274 {
1275 long n = PUN_UNIT_NUM (uptr);
1276 if (n < 0 || n >= N_PUN_UNITS_MAX)
1277 return SCPE_ARG;
1278 sim_printf("name : %s", pun_state [n] . device_name);
1279 return SCPE_OK;
1280 }
1281
1282 static t_stat pun_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1283 UNUSED const char * cptr, UNUSED void * desc)
1284 {
1285 long n = PUN_UNIT_NUM (uptr);
1286 if (n < 0 || n >= N_PUN_UNITS_MAX)
1287 return SCPE_ARG;
1288 if (cptr)
1289 {
1290 strncpy (pun_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1291 pun_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1292 }
1293 else
1294 pun_state [n] . device_name [0] = 0;
1295 return SCPE_OK;
1296 }
1297
1298 static t_stat pun_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1299 const UNUSED char * cptr, UNUSED void * desc)
1300 {
1301 if (! cptr)
1302 return SCPE_ARG;
1303
1304 size_t len = strlen(cptr);
1305
1306
1307
1308 if (len >= (sizeof(pun_path_prefix) - 2))
1309 return SCPE_ARG;
1310
1311 strncpy(pun_path_prefix, cptr, sizeof(pun_path_prefix) - 1);
1312 if (len > 0)
1313 {
1314 if (pun_path_prefix[len - 1] != '/')
1315 {
1316 pun_path_prefix[len++] = '/';
1317 pun_path_prefix[len] = 0;
1318 }
1319 }
1320 return SCPE_OK;
1321 }
1322
1323 static t_stat pun_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1324 UNUSED int val, UNUSED const void * desc)
1325 {
1326 if (pun_path_prefix [0])
1327 {
1328 sim_printf("\rPath to card punch directories is \"%s\".\r\n", pun_path_prefix);
1329 }
1330 else
1331 {
1332 sim_printf("\rPath to card punch directories is unset.\r\n");
1333 }
1334 return SCPE_OK;
1335 }
1336
1337 static t_stat pun_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
1338 const char * cptr, UNUSED void * desc)
1339 {
1340 int devUnitIdx = (int) PUN_UNIT_NUM (uptr);
1341 pun_state_t * psp = pun_state + devUnitIdx;
1342 config_state_t cfg_state = { NULL, NULL };
1343
1344 for (;;)
1345 {
1346 int64_t v;
1347 int rc = cfg_parse (__func__, cptr, pun_config_list, & cfg_state, & v);
1348 if (rc == -1)
1349 break;
1350
1351 if (rc == -2)
1352 {
1353 cfg_parse_done (& cfg_state);
1354 return SCPE_ARG;
1355 }
1356 const char * p = pun_config_list[rc].name;
1357
1358 if (strcmp (p, "logcards") == 0)
1359 {
1360 psp->log_cards = v != 0;
1361 continue;
1362 }
1363
1364 sim_warn ("error: pun_set_config: Invalid cfg_parse rc <%ld>\n",
1365 (long) rc);
1366 cfg_parse_done (& cfg_state);
1367 return SCPE_ARG;
1368 }
1369 cfg_parse_done (& cfg_state);
1370 return SCPE_OK;
1371 }
1372
1373 static t_stat pun_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
1374 UNUSED int val, UNUSED const void * desc)
1375 {
1376 int devUnitIdx = (int) PUN_UNIT_NUM (uptr);
1377 pun_state_t * psp = pun_state + devUnitIdx;
1378 sim_msg ("logcards : %d", psp->log_cards);
1379 return SCPE_OK;
1380 }