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