1
/* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator
3
Copyright (c) 2002-2004, Robert M Supnik
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:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
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.
22
Except as contained in this notice, the name of Robert M Supnik shall not
23
be 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.
26
ptr 1621 paper tape reader
27
ptp 1624 paper tape punch
29
25-Apr-03 RMS Revised for extended file support
32
#include "i1620_defs.h"
34
#define PT_EL 0x80 /* end record */
35
#define PT_X 0x40 /* X */
36
#define PT_O 0x20 /* O */
37
#define PT_C 0x10 /* C */
38
#define PT_FD 0x7F /* deleted */
40
extern uint8 M[MAXMEMSIZE];
41
extern uint8 ind[NUM_IND];
43
extern uint32 io_stop;
45
t_stat ptr_reset (DEVICE *dptr);
46
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
47
t_stat ptr_read (uint8 *c, t_bool ignfeed);
48
t_stat ptp_reset (DEVICE *dptr);
49
t_stat ptp_write (uint32 c);
50
t_stat ptp_num (uint32 pa, uint32 len);
52
/* PTR data structures
54
ptr_dev PTR device descriptor
55
ptr_unit PTR unit descriptor
56
ptr_reg PTR register list
60
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) };
63
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
67
"PTR", &ptr_unit, ptr_reg, NULL,
69
NULL, NULL, &ptr_reset,
70
&ptr_boot, NULL, NULL };
72
/* PTP data structures
74
ptp_dev PTP device descriptor
75
ptp_unit PTP unit descriptor
76
ptp_reg PTP register list
80
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
83
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
87
"PTP", &ptp_unit, ptp_reg, NULL,
89
NULL, NULL, &ptp_reset,
94
/* Paper tape reader odd parity chart: 1 = bad, 0 = ok */
96
const int8 bad_par[128] = {
97
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */
98
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */
99
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */
100
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */
101
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */
102
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */
103
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */
104
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; /* 70 */
106
/* Paper tape read (7b) to numeric (one digit) */
108
const int8 ptr_to_num[128] = {
109
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */
110
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
111
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */
112
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
113
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */
114
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
115
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */
116
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
117
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */
118
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
119
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */
120
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
121
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */
122
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
123
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */
124
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F };
126
/* Paper tape read (7b) to alphameric (two digits)
127
Codes XO82, 82, XO842, 842 do not have consistent translations
130
const int8 ptr_to_alp[128] = {
131
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */
132
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
133
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */
134
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
135
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */
136
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
137
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */
138
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
139
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */
140
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
141
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */
142
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
143
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */
144
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F,
145
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */
146
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F };
148
/* Numeric (flag + digit) to paper tape punch */
150
const int8 num_to_ptp[32] = {
151
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */
152
0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F,
153
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */
154
0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F };
156
/* Alphameric (two digits) to paper tape punch */
158
const int8 alp_to_ptp[256] = {
159
0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */
160
-1, -1, 0x2A, -1, -1, -1, -1, 0x1F,
161
0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */
162
-1, -1, -1, -1, -1, -1, -1, -1,
163
0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */
164
-1, -1, -1, -1, -1, -1, -1, -1,
165
-1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */
166
-1, -1, -1, -1, -1, -1, -1, -1,
167
-1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */
168
0x68, 0x79, -1, -1, -1, -1, -1, -1,
169
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */
170
0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F,
171
-1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */
172
0x38, 0x29, -1, -1, -1, -1, -1, -1,
173
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */
174
0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F,
175
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
176
-1, -1, -1, -1, -1, -1, -1, -1,
177
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
178
-1, -1, -1, -1, -1, -1, -1, -1,
179
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
180
-1, -1, -1, -1, -1, -1, -1, -1,
181
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
182
-1, -1, -1, -1, -1, -1, -1, -1,
183
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
184
-1, -1, -1, -1, -1, -1, -1, -1,
185
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
186
-1, -1, -1, -1, -1, -1, -1, -1,
187
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
188
-1, -1, -1, -1, -1, -1, -1, -1,
189
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
190
-1, -1, -1, -1, -1, -1, -1, -1 };
192
/* Paper tape reader IO routine
194
- Hard errors halt the operation and the system.
195
- Parity errors place an invalid character in memory and set
196
RDCHK, but the read continues until end of record. If IO
197
stop is set, the system then halts.
200
t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
205
t_stat r, inv = SCPE_OK;
207
switch (op) { /* case on op */
208
case OP_RN: /* read numeric */
209
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
210
r = ptr_read (&ptc, TRUE); /* read frame */
211
if (r != SCPE_OK) return r; /* error? */
212
if (ptc & PT_EL) { /* end record? */
213
M[pa] = REC_MARK; /* store rec mark */
214
CRETIOE (io_stop, inv); } /* done */
215
if (bad_par[ptc]) { /* bad parity? */
216
ind[IN_RDCHK] = 1; /* set read check */
217
inv = STOP_INVCHR; /* set return status */
218
M[pa] = 0; } /* store zero */
219
else M[pa] = ptr_to_num[ptc]; /* translate, store */
220
PP (pa); } /* incr mem addr */
222
case OP_RA: /* read alphameric */
223
for (i = 0; i < MEMSIZE; i = i + 2) { /* (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 */
229
CRETIOE (io_stop, inv); } /* done */
230
mc = ptr_to_alp[ptc]; /* translate */
231
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
232
ind[IN_RDCHK] = 1; /* set read check */
233
inv = STOP_INVCHR; /* set return status */
234
mc = 0; } /* store blank */
235
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
236
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
237
pa = ADDR_A (pa, 2); } /* incr mem addr */
239
default: /* invalid function */
240
return STOP_INVFNC; }
244
/* Binary paper tape reader IO routine - see above for error handling */
246
t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
250
t_stat r, inv = SCPE_OK;
252
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
253
switch (op) { /* case on op */
254
case OP_RA: /* read alphameric */
255
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
256
r = ptr_read (&ptc, FALSE); /* read frame */
257
if (r != SCPE_OK) return r; /* error? */
258
if (ptc & PT_EL) { /* end record? */
259
M[pa] = REC_MARK; /* store rec mark */
261
CRETIOE (io_stop, inv); } /* done */
262
if (bad_par[ptc]) { /* bad parity? */
263
ind[IN_RDCHK] = 1; /* set read check */
264
inv = STOP_INVCHR; } /* set return status */
265
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
266
M[pa - 1] = (M[pa - 1] & FLAG) |
267
(((ptc >> 5) & 06) | ((ptc >> 3) & 1));
268
pa = ADDR_A (pa, 2); } /* incr mem addr */
270
default: /* invalid function */
271
return STOP_INVFNC; }
275
/* Read ptr frame - all errors are 'hard' errors and halt the system */
277
t_stat ptr_read (uint8 *c, t_bool ignfeed)
281
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
282
ind[IN_RDCHK] = 1; /* no, error */
285
do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
286
ind[IN_RDCHK] = 1; /* err, rd chk */
287
if (feof (ptr_unit.fileref))
288
printf ("PTR end of file\n");
289
else perror ("PTR I/O error");
290
clearerr (ptr_unit.fileref);
292
*c = temp & 0377; /* save char */
293
ptr_unit.pos = ptr_unit.pos + 1; } /* incr file addr */
294
while (ignfeed && (*c == PT_FD)); /* until not feed */
300
t_stat ptr_reset (DEVICE *dptr)
305
/* Bootstrap routine */
307
const static uint8 boot_rom[] = {
308
4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */
309
3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */
310
2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */
311
3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */
312
2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */
313
1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */
314
4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 }; /* BR 12 */
317
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
319
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
322
extern int32 saved_PC;
324
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
325
saved_PC = BOOT_START;
329
/* Paper tape punch IO routine
331
- Hard errors halt the operation and the system.
332
- Parity errors stop the operation and set WRCHK.
333
If IO stop is set, the system then halts.
336
t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
343
switch (op) { /* decode op */
345
return ptp_num (pa, 20000 - (pa % 20000)); /* dump numeric */
347
return ptp_num (pa, 0); /* punch numeric */
349
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
350
d = M[pa] & DIGIT; /* get digit */
351
z = M[pa - 1] & DIGIT; /* get zone */
352
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
353
return ptp_write (PT_EL); /* end record */
354
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
355
if (ptc < 0) { /* bad char? */
356
ind[IN_WRCHK] = 1; /* write check */
357
CRETIOE (io_stop, STOP_INVCHR); }
358
r = ptp_write (ptc); /* write char */
359
if (r != SCPE_OK) return r; /* error? */
360
pa = ADDR_A (pa, 2); } /* incr mem addr */
362
default: /* invalid function */
363
return STOP_INVFNC; }
367
/* Binary paper tape punch IO routine - see above for error handling */
369
t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
375
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
376
switch (op) { /* decode op */
378
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
379
d = M[pa] & DIGIT; /* get digit */
380
z = M[pa - 1] & DIGIT; /* get zone */
381
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
382
return ptp_write (PT_EL); /* end record */
383
ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
384
if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */
385
r = ptp_write (ptc); /* write char */
386
if (r != SCPE_OK) return r; /* error? */
387
pa = ADDR_A (pa, 2); } /* incr mem addr */
389
default: /* invalid function */
390
return STOP_INVFNC; }
394
/* Punch tape numeric - cannot generate parity errors */
396
t_stat ptp_num (uint32 pa, uint32 len)
403
for (i = 0; i < MEMSIZE; i++) { /* stop runaway */
404
d = M[pa] & (FLAG | DIGIT); /* get char */
405
if (len? (pa >= end): /* dump: end reached? */
406
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
407
return ptp_write (PT_EL); /* end record */
408
r = ptp_write (num_to_ptp[d]); /* write */
409
if (r != SCPE_OK) return r; /* error? */
410
PP (pa); } /* incr mem addr */
414
/* Write ptp frame - all errors are hard errors */
416
t_stat ptp_write (uint32 c)
418
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
419
ind[IN_WRCHK] = 1; /* no, error */
422
if (putc (c, ptp_unit.fileref) == EOF) { /* write char */
423
ind[IN_WRCHK] = 1; /* error? */
424
perror ("PTP I/O error");
425
clearerr (ptp_unit.fileref);
427
ptp_unit.pos = ptp_unit.pos + 1; /* count char */
433
t_stat ptp_reset (DEVICE *dptr)