1 /* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator
2
3 Copyright (c) 2002-2012, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 ptr 1621 paper tape reader
27 ptp 1624 paper tape punch
28
29 19-Mar-12 RMS Fixed declaration of io_stop (Mark Pizzolato)
30 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility
31 25-Apr-03 RMS Revised for extended file support
32 */
33
34 #include "i1620_defs.h"
35
36 #define PT_EL 0x80 /* end record */
37 #define PT_X 0x40 /* X */
38 #define PT_O 0x20 /* O */
39 #define PT_C 0x10 /* C */
40 #define PT_FD 0x7F /* deleted */
41
42 extern uint8 M[MAXMEMSIZE];
43 extern uint8 ind[NUM_IND];
44 extern UNIT cpu_unit;
45 extern uint32 io_stop;
46
47 t_stat ptr_reset (DEVICE *dptr);
48 t_stat ptr_boot (int32 unitno, DEVICE *dptr);
49 t_stat ptr_read (uint8 *c, t_bool ignfeed);
50 t_stat ptp_reset (DEVICE *dptr);
51 t_stat ptp_write (uint32 c);
52 t_stat ptp_num (uint32 pa, uint32 len);
53
54 /* PTR data structures
55
56 ptr_dev PTR device descriptor
57 ptr_unit PTR unit descriptor
58 ptr_reg PTR register list
59 */
60
61 UNIT ptr_unit = {
62 UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0)
63 };
64
65 REG ptr_reg[] = {
66 { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
67 { NULL }
68 };
69
70 DEVICE ptr_dev = {
71 "PTR", &ptr_unit, ptr_reg, NULL,
72 1, 10, 31, 1, 8, 8,
73 NULL, NULL, &ptr_reset,
74 &ptr_boot, NULL, NULL
75 };
76
77 /* PTP data structures
78
79 ptp_dev PTP device descriptor
80 ptp_unit PTP unit descriptor
81 ptp_reg PTP register list
82 */
83
84 UNIT ptp_unit = {
85 UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0)
86 };
87
88 REG ptp_reg[] = {
89 { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
90 { NULL }
91 };
92
93 DEVICE ptp_dev = {
94 "PTP", &ptp_unit, ptp_reg, NULL,
95 1, 10, 31, 1, 8, 8,
96 NULL, NULL, &ptp_reset,
97 NULL, NULL, NULL
98 };
99
100 /* Data tables */
101
102 /* Paper tape reader odd parity chart: 1 = bad, 0 = ok */
103
104 const int8 bad_par[128] = {
105 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */
106 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */
107 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */
108 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */
109 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */
110 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */
111 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */
112 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 /* 70 */
113 };
114
115 /* Paper tape read (7b) to numeric (one digit) */
116
117 const int8 ptr_to_num[128] = {
118 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */
119 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
120 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */
121 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
122 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */
123 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
124 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */
125 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
126 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */
127 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
128 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */
129 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
130 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */
131 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
132 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */
133 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F
134 };
135
136 /* Paper tape read (7b) to alphameric (two digits)
137 Codes XO82, 82, XO842, 842 do not have consistent translations
138 */
139
140 const int8 ptr_to_alp[128] = {
141 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */
142 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
143 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */
144 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
145 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */
146 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
147 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */
148 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
149 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */
150 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
151 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */
152 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
153 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */
154 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F,
155 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */
156 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F
157 };
158
159 /* Numeric (flag + digit) to paper tape punch */
160
161 const int8 num_to_ptp[32] = {
162 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */
163 0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F,
164 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */
165 0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F
166 };
167
168 /* Alphameric (two digits) to paper tape punch */
169
170 const int8 alp_to_ptp[256] = {
171 0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */
172 -1, -1, 0x2A, -1, -1, -1, -1, 0x1F,
173 0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */
174 -1, -1, -1, -1, -1, -1, -1, -1,
175 0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */
176 -1, -1, -1, -1, -1, -1, -1, -1,
177 -1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */
178 -1, -1, -1, -1, -1, -1, -1, -1,
179 -1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */
180 0x68, 0x79, -1, -1, -1, -1, -1, -1,
181 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */
182 0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F,
183 -1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */
184 0x38, 0x29, -1, -1, -1, -1, -1, -1,
185 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */
186 0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F,
187 -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
188 -1, -1, -1, -1, -1, -1, -1, -1,
189 -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
190 -1, -1, -1, -1, -1, -1, -1, -1,
191 -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
192 -1, -1, -1, -1, -1, -1, -1, -1,
193 -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
194 -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
196 -1, -1, -1, -1, -1, -1, -1, -1,
197 -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
198 -1, -1, -1, -1, -1, -1, -1, -1,
199 -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
200 -1, -1, -1, -1, -1, -1, -1, -1,
201 -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
202 -1, -1, -1, -1, -1, -1, -1, -1
203 };
204
205 /* Paper tape reader IO routine
206
207 - Hard errors halt the operation and the system.
208 - Parity errors place an invalid character in memory and set
209 RDCHK, but the read continues until end of record. If IO
210 stop is set, the system then halts.
211 */
212
ptr(uint32 op,uint32 pa,uint32 f0,uint32 f1)213 t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
214 {
215 uint32 i;
216 int8 mc;
217 uint8 ptc;
218 t_stat r, sta;
219
220 sta = SCPE_OK;
221 switch (op) { /* case on op */
222
223 case OP_RN: /* read numeric */
224 for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
225 r = ptr_read (&ptc, TRUE); /* read frame */
226 if (r != SCPE_OK) /* error? */
227 return r;
228 if (ptc & PT_EL) { /* end record? */
229 M[pa] = REC_MARK; /* store rec mark */
230 return sta; /* done */
231 }
232 if (bad_par[ptc]) { /* bad parity? */
233 ind[IN_RDCHK] = 1; /* set read check */
234 if (io_stop) /* set return status */
235 sta = STOP_INVCHR;
236 M[pa] = 0; /* store zero */
237 }
238 else M[pa] = ptr_to_num[ptc]; /* translate, store */
239 PP (pa); /* incr mem addr */
240 }
241 break;
242
243 case OP_RA: /* read alphameric */
244 for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
245 r = ptr_read (&ptc, TRUE); /* read frame */
246 if (r != SCPE_OK) /* error? */
247 return r;
248 if (ptc & PT_EL) { /* end record? */
249 M[pa] = REC_MARK; /* store rec mark */
250 M[pa - 1] = 0;
251 return sta; /* done */
252 }
253 mc = ptr_to_alp[ptc]; /* translate */
254 if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
255 ind[IN_RDCHK] = 1; /* set read check */
256 if (io_stop) /* set return status */
257 sta = STOP_INVCHR;
258 mc = 0; /* store blank */
259 }
260 M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
261 M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
262 pa = ADDR_A (pa, 2); /* incr mem addr */
263 }
264 break;
265
266 default: /* invalid function */
267 return STOP_INVFNC;
268 }
269
270 return STOP_RWRAP;
271 }
272
273 /* Binary paper tape reader IO routine - see above for error handling */
274
btr(uint32 op,uint32 pa,uint32 f0,uint32 f1)275 t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
276 {
277 uint32 i;
278 uint8 ptc;
279 t_stat r, sta;
280
281 if ((cpu_unit.flags & IF_BIN) == 0)
282 return STOP_INVIO;
283
284 sta = SCPE_OK;
285 switch (op) { /* case on op */
286
287 case OP_RA: /* read alphameric */
288 for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
289 r = ptr_read (&ptc, FALSE); /* read frame */
290 if (r != SCPE_OK) /* error? */
291 return r;
292 if (ptc & PT_EL) { /* end record? */
293 M[pa] = REC_MARK; /* store rec mark */
294 M[pa - 1] = 0;
295 return sta; /* done */
296 }
297 if (bad_par[ptc]) { /* bad parity? */
298 ind[IN_RDCHK] = 1; /* set read check */
299 if (io_stop) /* set return status */
300 sta = STOP_INVCHR;
301 }
302 M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
303 M[pa - 1] = (M[pa - 1] & FLAG) |
304 (((ptc >> 5) & 06) | ((ptc >> 3) & 1));
305 pa = ADDR_A (pa, 2); /* incr mem addr */
306 }
307 break;
308
309 default: /* invalid function */
310 return STOP_INVFNC;
311 }
312
313 return STOP_RWRAP;
314 }
315
316 /* Read ptr frame - all errors are 'hard' errors and halt the system */
317
ptr_read(uint8 * c,t_bool ignfeed)318 t_stat ptr_read (uint8 *c, t_bool ignfeed)
319 {
320 int32 temp;
321
322 if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
323 ind[IN_RDCHK] = 1; /* no, error */
324 return SCPE_UNATT;
325 }
326
327 do {
328 if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
329 ind[IN_RDCHK] = 1; /* err, rd chk */
330 if (feof (ptr_unit.fileref))
331 printf ("PTR end of file\n");
332 else perror ("PTR I/O error");
333 clearerr (ptr_unit.fileref);
334 return SCPE_IOERR;
335 }
336 *c = temp & 0377; /* save char */
337 ptr_unit.pos = ptr_unit.pos + 1; /* incr file addr */
338 } while (ignfeed && (*c == PT_FD)); /* until not feed */
339 return SCPE_OK;
340 }
341
342 /* Reset routine */
343
ptr_reset(DEVICE * dptr)344 t_stat ptr_reset (DEVICE *dptr)
345 {
346 return SCPE_OK;
347 }
348
349 /* Bootstrap routine */
350
351 const static uint8 boot_rom[] = {
352 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */
353 3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */
354 2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */
355 3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */
356 2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */
357 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */
358 4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 /* BR 12 */
359 };
360
361 #define BOOT_START 0
362 #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
363
ptr_boot(int32 unitno,DEVICE * dptr)364 t_stat ptr_boot (int32 unitno, DEVICE *dptr)
365 {
366 int32 i;
367 extern uint32 saved_PC;
368
369 for (i = 0; i < BOOT_LEN; i++)
370 M[BOOT_START + i] = boot_rom[i];
371 saved_PC = BOOT_START;
372 return SCPE_OK;
373 }
374
375 /* Paper tape punch IO routine
376
377 - Hard errors halt the operation and the system.
378 - Parity errors stop the operation and set WRCHK.
379 If IO stop is set, the system then halts.
380 */
381
ptp(uint32 op,uint32 pa,uint32 f0,uint32 f1)382 t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
383 {
384 uint32 i;
385 int8 ptc;
386 uint8 z, d;
387 t_stat r;
388
389 switch (op) { /* decode op */
390
391 case OP_DN:
392 return ptp_num (pa, 20000 - (pa % 20000)); /* dump numeric */
393
394 case OP_WN:
395 return ptp_num (pa, 0); /* punch numeric */
396
397 case OP_WA:
398 for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
399 d = M[pa] & DIGIT; /* get digit */
400 z = M[pa - 1] & DIGIT; /* get zone */
401 if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
402 return ptp_write (PT_EL); /* end record */
403 ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
404 if (ptc < 0) { /* bad char? */
405 ind[IN_WRCHK] = 1; /* write check */
406 CRETIOE (io_stop, STOP_INVCHR);
407 }
408 r = ptp_write (ptc); /* write char */
409 if (r != SCPE_OK) /* error? */
410 return r;
411 pa = ADDR_A (pa, 2); /* incr mem addr */
412 }
413 break;
414
415 default: /* invalid function */
416 return STOP_INVFNC;
417 }
418
419 return STOP_RWRAP;
420 }
421
422 /* Binary paper tape punch IO routine - see above for error handling */
423
btp(uint32 op,uint32 pa,uint32 f0,uint32 f1)424 t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
425 {
426 uint32 i;
427 uint8 ptc, z, d;
428 t_stat r;
429
430 if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
431
432 switch (op) { /* decode op */
433
434 case OP_WA:
435 for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
436 d = M[pa] & DIGIT; /* get digit */
437 z = M[pa - 1] & DIGIT; /* get zone */
438 if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
439 return ptp_write (PT_EL); /* end record */
440 ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
441 if (bad_par[ptc]) /* set parity */
442 ptc = ptc | PT_C;
443 r = ptp_write (ptc); /* write char */
444 if (r != SCPE_OK) /* error? */
445 return r;
446 pa = ADDR_A (pa, 2); /* incr mem addr */
447 }
448 break;
449
450 default: /* invalid function */
451 return STOP_INVFNC;
452 }
453
454 return STOP_RWRAP;
455 }
456
457 /* Punch tape numeric - cannot generate parity errors */
458
ptp_num(uint32 pa,uint32 len)459 t_stat ptp_num (uint32 pa, uint32 len)
460 {
461 t_stat r;
462 uint8 d;
463 uint32 i, end;
464
465 end = pa + len;
466 for (i = 0; i < MEMSIZE; i++) { /* stop runaway */
467 d = M[pa] & (FLAG | DIGIT); /* get char */
468 if (len? (pa >= end): /* dump: end reached? */
469 ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
470 return ptp_write (PT_EL); /* end record */
471 r = ptp_write (num_to_ptp[d]); /* write */
472 if (r != SCPE_OK) /* error? */
473 return r;
474 PP (pa); /* incr mem addr */
475 }
476 return STOP_RWRAP;
477 }
478
479 /* Write ptp frame - all errors are hard errors */
480
ptp_write(uint32 c)481 t_stat ptp_write (uint32 c)
482 {
483 if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
484 ind[IN_WRCHK] = 1; /* no, error */
485 return SCPE_UNATT;
486 }
487 if (putc (c, ptp_unit.fileref) == EOF) { /* write char */
488 ind[IN_WRCHK] = 1; /* error? */
489 perror ("PTP I/O error");
490 clearerr (ptp_unit.fileref);
491 return SCPE_IOERR;
492 }
493 ptp_unit.pos = ptp_unit.pos + 1; /* count char */
494 return SCPE_OK;
495 }
496
497 /* Reset routine */
498
ptp_reset(DEVICE * dptr)499 t_stat ptp_reset (DEVICE *dptr)
500 {
501 return SCPE_OK;
502 }
503