1 /* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator
3 Copyright (c) 2002-2005, 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 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.
26 ptr 1621 paper tape reader
27 ptp 1624 paper tape punch
29 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility
30 25-Apr-03 RMS Revised for extended file support
33 #include "i1620_defs.h"
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 */
41 extern uint8 M
[MAXMEMSIZE
];
42 extern uint8 ind
[NUM_IND
];
44 extern uint32 io_stop
;
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
);
53 /* PTR data structures
55 ptr_dev PTR device descriptor
56 ptr_unit PTR unit descriptor
57 ptr_reg PTR register list
61 UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
+UNIT_ROABLE
, 0)
65 { DRDATA (POS
, ptr_unit
.pos
, T_ADDR_W
), PV_LEFT
},
70 "PTR", &ptr_unit
, ptr_reg
, NULL
,
72 NULL
, NULL
, &ptr_reset
,
76 /* PTP data structures
78 ptp_dev PTP device descriptor
79 ptp_unit PTP unit descriptor
80 ptp_reg PTP register list
84 UDATA (NULL
, UNIT_SEQ
+UNIT_ATTABLE
, 0)
88 { DRDATA (POS
, ptp_unit
.pos
, T_ADDR_W
), PV_LEFT
},
93 "PTP", &ptp_unit
, ptp_reg
, NULL
,
95 NULL
, NULL
, &ptp_reset
,
101 /* Paper tape reader odd parity chart: 1 = bad, 0 = ok */
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 */
114 /* Paper tape read (7b) to numeric (one digit) */
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
135 /* Paper tape read (7b) to alphameric (two digits)
136 Codes XO82, 82, XO842, 842 do not have consistent translations
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
158 /* Numeric (flag + digit) to paper tape punch */
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
167 /* Alphameric (two digits) to paper tape punch */
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
204 /* Paper tape reader IO routine
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.
212 t_stat
ptr (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
220 switch (op
) { /* case on op */
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 */
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 */
235 else M
[pa
] = ptr_to_num
[ptc
]; /* translate, store */
236 PP (pa
); /* incr mem addr */
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 */
247 return sta
; /* done */
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 */
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 */
261 default: /* invalid function */
268 /* Binary paper tape reader IO routine - see above for error handling */
270 t_stat
btr (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
276 if ((cpu_unit
.flags
& IF_BIN
) == 0) return STOP_INVIO
;
279 switch (op
) { /* case on op */
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 */
288 return sta
; /* done */
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 */
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 */
301 default: /* invalid function */
308 /* Read ptr frame - all errors are 'hard' errors and halt the system */
310 t_stat
ptr_read (uint8
*c
, t_bool ignfeed
)
314 if ((ptr_unit
.flags
& UNIT_ATT
) == 0) { /* attached? */
315 ind
[IN_RDCHK
] = 1; /* no, error */
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
);
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 */
336 t_stat
ptr_reset (DEVICE
*dptr
)
341 /* Bootstrap routine */
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 */
354 #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
356 t_stat
ptr_boot (int32 unitno
, DEVICE
*dptr
)
359 extern int32 saved_PC
;
361 for (i
= 0; i
< BOOT_LEN
; i
++) M
[BOOT_START
+ i
] = boot_rom
[i
];
362 saved_PC
= BOOT_START
;
366 /* Paper tape punch IO routine
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.
373 t_stat
ptp (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
380 switch (op
) { /* decode op */
383 return ptp_num (pa
, 20000 - (pa
% 20000)); /* dump numeric */
386 return ptp_num (pa
, 0); /* punch numeric */
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
);
399 r
= ptp_write (ptc
); /* write char */
400 if (r
!= SCPE_OK
) return r
; /* error? */
401 pa
= ADDR_A (pa
, 2); /* incr mem addr */
405 default: /* invalid function */
412 /* Binary paper tape punch IO routine - see above for error handling */
414 t_stat
btp (uint32 op
, uint32 pa
, uint32 f0
, uint32 f1
)
420 if ((cpu_unit
.flags
& IF_BIN
) == 0) return STOP_INVIO
;
422 switch (op
) { /* decode op */
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 */
438 default: /* invalid function */
445 /* Punch tape numeric - cannot generate parity errors */
447 t_stat
ptp_num (uint32 pa
, uint32 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 */
466 /* Write ptp frame - all errors are hard errors */
468 t_stat
ptp_write (uint32 c
)
470 if ((ptp_unit
.flags
& UNIT_ATT
) == 0) { /* attached? */
471 ind
[IN_WRCHK
] = 1; /* no, error */
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
);
480 ptp_unit
.pos
= ptp_unit
.pos
+ 1; /* count char */
486 t_stat
ptp_reset (DEVICE
*dptr
)