First Commit of my working state
[simh.git] / I1620 / i1620_dp.c
CommitLineData
196ba1fc
PH
1/* i1620_dp.c: IBM 1311 disk simulator\r
2\r
3 Copyright (c) 2002-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 1311 disk pack\r
27\r
28 The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.\r
29 Each sector contains 105 characters of information:\r
30\r
31 5c sector address\r
32 100c sector data\r
33\r
34 By default, a sector's address field will be '00000', which is interpreted\r
35 to mean the implied sector number that would be in place if the disk pack\r
36 had been formatted with sequential sector numbers.\r
37\r
38 18-Oct-02 RMS Fixed bug in error testing (found by Hans Pufal)\r
39*/\r
40\r
41#include "i1620_defs.h"\r
42\r
43#define DP_NUMDR 4 /* #drives */\r
44#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */\r
45#define UNIT_WAE (1 << UNIT_V_WAE)\r
46\r
47/* Disk format */\r
48\r
49#define DP_ADDR 5 /* address */\r
50#define DP_DATA 100 /* data */\r
51#define DP_NUMCH (DP_ADDR + DP_DATA)\r
52\r
53#define DP_NUMSC 20 /* #sectors */\r
54#define DP_NUMSF 10 /* #surfaces */\r
55#define DP_NUMCY 100 /* #cylinders */\r
56#define DP_TOTSC (DP_NUMCY * DP_NUMSF * DP_NUMSC)\r
57#define DP_SIZE (DP_TOTSC * DP_NUMCH)\r
58\r
59/* Disk control field */\r
60\r
61#define DCF_DRV 0 /* drive select */\r
62#define DCF_SEC 1 /* sector addr */\r
63#define DCF_SEC_LEN 5\r
64#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */\r
65#define DCF_CNT_LEN 3\r
66#define DCF_ADR (DCF_CNT + DCF_CNT_LEN) /* buffer address */\r
67#define DCF_ADR_LEN 5\r
68#define DCF_LEN (DCF_ADR + DCF_ADR_LEN)\r
69\r
70/* Functions */\r
71\r
72#define FNC_SEEK 1 /* seek */\r
73#define FNC_SEC 0 /* sectors */\r
74#define FNC_WCH 1 /* write check */\r
75#define FNC_NRL 2 /* no rec lnt chk */\r
76#define FNC_TRK 4 /* tracks */\r
77#define FNC_WRI 8 /* write offset */\r
78\r
79#define CYL u3 /* current cylinder */\r
80\r
81extern uint8 M[MAXMEMSIZE]; /* memory */\r
82extern uint8 ind[NUM_IND];\r
83extern UNIT cpu_unit;\r
84\r
85int32 dp_stop = 1; /* disk err stop */\r
86uint32 dp_ba = 0; /* buffer addr */\r
87\r
88t_stat dp_reset (DEVICE *dptr);\r
89t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);\r
90t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);\r
91t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr);\r
92t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr);\r
93int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd);\r
94t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd);\r
95t_bool dp_zeroad (uint8 *ap);\r
96int32 dp_cvt_ad (uint8 *ap);\r
97int32 dp_trkop (int32 drv, int32 sec);\r
98int32 dp_cvt_bcd (uint32 ad, int32 len);\r
99void dp_fill (UNIT *uptr, uint32 da, int32 cnt);\r
100t_stat dp_tstgm (uint32 c, int32 qnr);\r
101\r
102/* DP data structures\r
103\r
104 dp_dev DP device descriptor\r
105 dp_unit DP unit list\r
106 dp_reg DP register list\r
107 dp_mod DP modifier list\r
108*/\r
109\r
110UNIT dp_unit[] = {\r
111 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
112 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
113 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
114 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
115 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
116 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
117 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
118 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }\r
119 };\r
120\r
121REG dp_reg[] = {\r
122 { FLDATA (ADCHK, ind[IN_DACH], 0) },\r
123 { FLDATA (WLRC, ind[IN_DWLR], 0) },\r
124 { FLDATA (CYLO, ind[IN_DCYO], 0) },\r
125 { FLDATA (ERR, ind[IN_DERR], 0) },\r
126 { FLDATA (DPSTOP, dp_stop, 0) },\r
127 { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,\r
128 DP_NUMDR, PV_LEFT + REG_RO) },\r
129 { NULL }\r
130 };\r
131\r
132MTAB dp_mod[] = {\r
133 { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },\r
134 { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, \r
135 { 0 }\r
136 };\r
137\r
138DEVICE dp_dev = {\r
139 "DP", dp_unit, dp_reg, dp_mod,\r
140 DP_NUMDR, 10, 21, 1, 16, 5,\r
141 NULL, NULL, &dp_reset,\r
142 NULL, NULL, NULL\r
143 };\r
144\r
145/* Disk IO routine */\r
146\r
147t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1)\r
148{\r
149int32 drv, sa, sec, psec, cnt, qwc, qnr, t;\r
150UNIT *uptr;\r
151t_stat r;\r
152\r
153if (pa & 1) return STOP_INVDCF; /* dcf must be even */\r
154ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */\r
155ind[IN_DERR] = ind[IN_DCYO] = 0;\r
156sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */\r
157if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */\r
158 (dp_unit[1].flags & UNIT_DIS) &&\r
159 (dp_unit[2].flags & UNIT_DIS) &&\r
160 (dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */\r
161else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */\r
162if (drv >= DP_NUMDR) return STOP_INVDRV; /* invalid? */\r
163uptr = dp_dev.units + drv; /* get unit ptr */\r
164if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */\r
165 ind[IN_DERR] = 1; /* no, error */\r
166 CRETIOE (dp_stop, SCPE_UNATT);\r
167 }\r
168\r
169sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */\r
170if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */\r
171 return STOP_INVDSC;\r
172if (op == OP_K) { /* seek? */\r
173 if (f1 != FNC_SEEK) return STOP_INVFNC; /* really? */\r
174 uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */\r
175 DP_NUMCY;\r
176 return SCPE_OK; /* done! */\r
177 }\r
178\r
179cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */\r
180t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */\r
181if ((t < 0) || (t & 1)) return STOP_INVDBA; /* bad address? */\r
182dp_ba = t; /* save addr */\r
183\r
184if (f1 >= FNC_WRI) return STOP_INVFNC; /* invalid func? */\r
185if (op == OP_RN) qwc = f1 & FNC_WCH; /* read? set wch */\r
186else if (op == OP_WN) { /* write? */\r
187 if (op & FNC_WCH) return STOP_INVFNC; /* cant check */\r
188 f1 = f1 + FNC_WRI; /* offset fnc */\r
189 }\r
190else return STOP_INVFNC; /* not R or W */\r
191qnr = f1 & FNC_NRL; /* no rec check? */\r
192\r
193switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */\r
194\r
195 case FNC_SEC: /* read sectors */\r
196 if (cnt <= 0) return STOP_INVDCN; /* bad count? */\r
197 psec = dp_fndsec (uptr, sec, TRUE); /* find sector */\r
198 if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */\r
199 do { /* loop on count */\r
200 if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */\r
201 break;\r
202 sec++; psec++; /* next sector */\r
203 } while ((--cnt > 0) &&\r
204 ((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK));\r
205 break; /* done, clean up */\r
206\r
207 case FNC_TRK: /* read track */\r
208 psec = dp_trkop (drv, sec); /* start of track */\r
209 for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */\r
210 if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */\r
211 break; /* error? */\r
212 if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */\r
213 break; /* error? */\r
214 psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC);\r
215 }\r
216 break; /* done, clean up */ \r
217\r
218 case FNC_SEC + FNC_WRI: /* write */\r
219 if (cnt <= 0) return STOP_INVDCN; /* bad count? */\r
220 psec = dp_fndsec (uptr, sec, FALSE); /* find sector */\r
221 if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */\r
222 do { /* loop on count */\r
223 if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */\r
224 if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */\r
225 sec++; psec++; /* next sector */\r
226 } while ((--cnt > 0) &&\r
227 ((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK));\r
228 break; /* done, clean up */\r
229\r
230 case FNC_TRK + FNC_WRI: /* write track */\r
231 if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */\r
232 return STOP_WRADIS;\r
233 psec = dp_trkop (drv, sec); /* start of track */\r
234 for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */\r
235 if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */\r
236 if (r = dp_wradr (uptr, psec, qnr)) break; /* write addr */\r
237 if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */\r
238 psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC);\r
239 }\r
240 break; /* done, clean up */\r
241\r
242 default: /* unknown */\r
243 return STOP_INVFNC;\r
244 }\r
245\r
246if ((r == SCPE_OK) && !qnr) { /* eor check? */\r
247 if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */\r
248 ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */\r
249 r = STOP_WRLERR;\r
250 }\r
251 }\r
252if ((r != SCPE_OK) && /* error? */\r
253 (dp_stop || !ind[IN_DERR])) return r; /* iochk or stop? */\r
254return SCPE_OK; /* continue */\r
255}\r
256\r
257/* Read or compare address with memory */\r
258\r
259t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)\r
260{\r
261int32 i;\r
262uint8 ad;\r
263int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
264uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
265t_bool zad = dp_zeroad (ap); /* zero address */\r
266static const int32 dec_tab[DP_ADDR] = { /* powers of 10 */\r
267 10000, 1000, 100, 10, 1\r
268 } ;\r
269\r
270for (i = 0; i < DP_ADDR; i++) { /* copy/check addr */\r
271 if (zad) { /* addr zero? */\r
272 ad = sec / dec_tab[i]; /* get addr digit */\r
273 sec = sec % dec_tab[i]; /* get remainder */\r
274 }\r
275 else ad = *ap; /* addr digit */\r
276 if (qwc) { /* write check? */\r
277 if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */\r
278 return STOP_WRLERR; /* yes, error */\r
279 if (!zad && (M[dp_ba] != ad)) { /* digits equal? */\r
280 ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */\r
281 return STOP_DWCERR;\r
282 }\r
283 }\r
284 else M[dp_ba] = ad & (FLAG | DIGIT); /* store digit */\r
285 if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */\r
286 ap++; PP (dp_ba); /* adv ptrs */\r
287 }\r
288return SCPE_OK;\r
289}\r
290\r
291/* Read or compare data with memory */\r
292\r
293t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)\r
294{\r
295int32 i;\r
296int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
297uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */\r
298\r
299for (i = 0; i < DP_DATA; i++) { /* copy data */\r
300 if (qwc) { /* write check? */\r
301 if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */\r
302 return STOP_WRLERR; /* yes, error */\r
303 if (M[dp_ba] != *ap) { /* dig+flags equal? */\r
304 ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */\r
305 return STOP_DWCERR;\r
306 }\r
307 }\r
308 else M[dp_ba] = *ap & (FLAG | DIGIT); /* flag + digit */\r
309 if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */\r
310 ap++; PP (dp_ba); /* adv ptrs */\r
311 }\r
312return SCPE_OK;\r
313}\r
314\r
315/* Write address to disk */\r
316\r
317t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr)\r
318{\r
319int32 i;\r
320uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
321uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
322\r
323for (i = 0; i < DP_ADDR; i++) { /* copy address */\r
324 *ap = M[dp_ba] & (FLAG | DIGIT); /* flag + digit */\r
325 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
326 if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */\r
327 dp_fill (uptr, da + 1, DP_NUMCH - i - 1); /* fill addr+data */\r
328 return STOP_WRLERR; /* error */\r
329 }\r
330 da++; ap++; PP (dp_ba); /* adv ptrs */\r
331 }\r
332return SCPE_OK;\r
333}\r
334\r
335/* Write data to disk */\r
336\r
337t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr)\r
338{\r
339int32 i;\r
340uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */\r
341uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
342\r
343for (i = 0; i < DP_DATA; i++) { /* copy data */\r
344 *ap = M[dp_ba] & (FLAG | DIGIT); /* get character */\r
345 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
346 if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */\r
347 dp_fill (uptr, da + 1, DP_DATA - i - 1); /* fill data */ \r
348 return STOP_WRLERR; /* error */\r
349 }\r
350 da++; ap++; PP (dp_ba); /* adv ptrs */\r
351 }\r
352return SCPE_OK;\r
353}\r
354\r
355/* Find sector */\r
356\r
357int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd)\r
358{\r
359int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r
360int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;\r
361int32 da = psec * DP_NUMCH; /* char number */\r
362uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
363int32 dskad, i;\r
364\r
365if (dp_zeroad (ap)) return psec; /* addr zero? ok */\r
366dskad = dp_cvt_ad (ap); /* cvt addr */\r
367if (dskad == sec) { /* match? */\r
368 if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */\r
369 ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */\r
370 return -1;\r
371 } \r
372psec = psec - (psec % DP_NUMSC); /* sector 0 */\r
373for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */\r
374 da = psec * DP_NUMCH; /* char number */\r
375 ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */\r
376 if (dp_zeroad (ap)) continue; /* no implicit match */\r
377 dskad = dp_cvt_ad (ap); /* cvt addr */\r
378 if (dskad == sec) { /* match? */\r
379 if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */\r
380 ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */\r
381 return -1;\r
382 }\r
383 } \r
384ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */\r
385return -1;\r
386}\r
387\r
388/* Find next sector - must be sequential, cannot cross cylinder boundary */\r
389\r
390t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd)\r
391{\r
392int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r
393int32 da = psec * DP_NUMCH; /* word number */\r
394uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
395int32 dskad;\r
396\r
397if (ctrk) { /* not trk zero? */\r
398 if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */\r
399 dskad = dp_cvt_ad (ap); /* cvt addr */\r
400 if ((dskad == sec) && /* match? */\r
401 (rd || ((*ap & FLAG) == 0))) return SCPE_OK; /* read or !wprot? */\r
402 ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */\r
403 return STOP_DACERR;\r
404 }\r
405ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */\r
406return STOP_CYOERR;\r
407}\r
408\r
409/* Test for zero address */\r
410\r
411t_bool dp_zeroad (uint8 *ap)\r
412{\r
413int32 i;\r
414\r
415for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */\r
416 if (*ap & DIGIT) return FALSE; /* nonzero? lose */\r
417 }\r
418return TRUE; /* all zeroes */\r
419}\r
420\r
421/* Test for group mark when enabled */\r
422\r
423t_stat dp_tstgm (uint32 c, int32 qnr)\r
424{\r
425if (!qnr && ((c & DIGIT) == GRP_MARK)) { /* premature GM? */\r
426 ind[IN_DWLR] = ind[IN_DERR] = 1; /* error */\r
427 return STOP_WRLERR;\r
428 }\r
429return SCPE_OK;\r
430}\r
431\r
432/* Convert disk address to binary - invalid char force bad address */\r
433\r
434int32 dp_cvt_ad (uint8 *ap)\r
435{\r
436int32 i, r;\r
437uint8 c;\r
438\r
439for (i = r = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */\r
440 c = *ap & DIGIT; /* get digit */\r
441 if (BAD_DIGIT (c)) return -1; /* bad digit? */\r
442 r = (r * 10) + c; /* bcd to binary */\r
443 }\r
444return r;\r
445}\r
446\r
447/* Track operation setup */\r
448\r
449int32 dp_trkop (int32 drv, int32 sec)\r
450{\r
451int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;\r
452\r
453return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +\r
454 (ctrk * DP_NUMSC));\r
455}\r
456\r
457/* Convert DCF BCD field to binary */\r
458\r
459int32 dp_cvt_bcd (uint32 ad, int32 len)\r
460{\r
461uint8 c;\r
462int32 r;\r
463\r
464for (r = 0; len > 0; len--) { /* loop thru char */\r
465 c = M[ad] & DIGIT; /* get digit */\r
466 if (BAD_DIGIT (c)) return -1; /* invalid? */\r
467 r = (r * 10) + c; /* cvt to bin */\r
468 PP (ad); /* next digit */\r
469 }\r
470return r;\r
471}\r
472\r
473/* Fill sector buffer with zero */\r
474\r
475void dp_fill (UNIT *uptr, uint32 da, int32 cnt)\r
476{\r
477while (cnt-- > 0) { /* fill with zeroes*/\r
478 *(((uint8 *) uptr->filebuf) + da) = 0;\r
479 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
480 da++;\r
481 }\r
482return;\r
483}\r
484\r
485/* Reset routine */\r
486\r
487t_stat dp_reset (DEVICE *dptr)\r
488{\r
489int32 i;\r
490\r
491for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */\r
492ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */\r
493ind[IN_DERR] = ind[IN_DCYO] = 0;\r
494return SCPE_OK;\r
495}\r