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