Commit | Line | Data |
---|---|---|
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 | |
81 | extern uint8 M[MAXMEMSIZE]; /* memory */\r | |
82 | extern uint8 ind[NUM_IND];\r | |
83 | extern UNIT cpu_unit;\r | |
84 | \r | |
85 | int32 dp_stop = 1; /* disk err stop */\r | |
86 | uint32 dp_ba = 0; /* buffer addr */\r | |
87 | \r | |
88 | t_stat dp_reset (DEVICE *dptr);\r | |
89 | t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);\r | |
90 | t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);\r | |
91 | t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr);\r | |
92 | t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr);\r | |
93 | int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd);\r | |
94 | t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd);\r | |
95 | t_bool dp_zeroad (uint8 *ap);\r | |
96 | int32 dp_cvt_ad (uint8 *ap);\r | |
97 | int32 dp_trkop (int32 drv, int32 sec);\r | |
98 | int32 dp_cvt_bcd (uint32 ad, int32 len);\r | |
99 | void dp_fill (UNIT *uptr, uint32 da, int32 cnt);\r | |
100 | t_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 | |
110 | UNIT 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 | |
121 | REG 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 | |
132 | MTAB 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 | |
138 | DEVICE 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 | |
147 | t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1)\r | |
148 | {\r | |
149 | int32 drv, sa, sec, psec, cnt, qwc, qnr, t;\r | |
150 | UNIT *uptr;\r | |
151 | t_stat r;\r | |
152 | \r | |
153 | if (pa & 1) return STOP_INVDCF; /* dcf must be even */\r | |
154 | ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */\r | |
155 | ind[IN_DERR] = ind[IN_DCYO] = 0;\r | |
156 | sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */\r | |
157 | if (((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 | |
161 | else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */\r | |
162 | if (drv >= DP_NUMDR) return STOP_INVDRV; /* invalid? */\r | |
163 | uptr = dp_dev.units + drv; /* get unit ptr */\r | |
164 | if ((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 | |
169 | sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */\r | |
170 | if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */\r | |
171 | return STOP_INVDSC;\r | |
172 | if (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 | |
179 | cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */\r | |
180 | t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */\r | |
181 | if ((t < 0) || (t & 1)) return STOP_INVDBA; /* bad address? */\r | |
182 | dp_ba = t; /* save addr */\r | |
183 | \r | |
184 | if (f1 >= FNC_WRI) return STOP_INVFNC; /* invalid func? */\r | |
185 | if (op == OP_RN) qwc = f1 & FNC_WCH; /* read? set wch */\r | |
186 | else 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 | |
190 | else return STOP_INVFNC; /* not R or W */\r | |
191 | qnr = f1 & FNC_NRL; /* no rec check? */\r | |
192 | \r | |
193 | switch (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 | |
246 | if ((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 | |
252 | if ((r != SCPE_OK) && /* error? */\r | |
253 | (dp_stop || !ind[IN_DERR])) return r; /* iochk or stop? */\r | |
254 | return SCPE_OK; /* continue */\r | |
255 | }\r | |
256 | \r | |
257 | /* Read or compare address with memory */\r | |
258 | \r | |
259 | t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)\r | |
260 | {\r | |
261 | int32 i;\r | |
262 | uint8 ad;\r | |
263 | int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r | |
264 | uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r | |
265 | t_bool zad = dp_zeroad (ap); /* zero address */\r | |
266 | static const int32 dec_tab[DP_ADDR] = { /* powers of 10 */\r | |
267 | 10000, 1000, 100, 10, 1\r | |
268 | } ;\r | |
269 | \r | |
270 | for (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 | |
288 | return SCPE_OK;\r | |
289 | }\r | |
290 | \r | |
291 | /* Read or compare data with memory */\r | |
292 | \r | |
293 | t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)\r | |
294 | {\r | |
295 | int32 i;\r | |
296 | int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r | |
297 | uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */\r | |
298 | \r | |
299 | for (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 | |
312 | return SCPE_OK;\r | |
313 | }\r | |
314 | \r | |
315 | /* Write address to disk */\r | |
316 | \r | |
317 | t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr)\r | |
318 | {\r | |
319 | int32 i;\r | |
320 | uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */\r | |
321 | uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r | |
322 | \r | |
323 | for (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 | |
332 | return SCPE_OK;\r | |
333 | }\r | |
334 | \r | |
335 | /* Write data to disk */\r | |
336 | \r | |
337 | t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr)\r | |
338 | {\r | |
339 | int32 i;\r | |
340 | uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */\r | |
341 | uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r | |
342 | \r | |
343 | for (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 | |
352 | return SCPE_OK;\r | |
353 | }\r | |
354 | \r | |
355 | /* Find sector */\r | |
356 | \r | |
357 | int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd)\r | |
358 | {\r | |
359 | int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r | |
360 | int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;\r | |
361 | int32 da = psec * DP_NUMCH; /* char number */\r | |
362 | uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r | |
363 | int32 dskad, i;\r | |
364 | \r | |
365 | if (dp_zeroad (ap)) return psec; /* addr zero? ok */\r | |
366 | dskad = dp_cvt_ad (ap); /* cvt addr */\r | |
367 | if (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 | |
372 | psec = psec - (psec % DP_NUMSC); /* sector 0 */\r | |
373 | for (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 | |
384 | ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */\r | |
385 | return -1;\r | |
386 | }\r | |
387 | \r | |
388 | /* Find next sector - must be sequential, cannot cross cylinder boundary */\r | |
389 | \r | |
390 | t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd)\r | |
391 | {\r | |
392 | int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */\r | |
393 | int32 da = psec * DP_NUMCH; /* word number */\r | |
394 | uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */\r | |
395 | int32 dskad;\r | |
396 | \r | |
397 | if (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 | |
405 | ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */\r | |
406 | return STOP_CYOERR;\r | |
407 | }\r | |
408 | \r | |
409 | /* Test for zero address */\r | |
410 | \r | |
411 | t_bool dp_zeroad (uint8 *ap)\r | |
412 | {\r | |
413 | int32 i;\r | |
414 | \r | |
415 | for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */\r | |
416 | if (*ap & DIGIT) return FALSE; /* nonzero? lose */\r | |
417 | }\r | |
418 | return TRUE; /* all zeroes */\r | |
419 | }\r | |
420 | \r | |
421 | /* Test for group mark when enabled */\r | |
422 | \r | |
423 | t_stat dp_tstgm (uint32 c, int32 qnr)\r | |
424 | {\r | |
425 | if (!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 | |
429 | return SCPE_OK;\r | |
430 | }\r | |
431 | \r | |
432 | /* Convert disk address to binary - invalid char force bad address */\r | |
433 | \r | |
434 | int32 dp_cvt_ad (uint8 *ap)\r | |
435 | {\r | |
436 | int32 i, r;\r | |
437 | uint8 c;\r | |
438 | \r | |
439 | for (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 | |
444 | return r;\r | |
445 | }\r | |
446 | \r | |
447 | /* Track operation setup */\r | |
448 | \r | |
449 | int32 dp_trkop (int32 drv, int32 sec)\r | |
450 | {\r | |
451 | int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;\r | |
452 | \r | |
453 | return ((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 | |
459 | int32 dp_cvt_bcd (uint32 ad, int32 len)\r | |
460 | {\r | |
461 | uint8 c;\r | |
462 | int32 r;\r | |
463 | \r | |
464 | for (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 | |
470 | return r;\r | |
471 | }\r | |
472 | \r | |
473 | /* Fill sector buffer with zero */\r | |
474 | \r | |
475 | void dp_fill (UNIT *uptr, uint32 da, int32 cnt)\r | |
476 | {\r | |
477 | while (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 | |
482 | return;\r | |
483 | }\r | |
484 | \r | |
485 | /* Reset routine */\r | |
486 | \r | |
487 | t_stat dp_reset (DEVICE *dptr)\r | |
488 | {\r | |
489 | int32 i;\r | |
490 | \r | |
491 | for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */\r | |
492 | ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */\r | |
493 | ind[IN_DERR] = ind[IN_DCYO] = 0;\r | |
494 | return SCPE_OK;\r | |
495 | }\r |