First Commit of my working state
[simh.git] / Interdata / id_fd.c
CommitLineData
196ba1fc
PH
1/* id_fd.c: Interdata floppy disk simulator\r
2\r
3 Copyright (c) 2001-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 fd M46-630 floppy disk\r
27\r
28 A diskette consists of 77 tracks, each with 26 sectors of 128B. The\r
29 Interdata floppy uses a logical record numbering scheme from 1 to 2002.\r
30 Physical tracks are numbered 0-76, physical sectors 1-26.\r
31\r
32 To allow for deleted data handling, a directory is appended to the end\r
33 of the image, one byte per LRN. Zero (the default) is a normal record,\r
34 non-zero a deleted record.\r
35*/\r
36\r
37#include "id_defs.h"\r
38\r
39#define FD_NUMTR 77 /* tracks/disk */\r
40#define FD_NUMSC 26 /* sectors/track */\r
41#define FD_NUMBY 128 /* bytes/sector */\r
42#define FD_NUMLRN (FD_NUMTR * FD_NUMSC) /* LRNs/disk */\r
43#define FD_SIZE (FD_NUMLRN * FD_NUMBY) /* bytes/disk */\r
44#define FD_NUMDR 4 /* drives/controller */\r
45#define UNIT_V_WLK (UNIT_V_UF) /* write locked */\r
46#define UNIT_WLK (1u << UNIT_V_UF)\r
47#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */\r
48#define LRN u3 /* last LRN */\r
49#define FNC u4 /* last function */\r
50#define GET_DA(x) (((x) - 1) * FD_NUMBY)\r
51#define GET_TRK(x) (((x) - 1) / FD_NUMSC)\r
52#define GET_SEC(x) ((((x) - 1) % FD_NUMSC) + 1)\r
53#define LRN_BOOT 5 /* boot block LRN */\r
54\r
55/* Command byte */\r
56\r
57#define CMD_V_UNIT 4 /* unit */\r
58#define CMD_M_UNIT 0x3\r
59#define GET_UNIT(x) (((x) >> CMD_V_UNIT) & CMD_M_UNIT)\r
60#define CMD_V_FNC 0 /* function */\r
61#define CMD_M_FNC 0xF\r
62#define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC)\r
63#define FNC_RD 0x1 /* read */\r
64#define FNC_WR 0x2 /* write */\r
65#define FNC_RDID 0x3 /* read ID */\r
66#define FNC_RSTA 0x4 /* read status */\r
67#define FNC_DEL 0x5 /* write deleted */\r
68#define FNC_BOOT 0x6 /* boot */\r
69#define FNC_STOP 0x7 /* stop */\r
70#define FNC_RESET 0x8 /* reset */\r
71#define FNC_FMT 0x9 /* format NI */\r
72#define FNC_STOPPING 0x10 /* stopping */\r
73\r
74/* Status byte, * = dynamic */\r
75\r
76#define STA_WRP 0x80 /* *write prot */\r
77#define STA_DEF 0x40 /* def track NI */\r
78#define STA_DEL 0x20 /* del record */\r
79#define STA_ERR 0x10 /* error */\r
80#define STA_IDL 0x02 /* idle */\r
81#define STA_OFL 0x01 /* fault */\r
82#define STA_MASK (STA_DEF|STA_DEL|STA_ERR|STA_BSY|STA_IDL)\r
83#define SET_EX (STA_ERR) /* set EX */\r
84\r
85/* Extended status, 6 bytes, * = dynamic */\r
86\r
87#define ES_SIZE 6\r
88#define ES0_HCRC 0x80 /* ID CRC NI */\r
89#define ES0_DCRC 0x40 /* data CRC NI */\r
90#define ES0_LRN 0x20 /* illegal LRN */\r
91#define ES0_WRP 0x10 /* *write prot */\r
92#define ES0_ERR 0x08 /* error */\r
93#define ES0_DEF 0x04 /* def trk NI */\r
94#define ES0_DEL 0x02 /* del rec NI */\r
95#define ES0_FLT 0x01 /* fault */\r
96#define ES1_TK0 0x80 /* track 0 */\r
97#define ES1_NRDY 0x40 /* not ready */\r
98#define ES1_NOAM 0x20 /* no addr mk NI */\r
99#define ES1_CMD 0x10 /* illegal cmd */\r
100#define ES1_SKE 0x08 /* seek err NI */\r
101#define ES1_UNS 0x04 /* unsafe NI */\r
102#define ES1_UNIT 0x03 /* unit # */\r
103\r
104/* Processing options for commands */\r
105\r
106#define C_RD 0x1 /* cmd reads disk */\r
107#define C_WD 0x2 /* cmd writes disk */\r
108\r
109extern uint32 int_req[INTSZ], int_enb[INTSZ];\r
110\r
111uint32 fd_sta = 0; /* status */\r
112uint32 fd_cmd = 0; /* command */\r
113uint32 fd_db = 0; /* data buffer */\r
114uint32 fd_bptr = 0; /* buffer pointer */\r
115uint8 fdxb[FD_NUMBY] = { 0 }; /* sector buffer */\r
116uint8 fd_es[FD_NUMDR][ES_SIZE] = { 0 }; /* ext status */\r
117uint32 fd_lrn = 0; /* log rec # */\r
118uint32 fd_wdv = 0; /* wd valid */\r
119uint32 fd_stopioe = 1; /* stop on error */\r
120uint32 fd_arm = 0; /* intr arm */\r
121int32 fd_ctime = 100; /* command time */\r
122int32 fd_stime = 10; /* seek, per LRN */\r
123int32 fd_xtime = 1; /* tr set time */\r
124\r
125static uint32 ctab[16] = {\r
126 0, C_RD, C_WD, 0, /* 0, rd, wr, 0 */\r
127 0, C_WD, C_RD, 0, /* 0, del, boot, 0 */\r
128 0, 0, 0, 0,\r
129 0, 0, 0, 0\r
130 };\r
131\r
132DEVICE fd_dev;\r
133uint32 fd (uint32 dev, uint32 op, uint32 dat);\r
134t_stat fd_svc (UNIT *uptr);\r
135t_stat fd_reset (DEVICE *dptr);\r
136t_stat fd_clr (DEVICE *dptr);\r
137t_stat fd_boot (int32 unitno, DEVICE *dptr);\r
138t_bool fd_dte (UNIT *uptr, t_bool wr);\r
139uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt);\r
140void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1);\r
141void sched_seek (UNIT *uptr, int32 newlrn);\r
142\r
143/* FD data structures\r
144\r
145 fd_dev FD device descriptor\r
146 fd_unit FD unit list\r
147 fd_reg FD register list\r
148 fd_mod FD modifier list\r
149*/\r
150\r
151DIB fd_dib = { d_FD, -1, v_FD, NULL, &fd, NULL };\r
152\r
153UNIT fd_unit[] = {\r
154 { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
155 UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },\r
156 { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
157 UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },\r
158 { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
159 UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) },\r
160 { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
161 UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) }\r
162 };\r
163\r
164REG fd_reg[] = {\r
165 { HRDATA (CMD, fd_cmd, 8) },\r
166 { HRDATA (STA, fd_sta, 8) },\r
167 { HRDATA (BUF, fd_db, 8) },\r
168 { HRDATA (LRN, fd_lrn, 16) },\r
169 { BRDATA (ESTA, fd_es, 16, 8, ES_SIZE * FD_NUMDR) },\r
170 { BRDATA (DBUF, fdxb, 16, 8, FD_NUMBY) },\r
171 { HRDATA (DBPTR, fd_bptr, 8) },\r
172 { FLDATA (WDV, fd_wdv, 0) },\r
173 { FLDATA (IREQ, int_req[l_FD], i_FD) },\r
174 { FLDATA (IENB, int_enb[l_FD], i_FD) },\r
175 { FLDATA (IARM, fd_arm, 0) },\r
176 { DRDATA (CTIME, fd_ctime, 24), PV_LEFT },\r
177 { DRDATA (STIME, fd_stime, 24), PV_LEFT },\r
178 { DRDATA (XTIME, fd_xtime, 24), PV_LEFT },\r
179 { FLDATA (STOP_IOE, fd_stopioe, 0) },\r
180 { URDATA (ULRN, fd_unit[0].LRN, 16, 16, 0, FD_NUMDR, REG_HRO) },\r
181 { URDATA (UFNC, fd_unit[0].FNC, 16, 8, 0, FD_NUMDR, REG_HRO) },\r
182 { HRDATA (DEVNO, fd_dib.dno, 8), REG_HRO },\r
183 { NULL }\r
184 };\r
185\r
186MTAB fd_mod[] = {\r
187 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
188 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r
189 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
190 &set_dev, &show_dev, NULL },\r
191 { 0 }\r
192 };\r
193\r
194DEVICE fd_dev = {\r
195 "FD", fd_unit, fd_reg, fd_mod,\r
196 FD_NUMDR, 16, 20, 1, 16, 8,\r
197 NULL, NULL, &fd_reset,\r
198 &fd_boot, NULL, NULL,\r
199 &fd_dib, DEV_DISABLE\r
200 };\r
201\r
202/* Floppy disk: IO routine */\r
203\r
204uint32 fd (uint32 dev, uint32 op, uint32 dat)\r
205{\r
206int32 u, t, fnc;\r
207UNIT *uptr;\r
208\r
209fnc = GET_FNC (fd_cmd); /* get fnc */\r
210u = GET_UNIT (fd_cmd); /* get unit */\r
211uptr = fd_dev.units + u;\r
212switch (op) { /* case IO op */\r
213 case IO_ADR: /* select */\r
214 return BY; /* byte only */\r
215\r
216 case IO_RD: /* read */\r
217 if (fd_sta & (STA_IDL | STA_BSY)) return fd_db; /* idle, busy? */\r
218 if (fd_bptr < FD_NUMBY) fd_db = fdxb[fd_bptr++];/* get byte */\r
219 if (fd_bptr >= FD_NUMBY) { /* buf end? */\r
220 if (ctab[fnc] & C_RD) { /* disk read? */\r
221 sched_seek (uptr, uptr->LRN + 1); /* sched read */\r
222 fd_sta = fd_sta | STA_BSY; /* set busy */\r
223 }\r
224 else fd_bptr = 0; /* just wrap */\r
225 }\r
226 if ((ctab[fnc] & C_RD) && fd_arm) /* if rd & arm, */\r
227 SET_INT (v_FD); /* interrupt */\r
228 return fd_db; /* return buf */\r
229\r
230 case IO_WD: /* write */\r
231 if (fd_sta & STA_IDL) { /* idle? */\r
232 fd_lrn = ((fd_lrn << 8) | dat) & DMASK16; /* insert byte */\r
233 fd_wdv = 1;\r
234 break;\r
235 }\r
236 if (fd_bptr < FD_NUMBY) /* if room, */\r
237 fdxb[fd_bptr++] = fd_db = dat; /* store byte */\r
238 if (fd_bptr >= FD_NUMBY) { /* buf end? */\r
239 if (ctab[fnc] & C_WD) { /* disk write? */\r
240 sched_seek (uptr, uptr->LRN + 1); /* sched write */\r
241 fd_sta = fd_sta | STA_BSY; /* set busy */\r
242 }\r
243 else fd_bptr = 0; /* just wrap */\r
244 }\r
245 if ((ctab[fnc] & C_WD) && fd_arm) /* if wr & arm, */\r
246 SET_INT (v_FD); /* interrupt */\r
247 break;\r
248\r
249 case IO_SS: /* status */\r
250 t = fd_sta & STA_MASK; /* get status */\r
251 if ((uptr->flags & UNIT_ATT) == 0) t = t | STA_DU;\r
252 if (t & SET_EX) t = t | STA_EX; /* test for ex */\r
253 return t;\r
254\r
255 case IO_OC: /* command */\r
256 fd_arm = int_chg (v_FD, dat, fd_arm); /* upd int ctrl */\r
257 fnc = GET_FNC (dat); /* new fnc */\r
258 fd_cmd = dat; /* save cmd */\r
259 u = GET_UNIT (dat); /* get unit */\r
260 uptr = fd_dev.units + u;\r
261 if (fnc == FNC_STOP) { /* stop? */\r
262 uptr->FNC = uptr->FNC | FNC_STOPPING; /* flag stop */\r
263 if (sim_is_active (uptr)) break; /* busy? cont */\r
264 if (ctab[GET_FNC (uptr->FNC)] & C_WD) { /* write? */\r
265 sched_seek (uptr, uptr->LRN + 1); /* sched write */\r
266 fd_sta = fd_sta | STA_BSY; /* set busy */\r
267 }\r
268 else fd_done (u, 0, 0, 0); /* nrml done */\r
269 break;\r
270 }\r
271 else if (fd_sta & STA_IDL) { /* must be idle */\r
272 if (fnc != FNC_RSTA) { /* !rd status */\r
273 fd_sta = STA_BSY; /* busy, !idle */\r
274 fd_es[u][0] = 0;\r
275 fd_es[u][1] = u; /* init ext sta */\r
276 }\r
277 else fd_sta = (fd_sta & ~STA_IDL) | STA_BSY;\r
278 if (fnc == FNC_BOOT) t = LRN_BOOT; /* boot? fixed sec */\r
279 else if (fd_wdv) t = fd_lrn; /* valid data? use */\r
280 else t = uptr->LRN; /* use prev */\r
281 fd_wdv = 0; /* data invalid */\r
282 fd_bptr = 0; /* init buffer */\r
283 uptr->FNC = fnc; /* save function */\r
284 uptr->LRN = t; /* save LRN */\r
285 if (ctab[fnc] & C_RD) sched_seek (uptr, t); /* seek now? */\r
286 else sim_activate (uptr, fd_ctime); /* start cmd */\r
287 }\r
288 break;\r
289 }\r
290\r
291return 0;\r
292}\r
293\r
294/* Unit service; the action to be taken depends on command */\r
295\r
296t_stat fd_svc (UNIT *uptr)\r
297{\r
298uint32 i, u, tk, sc, crc, fnc, da;\r
299uint8 *fbuf = uptr->filebuf;\r
300\r
301u = uptr - fd_dev.units; /* get unit number */\r
302fnc = GET_FNC (uptr->FNC); /* get function */\r
303switch (fnc) { /* case on function */\r
304\r
305 case FNC_RESET: /* reset */\r
306 fd_clr (&fd_dev); /* clear device */\r
307 fd_done (u, 0, 0, 0); /* set idle */\r
308 return SCPE_OK;\r
309\r
310 case FNC_STOP: /* stop */\r
311 fd_done (u, 0, 0, 0); /* set idle */\r
312 return SCPE_OK;\r
313\r
314 case FNC_BOOT: /* boot, buf empty */\r
315 case FNC_RD: /* read, buf empty */\r
316 if (uptr->FNC & FNC_STOPPING) break; /* stopped? */\r
317 if (fd_dte (uptr, FALSE)) return SCPE_OK; /* xfr error? */\r
318 da = GET_DA (uptr->LRN); /* get disk addr */\r
319 for (i = 0; i < FD_NUMBY; i++) /* read sector */\r
320 fdxb[i] = fbuf[da + i];\r
321 if (fbuf[FD_SIZE + uptr->LRN - 1]) { /* deleted? set err */\r
322 fd_sta = fd_sta | STA_DEL;\r
323 fd_es[u][0] = fd_es[u][0] | ES0_DEL;\r
324 }\r
325 fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */\r
326 fd_es[u][3] = GET_TRK (uptr->LRN);\r
327 fd_bptr = 0; /* init buf */\r
328 uptr->LRN = uptr->LRN + 1; /* next block */\r
329 break;\r
330\r
331 case FNC_WR: case FNC_DEL: /* write block */\r
332 if (fd_dte (uptr, TRUE)) return SCPE_OK; /* xfr error? */\r
333 if (fd_bptr) { /* any transfer? */\r
334 da = GET_DA (uptr->LRN); /* get disk addr */\r
335 for (i = fd_bptr; i < FD_NUMBY; i++) /* pad sector */\r
336 fdxb[i] = fd_db;\r
337 for (i = 0; i < FD_NUMBY; i++) /* write sector */\r
338 fbuf[da + i] = fdxb[i]; /* then dir */\r
339 fbuf[FD_SIZE + uptr->LRN - 1] = ((fnc == FNC_DEL)? 1: 0);\r
340 uptr->hwmark = uptr->capac; /* rewrite all */\r
341 fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */\r
342 fd_es[u][3] = GET_TRK (uptr->LRN);\r
343 fd_bptr = 0; /* init buf */\r
344 uptr->LRN = uptr->LRN + 1; /* next block */\r
345 }\r
346 break;\r
347\r
348 case FNC_RSTA: /* read status */\r
349 if (uptr->flags & UNIT_WPRT) /* wr protected? */\r
350 fd_es[u][0] = fd_es[u][0] | ES0_WRP;\r
351 if (GET_TRK (uptr->LRN) == 0) /* on track 0? */\r
352 fd_es[u][1] = fd_es[u][1] | ES1_TK0;\r
353 if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */\r
354 fd_es[u][0] = fd_es[u][0] | ES0_FLT; /* set err */\r
355 fd_es[u][1] = fd_es[u][1] | ES1_NRDY;\r
356 }\r
357 for (i = 0; i < ES_SIZE; i++) fdxb[i] = fd_es[u][i]; /* copy to buf */\r
358 for (i = ES_SIZE; i < FD_NUMBY; i++) fdxb[i] = 0;\r
359 break;\r
360\r
361 case FNC_RDID: /* read ID */\r
362 if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */\r
363 fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY);\r
364 return SCPE_OK;\r
365 }\r
366 for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr buf */\r
367 tk = GET_TRK (uptr->LRN); /* get track */\r
368 sc = GET_SEC (uptr->LRN); /* get sector */\r
369 fdxb[0] = tk & 0xFF; /* store track */\r
370 fdxb[2] = sc & 0xFF; /* store sector */\r
371 crc = fd_crc (0xFFFF, 0xFE00, 8); /* CRC addr mark */\r
372 crc = fd_crc (crc, tk << 8, 16); /* CRC track */\r
373 crc = fd_crc (crc, sc << 8, 16); /* CRC sector */\r
374 fdxb[4] = (crc >> 8) & 0xFF; /* store CRC */\r
375 fdxb[5] = crc & 0xFF;\r
376 break;\r
377\r
378 case FNC_FMT: /* format */\r
379 default:\r
380 fd_done (u, STA_ERR, ES0_ERR, ES1_CMD); /* ill cmd */\r
381 uptr->LRN = 1; /* on track 0 */\r
382 return SCPE_OK;\r
383 }\r
384\r
385if (uptr->FNC & FNC_STOPPING) { /* stopping? */\r
386 uptr->FNC = FNC_STOP; /* fnc = STOP */\r
387 sim_activate (uptr, fd_ctime); /* schedule */\r
388 } \r
389fd_sta = fd_sta & ~STA_BSY; /* clear busy */\r
390if (fd_arm) SET_INT (v_FD); /* if armed, int */\r
391return SCPE_OK;\r
392}\r
393\r
394/* Schedule seek */\r
395\r
396void sched_seek (UNIT *uptr, int32 newlrn)\r
397{\r
398int32 diff = newlrn - uptr->LRN; /* LRN diff */\r
399\r
400if (diff < 0) diff = -diff; /* ABS */\r
401if (diff < 10) diff = 10; /* MIN 10 */\r
402sim_activate (uptr, diff * fd_stime); /* schedule */\r
403return;\r
404}\r
405\r
406/* Command complete */\r
407\r
408void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1)\r
409{\r
410fd_sta = (fd_sta | STA_IDL | nsta) & ~STA_BSY; /* set idle */\r
411if (fd_arm) SET_INT (v_FD); /* if armed, int */\r
412fd_es[u][0] = fd_es[u][0] | nes0; /* set ext state */\r
413fd_es[u][1] = fd_es[u][1] | nes1;\r
414return;\r
415}\r
416\r
417/* Test for data transfer error */\r
418\r
419t_bool fd_dte (UNIT *uptr, t_bool wr)\r
420{\r
421uint32 u = uptr - fd_dev.units;\r
422\r
423if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */\r
424 fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY);\r
425 return TRUE;\r
426 }\r
427if (wr && (uptr->flags & UNIT_WPRT)) { /* wr protected? */\r
428 fd_done (u, STA_ERR, ES0_ERR | ES0_WRP, 0);\r
429 return TRUE;\r
430 }\r
431if ((uptr->LRN == 0) || (uptr->LRN > FD_NUMLRN)) { /* bad LRN? */\r
432 fd_done (u, STA_ERR, ES0_ERR | ES0_LRN, 0);\r
433 return TRUE;\r
434 }\r
435return FALSE;\r
436}\r
437\r
438/* Header CRC calculation */\r
439\r
440uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt)\r
441{\r
442uint32 i, wrk;\r
443\r
444for (i = 0; i < cnt; i++) {\r
445 wrk = crc ^ dat;\r
446 crc = (crc << 1) & DMASK16;\r
447 if (wrk & SIGN16) crc = ((crc ^ 0x1020) + 1) & DMASK16;\r
448 dat = (dat << 1) & DMASK16;\r
449 }\r
450return crc;\r
451}\r
452\r
453/* Reset routine */\r
454\r
455t_stat fd_clr (DEVICE *dptr)\r
456{\r
457int32 i, j;\r
458UNIT *uptr;\r
459\r
460fd_sta = STA_IDL; /* idle */\r
461fd_cmd = 0; /* clear state */\r
462fd_db = 0;\r
463fd_bptr = 0;\r
464fd_lrn = 1;\r
465fd_wdv = 0;\r
466for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr xfr buf */\r
467for (i = 0; i < FD_NUMDR; i++) { /* loop thru units */\r
468 for (j = 0; j < ES_SIZE; j++) fd_es[i][j] = 0; /* clr ext sta */\r
469 fd_es[i][2] = 1; /* sector 1 */\r
470 uptr = fd_dev.units + i;\r
471 sim_cancel (uptr); /* stop drive */\r
472 uptr->LRN = 1; /* clear state */\r
473 uptr->FNC = 0;\r
474 }\r
475return SCPE_OK;\r
476}\r
477\r
478t_stat fd_reset (DEVICE *dptr)\r
479{\r
480CLR_INT (v_FD); /* clear int */\r
481CLR_ENB (v_FD); /* disable int */\r
482fd_arm = 0; /* disarm int */\r
483return fd_clr (dptr);;\r
484}\r
485\r
486/* Bootstrap routine */\r
487\r
488#define BOOT_START 0x50\r
489#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))\r
490\r
491static uint8 boot_rom[] = {\r
492 0xD5, 0x00, 0x00, 0xCF, /* ST: AL CF */\r
493 0x43, 0x00, 0x00, 0x80 /* BR 80 */\r
494 };\r
495\r
496t_stat fd_boot (int32 unitno, DEVICE *dptr)\r
497{\r
498extern uint32 PC, dec_flgs;\r
499extern uint16 decrom[];\r
500\r
501if (decrom[0xD5] & dec_flgs) return SCPE_NOFNC; /* AL defined? */\r
502IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */\r
503IOWriteB (AL_DEV, fd_dib.dno); /* set dev no */\r
504IOWriteB (AL_IOC, 0x86 + (unitno << CMD_V_UNIT)); /* set dev cmd, unit num */\r
505IOWriteB (AL_SCH, 0); /* clr sch dev no */\r
506PC = BOOT_START;\r
507return SCPE_OK;\r
508}\r