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