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) - 1);
942 state->raw_file_name[sizeof(state->raw_file_name) - 1] = '\0';
943
944 create_punch_file(state);
945
946
947 CARD_CACHE_ENTRY *current_entry = state -> first_cached_card;
948 while (current_entry != NULL)
949 {
950 write_punch_files (state, current_entry -> card_data, WORDS_PER_CARD, true);
951 current_entry = current_entry->next_entry;
952 }
953
954 clear_card_cache(state);
955
956 return NoEvent;
957 }
958
959 static enum parse_event do_state_cache_card(enum parse_event event,
960 pun_state_t * state,
961 word12 tally,
962 word36 * card_buffer)
963 {
964 transition_state(event, state, CacheCard);
965
966 save_card_in_cache(state, tally, card_buffer);
967
968 return NoEvent;
969 }
970
971 static enum parse_event do_state_end_of_deck(enum parse_event event,
972 pun_state_t * state,
973 word12 tally,
974 word36 * card_buffer)
975 {
976 transition_state(event, state, EndOfDeck);
977
978 save_card_in_cache(state, tally, card_buffer);
979
980 return NoEvent;
981 }
982
983 static enum parse_event do_state_end_of_job(enum parse_event event,
984 pun_state_t * state,
985 word12 tally,
986 word36 * card_buffer)
987 {
988 transition_state(event, state, EndOfJob);
989
990
991 CARD_CACHE_ENTRY *current_entry = state -> first_cached_card;
992 while (current_entry != NULL)
993 {
994 write_punch_files (state, current_entry -> card_data, WORDS_PER_CARD,
995 (current_entry -> next_entry == NULL));
996 current_entry = current_entry->next_entry;
997 }
998
999 clear_card_cache(state);
1000
1001 write_punch_files (state, card_buffer, tally, true);
1002
1003
1004 if (state -> punfile_raw >= 0)
1005 {
1006 close (state -> punfile_raw);
1007 state -> punfile_raw = -1;
1008 }
1009
1010 return Done;
1011 }
1012
1013 static void unexpected_event(enum parse_event event, pun_state_t * state)
1014 {
1015 sim_warn("*** Punch: Unexpected event ");
1016 print_event(event);
1017
1018 sim_warn(" in state ");
1019 print_state(state -> current_state);
1020
1021 sim_warn("***\n");
1022 }
1023
1024 static void parse_card(pun_state_t * state, word12 tally, word36 * card_buffer)
1025 {
1026 enum parse_event event = Card;
1027
1028 if (tally == WORDS_PER_CARD && memcmp (card_buffer, eodCard, sizeof (eodCard)) == 0)
1029 {
1030 event = EndOfDeckCard;
1031 }
1032
1033 if (tally == WORDS_PER_CARD && memcmp (card_buffer, bannerCard, sizeof (bannerCard)) == 0)
1034 {
1035 event = BannerCard;
1036 }
1037
1038 while (event != NoEvent)
1039 {
1040 enum parse_event current_event = event;
1041 event = NoEvent;
1042
1043 switch (current_event)
1044 {
1045 case BannerCard:
1046 switch (state -> current_state)
1047 {
1048 case Idle:
1049 event = do_state_starting_job(current_event, state, tally, card_buffer);
1050 break;
1051
1052 case PunchGlyphLookup:
1053 event = do_state_end_of_header(current_event, state, tally, card_buffer);
1054 break;
1055
1056 case EndOfDeck:
1057 event = do_state_end_of_job(current_event, state, tally, card_buffer);
1058 break;
1059
1060 default:
1061 unexpected_event(current_event, state);
1062 break;
1063 }
1064 break;
1065
1066 case EndOfDeckCard:
1067 switch (state -> current_state)
1068 {
1069 case StartingJob:
1070 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1071 break;
1072
1073 case PunchGlyphLookup:
1074 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1075 break;
1076
1077 case EndOfHeader:
1078 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1079 break;
1080
1081 case CacheCard:
1082 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1083 break;
1084
1085 case EndOfDeck:
1086 event = do_state_end_of_deck(current_event, state, tally, card_buffer);
1087 break;
1088
1089 default:
1090 unexpected_event(current_event, state);
1091 break;
1092 }
1093 break;
1094
1095 case Card:
1096 switch (state -> current_state)
1097 {
1098 case StartingJob:
1099 event = do_state_scan_card_for_glyphs(current_event, state, tally, card_buffer);
1100 break;
1101
1102 case PunchGlyphLookup:
1103 event = do_state_scan_card_for_glyphs(current_event, state, tally, card_buffer);
1104 break;
1105
1106 case EndOfHeader:
1107 event = do_state_cache_card(current_event, state, tally, card_buffer);
1108 break;
1109
1110 case CacheCard:
1111 event = do_state_cache_card(current_event, state, tally, card_buffer);
1112 break;
1113
1114 case EndOfDeck:
1115 event = do_state_cache_card(current_event, state, tally, card_buffer);
1116 break;
1117
1118 default:
1119 unexpected_event(current_event, state);
1120 break;
1121 }
1122 break;
1123
1124 case Done:
1125 switch (state -> current_state)
1126 {
1127 case EndOfJob:
1128 event = do_state_idle(current_event, state);
1129 break;
1130
1131 default:
1132 unexpected_event(current_event, state);
1133 break;
1134 }
1135 break;
1136
1137 default:
1138 sim_warn("*** Error: Punch received unknown event!\n");
1139 break;
1140 }
1141 }
1142
1143 }
1144
1145 static int punWriteRecord (uint iomUnitIdx, uint chan)
1146 {
1147 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1148 uint dev_code = p->IDCW_DEV_CODE;
1149 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1150 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][dev_code].unit_idx;
1151 UNIT * unitp = & pun_unit [devUnitIdx];
1152 long pun_unit_num = PUN_UNIT_NUM (unitp);
1153
1154 p -> isRead = false;
1155 if (p -> DDCW_TALLY != WORDS_PER_CARD)
1156 {
1157 sim_warn ("%s expected tally of 27\n", __func__);
1158 p -> chanStatus = chanStatIncorrectDCW;
1159 p -> stati = 05001;
1160 return -1;
1161 }
1162
1163
1164
1165
1166
1167
1168 word36 buffer [p -> DDCW_TALLY];
1169 uint wordsProcessed = 0;
1170 iom_indirect_data_service (iomUnitIdx, chan, buffer, & wordsProcessed, false);
1171 p->initiate = false;
1172
1173 if (pun_state [pun_unit_num] . log_cards)
1174 {
1175 log_card(p -> DDCW_TALLY, buffer);
1176 }
1177
1178 parse_card( &pun_state [pun_unit_num], p -> DDCW_TALLY, buffer);
1179
1180 p -> stati = 04000;
1181 return 0;
1182 }
1183
1184 iom_cmd_rc_t pun_iom_cmd (uint iomUnitIdx, uint chan) {
1185 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1186 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1187 uint dev_code = p->IDCW_DEV_CODE;
1188 #if defined(TESTING)
1189 cpu_state_t * cpup = _cpup;
1190
1191 sim_debug (DBG_TRACE, & pun_dev, "%s: PUN %c%02o_%02o\n",
1192 __func__, iomChar (iomUnitIdx), chan, dev_code);
1193 #endif
1194
1195 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1196 uint devUnitIdx = cables->urp_to_urd[ctlr_unit_idx][dev_code].unit_idx;
1197 pun_state_t * statep = & pun_state[devUnitIdx];
1198
1199
1200 if (IS_IDCW (p)) {
1201
1202 statep->ioMode = punNoMode;
1203 switch (p->IDCW_DEV_CMD) {
1204 case 011:
1205 sim_debug (DBG_DEBUG, & pun_dev, "%s: Punch Binary\n", __func__);
1206 statep->ioMode = punWrBin;
1207 p->stati = 04000;
1208 break;
1209
1210 case 031:
1211 sim_debug (DBG_DEBUG, & pun_dev, "%s: Set Diagnostic Mode\n", __func__);
1212 p->stati = 04000;
1213 break;
1214
1215 case 040:
1216 sim_debug (DBG_DEBUG, & pun_dev, "%s: Reset Status\n", __func__);
1217 p->stati = 04000;
1218 p->isRead = false;
1219 break;
1220
1221 default:
1222 if (p->IDCW_DEV_CMD != 051)
1223 sim_warn ("%s: PUN unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
1224 p->stati = 04501;
1225 p->chanStatus = chanStatIncorrectDCW;
1226 return IOM_CMD_ERROR;
1227 }
1228 sim_debug (DBG_DEBUG, & pun_dev, "%s: stati %04o\n", __func__, p->stati);
1229 return IOM_CMD_PROCEED;
1230 }
1231
1232
1233 switch (statep->ioMode) {
1234 case punNoMode:
1235
1236
1237
1238 break;
1239
1240 case punWrBin: {
1241 int rc = punWriteRecord (iomUnitIdx, chan);
1242 if (rc)
1243 return IOM_CMD_ERROR;
1244 }
1245 break;
1246
1247 default:
1248 sim_warn ("%s: Unrecognized ioMode %d\n", __func__, statep->ioMode);
1249 return IOM_CMD_ERROR;
1250 }
1251 return rc;
1252 }
1253
1254 static t_stat pun_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1255 UNUSED const void * desc)
1256 {
1257 sim_printf("Number of PUN units in system is %d\n", pun_dev . numunits);
1258 return SCPE_OK;
1259 }
1260
1261 static t_stat pun_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1262 UNUSED void * desc)
1263 {
1264 if (! cptr)
1265 return SCPE_ARG;
1266 int n = atoi (cptr);
1267 if (n < 1 || n > N_PUN_UNITS_MAX)
1268 return SCPE_ARG;
1269 pun_dev . numunits = (uint32) n;
1270 return SCPE_OK;
1271 }
1272
1273 static t_stat pun_show_device_name (UNUSED FILE * st, UNIT * uptr,
1274 UNUSED int val, UNUSED const void * desc)
1275 {
1276 long n = PUN_UNIT_NUM (uptr);
1277 if (n < 0 || n >= N_PUN_UNITS_MAX)
1278 return SCPE_ARG;
1279 sim_printf("name : %s", pun_state [n] . device_name);
1280 return SCPE_OK;
1281 }
1282
1283 static t_stat pun_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1284 UNUSED const char * cptr, UNUSED void * desc)
1285 {
1286 long n = PUN_UNIT_NUM (uptr);
1287 if (n < 0 || n >= N_PUN_UNITS_MAX)
1288 return SCPE_ARG;
1289 if (cptr)
1290 {
1291 strncpy (pun_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1292 pun_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1293 }
1294 else
1295 pun_state [n] . device_name [0] = 0;
1296 return SCPE_OK;
1297 }
1298
1299 static t_stat pun_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1300 const UNUSED char * cptr, UNUSED void * desc)
1301 {
1302 if (! cptr)
1303 return SCPE_ARG;
1304
1305 size_t len = strlen(cptr);
1306
1307
1308
1309 if (len >= (sizeof(pun_path_prefix) - 2))
1310 return SCPE_ARG;
1311
1312 strncpy(pun_path_prefix, cptr, sizeof(pun_path_prefix) - 1);
1313 if (len > 0)
1314 {
1315 if (pun_path_prefix[len - 1] != '/')
1316 {
1317 pun_path_prefix[len++] = '/';
1318 pun_path_prefix[len] = 0;
1319 }
1320 }
1321 return SCPE_OK;
1322 }
1323
1324 static t_stat pun_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1325 UNUSED int val, UNUSED const void * desc)
1326 {
1327 if (pun_path_prefix [0])
1328 {
1329 sim_printf("\rPath to card punch directories is \"%s\".\r\n", pun_path_prefix);
1330 }
1331 else
1332 {
1333 sim_printf("\rPath to card punch directories is unset.\r\n");
1334 }
1335 return SCPE_OK;
1336 }
1337
1338 static t_stat pun_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
1339 const char * cptr, UNUSED void * desc)
1340 {
1341 int devUnitIdx = (int) PUN_UNIT_NUM (uptr);
1342 pun_state_t * psp = pun_state + devUnitIdx;
1343 config_state_t cfg_state = { NULL, NULL };
1344
1345 for (;;)
1346 {
1347 int64_t v;
1348 int rc = cfg_parse (__func__, cptr, pun_config_list, & cfg_state, & v);
1349 if (rc == -1)
1350 break;
1351
1352 if (rc == -2)
1353 {
1354 cfg_parse_done (& cfg_state);
1355 return SCPE_ARG;
1356 }
1357 const char * p = pun_config_list[rc].name;
1358
1359 if (strcmp (p, "logcards") == 0)
1360 {
1361 psp->log_cards = v != 0;
1362 continue;
1363 }
1364
1365 sim_warn ("error: pun_set_config: Invalid cfg_parse rc <%ld>\n",
1366 (long) rc);
1367 cfg_parse_done (& cfg_state);
1368 return SCPE_ARG;
1369 }
1370 cfg_parse_done (& cfg_state);
1371 return SCPE_OK;
1372 }
1373
1374 static t_stat pun_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
1375 UNUSED int val, UNUSED const void * desc)
1376 {
1377 int devUnitIdx = (int) PUN_UNIT_NUM (uptr);
1378 pun_state_t * psp = pun_state + devUnitIdx;
1379 sim_msg ("logcards : %d", psp->log_cards);
1380 return SCPE_OK;
1381 }