First Commit of my working state
[simh.git] / Interdata / id_dp.c
1 /* id_dp.c: Interdata 2.5MB/10MB cartridge disk simulator
2
3 Copyright (c) 2001-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 dp M46-421 2.5MB/10MB cartridge disk
27
28 18-Mar-05 RMS Added attached test to detach routine
29 25-Jan-04 RMS Revised for device debug support
30 25-Apr-03 RMS Revised for extended file support
31 16-Feb-03 RMS Fixed read to test transfer ok before selch operation
32 */
33
34 #include "id_defs.h"
35 #include <math.h>
36
37 #define DP_NUMBY 256 /* bytes/sector */
38 #define DP_NUMSC 24 /* sectors/track */
39
40 #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
41 #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
42 #define UNIT_M_DTYPE 0x1
43 #define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */
44 #define UNIT_WLK (1 << UNIT_V_WLK)
45 #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
46 #define UNIT_AUTO (1 << UNIT_V_AUTO)
47 #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
48
49 #define CYL u3 /* current cylinder */
50 #define STD u4 /* drive status */
51 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
52
53 /* Controller status */
54
55 #define STC_OVR 0x80 /* overrun */
56 #define STC_ACF 0x40 /* addr cmp fail */
57 #define STC_DEF 0x20 /* def track NI */
58 #define STC_CYO 0x10 /* cylinder ovflo */
59 #define STC_IDL 0x02 /* ctrl idle */
60 #define STC_DTE 0x01 /* xfer error */
61 #define SETC_EX (STC_OVR|STC_ACF|STC_DEF|STC_CYO)
62 #define STC_MASK (STC_OVR|STC_ACF|STC_DEF|STC_CYO|STA_BSY|STC_IDL|STC_DTE)
63
64 /* Controller command */
65
66 #define CMC_MASK 0xF
67 #define CMC_CLR 0x8 /* reset */
68 #define CMC_RD 0x1 /* read */
69 #define CMC_WR 0x2 /* write */
70 #define CMC_RCHK 0x3 /* read check */
71 #define CMC_RFMT 0x5 /* read fmt NI */
72 #define CMC_WFMT 0x6 /* write fmt NI */
73
74 /* Drive status, ^ = dynamic, * = in unit status */
75
76 #define STD_WRP 0x80 /* ^write prot */
77 #define STD_WCK 0x40 /* write check NI */
78 #define STD_ILA 0x20 /* *illegal addr */
79 #define STD_ILK 0x10 /* ^addr interlock */
80 #define STD_MOV 0x08 /* *heads in motion */
81 #define STD_INC 0x02 /* seek incomplete NI */
82 #define STD_NRDY 0x01 /* ^not ready */
83 #define STD_UST (STD_ILA | STD_MOV) /* set from unit */
84 #define SETD_EX (STD_WCK | STD_ILA | STD_ILK) /* set examine */
85
86 /* Drive command */
87
88 #define CMD_SK 0x02 /* seek */
89 #define CMD_RST 0x01 /* restore */
90
91 /* Head/sector register */
92
93 #define HS_SMASK 0x1F /* sector mask */
94 #define HS_V_SRF 5 /* surface */
95 #define HS_HMASK 0x20 /* head mask */
96 #define HS_MASK (HS_HMASK | HS_SMASK)
97 #define GET_SEC(x) ((x) & HS_SMASK)
98 #define GET_SRF(x) (((x) & HS_HMASK) >> HS_V_SRF)
99
100 #define GET_SA(p,cy,sf,sc,t) (((((((p)*drv_tab[t].cyl)+(cy))*drv_tab[t].surf)+(sf))* \
101 DP_NUMSC)+(sc))
102 #define GET_ROTATE(x) ((int) fmod (sim_gtime() / ((double) (x)), \
103 ((double) DP_NUMSC)))
104
105 /* This controller supports two different disk drive types:
106
107 type #sectors/ #surfaces/ #cylinders/
108 surface cylinder drive
109
110 2315 24 2 203
111 5440 24 4 408
112
113 In theory, each drive can be a different type. The size field in
114 each unit selects the drive capacity for each drive and thus the
115 drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE AND MUST HAVE
116 THE SAME SECTORS/TRACK.
117 */
118
119 #define TYPE_2315 0
120 #define CYL_2315 203
121 #define SURF_2315 2
122 #define SIZE_2315 (DP_NUMSC * SURF_2315 * CYL_2315 * DP_NUMBY)
123
124 #define TYPE_5440 1
125 #define CYL_5440 408
126 #define SURF_5440 2
127 #define SIZE_5440 (2 * DP_NUMSC * SURF_5440 * CYL_5440 * DP_NUMBY)
128
129 struct drvtyp {
130 int32 cyl; /* cylinders */
131 uint32 surf; /* surfaces */
132 uint32 size; /* #blocks */
133 };
134
135 static struct drvtyp drv_tab[] = {
136 { CYL_2315, SURF_2315, SIZE_2315 },
137 { CYL_5440, SURF_5440, SIZE_5440 },
138 { 0 }
139 };
140
141 extern uint32 int_req[INTSZ], int_enb[INTSZ];
142 extern FILE *sim_deb;
143
144 uint8 dpxb[DP_NUMBY]; /* xfer buffer */
145 uint32 dp_bptr = 0; /* buffer ptr */
146 uint32 dp_db = 0; /* ctrl buffer */
147 uint32 dp_cyl = 0; /* drive buffer */
148 uint32 dp_sta = 0; /* ctrl status */
149 uint32 dp_cmd = 0; /* ctrl command */
150 uint32 dp_plat = 0; /* platter */
151 uint32 dp_hdsc = 0; /* head/sector */
152 uint32 dp_svun = 0; /* most recent unit */
153 uint32 dp_1st = 0; /* first byte */
154 uint32 dpd_arm[DP_NUMDR] = { 0 }; /* drives armed */
155 int32 dp_stime = 100; /* seek latency */
156 int32 dp_rtime = 100; /* rotate latency */
157 int32 dp_wtime = 1; /* word time */
158 uint8 dp_tplte[(2 * DP_NUMDR) + 2]; /* fix/rmv + ctrl + end */
159
160 DEVICE dp_dev;
161 uint32 dp (uint32 dev, uint32 op, uint32 dat);
162 void dp_ini (t_bool dtpl);
163 t_stat dp_svc (UNIT *uptr);
164 t_stat dp_reset (DEVICE *dptr);
165 t_stat dp_attach (UNIT *uptr, char *cptr);
166 t_stat dp_detach (UNIT *uptr);
167 t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
168 t_stat dp_rds (UNIT *uptr);
169 t_stat dp_wds (UNIT *uptr);
170 t_bool dp_dter (UNIT *uptr, uint32 first);
171 void dp_done (uint32 flg);
172
173 extern t_stat id_dboot (int32 u, DEVICE *dptr);
174
175 /* DP data structures
176
177 dp_dev DP device descriptor
178 dp_unit DP unit list
179 dp_reg DP register list
180 dp_mod DP modifier list
181 */
182
183 DIB dp_dib = { d_DPC, 0, v_DPC, dp_tplte, &dp, &dp_ini };
184
185 UNIT dp_unit[] = {
186 { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
187 UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
188 { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
189 UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
190 { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
191 UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) },
192 { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
193 UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) }
194 };
195
196 REG dp_reg[] = {
197 { HRDATA (CMD, dp_cmd, 3) },
198 { HRDATA (STA, dp_sta, 8) },
199 { HRDATA (BUF, dp_db, 8) },
200 { HRDATA (PLAT, dp_plat, 1) },
201 { HRDATA (HDSC, dp_hdsc, 6) },
202 { HRDATA (CYL, dp_cyl, 9) },
203 { HRDATA (SVUN, dp_svun, 8), REG_HIDDEN },
204 { BRDATA (DBUF, dpxb, 16, 8, DP_NUMBY) },
205 { HRDATA (DBPTR, dp_bptr, 9), REG_RO },
206 { FLDATA (FIRST, dp_1st, 0) },
207 { GRDATA (IREQ, int_req[l_DPC], 16, DP_NUMDR + 1, i_DPC) },
208 { GRDATA (IENB, int_enb[l_DPC], 16, DP_NUMDR + 1, i_DPC) },
209 { BRDATA (IARM, dpd_arm, 16, 1, DP_NUMDR) },
210 { DRDATA (RTIME, dp_rtime, 0), PV_LEFT | REG_NZ },
211 { DRDATA (STIME, dp_stime, 0), PV_LEFT | REG_NZ },
212 { DRDATA (WTIME, dp_wtime, 0), PV_LEFT | REG_NZ },
213 { URDATA (UCYL, dp_unit[0].CYL, 16, 9, 0,
214 DP_NUMDR, REG_RO) },
215 { URDATA (UST, dp_unit[0].STD, 16, 8, 0,
216 DP_NUMDR, REG_RO) },
217 { URDATA (CAPAC, dp_unit[0].capac, 10, T_ADDR_W, 0,
218 DP_NUMDR, PV_LEFT | REG_HRO) },
219 { HRDATA (DEVNO, dp_dib.dno, 8), REG_HRO },
220 { HRDATA (SELCH, dp_dib.sch, 2), REG_HRO },
221 { NULL }
222 };
223
224 MTAB dp_mod[] = {
225 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
226 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
227 { (UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE) + UNIT_ATT,
228 "2315", NULL, NULL },
229 { (UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE) + UNIT_ATT,
230 "5440", NULL, NULL },
231 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE),
232 "2315", NULL, NULL },
233 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE),
234 "5440", NULL, NULL },
235 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
236 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
237 { (UNIT_AUTO+UNIT_DTYPE), (TYPE_2315 << UNIT_V_DTYPE),
238 NULL, "2315", &dp_set_size },
239 { (UNIT_AUTO+UNIT_DTYPE), (TYPE_5440 << UNIT_V_DTYPE),
240 NULL, "5440", &dp_set_size },
241 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
242 &set_dev, &show_dev, NULL },
243 { MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH",
244 &set_sch, &show_sch, NULL },
245 { 0 }
246 };
247
248 DEVICE dp_dev = {
249 "DP", dp_unit, dp_reg, dp_mod,
250 DP_NUMDR, 16, 24, 1, 16, 8,
251 NULL, NULL, &dp_reset,
252 &id_dboot, &dp_attach, &dp_detach,
253 &dp_dib, DEV_DISABLE | DEV_DEBUG
254 };
255
256 /* Controller: IO routine */
257
258 uint32 dpc (uint32 dev, uint32 op, uint32 dat)
259 {
260 uint32 f, t, u;
261 UNIT *uptr;
262 static uint8 good_cmd[8] = { 0, 1, 1, 1, 0, 0, 0, 0 };
263
264 switch (op) { /* case IO op */
265
266 case IO_ADR: /* select */
267 sch_adr (dp_dib.sch, dev); /* inform sel ch */
268 return BY; /* byte only */
269
270 case IO_RD: /* read data */
271 if (dp_sta & STC_IDL) /* if idle */
272 return GET_ROTATE (dp_rtime); /* return sector */
273 else dp_sta = dp_sta | STA_BSY; /* xfr? set busy */
274 return dp_db; /* return data */
275
276 case IO_WD: /* write data */
277 if (DEBUG_PRS (dp_dev)) fprintf (sim_deb,
278 ">>DPC WD = %02X, STA = %02X\n", dat, dp_sta);
279 if (dp_sta & STC_IDL) dp_hdsc = dat & HS_MASK; /* idle? hdsc */
280 else { /* data xfer */
281 dp_sta = dp_sta | STA_BSY; /* set busy */
282 dp_db = dat & 0xFF; /* store data */
283 }
284 break;
285
286 case IO_SS: /* status */
287 t = dp_sta & STC_MASK; /* get status */
288 if (t & SETC_EX) t = t | STA_EX; /* test for EX */
289 return t;
290
291 case IO_OC: /* command */
292 if (DEBUG_PRS (dp_dev)) fprintf (sim_deb,
293 ">>DPC OC = %02X, STA = %02X\n", dat, dp_sta);
294 f = dat & CMC_MASK; /* get cmd */
295 if (f & CMC_CLR) { /* clear? */
296 dp_reset (&dp_dev); /* reset world */
297 break;
298 }
299 u = (dp_svun - dp_dib.dno - o_DP0) / o_DP0; /* get unit */
300 uptr = dp_dev.units + u; /* ignore if busy */
301 if (!(dp_sta & STC_IDL) || sim_is_active (uptr)) break;
302 dp_cmd = f; /* save cmd */
303 if (dp_cmd == CMC_WR) dp_sta = 0; /* write: bsy=0 else */
304 else dp_sta = STA_BSY; /* bsy=1,idl,err=0 */
305 dp_1st = 1; /* xfr not started */
306 dp_bptr = 0; /* buffer empty */
307 if (dp_svun & o_DPF) dp_plat = 1; /* upper platter? */
308 else dp_plat = 0; /* no, lower */
309 if (good_cmd[f]) sim_activate (uptr, dp_rtime); /* legal? sched */
310 break;
311 }
312
313 return 0;
314 }
315
316 /* Drives: IO routine */
317
318 uint32 dp (uint32 dev, uint32 op, uint32 dat)
319 {
320 int32 diff;
321 uint32 t, u;
322 UNIT *uptr;
323
324 if (dev == dp_dib.dno) return dpc (dev, op, dat); /* controller? */
325 u = (dev - dp_dib.dno - o_DP0) / o_DP0; /* get unit num */
326 uptr = dp_dev.units + u; /* get unit ptr */
327 switch (op) { /* case IO op */
328
329 case IO_ADR: /* select */
330 if (dp_sta & STC_IDL) dp_svun = dev; /* idle? save unit */
331 return BY; /* byte only */
332
333 case IO_WD: /* write data */
334 if (DEBUG_PRS (dp_dev)) fprintf (sim_deb,
335 ">>DP%d WD = %02X, STA = %02X\n", u, dat, dp_sta);
336 if (GET_DTYPE (uptr->flags) == TYPE_2315) /* 2.5MB drive? */
337 dp_cyl = dat & 0xFF; /* cyl is 8b */
338 else dp_cyl = ((dp_cyl << 8) | dat) & DMASK16; /* insert byte */
339 break;
340
341 case IO_SS: /* status */
342 if (uptr->flags & UNIT_ATT) t = /* onl? */
343 ((uptr->flags & UNIT_WPRT)? STD_WRP: 0) |
344 ((dp_sta & STC_IDL)? 0: STD_ILK) |
345 (uptr->STD & STD_UST);
346 else t = STD_MOV | STD_NRDY; /* off = X'09' */
347 if (t & SETD_EX) t = t | STA_EX; /* test for ex */
348 return t;
349
350 case IO_OC: /* command */
351 if (DEBUG_PRS (dp_dev)) fprintf (sim_deb,
352 ">>DP%d OC = %02X, STA = %02X\n", u, dat, dp_sta);
353 dpd_arm[u] = int_chg (v_DPC + u + 1, dat, dpd_arm[u]);
354 if (dat & CMD_SK) t = dp_cyl; /* seek? get cyl */
355 else if (dat & CMD_RST) t = 0; /* rest? cyl 0 */
356 else break; /* no action */
357 diff = t - uptr->CYL;
358 if (diff < 0) diff = -diff; /* ABS cyl diff */
359 else if (diff == 0) diff = 1; /* must be nz */
360 uptr->STD = STD_MOV; /* stat = moving */
361 uptr->CYL = t; /* put on cyl */
362 sim_activate (uptr, diff * dp_stime); /* schedule */
363 break;
364 }
365
366 return 0;
367 }
368
369 /* Unit service
370
371 If seek done, on cylinder;
372 if read check, signal completion;
373 else, do read or write
374 */
375
376 t_stat dp_svc (UNIT *uptr)
377 {
378 uint32 u = uptr - dp_dev.units; /* get unit number */
379 int32 cyl = uptr->CYL; /* get cylinder */
380 uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
381 uint32 t;
382 t_stat r;
383
384 if (uptr->STD & STD_MOV) { /* seek? */
385 uptr->STD = 0; /* clr seek in prog */
386 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* offl? hangs */
387 if (cyl >= drv_tab[dtype].cyl) { /* bad cylinder? */
388 uptr->STD = STD_ILA; /* error */
389 uptr->CYL = drv_tab[dtype].cyl - 1; /* put at edge */
390 }
391 if (dpd_arm[u]) SET_INT (v_DPC + u + 1); /* req intr */
392 return SCPE_OK;
393 }
394
395 switch (dp_cmd & 0x7) { /* case on func */
396
397 case CMC_RCHK: /* read check */
398 dp_dter (uptr, 1); /* check xfr err */
399 break;
400
401 case CMC_RD: /* read */
402 if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */
403 if (dp_dter (uptr, dp_1st)) return SCPE_OK; /* check xfr err */
404 if (r = dp_rds (uptr)) return r; /* read sec, err? */
405 dp_1st = 0;
406 t = sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */
407 if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */
408 sim_activate (uptr, dp_rtime); /* reschedule */
409 return SCPE_OK;
410 }
411 break; /* no, set done */
412 }
413 dp_sta = dp_sta | STC_DTE; /* can't work */
414 break;
415
416 case CMC_WR: /* write */
417 if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */
418 if (dp_dter (uptr, dp_1st)) return SCPE_OK; /* check xfr err */
419 dp_bptr = sch_rdmem (dp_dib.sch, dpxb, DP_NUMBY); /* read from mem */
420 dp_db = dpxb[dp_bptr - 1]; /* last byte */
421 if (r = dp_wds (uptr)) return r; /* write sec, err? */
422 dp_1st = 0;
423 if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */
424 sim_activate (uptr, dp_rtime); /* reschedule */
425 return SCPE_OK;
426 }
427 break; /* no, set done */
428 }
429 dp_sta = dp_sta | STC_DTE; /* can't work */
430 break;
431 } /* end case func */
432
433 dp_done (0); /* done */
434 return SCPE_OK;
435 }
436
437 /* Read data sector */
438
439 t_stat dp_rds (UNIT *uptr)
440 {
441 uint32 i;
442
443 i = fxread (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref);
444 for ( ; i < DP_NUMBY; i++) dpxb[i] = 0; /* fill with 0's */
445 if (ferror (uptr->fileref)) { /* error? */
446 perror ("DP I/O error");
447 clearerr (uptr->fileref);
448 dp_done (STC_DTE);
449 return SCPE_IOERR;
450 }
451 return SCPE_OK;
452 }
453
454 /* Write data sector */
455
456 t_stat dp_wds (UNIT *uptr)
457 {
458 for ( ; dp_bptr < DP_NUMBY; dp_bptr++)
459 dpxb[dp_bptr] = dp_db; /* fill with last */
460 fxwrite (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref);
461 if (ferror (uptr->fileref)) { /* error? */
462 perror ("DP I/O error");
463 clearerr (uptr->fileref);
464 dp_done (STC_DTE);
465 return SCPE_IOERR;
466 }
467 return SCPE_OK;
468 }
469
470 /* Data transfer error test routine */
471
472 t_bool dp_dter (UNIT *uptr, uint32 first)
473 {
474 uint32 hd, sc, sa;
475 uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */
476
477 if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */
478 ((uptr->flags & UNIT_WPRT) && (dp_cmd == CMC_WR))) {
479 dp_done (STC_DTE); /* error, done */
480 return TRUE;
481 }
482 hd = GET_SRF (dp_hdsc); /* get head */
483 sc = GET_SEC (dp_hdsc); /* get sector */
484 if (dp_cyl != (uint32) uptr->CYL) { /* wrong cylinder? */
485 if (dp_cyl == 0) uptr->CYL = 0;
486 else {
487 dp_done (STC_ACF); /* error, done */
488 return TRUE;
489 }
490 }
491 if (sc >= DP_NUMSC) { /* bad sector? */
492 dp_done (STC_OVR); /* error, done */
493 return TRUE;
494 }
495 if (!first && (sc == 0) && (hd == 0)) { /* cyl overflow? */
496 dp_done (STC_CYO); /* error, done */
497 return TRUE;
498 }
499 sa = GET_SA (dp_plat, uptr->CYL, hd, sc, dtype); /* curr disk addr */
500 fseek (uptr->fileref, sa * DP_NUMBY, SEEK_SET);
501 if ((sc + 1) < DP_NUMSC) dp_hdsc = dp_hdsc + 1; /* end of track? */
502 else dp_hdsc = (dp_hdsc ^ HS_HMASK) & HS_HMASK; /* sec 0, nxt srf */
503 return FALSE;
504 }
505
506 /* Data transfer done routine */
507
508 void dp_done (uint32 flg)
509 {
510 dp_sta = (dp_sta | STC_IDL | flg) & ~STA_BSY; /* set flag, idle */
511 SET_INT (v_DPC); /* unmaskable intr */
512 if (flg) sch_stop (dp_dib.sch); /* if err, stop ch */
513 return;
514 }
515
516 /* Reset routine */
517
518 t_stat dp_reset (DEVICE *dptr)
519 {
520 uint32 u;
521 UNIT *uptr;
522
523 dp_cmd = 0; /* clear cmd */
524 dp_sta = STA_BSY | STC_IDL; /* idle, busy */
525 dp_1st = 0; /* clear flag */
526 dp_svun = dp_db = 0; /* clear unit, buf */
527 dp_plat = 0;
528 dp_hdsc = 0; /* clear addr */
529 CLR_INT (v_DPC); /* clear ctrl int */
530 SET_ENB (v_DPC); /* always enabled */
531 for (u = 0; u < DP_NUMDR; u++) { /* loop thru units */
532 uptr = dp_dev.units + u;
533 uptr->CYL = uptr->STD = 0;
534 CLR_INT (v_DPC + u + 1); /* clear intr */
535 CLR_ENB (v_DPC + u + 1); /* clear enable */
536 dpd_arm[u] = 0; /* clear arm */
537 sim_cancel (uptr); /* cancel activity */
538 }
539 return SCPE_OK;
540 }
541
542 /* Attach routine (with optional autosizing) */
543
544 t_stat dp_attach (UNIT *uptr, char *cptr)
545 {
546 uint32 i, p;
547 t_stat r;
548
549 uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
550 r = attach_unit (uptr, cptr); /* attach unit */
551 if (r != SCPE_OK) return r; /* error? */
552 uptr->CYL = 0;
553 if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */
554 if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK;
555 for (i = 0; drv_tab[i].surf != 0; i++) {
556 if (p <= drv_tab[i].size) {
557 uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
558 uptr->capac = drv_tab[i].size;
559 return SCPE_OK;
560 }
561 }
562 return SCPE_OK;
563 }
564
565 /* Detach routine (generates an interrupt) */
566
567 t_stat dp_detach (UNIT *uptr)
568 {
569 uint32 u = uptr - dp_dev.units;
570
571 if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
572 if (dpd_arm[u]) SET_INT (v_DPC + u + 1); /* if arm, intr */
573 return detach_unit (uptr);
574 }
575
576 /* Set size command validation routine */
577
578 t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
579 {
580 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
581 uptr->capac = drv_tab[GET_DTYPE (val)].size;
582 return SCPE_OK;
583 }
584
585 /* Create device number (T) or interrupt (F) template */
586
587 void dp_ini (t_bool dtpl)
588 {
589 int32 u, j, dev;
590
591 dp_tplte[0] = 0; /* controller */
592 for (u = 0, j = 1; u < DP_NUMDR; u++) { /* loop thru units */
593 dev = (u + 1) * o_DP0; /* drive dev # */
594 dp_tplte[j++] = dev;
595 if (dtpl && (GET_DTYPE (dp_unit[u].flags) == TYPE_5440))
596 dp_tplte[j++] = dev + o_DPF; /* if fixed */
597 }
598 dp_tplte[j] = TPL_END; /* end marker */
599 return;
600 }