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