First Commit of my working state
[simh.git] / I1401 / i1401_dp.c
CommitLineData
196ba1fc
PH
1/* i1401_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 18-Oct-02 RMS Fixed bug in address comparison logic\r
29 19-Sep-02 RMS Minor edit for consistency with 1620\r
30 15-Jun-02 RMS Reworked address comparison logic\r
31\r
32 The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.\r
33 Each sector contains 106 characters of information:\r
34\r
35 6c sector address\r
36 100c sector data\r
37\r
38 By default, a sector's address field will be '000000', which is illegal.\r
39 This is interpreted to mean the implied sector number that would be in\r
40 place if the disk pack had been formatted with sequential sector numbers.\r
41\r
42 The sector data can be 100 characters without word marks, or 90 characters\r
43 with word marks. Load mode transfers 90 characters per sector with\r
44 word marks, move mode transfers 100 characters per sector without word\r
45 marks. No attempt is made to catch incompatible writes (eg, load mode\r
46 write followed by move mode read).\r
47*/\r
48\r
49#include "i1401_defs.h"\r
50\r
51#define DP_NUMDR 5 /* #drives */\r
52#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */\r
53#define UNIT_WAE (1 << UNIT_V_WAE)\r
54\r
55/* Disk format */\r
56\r
57#define DP_ADDR 6 /* address */\r
58#define DP_DATA 100 /* data */\r
59#define DP_NUMCH (DP_ADDR + DP_DATA)\r
60\r
61#define DP_NUMSC 20 /* #sectors */\r
62#define DP_NUMSF 10 /* #surfaces */\r
63#define DP_NUMCY 100 /* #cylinders */\r
64#define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC)\r
65#define DP_SIZE (DP_TOTSC*DP_NUMCH)\r
66\r
67/* Disk control field */\r
68\r
69#define DCF_DRV 0 /* drive select */\r
70#define DCF_SEC 1 /* sector addr */\r
71#define DCF_SEC_LEN 6\r
72#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */\r
73#define DCF_CNT_LEN 3\r
74#define DCF_LEN (DCF_CNT + DCF_CNT_LEN)\r
75#define DCF_DIR 1 /* direct seek */\r
76#define DCF_DIR_LEN 4\r
77#define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */\r
78#define DCF_DSEEK 0xB\r
79\r
80/* Functions */\r
81\r
82#define FNC_SEEK 0 /* seek */\r
83#define FNC_CHECK 3 /* check */\r
84#define FNC_READ 1 /* read sectors */\r
85#define FNC_RSCO 5 /* read sec cnt overlay */\r
86#define FNC_RTRK 6 /* read track */\r
87#define FNC_WOFF 10 /* offset for write */\r
88#define FNC_WRITE 11 /* write sectors */\r
89#define FNC_WRSCO 15 /* write sec cnt overlay */\r
90#define FNC_WRTRK 16 /* write track */\r
91\r
92#define CYL u3 /* current cylinder */\r
93\r
94extern uint8 M[]; /* memory */\r
95extern int32 ind[64];\r
96extern int32 AS, BS, iochk;\r
97extern int32 bcd_to_bin[16];\r
98extern int32 bin_to_bcd[16];\r
99extern UNIT cpu_unit;\r
100\r
101int32 dp_lastf = 0; /* prior function */\r
102int32 dp_time = 0; /* seek time */\r
103\r
104t_stat dp_reset (DEVICE *dptr);\r
105t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk);\r
106t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk);\r
107t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg);\r
108t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg);\r
109int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf);\r
110t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf);\r
111t_bool dp_zeroad (uint8 *ap);\r
112t_bool dp_cmp_ad (uint8 *ap, int32 dcf);\r
113int32 dp_trkop (int32 drv, int32 sec);\r
114int32 dp_cvt_bcd (int32 ad, int32 len);\r
115void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg);\r
116int32 dp_get_cnt (int32 dcf);\r
117void dp_fill (UNIT *uptr, uint32 da, int32 cnt);\r
118\r
119/* DP data structures\r
120\r
121 dp_dev DSK device descriptor\r
122 dp_unit DSK unit list\r
123 dp_reg DSK register list\r
124 dp_mod DSK modifier list\r
125*/\r
126\r
127UNIT dp_unit[] = {\r
128 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
129 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
130 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
131 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
132 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
133 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
134 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
135 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },\r
136 { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +\r
137 UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }\r
138 };\r
139\r
140REG dp_reg[] = {\r
141 { FLDATA (ACC, ind[IN_ACC], 0) },\r
142 { FLDATA (PWC, ind[IN_DPW], 0) },\r
143 { FLDATA (WLR, ind[IN_LNG], 0) },\r
144 { FLDATA (UNA, ind[IN_UNA], 0) },\r
145 { FLDATA (ERR, ind[IN_DSK], 0) },\r
146 { FLDATA (BSY, ind[IN_DBY], 0) },\r
147 { DRDATA (LASTF, dp_lastf, 3) },\r
148 { DRDATA (TIME, dp_time, 24), PV_LEFT },\r
149 { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,\r
150 DP_NUMDR, PV_LEFT + REG_RO) },\r
151 { NULL }\r
152 };\r
153\r
154MTAB dp_mod[] = {\r
155 { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },\r
156 { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, \r
157 { 0 }\r
158 };\r
159\r
160DEVICE dp_dev = {\r
161 "DP", dp_unit, dp_reg, dp_mod,\r
162 DP_NUMDR, 10, 21, 1, 8, 7,\r
163 NULL, NULL, &dp_reset,\r
164 NULL, NULL, NULL\r
165 };\r
166\r
167/* Disk IO routine\r
168\r
169 Inputs:\r
170 fnc = function character\r
171 flg = load vs move mode\r
172 mod = modifier character\r
173 Outputs:\r
174 status = status\r
175*/\r
176\r
177t_stat dp_io (int32 fnc, int32 flg, int32 mod)\r
178{\r
179int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff;\r
180UNIT *uptr;\r
181t_stat r;\r
182\r
183dcf = BS; /* save DCF addr */\r
184qwc = 0; /* not wcheck */\r
185ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */\r
186ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;\r
187if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */\r
188 ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */\r
189 return SCPE_OK; /* done */\r
190 }\r
191\r
192AS = dcf + 6; /* AS for most ops */\r
193BS = dcf + DCF_CNT - 1; /* minimum DCF */\r
194if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */\r
195if (M[dcf] & BBIT) drv = M[dcf + DCF_SEC + 1] & 0xE; /* impl sel? cyl 8-4-2 */\r
196else drv = M[dcf] & DIGIT; /* get drive sel */\r
197if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */\r
198 return STOP_INVDSK;\r
199drv = bcd_to_bin[drv] >> 1; /* convert */\r
200uptr = dp_dev.units + drv; /* get unit ptr */\r
201if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */\r
202 ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */\r
203 CRETIOE (iochk, SCPE_UNATT);\r
204 }\r
205\r
206if ((fnc == FNC_SEEK) && /* seek and */\r
207 (M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */\r
208 diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */\r
209 if (diff < 0) return STOP_INVDSC; /* error? */\r
210 diff = diff >> 1; /* diff is *2 */\r
211 if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT)\r
212 diff = -diff; /* get sign */\r
213 uptr->CYL = uptr->CYL + diff; /* bound seek */\r
214 if (uptr->CYL < 0) uptr->CYL = 0;\r
215 else if (uptr->CYL >= DP_NUMCY) { /* too big? */\r
216 uptr->CYL = 0; /* system hangs */\r
217 return STOP_INVDCY;\r
218 }\r
219 sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */\r
220 return SCPE_OK; /* done! */\r
221 }\r
222\r
223sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */\r
224if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */\r
225 return STOP_INVDSC;\r
226if (fnc == FNC_SEEK) { /* seek? */\r
227 uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */\r
228 DP_NUMCY;\r
229 sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */\r
230 return SCPE_OK; /* done! */\r
231 }\r
232\r
233BS = dcf + DCF_LEN; /* full DCF */\r
234if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */\r
235cnt = dp_get_cnt (dcf); /* get count */\r
236if (cnt < 0) return STOP_INVDCN; /* bad count? */\r
237\r
238if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */\r
239if (mod == BCD_W) { /* write? */\r
240 if (fnc == FNC_CHECK) { /* write check? */\r
241 qwc = 1; /* special read */\r
242 fnc = dp_lastf; /* use last func */\r
243 }\r
244 else {\r
245 dp_lastf = fnc; /* save func */ \r
246 fnc = fnc + FNC_WOFF; /* change to write */\r
247 }\r
248 }\r
249else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */\r
250else return STOP_INVM; /* other? error */\r
251\r
252switch (fnc) { /* case on function */\r
253\r
254 case FNC_RSCO: /* read sec cnt ov */\r
255 BS = dcf + DCF_CNT; /* set count back */\r
256 /* fall thru */\r
257 case FNC_READ: /* read */\r
258 psec = dp_fndsec (uptr, sec, dcf); /* find sector */\r
259 if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */\r
260 for (;;) { /* loop */\r
261 qzr = (--cnt == 0); /* set zero latch */\r
262 dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */\r
263 if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */\r
264 break;\r
265 cnt = dp_get_cnt (dcf); /* get new count */\r
266 if (cnt < 0) return STOP_INVDCN; /* bad count? */\r
267 if (qzr) break; /* zero latch? done */\r
268 sec++; psec++; /* next sector */\r
269 dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */\r
270 if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */\r
271 }\r
272 break; /* done, clean up */\r
273\r
274 case FNC_RTRK: /* read track */\r
275 AS = dcf + 9; /* special AS */\r
276 psec = dp_trkop (drv, sec); /* start of track */\r
277 for (;;) { /* loop */\r
278 qzr = (--cnt == 0); /* set zero latch */\r
279 dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */\r
280 if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */\r
281 break; /* error? */\r
282 if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */\r
283 break; /* error? */\r
284 cnt = dp_get_cnt (dcf); /* get new count */\r
285 if (cnt < 0) return STOP_INVDCN; /* bad count? */\r
286 if (qzr) break; /* zero latch? done */\r
287 psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC);\r
288 }\r
289 break; /* done, clean up */ \r
290\r
291 case FNC_WRSCO: /* write sec cnt ov */\r
292 BS = dcf + DCF_CNT; /* set count back */\r
293 /* fall through */\r
294 case FNC_WRITE: /* read */\r
295 psec = dp_fndsec (uptr, sec, dcf); /* find sector */\r
296 if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */\r
297 for (;;) { /* loop */\r
298 qzr = (--cnt == 0); /* set zero latch */\r
299 dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */\r
300 if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */\r
301 if (qzr) break; /* zero latch? done */\r
302 sec++; psec++; /* next sector */\r
303 dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */\r
304 if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */\r
305 }\r
306 break; /* done, clean up */\r
307\r
308 case FNC_WRTRK: /* write track */\r
309 if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */\r
310 return STOP_WRADIS;\r
311 AS = dcf + 9; /* special AS */\r
312 psec = dp_trkop (drv, sec); /* start of track */\r
313 for (;;) { /* loop */\r
314 qzr = (--cnt == 0); /* set zero latch */\r
315 dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */\r
316 if (r = dp_wradr (uptr, psec, flg)) break; /* write addr */\r
317 if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */\r
318 if (qzr) break; /* zero latch? done */\r
319 psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC);\r
320 }\r
321 break; /* done, clean up */\r
322\r
323 default: /* unknown */\r
324 return STOP_INVDFN;\r
325 }\r
326\r
327if (r == SCPE_OK) { /* normal so far? */\r
328 BS++; /* advance BS */\r
329 if (ADDR_ERR (BS)) return STOP_WRAP; /* address error? */\r
330 if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */\r
331 ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */\r
332 r = STOP_INVDLN;\r
333 }\r
334 }\r
335CRETIOE (iochk || !ind[IN_DSK], r); /* return status */\r
336}\r
337\r
338/* Read or compare address with memory */\r
339\r
340t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc)\r
341{\r
342int32 i;\r
343uint8 ac;\r
344int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
345uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
346t_bool zad = dp_zeroad (ap); /* zero address */\r
347static const int32 dec_tab[DP_ADDR] = { /* powers of 10 */\r
348 100000, 10000, 1000, 100, 10, 1\r
349 } ;\r
350\r
351for (i = 0; i < DP_ADDR; i++) { /* copy address */\r
352 if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */\r
353 ind[IN_LNG] = ind[IN_DSK] = 1; /* error */\r
354 return STOP_INVDLN;\r
355 }\r
356 if (zad) { /* addr zero? */\r
357 ac = sec / dec_tab[i]; /* get addr digit */\r
358 sec = sec % dec_tab[i]; /* get remainder */\r
359 ac = bcd_to_bin[ac]; /* cvt to BCD */\r
360 }\r
361 else ac = *ap; /* addr char */\r
362 if (qwc) { /* wr chk? skip if zad */\r
363 if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */\r
364 ((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */\r
365 ind[IN_DPW] = ind[IN_DSK] = 1;\r
366 return STOP_WRCHKE;\r
367 }\r
368 }\r
369 else if (flg) M[BS] = ac & CHAR; /* load mode */\r
370 else M[BS] = (M[BS] & WM) | (ac & CHAR); /* move mode */\r
371 ap++; BS++; /* adv ptrs */\r
372 if (ADDR_ERR (BS)) return STOP_WRAP;\r
373 }\r
374return SCPE_OK;\r
375}\r
376\r
377/* Read or compare data with memory */\r
378\r
379t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc)\r
380{\r
381int32 i, lim;\r
382int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
383uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */\r
384\r
385lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */\r
386for (i = 0; i < lim; i++) { /* copy data */\r
387 if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */\r
388 ind[IN_LNG] = ind[IN_DSK] = 1; /* error */\r
389 return STOP_INVDLN;\r
390 }\r
391 if (qwc) { /* write check? */\r
392 if (flg? (M[BS] != *ap): /* load mode cmp */\r
393 ((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */\r
394 ind[IN_DPW] = ind[IN_DSK] = 1; /* error */\r
395 return STOP_WRCHKE;\r
396 }\r
397 }\r
398 else if (flg) M[BS] = *ap & (WM | CHAR); /* load mode */\r
399 else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */\r
400 ap++; BS++; /* adv ptrs */\r
401 if (ADDR_ERR (BS)) return STOP_WRAP;\r
402 }\r
403return SCPE_OK;\r
404}\r
405\r
406/* Write address to disk */\r
407\r
408t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg)\r
409{\r
410int32 i;\r
411uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r
412uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
413\r
414for (i = 0; i < DP_ADDR; i++) { /* copy address */\r
415 if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */\r
416 dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */ \r
417 ind[IN_LNG] = ind[IN_DSK] = 1; /* error */\r
418 return STOP_INVDLN;\r
419 }\r
420 if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */\r
421 else *ap = M[BS] & CHAR; /* M? strip WM */\r
422 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
423 da++; ap++; BS++; /* adv ptrs */\r
424 if (ADDR_ERR (BS)) return STOP_WRAP;\r
425 }\r
426return SCPE_OK;\r
427}\r
428\r
429/* Write data to disk */\r
430\r
431t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg)\r
432{\r
433int32 i, lim;\r
434uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */\r
435uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
436\r
437lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */\r
438for (i = 0; i < lim; i++) { /* copy data */\r
439 if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */\r
440 dp_fill (uptr, da, DP_DATA - i); /* fill, set err */\r
441 ind[IN_LNG] = ind[IN_DSK] = 1; /* error */\r
442 return STOP_INVDLN;\r
443 }\r
444 if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */\r
445 else *ap = M[BS] & CHAR; /* move, strip WM */\r
446 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
447 da++; ap++; BS++; /* adv ptrs */\r
448 if (ADDR_ERR (BS)) return STOP_WRAP;\r
449 }\r
450return SCPE_OK;\r
451}\r
452\r
453/* Find sector */\r
454\r
455int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf)\r
456{\r
457int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r
458int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;\r
459int32 da = psec * DP_NUMCH; /* char number */\r
460uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
461int32 i;\r
462\r
463if (dp_zeroad (ap)) return psec; /* addr zero? ok */\r
464if (dp_cmp_ad (ap, dcf)) return psec; /* addr comp? ok */\r
465psec = psec - (psec % DP_NUMSC); /* sector 0 */\r
466for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */\r
467 da = psec * DP_NUMCH; /* char number */\r
468 ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */\r
469 if (dp_zeroad (ap)) continue; /* no implicit match */\r
470 if (dp_cmp_ad (ap, dcf)) return psec; /* match? */\r
471 }\r
472ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */\r
473return -1;\r
474}\r
475\r
476/* Find next sector - must be sequential, cannot cross cylinder boundary */\r
477\r
478t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf)\r
479{\r
480int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r
481int32 da = psec * DP_NUMCH; /* word number */\r
482uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r
483\r
484if (ctrk) { /* not trk zero? */\r
485 if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */\r
486 if (dp_cmp_ad (ap, dcf)) return SCPE_OK; /* addr comp? ok */\r
487 }\r
488ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */\r
489return STOP_INVDAD;\r
490}\r
491\r
492/* Test for zero address */\r
493\r
494t_bool dp_zeroad (uint8 *ap)\r
495{\r
496int32 i;\r
497\r
498for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */\r
499 if (*ap & CHAR) return FALSE; /* nonzero? lose */\r
500 }\r
501return TRUE; /* all zeroes */\r
502}\r
503\r
504/* Compare disk address to memory sector address - always omit word marks */\r
505\r
506t_bool dp_cmp_ad (uint8 *ap, int32 dcf)\r
507{\r
508int32 i;\r
509uint8 c;\r
510\r
511for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */\r
512 c = M[dcf + DCF_SEC + i]; /* sector addr char */\r
513 if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */\r
514 return FALSE;\r
515 }\r
516return TRUE; /* compare ok */\r
517}\r
518\r
519/* Track operation setup */\r
520\r
521int32 dp_trkop (int32 drv, int32 sec)\r
522{\r
523int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;\r
524\r
525return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +\r
526 (ctrk * DP_NUMSC));\r
527}\r
528\r
529/* Convert DCF BCD field to binary */\r
530\r
531int32 dp_cvt_bcd (int32 ad, int32 len)\r
532{\r
533uint8 c;\r
534int32 r;\r
535\r
536for (r = 0; len > 0; len--) { /* loop thru char */\r
537 c = M[ad] & DIGIT; /* get digit */\r
538 if ((c == 0) || (c > BCD_ZERO)) return -1; /* invalid? */\r
539 r = (r * 10) + bcd_to_bin[c]; /* cvt to bin */\r
540 ad++; /* next digit */\r
541 }\r
542return r;\r
543}\r
544\r
545/* Convert binary to DCF BCD field */\r
546\r
547void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg)\r
548{\r
549int32 r;\r
550\r
551for ( ; len > 0; len--) { /* loop thru char */\r
552 r = val % 10; /* get digit */\r
553 if (flg) M[ad + len - 1] = bin_to_bcd[r]; /* load mode? */\r
554 else M[ad + len - 1] = (M[ad + len - 1] & WM) | bin_to_bcd[r];\r
555 val = val / 10;\r
556 }\r
557return;\r
558} \r
559\r
560/* Get and validate count */\r
561\r
562int32 dp_get_cnt (int32 dcf)\r
563{\r
564int32 cnt = dp_cvt_bcd (dcf + DCF_CNT, DCF_CNT_LEN); /* get new count */\r
565if (cnt < 0) return -1; /* bad count? */\r
566if (cnt == 0) return 1000; /* 0 => 1000 */\r
567return cnt;\r
568}\r
569\r
570/* Fill sector buffer with blanks */\r
571\r
572void dp_fill (UNIT *uptr, uint32 da, int32 cnt)\r
573{\r
574while (cnt-- > 0) { /* fill with blanks */\r
575 *(((uint8 *) uptr->filebuf) + da) = BCD_BLANK;\r
576 if (da >= uptr->hwmark) uptr->hwmark = da + 1;\r
577 da++;\r
578 }\r
579return;\r
580}\r
581\r
582/* Reset routine */\r
583\r
584t_stat dp_reset (DEVICE *dptr)\r
585{\r
586int32 i;\r
587\r
588for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */\r
589dp_lastf = 0; /* clear state */\r
590ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */\r
591ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;\r
592sim_cancel (&dp_unit[0]); /* cancel timer */\r
593return SCPE_OK;\r
594}\r