1 /* i1401_dp.c: IBM 1311 disk simulator
3 Copyright (c) 2002-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.
28 18-Oct-02 RMS Fixed bug in address comparison logic
29 19-Sep-02 RMS Minor edit for consistency with 1620
30 15-Jun-02 RMS Reworked address comparison logic
32 The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.
33 Each sector contains 106 characters of information:
38 By default, a sector's address field will be '000000', which is illegal.
39 This is interpreted to mean the implied sector number that would be in
40 place if the disk pack had been formatted with sequential sector numbers.
42 The sector data can be 100 characters without word marks, or 90 characters
43 with word marks. Load mode transfers 90 characters per sector with
44 word marks, move mode transfers 100 characters per sector without word
45 marks. No attempt is made to catch incompatible writes (eg, load mode
46 write followed by move mode read).
49 #include "i1401_defs.h"
51 #define DP_NUMDR 5 /* #drives */
52 #define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */
53 #define UNIT_WAE (1 << UNIT_V_WAE)
57 #define DP_ADDR 6 /* address */
58 #define DP_DATA 100 /* data */
59 #define DP_NUMCH (DP_ADDR + DP_DATA)
61 #define DP_NUMSC 20 /* #sectors */
62 #define DP_NUMSF 10 /* #surfaces */
63 #define DP_NUMCY 100 /* #cylinders */
64 #define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC)
65 #define DP_SIZE (DP_TOTSC*DP_NUMCH)
67 /* Disk control field */
69 #define DCF_DRV 0 /* drive select */
70 #define DCF_SEC 1 /* sector addr */
72 #define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */
74 #define DCF_LEN (DCF_CNT + DCF_CNT_LEN)
75 #define DCF_DIR 1 /* direct seek */
77 #define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */
82 #define FNC_SEEK 0 /* seek */
83 #define FNC_CHECK 3 /* check */
84 #define FNC_READ 1 /* read sectors */
85 #define FNC_RSCO 5 /* read sec cnt overlay */
86 #define FNC_RTRK 6 /* read track */
87 #define FNC_WOFF 10 /* offset for write */
88 #define FNC_WRITE 11 /* write sectors */
89 #define FNC_WRSCO 15 /* write sec cnt overlay */
90 #define FNC_WRTRK 16 /* write track */
92 #define CYL u3 /* current cylinder */
94 extern uint8 M
[]; /* memory */
96 extern int32 AS
, BS
, iochk
;
97 extern int32 bcd_to_bin
[16];
98 extern int32 bin_to_bcd
[16];
101 int32 dp_lastf
= 0; /* prior function */
102 int32 dp_time
= 0; /* seek time */
104 t_stat
dp_reset (DEVICE
*dptr
);
105 t_stat
dp_rdadr (UNIT
*uptr
, int32 sec
, int32 flg
, int32 wchk
);
106 t_stat
dp_rdsec (UNIT
*uptr
, int32 sec
, int32 flg
, int32 wchk
);
107 t_stat
dp_wradr (UNIT
*uptr
, int32 sec
, int32 flg
);
108 t_stat
dp_wrsec (UNIT
*uptr
, int32 sec
, int32 flg
);
109 int32
dp_fndsec (UNIT
*uptr
, int32 sec
, int32 dcf
);
110 t_stat
dp_nexsec (UNIT
*uptr
, int32 psec
, int32 dcf
);
111 t_bool
dp_zeroad (uint8
*ap
);
112 t_bool
dp_cmp_ad (uint8
*ap
, int32 dcf
);
113 int32
dp_trkop (int32 drv
, int32 sec
);
114 int32
dp_cvt_bcd (int32 ad
, int32 len
);
115 void dp_cvt_bin (int32 ad
, int32 len
, int32 val
, int32 flg
);
116 int32
dp_get_cnt (int32 dcf
);
117 void dp_fill (UNIT
*uptr
, uint32 da
, int32 cnt
);
119 /* DP data structures
121 dp_dev DSK device descriptor
122 dp_unit DSK unit list
123 dp_reg DSK register list
124 dp_mod DSK modifier list
128 { UDATA (NULL
, UNIT_FIX
+ UNIT_DISABLE
+ UNIT_ATTABLE
+
129 UNIT_BUFABLE
+ UNIT_MUSTBUF
+ UNIT_BCD
, DP_SIZE
) },
130 { UDATA (NULL
, UNIT_FIX
+ UNIT_DISABLE
+ UNIT_ATTABLE
+
131 UNIT_BUFABLE
+ UNIT_MUSTBUF
+ UNIT_BCD
, DP_SIZE
) },
132 { UDATA (NULL
, UNIT_FIX
+ UNIT_DISABLE
+ UNIT_ATTABLE
+
133 UNIT_BUFABLE
+ UNIT_MUSTBUF
+ UNIT_BCD
, DP_SIZE
) },
134 { UDATA (NULL
, UNIT_FIX
+ UNIT_DISABLE
+ UNIT_ATTABLE
+
135 UNIT_BUFABLE
+ UNIT_MUSTBUF
+ UNIT_BCD
, DP_SIZE
) },
136 { UDATA (NULL
, UNIT_FIX
+ UNIT_DISABLE
+ UNIT_ATTABLE
+
137 UNIT_BUFABLE
+ UNIT_MUSTBUF
+ UNIT_BCD
, DP_SIZE
) }
141 { FLDATA (ACC
, ind
[IN_ACC
], 0) },
142 { FLDATA (PWC
, ind
[IN_DPW
], 0) },
143 { FLDATA (WLR
, ind
[IN_LNG
], 0) },
144 { FLDATA (UNA
, ind
[IN_UNA
], 0) },
145 { FLDATA (ERR
, ind
[IN_DSK
], 0) },
146 { FLDATA (BSY
, ind
[IN_DBY
], 0) },
147 { DRDATA (LASTF
, dp_lastf
, 3) },
148 { DRDATA (TIME
, dp_time
, 24), PV_LEFT
},
149 { URDATA (CYL
, dp_unit
[0].CYL
, 10, 8, 0,
150 DP_NUMDR
, PV_LEFT
+ REG_RO
) },
155 { UNIT_WAE
, 0, "write address disabled", "ADDROFF", NULL
},
156 { UNIT_WAE
, UNIT_WAE
, "write address enabled", "ADDRON", NULL
},
161 "DP", dp_unit
, dp_reg
, dp_mod
,
162 DP_NUMDR
, 10, 21, 1, 8, 7,
163 NULL
, NULL
, &dp_reset
,
170 fnc = function character
171 flg = load vs move mode
172 mod = modifier character
177 t_stat
dp_io (int32 fnc
, int32 flg
, int32 mod
)
179 int32 dcf
, drv
, sec
, psec
, cnt
, qwc
, qzr
, diff
;
183 dcf
= BS
; /* save DCF addr */
184 qwc
= 0; /* not wcheck */
185 ind
[IN_DPW
] = ind
[IN_LNG
] = ind
[IN_UNA
] = 0; /* clr indicators */
186 ind
[IN_DSK
] = ind
[IN_ACC
] = ind
[IN_DBY
] = 0;
187 if (sim_is_active (&dp_unit
[0])) { /* ctlr busy? */
188 ind
[IN_DBY
] = ind
[IN_DSK
] = 1; /* set indicators */
189 return SCPE_OK
; /* done */
192 AS
= dcf
+ 6; /* AS for most ops */
193 BS
= dcf
+ DCF_CNT
- 1; /* minimum DCF */
194 if (ADDR_ERR (BS
)) return STOP_WRAP
; /* DCF in memory? */
195 if (M
[dcf
] & BBIT
) drv
= M
[dcf
+ DCF_SEC
+ 1] & 0xE; /* impl sel? cyl 8-4-2 */
196 else drv
= M
[dcf
] & DIGIT
; /* get drive sel */
197 if ((drv
== 0) || (drv
& 1) || (drv
> BCD_ZERO
)) /* bad drive #? */
199 drv
= bcd_to_bin
[drv
] >> 1; /* convert */
200 uptr
= dp_dev
.units
+ drv
; /* get unit ptr */
201 if ((uptr
->flags
& UNIT_ATT
) == 0) { /* attached? */
202 ind
[IN_DSK
] = ind
[IN_ACC
] = 1; /* no, error */
203 CRETIOE (iochk
, SCPE_UNATT
);
206 if ((fnc
== FNC_SEEK
) && /* seek and */
207 (M
[dcf
+ DCF_DIR_FL
] & DCF_DSEEK
) == DCF_DSEEK
) { /* direct flag? */
208 diff
= dp_cvt_bcd (dcf
+ DCF_DIR
, DCF_DIR_LEN
); /* cvt diff */
209 if (diff
< 0) return STOP_INVDSC
; /* error? */
210 diff
= diff
>> 1; /* diff is *2 */
211 if ((M
[dcf
+ DCF_DIR
+ DCF_DIR_LEN
- 1] & ZONE
) == BBIT
)
212 diff
= -diff
; /* get sign */
213 uptr
->CYL
= uptr
->CYL
+ diff
; /* bound seek */
214 if (uptr
->CYL
< 0) uptr
->CYL
= 0;
215 else if (uptr
->CYL
>= DP_NUMCY
) { /* too big? */
216 uptr
->CYL
= 0; /* system hangs */
219 sim_activate (&dp_unit
[0], dp_time
); /* set ctlr busy */
220 return SCPE_OK
; /* done! */
223 sec
= dp_cvt_bcd (dcf
+ DCF_SEC
, DCF_SEC_LEN
); /* cvt sector */
224 if ((sec
< 0) || (sec
>= (DP_NUMDR
* DP_TOTSC
))) /* bad sector? */
226 if (fnc
== FNC_SEEK
) { /* seek? */
227 uptr
->CYL
= (sec
/ (DP_NUMSF
* DP_NUMSC
)) % /* set cyl # */
229 sim_activate (&dp_unit
[0], dp_time
); /* set ctlr busy */
230 return SCPE_OK
; /* done! */
233 BS
= dcf
+ DCF_LEN
; /* full DCF */
234 if (ADDR_ERR (BS
)) return STOP_WRAP
; /* DCF in memory? */
235 cnt
= dp_get_cnt (dcf
); /* get count */
236 if (cnt
< 0) return STOP_INVDCN
; /* bad count? */
238 if (fnc
>= FNC_WOFF
) return STOP_INVDFN
; /* invalid func */
239 if (mod
== BCD_W
) { /* write? */
240 if (fnc
== FNC_CHECK
) { /* write check? */
241 qwc
= 1; /* special read */
242 fnc
= dp_lastf
; /* use last func */
245 dp_lastf
= fnc
; /* save func */
246 fnc
= fnc
+ FNC_WOFF
; /* change to write */
249 else if (mod
== BCD_R
) dp_lastf
= fnc
; /* read? save func */
250 else return STOP_INVM
; /* other? error */
252 switch (fnc
) { /* case on function */
254 case FNC_RSCO
: /* read sec cnt ov */
255 BS
= dcf
+ DCF_CNT
; /* set count back */
257 case FNC_READ
: /* read */
258 psec
= dp_fndsec (uptr
, sec
, dcf
); /* find sector */
259 if (psec
< 0) CRETIOE (iochk
, STOP_INVDAD
); /* addr cmp error? */
260 for (;;) { /* loop */
261 qzr
= (--cnt
== 0); /* set zero latch */
262 dp_cvt_bin (dcf
+ DCF_CNT
, DCF_CNT_LEN
, cnt
, MD_WM
); /* redo count */
263 if (r
= dp_rdsec (uptr
, psec
, flg
, qwc
)) /* read sector */
265 cnt
= dp_get_cnt (dcf
); /* get new count */
266 if (cnt
< 0) return STOP_INVDCN
; /* bad count? */
267 if (qzr
) break; /* zero latch? done */
268 sec
++; psec
++; /* next sector */
269 dp_cvt_bin (dcf
+ DCF_SEC
, DCF_SEC_LEN
, sec
, flg
); /* rewr sec */
270 if (r
= dp_nexsec (uptr
, psec
, dcf
)) break; /* find next */
272 break; /* done, clean up */
274 case FNC_RTRK
: /* read track */
275 AS
= dcf
+ 9; /* special AS */
276 psec
= dp_trkop (drv
, sec
); /* start of track */
277 for (;;) { /* loop */
278 qzr
= (--cnt
== 0); /* set zero latch */
279 dp_cvt_bin (dcf
+ DCF_CNT
, DCF_CNT_LEN
, cnt
, MD_WM
); /* redo count */
280 if (r
= dp_rdadr (uptr
, psec
, flg
, qwc
)) /* read addr */
282 if (r
= dp_rdsec (uptr
, psec
, flg
, qwc
)) /* read data */
284 cnt
= dp_get_cnt (dcf
); /* get new count */
285 if (cnt
< 0) return STOP_INVDCN
; /* bad count? */
286 if (qzr
) break; /* zero latch? done */
287 psec
= dp_trkop (drv
, sec
) + ((psec
+ 1) % DP_NUMSC
);
289 break; /* done, clean up */
291 case FNC_WRSCO
: /* write sec cnt ov */
292 BS
= dcf
+ DCF_CNT
; /* set count back */
294 case FNC_WRITE
: /* read */
295 psec
= dp_fndsec (uptr
, sec
, dcf
); /* find sector */
296 if (psec
< 0) CRETIOE (iochk
, STOP_INVDAD
); /* addr cmp error? */
297 for (;;) { /* loop */
298 qzr
= (--cnt
== 0); /* set zero latch */
299 dp_cvt_bin (dcf
+ DCF_CNT
, DCF_CNT_LEN
, cnt
, MD_WM
); /* rewr cnt */
300 if (r
= dp_wrsec (uptr
, psec
, flg
)) break; /* write data */
301 if (qzr
) break; /* zero latch? done */
302 sec
++; psec
++; /* next sector */
303 dp_cvt_bin (dcf
+ DCF_SEC
, DCF_SEC_LEN
, sec
, flg
); /* rewr sec */
304 if (r
= dp_nexsec (uptr
, psec
, dcf
)) break; /* find next */
306 break; /* done, clean up */
308 case FNC_WRTRK
: /* write track */
309 if ((uptr
->flags
& UNIT_WAE
) == 0) /* enabled? */
311 AS
= dcf
+ 9; /* special AS */
312 psec
= dp_trkop (drv
, sec
); /* start of track */
313 for (;;) { /* loop */
314 qzr
= (--cnt
== 0); /* set zero latch */
315 dp_cvt_bin (dcf
+ DCF_CNT
, DCF_CNT_LEN
, cnt
, MD_WM
); /* redo count */
316 if (r
= dp_wradr (uptr
, psec
, flg
)) break; /* write addr */
317 if (r
= dp_wrsec (uptr
, psec
, flg
)) break; /* write data */
318 if (qzr
) break; /* zero latch? done */
319 psec
= dp_trkop (drv
, sec
) + ((psec
+ 1) % DP_NUMSC
);
321 break; /* done, clean up */
323 default: /* unknown */
327 if (r
== SCPE_OK
) { /* normal so far? */
328 BS
++; /* advance BS */
329 if (ADDR_ERR (BS
)) return STOP_WRAP
; /* address error? */
330 if (M
[BS
- 1] != (WM
+ BCD_GRPMRK
)) { /* GM + WM at end? */
331 ind
[IN_LNG
] = ind
[IN_DSK
] = 1; /* no, error */
335 CRETIOE (iochk
|| !ind
[IN_DSK
], r
); /* return status */
338 /* Read or compare address with memory */
340 t_stat
dp_rdadr (UNIT
*uptr
, int32 sec
, int32 flg
, int32 qwc
)
344 int32 da
= (sec
% DP_TOTSC
) * DP_NUMCH
; /* char number */
345 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
; /* buf ptr */
346 t_bool zad
= dp_zeroad (ap
); /* zero address */
347 static const int32 dec_tab
[DP_ADDR
] = { /* powers of 10 */
348 100000, 10000, 1000, 100, 10, 1
351 for (i
= 0; i
< DP_ADDR
; i
++) { /* copy address */
352 if (M
[BS
] == (WM
| BCD_GRPMRK
)) { /* premature GWM? */
353 ind
[IN_LNG
] = ind
[IN_DSK
] = 1; /* error */
356 if (zad
) { /* addr zero? */
357 ac
= sec
/ dec_tab
[i
]; /* get addr digit */
358 sec
= sec
% dec_tab
[i
]; /* get remainder */
359 ac
= bcd_to_bin
[ac
]; /* cvt to BCD */
361 else ac
= *ap
; /* addr char */
362 if (qwc
) { /* wr chk? skip if zad */
363 if (!zad
&& (flg
? (M
[BS
] != ac
): /* L? cmp with WM */
364 ((M
[BS
] & CHAR
) != (ac
& CHAR
)))) { /* M? cmp w/o WM */
365 ind
[IN_DPW
] = ind
[IN_DSK
] = 1;
369 else if (flg
) M
[BS
] = ac
& CHAR
; /* load mode */
370 else M
[BS
] = (M
[BS
] & WM
) | (ac
& CHAR
); /* move mode */
371 ap
++; BS
++; /* adv ptrs */
372 if (ADDR_ERR (BS
)) return STOP_WRAP
;
377 /* Read or compare data with memory */
379 t_stat
dp_rdsec (UNIT
*uptr
, int32 sec
, int32 flg
, int32 qwc
)
382 int32 da
= (sec
% DP_TOTSC
) * DP_NUMCH
; /* char number */
383 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
+ DP_ADDR
; /* buf ptr */
385 lim
= flg
? (DP_DATA
- 10): DP_DATA
; /* load vs move */
386 for (i
= 0; i
< lim
; i
++) { /* copy data */
387 if (M
[BS
] == (WM
| BCD_GRPMRK
)) { /* premature GWM? */
388 ind
[IN_LNG
] = ind
[IN_DSK
] = 1; /* error */
391 if (qwc
) { /* write check? */
392 if (flg
? (M
[BS
] != *ap
): /* load mode cmp */
393 ((M
[BS
] & CHAR
) != (*ap
& CHAR
))) { /* move mode cmp */
394 ind
[IN_DPW
] = ind
[IN_DSK
] = 1; /* error */
398 else if (flg
) M
[BS
] = *ap
& (WM
| CHAR
); /* load mode */
399 else M
[BS
] = (M
[BS
] & WM
) | (*ap
& CHAR
); /* word mode */
400 ap
++; BS
++; /* adv ptrs */
401 if (ADDR_ERR (BS
)) return STOP_WRAP
;
406 /* Write address to disk */
408 t_stat
dp_wradr (UNIT
*uptr
, int32 sec
, int32 flg
)
411 uint32 da
= (sec
% DP_TOTSC
) * DP_NUMCH
; /* char number */
412 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
; /* buf ptr */
414 for (i
= 0; i
< DP_ADDR
; i
++) { /* copy address */
415 if (M
[BS
] == (WM
| BCD_GRPMRK
)) { /* premature GWM? */
416 dp_fill (uptr
, da
, DP_NUMCH
- i
); /* fill, set err */
417 ind
[IN_LNG
] = ind
[IN_DSK
] = 1; /* error */
420 if (flg
) *ap
= M
[BS
] & (WM
| CHAR
); /* L? copy WM */
421 else *ap
= M
[BS
] & CHAR
; /* M? strip WM */
422 if (da
>= uptr
->hwmark
) uptr
->hwmark
= da
+ 1;
423 da
++; ap
++; BS
++; /* adv ptrs */
424 if (ADDR_ERR (BS
)) return STOP_WRAP
;
429 /* Write data to disk */
431 t_stat
dp_wrsec (UNIT
*uptr
, int32 sec
, int32 flg
)
434 uint32 da
= ((sec
% DP_TOTSC
) * DP_NUMCH
) + DP_ADDR
; /* char number */
435 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
; /* buf ptr */
437 lim
= flg
? (DP_DATA
- 10): DP_DATA
; /* load vs move */
438 for (i
= 0; i
< lim
; i
++) { /* copy data */
439 if (M
[BS
] == (WM
| BCD_GRPMRK
)) { /* premature GWM? */
440 dp_fill (uptr
, da
, DP_DATA
- i
); /* fill, set err */
441 ind
[IN_LNG
] = ind
[IN_DSK
] = 1; /* error */
444 if (flg
) *ap
= M
[BS
] & (WM
| CHAR
); /* load, copy WM */
445 else *ap
= M
[BS
] & CHAR
; /* move, strip WM */
446 if (da
>= uptr
->hwmark
) uptr
->hwmark
= da
+ 1;
447 da
++; ap
++; BS
++; /* adv ptrs */
448 if (ADDR_ERR (BS
)) return STOP_WRAP
;
455 int32
dp_fndsec (UNIT
*uptr
, int32 sec
, int32 dcf
)
457 int32 ctrk
= sec
% (DP_NUMSF
* DP_NUMSC
); /* curr trk-sec */
458 int32 psec
= ((uptr
->CYL
) * (DP_NUMSF
* DP_NUMSC
)) + ctrk
;
459 int32 da
= psec
* DP_NUMCH
; /* char number */
460 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
; /* buf ptr */
463 if (dp_zeroad (ap
)) return psec
; /* addr zero? ok */
464 if (dp_cmp_ad (ap
, dcf
)) return psec
; /* addr comp? ok */
465 psec
= psec
- (psec
% DP_NUMSC
); /* sector 0 */
466 for (i
= 0; i
< DP_NUMSC
; i
++, psec
++) { /* check track */
467 da
= psec
* DP_NUMCH
; /* char number */
468 ap
= ((uint8
*) uptr
->filebuf
) + da
; /* word pointer */
469 if (dp_zeroad (ap
)) continue; /* no implicit match */
470 if (dp_cmp_ad (ap
, dcf
)) return psec
; /* match? */
472 ind
[IN_UNA
] = ind
[IN_DSK
] = 1; /* no match */
476 /* Find next sector - must be sequential, cannot cross cylinder boundary */
478 t_stat
dp_nexsec (UNIT
*uptr
, int32 psec
, int32 dcf
)
480 int32 ctrk
= psec
% (DP_NUMSF
* DP_NUMSC
); /* curr trk-sec */
481 int32 da
= psec
* DP_NUMCH
; /* word number */
482 uint8
*ap
= ((uint8
*) uptr
->filebuf
) + da
; /* buf ptr */
484 if (ctrk
) { /* not trk zero? */
485 if (dp_zeroad (ap
)) return SCPE_OK
; /* addr zero? ok */
486 if (dp_cmp_ad (ap
, dcf
)) return SCPE_OK
; /* addr comp? ok */
488 ind
[IN_UNA
] = ind
[IN_DSK
] = 1; /* no, error */
492 /* Test for zero address */
494 t_bool
dp_zeroad (uint8
*ap
)
498 for (i
= 0; i
< DP_ADDR
; i
++, ap
++) { /* loop thru addr */
499 if (*ap
& CHAR
) return FALSE
; /* nonzero? lose */
501 return TRUE
; /* all zeroes */
504 /* Compare disk address to memory sector address - always omit word marks */
506 t_bool
dp_cmp_ad (uint8
*ap
, int32 dcf
)
511 for (i
= 0; i
< DP_ADDR
; i
++, ap
++) { /* loop thru addr */
512 c
= M
[dcf
+ DCF_SEC
+ i
]; /* sector addr char */
513 if ((c
& CHAR
) != (*ap
& CHAR
)) /* cmp w/o WM */
516 return TRUE
; /* compare ok */
519 /* Track operation setup */
521 int32
dp_trkop (int32 drv
, int32 sec
)
523 int32 ctrk
= (sec
/ DP_NUMSC
) % DP_NUMSF
;
525 return ((drv
* DP_TOTSC
) + (dp_unit
[drv
].CYL
* DP_NUMSF
* DP_NUMSC
) +
529 /* Convert DCF BCD field to binary */
531 int32
dp_cvt_bcd (int32 ad
, int32 len
)
536 for (r
= 0; len
> 0; len
--) { /* loop thru char */
537 c
= M
[ad
] & DIGIT
; /* get digit */
538 if ((c
== 0) || (c
> BCD_ZERO
)) return -1; /* invalid? */
539 r
= (r
* 10) + bcd_to_bin
[c
]; /* cvt to bin */
540 ad
++; /* next digit */
545 /* Convert binary to DCF BCD field */
547 void dp_cvt_bin (int32 ad
, int32 len
, int32 val
, int32 flg
)
551 for ( ; len
> 0; len
--) { /* loop thru char */
552 r
= val
% 10; /* get digit */
553 if (flg
) M
[ad
+ len
- 1] = bin_to_bcd
[r
]; /* load mode? */
554 else M
[ad
+ len
- 1] = (M
[ad
+ len
- 1] & WM
) | bin_to_bcd
[r
];
560 /* Get and validate count */
562 int32
dp_get_cnt (int32 dcf
)
564 int32 cnt
= dp_cvt_bcd (dcf
+ DCF_CNT
, DCF_CNT_LEN
); /* get new count */
565 if (cnt
< 0) return -1; /* bad count? */
566 if (cnt
== 0) return 1000; /* 0 => 1000 */
570 /* Fill sector buffer with blanks */
572 void dp_fill (UNIT
*uptr
, uint32 da
, int32 cnt
)
574 while (cnt
-- > 0) { /* fill with blanks */
575 *(((uint8
*) uptr
->filebuf
) + da
) = BCD_BLANK
;
576 if (da
>= uptr
->hwmark
) uptr
->hwmark
= da
+ 1;
584 t_stat
dp_reset (DEVICE
*dptr
)
588 for (i
= 0; i
< DP_NUMDR
; i
++) dp_unit
[i
].CYL
= 0; /* reset cylinder */
589 dp_lastf
= 0; /* clear state */
590 ind
[IN_DPW
] = ind
[IN_LNG
] = ind
[IN_UNA
] = 0; /* clr indicators */
591 ind
[IN_DSK
] = ind
[IN_ACC
] = ind
[IN_DBY
] = 0;
592 sim_cancel (&dp_unit
[0]); /* cancel timer */