| 1 | /* h316_fhd.c: H316/516 fixed head simulator\r |
| 2 | \r |
| 3 | Copyright (c) 2003-2006, 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 | fhd 516-4400 fixed head disk\r |
| 27 | \r |
| 28 | 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein)\r |
| 29 | 04-Jan-04 RMS Changed sim_fsize calling sequence\r |
| 30 | \r |
| 31 | These head-per-track devices are buffered in memory, to minimize overhead.\r |
| 32 | */\r |
| 33 | \r |
| 34 | #include "h316_defs.h"\r |
| 35 | #include <math.h>\r |
| 36 | \r |
| 37 | /* Constants */\r |
| 38 | \r |
| 39 | #define FH_NUMWD 1536 /* words/track */\r |
| 40 | #define FH_NUMTK 64 /* tracks/surface */\r |
| 41 | #define FH_WDPSF (FH_NUMWD * FH_NUMTK) /* words/surface */ \r |
| 42 | #define FH_NUMSF 16 /* surfaces/ctlr */\r |
| 43 | #define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */\r |
| 44 | #define UNIT_V_SF (UNIT_V_UF + 1) /* #surfaces - 1 */\r |
| 45 | #define UNIT_M_SF 017\r |
| 46 | #define UNIT_AUTO (1 << UNIT_V_AUTO)\r |
| 47 | #define UNIT_SF (UNIT_M_SF << UNIT_V_SF)\r |
| 48 | #define UNIT_GETSF(x) ((((x) >> UNIT_V_SF) & UNIT_M_SF) + 1)\r |
| 49 | \r |
| 50 | /* Command word 1 */\r |
| 51 | \r |
| 52 | #define CW1_RW 0100000 /* read vs write */\r |
| 53 | #define CW1_V_SF 10 /* surface */\r |
| 54 | #define CW1_M_SF 017\r |
| 55 | #define CW1_GETSF(x) (((x) >> CW1_V_SF) & CW1_M_SF)\r |
| 56 | #define CW1_V_TK 4 /* track */\r |
| 57 | #define CW1_M_TK 077\r |
| 58 | #define CW1_GETTK(x) (((x) >> CW1_V_TK) & CW1_M_TK)\r |
| 59 | \r |
| 60 | /* Command word 2 */\r |
| 61 | \r |
| 62 | #define CW2_V_CA 0 /* character addr */\r |
| 63 | #define CW2_M_CA 07777\r |
| 64 | #define CW2_GETCA(x) (((x) >> CW2_V_CA) & CW2_M_CA)\r |
| 65 | \r |
| 66 | #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \\r |
| 67 | ((double) FH_NUMWD)))\r |
| 68 | \r |
| 69 | /* OTA states */\r |
| 70 | \r |
| 71 | #define OTA_NOP 0 /* normal */\r |
| 72 | #define OTA_CW1 1 /* expecting CW1 */\r |
| 73 | #define OTA_CW2 2 /* expecting CW2 */\r |
| 74 | \r |
| 75 | extern int32 dev_int, dev_enb, chan_req;\r |
| 76 | extern int32 stop_inst;\r |
| 77 | extern uint32 dma_ad[DMA_MAX];\r |
| 78 | \r |
| 79 | uint32 fhd_cw1 = 0; /* cmd word 1 */\r |
| 80 | uint32 fhd_cw2 = 0; /* cmd word 2 */\r |
| 81 | uint32 fhd_buf = 0; /* buffer */\r |
| 82 | uint32 fhd_otas = 0; /* state */\r |
| 83 | uint32 fhd_busy = 0; /* busy */\r |
| 84 | uint32 fhd_rdy = 0; /* word ready */\r |
| 85 | uint32 fhd_dte = 0; /* data err */\r |
| 86 | uint32 fhd_ace = 0; /* access error */\r |
| 87 | uint32 fhd_dma = 0; /* DMA/DMC */\r |
| 88 | uint32 fhd_eor = 0; /* end of range */\r |
| 89 | uint32 fhd_csum = 0; /* parity checksum */\r |
| 90 | uint32 fhd_stopioe = 1; /* stop on error */\r |
| 91 | int32 fhd_time = 10; /* time per word */\r |
| 92 | \r |
| 93 | int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev);\r |
| 94 | t_stat fhd_svc (UNIT *uptr);\r |
| 95 | t_stat fhd_reset (DEVICE *dptr);\r |
| 96 | t_stat fhd_attach (UNIT *uptr, char *cptr);\r |
| 97 | t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r |
| 98 | void fhd_go (uint32 dma);\r |
| 99 | void fhd_go1 (uint32 dat);\r |
| 100 | void fhd_go2 (uint32 dat);\r |
| 101 | t_bool fhd_getc (UNIT *uptr, uint32 *ch);\r |
| 102 | t_bool fhd_putc (UNIT *uptr, uint32 ch);\r |
| 103 | t_bool fhd_bad_wa (uint32 wa);\r |
| 104 | uint32 fhd_csword (uint32 cs, uint32 ch);\r |
| 105 | \r |
| 106 | /* FHD data structures\r |
| 107 | \r |
| 108 | fhd_dev device descriptor\r |
| 109 | fhd_unit unit descriptor\r |
| 110 | fhd_mod unit modifiers\r |
| 111 | fhd_reg register list\r |
| 112 | */\r |
| 113 | \r |
| 114 | DIB fhd_dib = { FHD, IOBUS, 1, &fhdio };\r |
| 115 | \r |
| 116 | UNIT fhd_unit = { \r |
| 117 | UDATA (&fhd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,\r |
| 118 | FH_WDPSF)\r |
| 119 | };\r |
| 120 | \r |
| 121 | REG fhd_reg[] = {\r |
| 122 | { ORDATA (CW1, fhd_cw1, 16) },\r |
| 123 | { ORDATA (CW2, fhd_cw2, 16) },\r |
| 124 | { ORDATA (BUF, fhd_buf, 16) },\r |
| 125 | { FLDATA (BUSY, fhd_busy, 0) },\r |
| 126 | { FLDATA (RDY, fhd_rdy, 0) },\r |
| 127 | { FLDATA (DTE, fhd_dte, 0) },\r |
| 128 | { FLDATA (ACE, fhd_ace, 0) },\r |
| 129 | { FLDATA (EOR, fhd_eor, 0) },\r |
| 130 | { FLDATA (DMA, fhd_dma, 0) },\r |
| 131 | { FLDATA (CSUM, fhd_csum, 7) },\r |
| 132 | { FLDATA (INTREQ, dev_int, INT_V_MT) },\r |
| 133 | { FLDATA (ENABLE, dev_enb, INT_V_MT) },\r |
| 134 | { DRDATA (TIME, fhd_time, 31), REG_NZ + PV_LEFT },\r |
| 135 | { ORDATA (OTAS, fhd_otas, 2), REG_HRO },\r |
| 136 | { ORDATA (CHAN, fhd_dib.chan, 5), REG_HRO },\r |
| 137 | { FLDATA (STOP_IOE, fhd_stopioe, 0) },\r |
| 138 | { NULL }\r |
| 139 | };\r |
| 140 | \r |
| 141 | MTAB fhd_mod[] = {\r |
| 142 | { UNIT_SF, (0 << UNIT_V_SF), NULL, "1S", &fhd_set_size },\r |
| 143 | { UNIT_SF, (1 << UNIT_V_SF), NULL, "2S", &fhd_set_size },\r |
| 144 | { UNIT_SF, (2 << UNIT_V_SF), NULL, "3S", &fhd_set_size },\r |
| 145 | { UNIT_SF, (3 << UNIT_V_SF), NULL, "4S", &fhd_set_size },\r |
| 146 | { UNIT_SF, (4 << UNIT_V_SF), NULL, "5S", &fhd_set_size },\r |
| 147 | { UNIT_SF, (5 << UNIT_V_SF), NULL, "6S", &fhd_set_size },\r |
| 148 | { UNIT_SF, (6 << UNIT_V_SF), NULL, "7S", &fhd_set_size },\r |
| 149 | { UNIT_SF, (7 << UNIT_V_SF), NULL, "8S", &fhd_set_size },\r |
| 150 | { UNIT_SF, (8 << UNIT_V_SF), NULL, "9S", &fhd_set_size },\r |
| 151 | { UNIT_SF, (9 << UNIT_V_SF), NULL, "10S", &fhd_set_size },\r |
| 152 | { UNIT_SF, (10 << UNIT_V_SF), NULL, "11S", &fhd_set_size },\r |
| 153 | { UNIT_SF, (11 << UNIT_V_SF), NULL, "12S", &fhd_set_size },\r |
| 154 | { UNIT_SF, (12 << UNIT_V_SF), NULL, "13S", &fhd_set_size },\r |
| 155 | { UNIT_SF, (13 << UNIT_V_SF), NULL, "14S", &fhd_set_size },\r |
| 156 | { UNIT_SF, (14 << UNIT_V_SF), NULL, "15S", &fhd_set_size },\r |
| 157 | { UNIT_SF, (15 << UNIT_V_SF), NULL, "16S", &fhd_set_size },\r |
| 158 | { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },\r |
| 159 | { MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS",\r |
| 160 | &io_set_iobus, NULL, NULL },\r |
| 161 | { MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",\r |
| 162 | &io_set_dmc, NULL, NULL },\r |
| 163 | { MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",\r |
| 164 | &io_set_dma, NULL, NULL },\r |
| 165 | { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,\r |
| 166 | NULL, &io_show_chan, NULL },\r |
| 167 | { 0 }\r |
| 168 | };\r |
| 169 | \r |
| 170 | DEVICE fhd_dev = {\r |
| 171 | "FHD", &fhd_unit, fhd_reg, fhd_mod,\r |
| 172 | 1, 8, 22, 1, 8, 16,\r |
| 173 | NULL, NULL, &fhd_reset,\r |
| 174 | NULL, &fhd_attach, NULL,\r |
| 175 | &fhd_dib, DEV_DISABLE\r |
| 176 | };\r |
| 177 | \r |
| 178 | /* IO routines */\r |
| 179 | \r |
| 180 | int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev)\r |
| 181 | {\r |
| 182 | switch (inst) { /* case on opcode */\r |
| 183 | \r |
| 184 | case ioOCP: /* control */\r |
| 185 | if (fnc == 04) { /* terminate output? */\r |
| 186 | fhd_eor = 1; /* stop */\r |
| 187 | CLR_INT (INT_FHD); /* clear int req */\r |
| 188 | }\r |
| 189 | else if (fnc == 003) fhd_go (1); /* start, DMA */\r |
| 190 | else if (fnc == 007) fhd_go (0); /* start, IO bus */\r |
| 191 | else return IOBADFNC (dat);\r |
| 192 | break;\r |
| 193 | \r |
| 194 | case ioOTA: /* output */\r |
| 195 | if (fnc) return IOBADFNC (dat); /* only fnc 0 */\r |
| 196 | if (fhd_rdy) { /* ready? */\r |
| 197 | fhd_buf = dat; /* store data */\r |
| 198 | if (fhd_otas == OTA_CW1) fhd_go1 (dat); /* expecting CW1? */\r |
| 199 | else if (fhd_otas == OTA_CW2) fhd_go2 (dat);/* expecting CW2? */\r |
| 200 | else fhd_rdy = 0; /* normal, clr ready */\r |
| 201 | return IOSKIP (dat);\r |
| 202 | }\r |
| 203 | break;\r |
| 204 | \r |
| 205 | case ioINA: /* input */\r |
| 206 | if (fnc) return IOBADFNC (dat); /* only fnc 0 */\r |
| 207 | if (fhd_rdy) { /* ready? */\r |
| 208 | fhd_rdy = 0; /* clear ready */\r |
| 209 | return IOSKIP (dat | fhd_buf); /* return data */\r |
| 210 | }\r |
| 211 | break;\r |
| 212 | \r |
| 213 | case ioSKS: /* sense */\r |
| 214 | if (((fnc == 000) && fhd_rdy) || /* 0 = skip if ready */\r |
| 215 | ((fnc == 001) && !fhd_busy) || /* 1 = skip if !busy */\r |
| 216 | ((fnc == 002) && !fhd_dte) || /* 2 = skip if !data err */\r |
| 217 | ((fnc == 003) && !fhd_ace) || /* 3 = skip if !access err */\r |
| 218 | ((fnc == 004) && !TST_INTREQ (INT_FHD))) /* 4 = skip if !interrupt */\r |
| 219 | return IOSKIP (dat);\r |
| 220 | break;\r |
| 221 | \r |
| 222 | case ioEND:\r |
| 223 | fhd_eor = 1;\r |
| 224 | break;\r |
| 225 | }\r |
| 226 | \r |
| 227 | return dat;\r |
| 228 | }\r |
| 229 | \r |
| 230 | /* Start new operation */\r |
| 231 | \r |
| 232 | void fhd_go (uint32 dma)\r |
| 233 | {\r |
| 234 | int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */\r |
| 235 | \r |
| 236 | if (fhd_busy) return; /* ignore if busy */\r |
| 237 | fhd_busy = 1; /* ctlr is busy */\r |
| 238 | fhd_eor = 0; /* transfer not done */\r |
| 239 | fhd_csum = 0; /* init checksum */\r |
| 240 | fhd_dte = 0; /* clear errors */\r |
| 241 | fhd_ace = 0;\r |
| 242 | if (ch >= 0) fhd_dma = dma; /* DMA allowed? */\r |
| 243 | else fhd_dma = 0; /* no, force IO bus */\r |
| 244 | fhd_otas = OTA_CW1; /* expect CW1 */\r |
| 245 | fhd_rdy = 1; /* set ready */\r |
| 246 | if (fhd_dma && Q_DMA (ch)) { /* DMA and DMA channel? */\r |
| 247 | SET_CH_REQ (ch); /* set channel request */\r |
| 248 | dma_ad[ch] = dma_ad[ch] & ~DMA_IN; /* force output */\r |
| 249 | }\r |
| 250 | return;\r |
| 251 | }\r |
| 252 | \r |
| 253 | /* Process command word 1 */\r |
| 254 | \r |
| 255 | void fhd_go1 (uint32 dat)\r |
| 256 | {\r |
| 257 | int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */\r |
| 258 | \r |
| 259 | fhd_cw1 = dat; /* store CW1 */\r |
| 260 | fhd_otas = OTA_CW2; /* expect CW2 */\r |
| 261 | fhd_rdy = 1; /* set ready */\r |
| 262 | if (fhd_dma && Q_DMA (ch)) SET_CH_REQ (ch); /* DMA? set chan request */\r |
| 263 | return;\r |
| 264 | }\r |
| 265 | \r |
| 266 | /* Process command word 2 - initiate seek */\r |
| 267 | \r |
| 268 | void fhd_go2 (uint32 dat)\r |
| 269 | {\r |
| 270 | int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */\r |
| 271 | uint32 sf = CW1_GETSF (fhd_cw1); /* surface */\r |
| 272 | int32 t, wa;\r |
| 273 | \r |
| 274 | fhd_cw2 = dat; /* store CW2 */\r |
| 275 | fhd_otas = OTA_NOP; /* next state */\r |
| 276 | wa = CW2_GETCA (fhd_cw2) >> 1; /* word addr */\r |
| 277 | if ((wa >= FH_NUMWD) || /* if bad char addr */\r |
| 278 | ((fhd_unit.flags & UNIT_ATT) == 0) || /* or unattached */\r |
| 279 | (sf >= UNIT_GETSF (fhd_unit.flags))) { /* or bad surface */\r |
| 280 | fhd_ace = 1; /* access error */\r |
| 281 | fhd_busy = 0; /* abort operation */\r |
| 282 | SET_INT (INT_FHD);\r |
| 283 | return;\r |
| 284 | }\r |
| 285 | if (fhd_cw1 & CW1_RW) { /* write? */\r |
| 286 | fhd_rdy = 1; /* set ready */\r |
| 287 | if (fhd_dma) SET_CH_REQ (ch); /* if DMA/DMC, req chan */\r |
| 288 | }\r |
| 289 | else {\r |
| 290 | fhd_rdy = 0; /* read, clear ready */\r |
| 291 | if (fhd_dma && (ch < DMC_V_DMC1)) /* read and DMA chan? */\r |
| 292 | dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */\r |
| 293 | }\r |
| 294 | t = wa - GET_POS (fhd_time); /* delta to new loc */\r |
| 295 | if (t < 0) t = t + FH_NUMWD; /* wrap around? */\r |
| 296 | sim_activate (&fhd_unit, t * fhd_time); /* schedule op */\r |
| 297 | return;\r |
| 298 | }\r |
| 299 | \r |
| 300 | /* Unit service */\r |
| 301 | \r |
| 302 | t_stat fhd_svc (UNIT *uptr)\r |
| 303 | {\r |
| 304 | int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan (-1 if IO bus) */\r |
| 305 | uint32 c1, c2;\r |
| 306 | \r |
| 307 | if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */\r |
| 308 | fhd_ace = 1; /* access error */\r |
| 309 | fhd_busy = 0; /* abort operation */\r |
| 310 | SET_INT (INT_FHD);\r |
| 311 | return IORETURN (fhd_stopioe, SCPE_UNATT);\r |
| 312 | }\r |
| 313 | \r |
| 314 | if (fhd_eor || fhd_rdy) { /* done or ready set? */\r |
| 315 | if (fhd_rdy) fhd_dte = 1; /* if ready set, data err */\r |
| 316 | if (fhd_cw1 & CW1_RW) { /* write? */\r |
| 317 | if (!fhd_rdy) { /* buffer full? */\r |
| 318 | fhd_putc (uptr, fhd_buf >> 8); /* store last word */\r |
| 319 | fhd_putc (uptr, fhd_buf);\r |
| 320 | }\r |
| 321 | fhd_putc (uptr, fhd_csum); /* store csum */\r |
| 322 | }\r |
| 323 | else { /* read */\r |
| 324 | fhd_getc (uptr, &c1); /* get csum */\r |
| 325 | if (fhd_csum) fhd_dte = 1; /* if csum != 0, err */\r |
| 326 | }\r |
| 327 | fhd_busy = 0; /* operation complete */\r |
| 328 | SET_INT (INT_FHD);\r |
| 329 | return SCPE_OK;\r |
| 330 | }\r |
| 331 | \r |
| 332 | if (fhd_cw1 & CW1_RW) { /* write? */\r |
| 333 | if (fhd_putc (uptr, fhd_buf >> 8)) return SCPE_OK;\r |
| 334 | if (fhd_putc (uptr, fhd_buf)) return SCPE_OK;\r |
| 335 | }\r |
| 336 | else {\r |
| 337 | if (fhd_getc (uptr, &c1)) return SCPE_OK; /* read */\r |
| 338 | if (fhd_getc (uptr, &c2)) return SCPE_OK;\r |
| 339 | fhd_buf = (c1 << 8) | c2;\r |
| 340 | }\r |
| 341 | sim_activate (uptr, fhd_time); /* next word */\r |
| 342 | fhd_rdy = 1; /* set ready */\r |
| 343 | if (fhd_dma) SET_CH_REQ (ch); /* if DMA/DMC, req chan */\r |
| 344 | return SCPE_OK;\r |
| 345 | }\r |
| 346 | \r |
| 347 | /* Read character from disk */\r |
| 348 | \r |
| 349 | t_bool fhd_getc (UNIT *uptr, uint32 *ch)\r |
| 350 | {\r |
| 351 | uint32 sf = CW1_GETSF (fhd_cw1); /* surface */\r |
| 352 | uint32 tk = CW1_GETTK (fhd_cw1); /* track */\r |
| 353 | uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */\r |
| 354 | uint32 wa = ca >> 1; /* word addr */\r |
| 355 | uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */\r |
| 356 | uint16 *fbuf = uptr->filebuf; /* buffer base */\r |
| 357 | uint32 wd;\r |
| 358 | \r |
| 359 | if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */\r |
| 360 | fhd_cw2 = fhd_cw2 + 1; /* incr char addr */\r |
| 361 | if (ca & 1) wd = fbuf[ba] & 0377; /* select char */\r |
| 362 | else wd = (fbuf[ba] >> 8) & 0377;\r |
| 363 | fhd_csum = fhd_csword (fhd_csum, wd); /* put in csum */\r |
| 364 | *ch = wd; /* return */\r |
| 365 | return FALSE;\r |
| 366 | }\r |
| 367 | \r |
| 368 | /* Write character to disk */\r |
| 369 | \r |
| 370 | t_bool fhd_putc (UNIT *uptr, uint32 ch)\r |
| 371 | {\r |
| 372 | uint32 sf = CW1_GETSF (fhd_cw1); /* surface */\r |
| 373 | uint32 tk = CW1_GETTK (fhd_cw1); /* track */\r |
| 374 | uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */\r |
| 375 | uint32 wa = ca >> 1; /* word addr */\r |
| 376 | uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */\r |
| 377 | uint16 *fbuf = uptr->filebuf; /* buffer base */\r |
| 378 | \r |
| 379 | ch = ch & 0377; /* mask char */\r |
| 380 | if (fhd_bad_wa (wa)) return TRUE; /* addr bad? */\r |
| 381 | fhd_cw2 = fhd_cw2 + 1; /* incr char addr */\r |
| 382 | if (ca & 1) fbuf[ba] = (fbuf[ba] & ~0377) | ch; /* odd? low char */\r |
| 383 | else fbuf[ba] = (fbuf[ba] & 0377) | (ch << 8); /* even, hi char */\r |
| 384 | fhd_csum = fhd_csword (fhd_csum, ch); /* put in csum */\r |
| 385 | if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; /* update hwmark */\r |
| 386 | return FALSE;\r |
| 387 | }\r |
| 388 | \r |
| 389 | /* Check word address */\r |
| 390 | \r |
| 391 | t_bool fhd_bad_wa (uint32 wa)\r |
| 392 | {\r |
| 393 | if (wa >= FH_NUMWD) { /* bad address? */\r |
| 394 | fhd_ace = 1; /* access error */\r |
| 395 | fhd_busy = 0; /* abort operation */\r |
| 396 | SET_INT (INT_FHD);\r |
| 397 | return TRUE;\r |
| 398 | }\r |
| 399 | return FALSE;\r |
| 400 | }\r |
| 401 | \r |
| 402 | /* Add character to checksum (parity) */\r |
| 403 | \r |
| 404 | uint32 fhd_csword (uint32 cs, uint32 ch)\r |
| 405 | {\r |
| 406 | while (ch) { /* count bits */\r |
| 407 | ch = ch & ~(ch & (-(int32) ch));\r |
| 408 | cs = cs ^ 0200; /* invert cs for each 1 */\r |
| 409 | }\r |
| 410 | return cs;\r |
| 411 | }\r |
| 412 | \r |
| 413 | /* Reset routine */\r |
| 414 | \r |
| 415 | t_stat fhd_reset (DEVICE *dptr)\r |
| 416 | {\r |
| 417 | fhd_busy = 0; /* reset state */\r |
| 418 | fhd_rdy = 0;\r |
| 419 | fhd_ace = 0;\r |
| 420 | fhd_dte = 0;\r |
| 421 | fhd_eor = 0;\r |
| 422 | fhd_otas = OTA_NOP;\r |
| 423 | fhd_cw1 = fhd_cw2 = fhd_buf = 0;\r |
| 424 | CLR_INT (INT_FHD); /* clear int, enb */\r |
| 425 | CLR_ENB (INT_FHD);\r |
| 426 | sim_cancel (&fhd_unit); /* cancel operation */\r |
| 427 | return SCPE_OK;\r |
| 428 | }\r |
| 429 | \r |
| 430 | /* Attach routine */\r |
| 431 | \r |
| 432 | t_stat fhd_attach (UNIT *uptr, char *cptr)\r |
| 433 | {\r |
| 434 | uint32 sz, sf;\r |
| 435 | uint32 ds_bytes = FH_WDPSF * sizeof (int16);\r |
| 436 | \r |
| 437 | if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {\r |
| 438 | sf = (sz + ds_bytes - 1) / ds_bytes;\r |
| 439 | if (sf >= FH_NUMSF) sf = FH_NUMSF - 1;\r |
| 440 | uptr->flags = (uptr->flags & ~UNIT_SF) |\r |
| 441 | (sf << UNIT_V_SF);\r |
| 442 | }\r |
| 443 | uptr->capac = UNIT_GETSF (uptr->flags) * FH_WDPSF;\r |
| 444 | return attach_unit (uptr, cptr);\r |
| 445 | }\r |
| 446 | \r |
| 447 | /* Set size routine */\r |
| 448 | \r |
| 449 | t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r |
| 450 | {\r |
| 451 | if (val < 0) return SCPE_IERR;\r |
| 452 | if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r |
| 453 | uptr->capac = UNIT_GETSF (val) * FH_WDPSF;\r |
| 454 | return SCPE_OK;\r |
| 455 | }\r |