| 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 |