8a216ee7d2dd07ff6d0e04d0bf51a0f4cf703090
1 /* id_dp.c: Interdata 2.5MB/10MB cartridge disk simulator
3 Copyright (c) 2001-2005, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 dp M46-421 2.5MB/10MB cartridge disk
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
37 #define DP_NUMBY 256 /* bytes/sector */
38 #define DP_NUMSC 24 /* sectors/track */
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)
49 #define CYL u3 /* current cylinder */
50 #define STD u4 /* drive status */
51 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
53 /* Controller status */
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)
64 /* Controller command */
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 */
74 /* Drive status, ^ = dynamic, * = in unit status */
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 */
88 #define CMD_SK 0x02 /* seek */
89 #define CMD_RST 0x01 /* restore */
91 /* Head/sector register */
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)
100 #define GET_SA(p,cy,sf,sc,t) (((((((p)*drv_tab[t].cyl)+(cy))*drv_tab[t].surf)+(sf))* \
102 #define GET_ROTATE(x) ((int) fmod (sim_gtime() / ((double) (x)), \
103 ((double) DP_NUMSC)))
105 /* This controller supports two different disk drive types:
107 type #sectors/ #surfaces/ #cylinders/
108 surface cylinder drive
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.
122 #define SIZE_2315 (DP_NUMSC * SURF_2315 * CYL_2315 * DP_NUMBY)
127 #define SIZE_5440 (2 * DP_NUMSC * SURF_5440 * CYL_5440 * DP_NUMBY)
130 int32 cyl
; /* cylinders */
131 uint32 surf
; /* surfaces */
132 uint32 size
; /* #blocks */
135 static struct drvtyp drv_tab
[] = {
136 { CYL_2315
, SURF_2315
, SIZE_2315
},
137 { CYL_5440
, SURF_5440
, SIZE_5440
},
141 extern uint32 int_req
[INTSZ
], int_enb
[INTSZ
];
142 extern FILE *sim_deb
;
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 */
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
);
173 extern t_stat
id_dboot (int32 u
, DEVICE
*dptr
);
175 /* DP data structures
177 dp_dev DP device descriptor
179 dp_reg DP register list
180 dp_mod DP modifier list
183 DIB dp_dib
= { d_DPC
, 0, v_DPC
, dp_tplte
, &dp
, &dp_ini
};
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
) }
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,
215 { URDATA (UST
, dp_unit
[0].STD
, 16, 8, 0,
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
},
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
},
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
256 /* Controller: IO routine */
258 uint32
dpc (uint32 dev
, uint32 op
, uint32 dat
)
262 static uint8 good_cmd
[8] = { 0, 1, 1, 1, 0, 0, 0, 0 };
264 switch (op
) { /* case IO op */
266 case IO_ADR
: /* select */
267 sch_adr (dp_dib
.sch
, dev
); /* inform sel ch */
268 return BY
; /* byte only */
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 */
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 */
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 */
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 */
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 */
316 /* Drives: IO routine */
318 uint32
dp (uint32 dev
, uint32 op
, uint32 dat
)
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 */
329 case IO_ADR
: /* select */
330 if (dp_sta
& STC_IDL
) dp_svun
= dev
; /* idle? save unit */
331 return BY
; /* byte only */
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 */
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 */
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 */
371 If seek done, on cylinder;
372 if read check, signal completion;
373 else, do read or write
376 t_stat
dp_svc (UNIT
*uptr
)
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 */
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 */
391 if (dpd_arm
[u
]) SET_INT (v_DPC
+ u
+ 1); /* req intr */
395 switch (dp_cmd
& 0x7) { /* case on func */
397 case CMC_RCHK
: /* read check */
398 dp_dter (uptr
, 1); /* check xfr err */
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? */
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 */
411 break; /* no, set done */
413 dp_sta
= dp_sta
| STC_DTE
; /* can't work */
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? */
423 if (sch_actv (dp_dib
.sch
, dp_dib
.dno
)) { /* more to do? */
424 sim_activate (uptr
, dp_rtime
); /* reschedule */
427 break; /* no, set done */
429 dp_sta
= dp_sta
| STC_DTE
; /* can't work */
431 } /* end case func */
433 dp_done (0); /* done */
437 /* Read data sector */
439 t_stat
dp_rds (UNIT
*uptr
)
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
);
454 /* Write data sector */
456 t_stat
dp_wds (UNIT
*uptr
)
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
);
470 /* Data transfer error test routine */
472 t_bool
dp_dter (UNIT
*uptr
, uint32 first
)
475 uint32 dtype
= GET_DTYPE (uptr
->flags
); /* get drive type */
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 */
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;
487 dp_done (STC_ACF
); /* error, done */
491 if (sc
>= DP_NUMSC
) { /* bad sector? */
492 dp_done (STC_OVR
); /* error, done */
495 if (!first
&& (sc
== 0) && (hd
== 0)) { /* cyl overflow? */
496 dp_done (STC_CYO
); /* error, done */
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 */
506 /* Data transfer done routine */
508 void dp_done (uint32 flg
)
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 */
518 t_stat
dp_reset (DEVICE
*dptr
)
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 */
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 */
542 /* Attach routine (with optional autosizing) */
544 t_stat
dp_attach (UNIT
*uptr
, char *cptr
)
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? */
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
;
565 /* Detach routine (generates an interrupt) */
567 t_stat
dp_detach (UNIT
*uptr
)
569 uint32 u
= uptr
- dp_dev
.units
;
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
);
576 /* Set size command validation routine */
578 t_stat
dp_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
580 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
581 uptr
->capac
= drv_tab
[GET_DTYPE (val
)].size
;
585 /* Create device number (T) or interrupt (F) template */
587 void dp_ini (t_bool dtpl
)
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 # */
595 if (dtpl
&& (GET_DTYPE (dp_unit
[u
].flags
) == TYPE_5440
))
596 dp_tplte
[j
++] = dev
+ o_DPF
; /* if fixed */
598 dp_tplte
[j
] = TPL_END
; /* end marker */