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