| 1 | /* ibm1130_ptrp.c: IBM 1130 paper tape reader/punch emulation\r |
| 2 | \r |
| 3 | Based on the SIMH simulator package written by Robert M Supnik\r |
| 4 | \r |
| 5 | Brian Knittel\r |
| 6 | Revision History\r |
| 7 | \r |
| 8 | 2004.10.22 - Written.\r |
| 9 | \r |
| 10 | * (C) Copyright 2004, Brian Knittel.\r |
| 11 | * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r |
| 12 | * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r |
| 13 | * usual yada-yada. Please keep this notice and the copyright in any distributions\r |
| 14 | * or modifications.\r |
| 15 | *\r |
| 16 | * This is not a supported product, but I welcome bug reports and fixes.\r |
| 17 | * Mail to simh@ibm1130.org\r |
| 18 | */\r |
| 19 | \r |
| 20 | #include "ibm1130_defs.h"\r |
| 21 | \r |
| 22 | /***************************************************************************************\r |
| 23 | * 1134 Paper Tape Reader device PTR\r |
| 24 | * 1055 Paper Tape Punch device PTP (shares DSW with PTR)\r |
| 25 | ***************************************************************************************/\r |
| 26 | \r |
| 27 | #define PTR1134_DSW_READER_RESPONSE 0x4000\r |
| 28 | #define PTR1134_DSW_PUNCH_RESPONSE 0x1000\r |
| 29 | #define PTR1134_DSW_READER_BUSY 0x0800\r |
| 30 | #define PTR1134_DSW_READER_NOT_READY 0x0400\r |
| 31 | #define PTR1134_DSW_PUNCH_BUSY 0x0200\r |
| 32 | #define PTR1134_DSW_PUNCH_NOT_READY 0x0100\r |
| 33 | \r |
| 34 | #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)\r |
| 35 | \r |
| 36 | static t_stat ptr_svc (UNIT *uptr);\r |
| 37 | static t_stat ptr_reset (DEVICE *dptr);\r |
| 38 | static t_stat ptr_attach (UNIT *uptr, char *cptr);\r |
| 39 | static t_stat ptr_detach (UNIT *uptr);\r |
| 40 | static t_stat ptr_boot (int unitno, DEVICE *dptr);\r |
| 41 | static t_stat ptp_svc (UNIT *uptr);\r |
| 42 | static t_stat ptp_reset (DEVICE *dptr);\r |
| 43 | static t_stat ptp_attach (UNIT *uptr, char *cptr);\r |
| 44 | static t_stat ptp_detach (UNIT *uptr);\r |
| 45 | \r |
| 46 | static int16 ptr_dsw = 0; /* device status word */\r |
| 47 | static int32 ptr_wait = 1000; /* character read wait */\r |
| 48 | static uint8 ptr_char = 0; /* last character read */\r |
| 49 | static int32 ptp_wait = 1000; /* character punch wait */\r |
| 50 | \r |
| 51 | UNIT ptr_unit[1] = {\r |
| 52 | { UDATA (&ptr_svc, UNIT_ATTABLE, 0) },\r |
| 53 | };\r |
| 54 | \r |
| 55 | REG ptr_reg[] = {\r |
| 56 | { HRDATA (DSW, ptr_dsw, 16) }, /* device status word */\r |
| 57 | { DRDATA (WTIME, ptr_wait, 24), PV_LEFT }, /* character read wait */\r |
| 58 | { DRDATA (LASTCHAR, ptr_char, 8), PV_LEFT }, /* last character read */\r |
| 59 | { NULL } };\r |
| 60 | \r |
| 61 | DEVICE ptr_dev = {\r |
| 62 | "PTR", ptr_unit, ptr_reg, NULL,\r |
| 63 | 1, 16, 16, 1, 16, 16,\r |
| 64 | NULL, NULL, ptr_reset,\r |
| 65 | ptr_boot, ptr_attach, ptr_detach};\r |
| 66 | \r |
| 67 | UNIT ptp_unit[1] = {\r |
| 68 | { UDATA (&ptp_svc, UNIT_ATTABLE, 0) },\r |
| 69 | };\r |
| 70 | \r |
| 71 | REG ptp_reg[] = {\r |
| 72 | { HRDATA (DSW, ptr_dsw, 16) }, /* device status word (this is the same as the reader's!) */\r |
| 73 | { DRDATA (WTIME, ptp_wait, 24), PV_LEFT }, /* character punch wait */\r |
| 74 | { NULL } };\r |
| 75 | \r |
| 76 | DEVICE ptp_dev = {\r |
| 77 | "PTP", ptp_unit, ptp_reg, NULL,\r |
| 78 | 1, 16, 16, 1, 16, 16,\r |
| 79 | NULL, NULL, ptp_reset,\r |
| 80 | NULL, ptp_attach, ptp_detach};\r |
| 81 | \r |
| 82 | /* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */\r |
| 83 | \r |
| 84 | void xio_1134_papertape (int32 iocc_addr, int32 iocc_func, int32 iocc_mod)\r |
| 85 | {\r |
| 86 | char msg[80];\r |
| 87 | \r |
| 88 | switch (iocc_func) {\r |
| 89 | case XIO_READ: /* read: return last character read */\r |
| 90 | M[iocc_addr & mem_mask] = (uint16) (ptr_char << 8);\r |
| 91 | break;\r |
| 92 | \r |
| 93 | case XIO_WRITE: /* write: initiate punch operation */\r |
| 94 | if ((ptr_dsw & PTR1134_DSW_PUNCH_NOT_READY) == 0 && IS_ONLINE(ptp_unit)) {\r |
| 95 | putc((M[iocc_addr & mem_mask] >> 8) & 0xFF, ptp_unit->fileref);\r |
| 96 | ptp_unit->pos++;\r |
| 97 | }\r |
| 98 | sim_activate(ptp_unit, ptp_wait); /* schedule interrupt */\r |
| 99 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY | PTR1134_DSW_PUNCH_BUSY);\r |
| 100 | break;\r |
| 101 | \r |
| 102 | case XIO_SENSE_DEV: /* sense device status */\r |
| 103 | ACC = ptr_dsw;\r |
| 104 | if (iocc_mod & 0x01) { /* reset interrupts */\r |
| 105 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE | PTR1134_DSW_PUNCH_RESPONSE);\r |
| 106 | CLRBIT(ILSW[4], ILSW_4_1134_TAPE);\r |
| 107 | }\r |
| 108 | break;\r |
| 109 | \r |
| 110 | case XIO_CONTROL: /* control: initiate character read */\r |
| 111 | sim_activate(ptr_unit, ptr_wait); /* schedule interrupt */\r |
| 112 | SETBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_NOT_READY);\r |
| 113 | break;\r |
| 114 | \r |
| 115 | default:\r |
| 116 | sprintf(msg, "Invalid 1134 reader/1055 punch XIO function %x", iocc_func);\r |
| 117 | xio_error(msg);\r |
| 118 | }\r |
| 119 | }\r |
| 120 | \r |
| 121 | /* ptr_svc - emulated timeout - 1134 read operation complete */\r |
| 122 | \r |
| 123 | static t_stat ptr_svc (UNIT *uptr)\r |
| 124 | {\r |
| 125 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY); /* clear reader busy flag */\r |
| 126 | SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume at end of file */\r |
| 127 | \r |
| 128 | if (IS_ONLINE(uptr)) { /* fetch character from file */\r |
| 129 | ptr_char = getc(uptr->fileref);\r |
| 130 | uptr->pos++;\r |
| 131 | \r |
| 132 | if (! feof(uptr->fileref)) /* there's more left */\r |
| 133 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);\r |
| 134 | }\r |
| 135 | \r |
| 136 | SETBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE); /* indicate read complete */\r |
| 137 | \r |
| 138 | SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */\r |
| 139 | calc_ints();\r |
| 140 | \r |
| 141 | return SCPE_OK;\r |
| 142 | }\r |
| 143 | \r |
| 144 | /* ptp_svc - emulated timeout -- 1055 punch operation complete */\r |
| 145 | \r |
| 146 | static t_stat ptp_svc (UNIT *uptr)\r |
| 147 | {\r |
| 148 | CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY); /* clear punch busy flag */\r |
| 149 | \r |
| 150 | if (IS_ONLINE(uptr)) /* update punch ready status */\r |
| 151 | CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);\r |
| 152 | else\r |
| 153 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);\r |
| 154 | \r |
| 155 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_RESPONSE); /* indicate punch complete */\r |
| 156 | \r |
| 157 | SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */\r |
| 158 | calc_ints();\r |
| 159 | \r |
| 160 | return SCPE_OK;\r |
| 161 | }\r |
| 162 | \r |
| 163 | /* ptr_reset - reset emulated paper tape reader */\r |
| 164 | \r |
| 165 | static t_stat ptr_reset (DEVICE *dptr)\r |
| 166 | {\r |
| 167 | sim_cancel(ptr_unit);\r |
| 168 | \r |
| 169 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_RESPONSE);\r |
| 170 | SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);\r |
| 171 | \r |
| 172 | if (IS_ONLINE(ptr_unit) && ! feof(ptr_unit->fileref))\r |
| 173 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);\r |
| 174 | \r |
| 175 | if ((ptr_dsw & PTR1134_DSW_PUNCH_RESPONSE) == 0) { /* punch isn't interrupting either */\r |
| 176 | CLRBIT(ILSW[4], ILSW_4_1134_TAPE);\r |
| 177 | calc_ints();\r |
| 178 | }\r |
| 179 | \r |
| 180 | return SCPE_OK;\r |
| 181 | }\r |
| 182 | \r |
| 183 | /* ptp_reset - reset emulated paper tape punch */\r |
| 184 | \r |
| 185 | static t_stat ptp_reset (DEVICE *dptr)\r |
| 186 | {\r |
| 187 | sim_cancel(ptp_unit);\r |
| 188 | \r |
| 189 | CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY | PTR1134_DSW_PUNCH_RESPONSE);\r |
| 190 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);\r |
| 191 | \r |
| 192 | if (IS_ONLINE(ptp_unit))\r |
| 193 | CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);\r |
| 194 | \r |
| 195 | if ((ptr_dsw & PTR1134_DSW_READER_RESPONSE) == 0) { /* reader isn't interrupting either */\r |
| 196 | CLRBIT(ILSW[4], ILSW_4_1134_TAPE);\r |
| 197 | calc_ints();\r |
| 198 | }\r |
| 199 | \r |
| 200 | return SCPE_OK;\r |
| 201 | }\r |
| 202 | \r |
| 203 | /* ptr_attach - attach file to simulated paper tape reader */\r |
| 204 | \r |
| 205 | static t_stat ptr_attach (UNIT *uptr, char *cptr)\r |
| 206 | {\r |
| 207 | t_stat rval;\r |
| 208 | \r |
| 209 | SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume failure */\r |
| 210 | \r |
| 211 | if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */\r |
| 212 | return rval;\r |
| 213 | \r |
| 214 | if ((ptr_dsw & PTR1134_DSW_READER_BUSY) == 0 && ! feof(uptr->fileref))\r |
| 215 | CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* we're in business */\r |
| 216 | \r |
| 217 | return SCPE_OK;\r |
| 218 | }\r |
| 219 | \r |
| 220 | /* ptr_attach - detach file from simulated paper tape reader */\r |
| 221 | \r |
| 222 | static t_stat ptr_detach (UNIT *uptr)\r |
| 223 | {\r |
| 224 | SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);\r |
| 225 | \r |
| 226 | return detach_unit(uptr);\r |
| 227 | }\r |
| 228 | \r |
| 229 | /* ptr_attach - perform paper tape initial program load */\r |
| 230 | \r |
| 231 | static t_stat ptr_boot (int unitno, DEVICE *dptr)\r |
| 232 | {\r |
| 233 | int ch, nch, val, addr;\r |
| 234 | t_bool leader = TRUE, start = FALSE;\r |
| 235 | t_stat rval;\r |
| 236 | \r |
| 237 | addr = 0;\r |
| 238 | nch = 0;\r |
| 239 | val = 0;\r |
| 240 | \r |
| 241 | for (;;) {\r |
| 242 | if ((ch = getc(ptr_unit->fileref)) == EOF) {\r |
| 243 | printf("EOF on paper tape without finding Channel 5 end-of-load mark\n");\r |
| 244 | break;\r |
| 245 | }\r |
| 246 | \r |
| 247 | if (leader) {\r |
| 248 | if ((ch & 0x7F) == 0x7F) /* ignore leading rubouts or "delete" characters */\r |
| 249 | continue;\r |
| 250 | \r |
| 251 | leader = FALSE; /* after first nonrubout, any punch in channel 5 terminates load */\r |
| 252 | }\r |
| 253 | \r |
| 254 | /* this is untested -- not sure of actual byte ordering */\r |
| 255 | \r |
| 256 | val = (val << 4) | (ch & 0x0F); /* get next nybble */\r |
| 257 | \r |
| 258 | if (++nch == 4) { /* if we now have four nybbles, store the word */\r |
| 259 | M[addr & mem_mask] = (uint16) val;\r |
| 260 | \r |
| 261 | addr++; /* prepare for next word */\r |
| 262 | nch = 0;\r |
| 263 | val = 0;\r |
| 264 | }\r |
| 265 | \r |
| 266 | if (ch & 0x10) { /* channel 5 punch terminates load */\r |
| 267 | start = TRUE;\r |
| 268 | break;\r |
| 269 | }\r |
| 270 | }\r |
| 271 | \r |
| 272 | if (! start) /* if we didn't get a valid load, report EOF error */\r |
| 273 | return SCPE_EOF;\r |
| 274 | \r |
| 275 | if ((rval = reset_all(0)) != SCPE_OK) /* force a reset */\r |
| 276 | return rval;\r |
| 277 | \r |
| 278 | IAR = 0; /* start running at address 0 */\r |
| 279 | return SCPE_OK;\r |
| 280 | }\r |
| 281 | \r |
| 282 | /* ptp_attach - attach file to simulated paper tape punch */\r |
| 283 | \r |
| 284 | static t_stat ptp_attach (UNIT *uptr, char *cptr)\r |
| 285 | {\r |
| 286 | t_stat rval;\r |
| 287 | \r |
| 288 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* assume failure */\r |
| 289 | \r |
| 290 | if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */\r |
| 291 | return rval;\r |
| 292 | \r |
| 293 | fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */\r |
| 294 | uptr->pos = ftell(uptr->fileref);\r |
| 295 | \r |
| 296 | if ((ptr_dsw & PTR1134_DSW_PUNCH_BUSY) == 0)\r |
| 297 | CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* we're in business */\r |
| 298 | \r |
| 299 | return SCPE_OK;\r |
| 300 | }\r |
| 301 | \r |
| 302 | /* ptp_detach - detach file from simulated paper tape punch */\r |
| 303 | \r |
| 304 | static t_stat ptp_detach (UNIT *uptr)\r |
| 305 | {\r |
| 306 | SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);\r |
| 307 | \r |
| 308 | return detach_unit(uptr);\r |
| 309 | }\r |