First Commit of my working state
[simh.git] / Interdata / id_pt.c
1 /* id_pt.c: Interdata paper tape reader
2
3 Copyright (c) 2000-2005, 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 (from 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
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) SET_INT (v_PT); /* no, set int */
139 }
140 }
141 if (pt_rd) { /* reader? */
142 pt_run = io_2b (dat, CMD_V_RUN, pt_run); /* upd run/stop */
143 pt_slew = io_2b (dat, CMD_V_SLEW, pt_slew); /* upd slew/inc */
144 if (pt_run) { /* run set? */
145 if (old_run == 0) { /* run 0 -> 1? */
146 sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
147 pt_sta = pt_sta & ~STA_DU; /* clear eof */
148 }
149 }
150 else sim_cancel (&pt_unit[PTR]); /* clr, stop rdr */
151 }
152 else pt_sta = pt_sta & ~STA_DU; /* punch, clr eof */
153 break;
154
155 case IO_RD: /* read */
156 if (pt_run && !pt_slew) { /* incremental? */
157 sim_activate (&pt_unit[PTR], pt_unit[PTR].wait);
158 pt_sta = pt_sta & ~STA_DU; /* clr eof */
159 }
160 pt_chp = 0; /* clr char pend */
161 if (pt_rd) pt_sta = pt_sta | STA_BSY; /* set busy */
162 return (pt_unit[PTR].buf & 0xFF); /* return char */
163
164 case IO_WD: /* write */
165 pt_unit[PTP].buf = dat & DMASK8; /* save char */
166 if (!pt_rd) pt_sta = pt_sta | STA_BSY; /* set busy */
167 sim_activate (&pt_unit[PTP], pt_unit[PTP].wait);
168 break;
169
170 case IO_SS: /* status */
171 t = pt_sta & STA_MASK; /* get status */
172 if (pt_rd && !pt_run && !sim_is_active (&pt_unit[PTR]))
173 t = t | STA_NMTN; /* stopped? */
174 if ((pt_unit[pt_rd? PTR: PTP].flags & UNIT_ATT) == 0)
175 t = t | STA_DU; /* offline? */
176 if (t & SET_EX) t = t | STA_EX; /* test for EX */
177 return t;
178 }
179
180 return 0;
181 }
182
183 /* Unit service */
184
185 t_stat ptr_svc (UNIT *uptr)
186 {
187 int32 temp;
188
189 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
190 return IORETURN (ptr_stopioe, SCPE_UNATT);
191 if (pt_rd) { /* read mode? */
192 pt_sta = pt_sta & ~STA_BSY; /* clear busy */
193 if (pt_arm) SET_INT (v_PT); /* if armed, intr */
194 if (pt_chp) pt_sta = pt_sta | STA_OVR; /* overrun? */
195 }
196 pt_chp = 1; /* char pending */
197 if ((temp = getc (uptr->fileref)) == EOF) { /* error? */
198 if (feof (uptr->fileref)) { /* eof? */
199 pt_sta = pt_sta | STA_DU; /* set DU */
200 if (ptr_stopioe) printf ("PTR end of file\n");
201 else return SCPE_OK;
202 }
203 else perror ("PTR I/O error");
204 clearerr (uptr->fileref);
205 return SCPE_IOERR;
206 }
207 uptr->buf = temp & DMASK8; /* store char */
208 uptr->pos = uptr->pos + 1; /* incr pos */
209 if (pt_slew) sim_activate (uptr, uptr->wait); /* slew? continue */
210 return SCPE_OK;
211 }
212
213 t_stat ptp_svc (UNIT *uptr)
214 {
215 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
216 return IORETURN (ptp_stopioe, SCPE_UNATT);
217 if (!pt_rd) { /* write mode? */
218 pt_sta = pt_sta & ~STA_BSY; /* clear busy */
219 if (pt_arm) SET_INT (v_PT); /* if armed, intr */
220 }
221 if (putc (uptr->buf, uptr -> fileref) == EOF) { /* write char */
222 perror ("PTP I/O error");
223 clearerr (uptr -> fileref);
224 return SCPE_IOERR;
225 }
226 uptr -> pos = uptr -> pos + 1; /* incr pos */
227 return SCPE_OK;
228 }
229
230 /* Reset routine */
231
232 t_stat pt_reset (DEVICE *dptr)
233 {
234 sim_cancel (&pt_unit[PTR]); /* deactivate units */
235 sim_cancel (&pt_unit[PTP]);
236 pt_rd = 1; /* read */
237 pt_chp = pt_run = pt_slew = 0; /* stop, inc, disarm */
238 pt_sta = STA_BSY; /* buf empty */
239 CLR_INT (v_PT); /* clear int */
240 CLR_ENB (v_PT); /* disable int */
241 pt_arm = 0; /* disarm int */
242 return SCPE_OK;
243 }
244
245 /* Bootstrap routine */
246
247 #define BOOT_START 0x50
248 #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
249 #define BOOT3_START 0x3E
250 #define BOOT3_LEN (sizeof (boot_rom) / sizeof (uint8))
251
252 static uint8 boot_rom[] = {
253 0xD5, 0x00, 0x00, 0xCF, /* ST AL CF */
254 0x43, 0x00, 0x00, 0x80 /* BR 80 */
255 };
256
257 static uint8 boot3_rom[] = {
258 0xC8, 0x20, 0x00, 0x80, /* ST LHI 2,80 */
259 0xC8, 0x30, 0x00, 0x01, /* LHI 3,1 */
260 0xC8, 0x40, 0x00, 0xCF, /* LHI 4,CF */
261 0xD3, 0xA0, 0x00, 0x78, /* LB A,78 */
262 0xDE, 0xA0, 0x00, 0x79, /* OC A,79 */
263 0x9D, 0xAE, /* LP SSR A,E */
264 0x42, 0xF0, 0x00, 0x52, /* BTC F,LP */
265 0x9B, 0xAE, /* RDR A,E */
266 0x08, 0xEE, /* LHR E,E */
267 0x43, 0x30, 0x00, 0x52, /* BZ LP */
268 0x43, 0x00, 0x00, 0x6C, /* BR STO */
269 0x9D, 0xAE, /* LP1 SSR A,E */
270 0x42, 0xF0, 0x00, 0x64, /* BTC F,LP1 */
271 0x9B, 0xAE, /* RDR A,E */
272 0xD2, 0xE2, 0x00, 0x00, /* STO STB E,0(2) */
273 0xC1, 0x20, 0x00, 0x64, /* BXLE 2,LP1 */
274 0x43, 0x00, 0x00, 0x80 /* BR 80 */
275 };
276
277 t_stat pt_boot (int32 unitno, DEVICE *dptr)
278 {
279 extern uint32 PC, dec_flgs;
280 extern uint16 decrom[];
281
282 if (decrom[0xD5] & dec_flgs) /* AL defined? */
283 IOWriteBlk (BOOT3_START, BOOT3_LEN, boot3_rom); /* no, 50 seq */
284 else IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy AL boot */
285 IOWriteB (AL_DEV, pt_dib.dno); /* set dev no */
286 IOWriteB (AL_IOC, 0x99); /* set dev cmd */
287 IOWriteB (AL_SCH, 0); /* clr sch dev no */
288 PC = BOOT_START;
289 return SCPE_OK;
290 }
291
292 /* Dump routine */
293
294 #define LOAD_START 0x80
295 #define LOAD_LO 0x8A
296 #define LOAD_HI 0x8E
297 #define LOAD_CS 0x93
298 #define LOAD_LEN (sizeof (load_rom) / sizeof (uint8))
299 #define LOAD_LDR 50
300
301 static uint8 load_rom[] = {
302 0x24, 0x21, /* BOOT LIS R2,1 */
303 0x23, 0x03, /* BS BOOT */
304 0x00, 0x00, /* 32b psw pointer */
305 0x00, 0x00, /* 32b reg pointer */
306 0xC8, 0x10, /* ST LHI R1,lo */
307 0x00, 0x00,
308 0xC8, 0x30, /* LHI R3,hi */
309 0x00, 0x00,
310 0xC8, 0x60, /* LHI R3,cs */
311 0x00, 0x00,
312 0xD3, 0x40, /* LB R4,X'78' */
313 0x00, 0x78,
314 0xDE, 0x40, /* OC R4,X'79' */
315 0x00, 0x79,
316 0x9D, 0x45, /* LDR SSR R4,R5 */
317 0x20, 0x91, /* BTBS 9,.-2 */
318 0x9B, 0x45, /* RDR R4,R5 */
319 0x08, 0x55, /* L(H)R R5,R5 */
320 0x22, 0x34, /* BZS LDR */
321 0xD2, 0x51, /* LOOP STB R5,0(R1) */
322 0x00, 0x00,
323 0x07, 0x65, /* X(H)R R6,R5 */
324 0x9A, 0x26, /* WDR R2,R6 */
325 0x9D, 0x45, /* SSR R4,R5 */
326 0x20, 0x91, /* BTBS 9,.-2 */
327 0x9B, 0x45, /* RDR R4,R5 */
328 0xC1, 0x10, /* BXLE R1,LOOP */
329 0x00, 0xA6,
330 0x24, 0x78, /* LIS R7,8 */
331 0x91, 0x7C, /* SLLS R7,12 */
332 0x95, 0x57, /* EPSR R5,R7 */
333 0x22, 0x03 /* BS .-6 */
334 };
335
336 t_stat pt_dump (FILE *of, char *cptr, char *fnam)
337 {
338 uint32 i, lo, hi, cs;
339 char *tptr;
340 extern DEVICE cpu_dev;
341
342 if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG;
343 tptr = get_range (NULL, cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0);
344 if ((tptr == NULL) || (lo < INTSVT)) return SCPE_ARG;
345 if (*tptr != 0) return SCPE_2MARG;
346 for (i = lo, cs = 0; i <= hi; i++) cs = cs ^ IOReadB (i);
347 IOWriteBlk (LOAD_START, LOAD_LEN, load_rom);
348 IOWriteB (LOAD_LO, (lo >> 8) & 0xFF);
349 IOWriteB (LOAD_LO + 1, lo & 0xFF);
350 IOWriteB (LOAD_HI, (hi >> 8) & 0xFF);
351 IOWriteB (LOAD_HI + 1, hi & 0xFF);
352 IOWriteB (LOAD_CS, cs & 0xFF);
353 for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
354 for (i = LOAD_START; i < (LOAD_START + LOAD_LEN); i++)
355 fputc (IOReadB (i), of);
356 for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
357 for (i = lo; i <= hi; i++) fputc (IOReadB (i), of);
358 for (i = 0; i < LOAD_LDR; i++) fputc (0, of);
359 return SCPE_OK;
360 }