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