1 /* id_pt.c: Interdata paper tape reader
2 
3    Copyright (c) 2000-2008, 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    pt           paper tape reader and punch
27 
28    25-Apr-03    RMS     Revised for extended file support
29    10-Apr-03    RMS     Fixed type problem in ptr service (Mark Pizzolato)
30 */
31 
32 #include "id_defs.h"
33 #include <ctype.h>
34 
35 /* Device definitions */
36 
37 #define PTR             0                               /* unit subscripts */
38 #define PTP             1
39 
40 #define STA_OVR         0x80                            /* overrun */
41 #define STA_NMTN        0x10                            /* no motion */
42 #define STA_MASK        (STA_BSY | STA_OVR | STA_DU)    /* static bits */
43 #define SET_EX          (STA_OVR | STA_NMTN)            /* set EX */
44 
45 #define CMD_V_RUN       4                               /* run/stop */
46 #define CMD_V_SLEW      2                               /* slew/step */
47 #define CMD_V_RD        0                               /* read/write */
48 
49 extern uint32 int_req[INTSZ], int_enb[INTSZ];
50 
51 uint32 pt_run = 0, pt_slew = 0;                         /* ptr modes */
52 uint32 pt_rd = 1, pt_chp = 0;                           /* pt state */
53 uint32 pt_arm = 0;                                      /* int arm */
54 uint32 pt_sta = STA_BSY;                                /* status */
55 uint32 ptr_stopioe = 0, ptp_stopioe = 0;                /* stop on error */
56 
57 DEVICE pt_dev;
58 uint32 pt (uint32 dev, uint32 op, uint32 dat);
59 t_stat ptr_svc (UNIT *uptr);
60 t_stat ptp_svc (UNIT *uptr);
61 t_stat pt_boot (int32 unitno, DEVICE *dptr);
62 t_stat pt_reset (DEVICE *dptr);
63 
64 /* PT data structures
65 
66    pt_dev       PT device descriptor
67    pt_unit      PT unit descriptors
68    pt_reg       PT register list
69 */
70 
71 DIB pt_dib = { d_PT, -1, v_PT, NULL, &pt, NULL };
72 
73 UNIT pt_unit[] = {
74     { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
75              SERIAL_IN_WAIT },
76     { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }
77     };
78 
79 REG pt_reg[] = {
80     { HRDATA (STA, pt_sta, 8) },
81     { HRDATA (RBUF, pt_unit[PTR].buf, 8) },
82     { DRDATA (RPOS, pt_unit[PTR].pos, T_ADDR_W), PV_LEFT },
83     { DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT },
84     { FLDATA (RSTOP_IOE, ptr_stopioe, 0) },
85     { HRDATA (PBUF, pt_unit[PTP].buf, 8) },
86     { DRDATA (PPOS, pt_unit[PTP].pos, T_ADDR_W), PV_LEFT },
87     { DRDATA (PTIME, pt_unit[PTP].wait, 24), PV_LEFT },
88     { FLDATA (PSTOP_IOE, ptp_stopioe, 0) },
89     { FLDATA (IREQ, int_req[l_PT], i_PT) },
90     { FLDATA (IENB, int_enb[l_PT], i_PT) },
91     { FLDATA (IARM, pt_arm, 0) },
92     { FLDATA (RD, pt_rd, 0) },
93     { FLDATA (RUN, pt_run, 0) },
94     { FLDATA (SLEW, pt_slew, 0) },
95     { FLDATA (CHP, pt_chp, 0) },
96     { HRDATA (DEVNO, pt_dib.dno, 8), REG_HRO },
97     { NULL }
98     };
99 
100 MTAB pt_mod[] = {
101     { MTAB_XTD|MTAB_VDV, 0, "devno", "DEVNO",
102       &set_dev, &show_dev, NULL },
103     { 0 }
104     };
105 
106 DEVICE pt_dev = {
107     "PT", pt_unit, pt_reg, pt_mod,
108     2, 10, 31, 1, 16, 8,
109     NULL, NULL, &pt_reset,
110     &pt_boot, NULL, NULL,
111     &pt_dib, DEV_DISABLE
112     };
113 
114 /* Paper tape: IO routine */
115 
pt(uint32 dev,uint32 op,uint32 dat)116 uint32 pt (uint32 dev, uint32 op, uint32 dat)
117 {
118 uint32 t, old_rd, old_run;
119 
120 switch (op) {                                           /* case IO op */
121 
122     case IO_ADR:                                        /* select */
123         return BY;                                      /* byte only */
124 
125     case IO_OC:                                         /* command */
126         old_rd = pt_rd;                                 /* save curr rw */
127         old_run = pt_run;                               /* save curr run */
128         pt_arm = int_chg (v_PT, dat, pt_arm);           /* upd int ctrl */
129         pt_rd = io_2b (dat, CMD_V_RD, pt_rd);           /* upd read/wr */
130         if (old_rd != pt_rd) {                          /* rw change? */
131             pt_sta = pt_sta & ~STA_OVR;                 /* clr overrun */
132             if (sim_is_active (&pt_unit[pt_rd? PTR: PTP])) {
133                 pt_sta = pt_sta | STA_BSY;              /* busy = 1 */
134                 CLR_INT (v_PT);                         /* clear int */
135                 }
136             else {                                      /* not active */
137                 pt_sta = pt_sta & ~STA_BSY;             /* busy = 0 */
138                 if (pt_arm)                             /* no, set int */
139                     SET_INT (v_PT);
140                 }
141             }
142         if (pt_rd) {                                    /* reader? */
143             pt_run = io_2b (dat, CMD_V_RUN, pt_run);    /* upd run/stop */
144             pt_slew = io_2b (dat, CMD_V_SLEW, pt_slew); /* upd slew/inc */
145             if (pt_run) {                               /* run set? */
146                 if (old_run == 0) {                     /* run 0 -> 1? */
147                     sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
148                     pt_sta = pt_sta & ~STA_DU;          /* clear eof */
149                     }
150                 }
151             else sim_cancel (&pt_unit[PTR]);            /* clr, stop rdr */
152             }
153         else pt_sta = pt_sta & ~STA_DU;                 /* punch, clr eof */
154         break;
155 
156     case IO_RD:                                         /* read */
157         if (pt_run && !pt_slew) {                       /* incremental? */
158             sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
159             pt_sta = pt_sta & ~STA_DU;                  /* clr eof */
160             }
161         pt_chp = 0;                                     /* clr char pend */
162         if (pt_rd)                                      /* set busy */
163             pt_sta = pt_sta | STA_BSY;
164         return (pt_unit[PTR].buf & 0xFF);               /* return char */
165 
166     case IO_WD:                                         /* write */
167         pt_unit[PTP].buf = dat & DMASK8;                /* save char */
168         if (!pt_rd)                                     /* set busy */
169             pt_sta = pt_sta | STA_BSY;
170         sim_activate (&pt_unit[PTP], pt_unit[PTP].wait);
171         break;
172 
173     case IO_SS:                                         /* status */
174         t = pt_sta & STA_MASK;                          /* get status */
175         if (pt_rd && !pt_run && !sim_is_active (&pt_unit[PTR]))
176             t = t | STA_NMTN;                           /* stopped? */
177         if ((pt_unit[pt_rd? PTR: PTP].flags & UNIT_ATT) == 0)
178             t = t | STA_DU;                             /* offline? */
179         if (t & SET_EX)                                 /* test for EX */
180             t = t | STA_EX;
181         return t;
182         }
183 
184 return 0;
185 }
186 
187 /* Unit service */
188 
ptr_svc(UNIT * uptr)189 t_stat ptr_svc (UNIT *uptr)
190 {
191 int32 temp;
192 
193 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
194     return IORETURN (ptr_stopioe, SCPE_UNATT);
195 if (pt_rd) {                                            /* read mode? */
196     pt_sta = pt_sta & ~STA_BSY;                         /* clear busy */
197     if (pt_arm)                                         /* if armed, intr */
198         SET_INT (v_PT);
199     if (pt_chp)                                         /* overrun? */
200         pt_sta = pt_sta | STA_OVR;
201     }
202 pt_chp = 1;                                             /* char pending */
203 if ((temp = getc (uptr->fileref)) == EOF) {             /* error? */
204     if (feof (uptr->fileref)) {                         /* eof? */
205         pt_sta = pt_sta | STA_DU;                       /* set DU */
206         if (ptr_stopioe)
207             printf ("PTR end of file\n");
208         else return SCPE_OK;
209         }
210     else perror ("PTR I/O error");
211     clearerr (uptr->fileref);
212     return SCPE_IOERR;
213     }
214 uptr->buf = temp & DMASK8;                              /* store char */
215 uptr->pos = uptr->pos + 1;                              /* incr pos */
216 if (pt_slew)                                            /* slew? continue */
217     sim_activate (uptr, uptr->wait);
218 return SCPE_OK;
219 }
220 
ptp_svc(UNIT * uptr)221 t_stat ptp_svc (UNIT *uptr)
222 {
223 if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
224     return IORETURN (ptp_stopioe, SCPE_UNATT);
225 if (!pt_rd) {                                           /* write mode? */
226     pt_sta = pt_sta & ~STA_BSY;                         /* clear busy */
227     if (pt_arm)                                         /* if armed, intr */
228         SET_INT (v_PT);
229     }
230 if (putc (uptr->buf, uptr -> fileref) == EOF) {         /* write char */
231     perror ("PTP I/O error");
232     clearerr (uptr -> fileref);
233     return SCPE_IOERR;
234     }
235 uptr -> pos = uptr -> pos + 1;                          /* incr pos */
236 return SCPE_OK;
237 }
238 
239 /* Reset routine */
240 
pt_reset(DEVICE * dptr)241 t_stat pt_reset (DEVICE *dptr)
242 {
243 sim_cancel (&pt_unit[PTR]);                             /* deactivate units */
244 sim_cancel (&pt_unit[PTP]);
245 pt_rd = 1;                                              /* read */
246 pt_chp = pt_run = pt_slew = 0;                          /* stop, inc, disarm */
247 pt_sta = STA_BSY;                                       /* buf empty */
248 CLR_INT (v_PT);                                         /* clear int */
249 CLR_ENB (v_PT);                                         /* disable int */
250 pt_arm = 0;                                             /* disarm int */
251 return SCPE_OK;
252 }
253 
254 /* Bootstrap routine */
255 
256 #define BOOT_START      0x50
257 #define BOOT_LEN        (sizeof (boot_rom) / sizeof (uint8))
258 #define BOOT3_START     0x3E
259 #define BOOT3_LEN       (sizeof (boot_rom) / sizeof (uint8))
260 
261 static uint8 boot_rom[] = {
262     0xD5, 0x00, 0x00, 0xCF,                             /* ST   AL CF */
263     0x43, 0x00, 0x00, 0x80                              /*      BR 80 */
264     };
265 
266 static uint8 boot3_rom[] = {
267     0xC8, 0x20, 0x00, 0x80,                             /* ST   LHI 2,80 */
268     0xC8, 0x30, 0x00, 0x01,                             /*      LHI 3,1 */
269     0xC8, 0x40, 0x00, 0xCF,                             /*      LHI 4,CF */
270     0xD3, 0xA0, 0x00, 0x78,                             /*      LB A,78 */
271     0xDE, 0xA0, 0x00, 0x79,                             /*      OC A,79 */
272     0x9D, 0xAE,                                         /* LP   SSR A,E */
273     0x42, 0xF0, 0x00, 0x52,                             /*      BTC F,LP */
274     0x9B, 0xAE,                                         /*      RDR A,E */
275     0x08, 0xEE,                                         /*      LHR E,E */
276     0x43, 0x30, 0x00, 0x52,                             /*      BZ LP */
277     0x43, 0x00, 0x00, 0x6C,                             /*      BR STO */
278     0x9D, 0xAE,                                         /* LP1  SSR A,E */
279     0x42, 0xF0, 0x00, 0x64,                             /*      BTC F,LP1 */
280     0x9B, 0xAE,                                         /*      RDR A,E */
281     0xD2, 0xE2, 0x00, 0x00,                             /* STO  STB E,0(2) */
282     0xC1, 0x20, 0x00, 0x64,                             /*      BXLE 2,LP1 */
283     0x43, 0x00, 0x00, 0x80                              /*      BR 80 */
284     };
285 
pt_boot(int32 unitno,DEVICE * dptr)286 t_stat pt_boot (int32 unitno, DEVICE *dptr)
287 {
288 extern uint32 PC, dec_flgs;
289 extern uint16 decrom[];
290 
291 if (decrom[0xD5] & dec_flgs)                            /* AL defined? */
292     IOWriteBlk (BOOT3_START, BOOT3_LEN, boot3_rom);     /* no, 50 seq */
293 else IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom);       /* copy AL boot */
294 IOWriteB (AL_DEV, pt_dib.dno);                          /* set dev no */
295 IOWriteB (AL_IOC, 0x99);                                /* set dev cmd */
296 IOWriteB (AL_SCH, 0);                                   /* clr sch dev no */
297 PC = BOOT_START;
298 return SCPE_OK;
299 }
300 
301 /* Dump routine */
302 
303 #define LOAD_START      0x80
304 #define LOAD_LO         0x8A
305 #define LOAD_HI         0x8E
306 #define LOAD_CS         0x93
307 #define LOAD_LEN        (sizeof (load_rom) / sizeof (uint8))
308 #define LOAD_LDR        50
309 
310 static uint8 load_rom[] = {
311     0x24, 0x21,                                         /* BOOT LIS R2,1 */
312     0x23, 0x03,                                         /*      BS BOOT */
313     0x00, 0x00,                                         /* 32b psw pointer */
314     0x00, 0x00,                                         /* 32b reg pointer */
315     0xC8, 0x10,                                         /* ST   LHI R1,lo */
316     0x00, 0x00,
317     0xC8, 0x30,                                         /*      LHI R3,hi */
318     0x00, 0x00,
319     0xC8, 0x60,                                         /*      LHI R3,cs */
320     0x00, 0x00,
321     0xD3, 0x40,                                         /*      LB R4,X'78' */
322     0x00, 0x78,
323     0xDE, 0x40,                                         /*      OC R4,X'79' */
324     0x00, 0x79,
325     0x9D, 0x45,                                         /* LDR  SSR R4,R5 */
326     0x20, 0x91,                                         /*      BTBS 9,.-2 */
327     0x9B, 0x45,                                         /*      RDR R4,R5 */
328     0x08, 0x55,                                         /*      L(H)R R5,R5 */
329     0x22, 0x34,                                         /*      BZS LDR */
330     0xD2, 0x51,                                         /* LOOP STB R5,0(R1) */
331     0x00, 0x00,
332     0x07, 0x65,                                         /*      X(H)R R6,R5 */
333     0x9A, 0x26,                                         /*      WDR R2,R6 */
334     0x9D, 0x45,                                         /*      SSR R4,R5 */
335     0x20, 0x91,                                         /*      BTBS 9,.-2 */
336     0x9B, 0x45,                                         /*      RDR R4,R5 */
337     0xC1, 0x10,                                         /*      BXLE R1,LOOP */
338     0x00, 0xA6,
339     0x24, 0x78,                                         /*      LIS R7,8 */
340     0x91, 0x7C,                                         /*      SLLS R7,12 */
341     0x95, 0x57,                                         /*      EPSR R5,R7 */
342     0x22, 0x03                                          /*      BS .-6 */
343     };
344 
pt_dump(FILE * of,char * cptr,char * fnam)345 t_stat pt_dump (FILE *of, char *cptr, char *fnam)
346 {
347 uint32 i, lo, hi, cs;
348 char *tptr;
349 extern DEVICE cpu_dev;
350 
351 if ((cptr == NULL) || (*cptr == 0))
352     return SCPE_2FARG;
353 tptr = get_range (NULL, cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0);
354 if ((tptr == NULL) || (lo < INTSVT))
355     return SCPE_ARG;
356 if (*tptr != 0)
357     return SCPE_2MARG;
358 for (i = lo, cs = 0; i <= hi; i++)
359     cs = cs ^ IOReadB (i);
360 IOWriteBlk (LOAD_START, LOAD_LEN, load_rom);
361 IOWriteB (LOAD_LO, (lo >> 8) & 0xFF);
362 IOWriteB (LOAD_LO + 1, lo & 0xFF);
363 IOWriteB (LOAD_HI, (hi >> 8) & 0xFF);
364 IOWriteB (LOAD_HI + 1, hi & 0xFF);
365 IOWriteB (LOAD_CS, cs & 0xFF);
366 for (i = 0; i < LOAD_LDR; i++)
367     fputc (0, of);
368 for (i = LOAD_START; i < (LOAD_START + LOAD_LEN); i++)
369     fputc (IOReadB (i), of);
370 for (i = 0; i < LOAD_LDR; i++)
371     fputc (0, of);
372 for (i = lo; i <= hi; i++)
373     fputc (IOReadB (i), of);
374 for (i = 0; i < LOAD_LDR; i++)
375     fputc (0, of);
376 return SCPE_OK;
377 }
378