1 /* nova_dkp.c: NOVA moving head disk simulator
2 
3    Copyright (c) 1993-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    dkp          moving head disk
27 
28    27-Apr-12    RMS     Changed ??? string digraphs to ?, per C rules
29    04-Jul-04    BKR     device name changed to DG's DKP from DEC's DP,
30                         DEV_SET/CLR/INTR macro use started,
31                         fixed 'P' pulse code and secret quirks,
32                         added 6097 diag and size support,
33                         fixed losing unit drive type during unit change,
34                         tightened sector size determination calculations,
35                         controller DONE flag handling fixed,
36                         fixed cylinder overflow test error,
37                         seek error code fixed,
38                         restructured dkp_go() and dkp_svc() routines
39                         (for known future fixes needed),
40                         fixed DIA status calculation,
41                         fixed DKP read/write loop to properly emulate DG cylinder and sector overflows,
42                         added trace facility,
43                         changed 'stime' calculation to force delay time if no cylinders are crossed
44                         (this fixes some DG code that assumes disk seek takes some time),
45                         fixed boot code to match DG hardware standard
46    04-Jan-04    RMS     Changed attach routine to use sim_fsize
47    28-Nov-03    CEO     Boot from DP now puts device address in SR
48    24-Nov-03    CEO     Added support for disk sizing on 6099/6103
49    19-Nov-03    CEO     Corrected major DMA Mapping bug
50    25-Apr-03    RMS     Revised autosizing
51    08-Oct-02    RMS     Added DIB
52    06-Jan-02    RMS     Revised enable/disable support
53    30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
54    24-Nov-01    RMS     Changed FLG, CAPAC to arrays
55    26-Apr-01    RMS     Added device enable/disable support
56    12-Dec-00    RMS     Added Eclipse support from Charles Owen
57    15-Oct-00    RMS     Editorial changes
58    14-Apr-99    RMS     Changed t_addr to unsigned
59    15-Sep-97    RMS     Fixed bug in DIB/DOB for new disks
60    15-Sep-97    RMS     Fixed bug in cylinder extraction (found by Charles Owen)
61    10-Sep-97    RMS     Fixed bug in error reporting (found by Charles Owen)
62    25-Nov-96    RMS     Defaulted to autosize
63    29-Jun-96    RMS     Added unit disable support
64 */
65 
66 #include "nova_defs.h"
67 
68 #define DKP_NUMDR       4                               /* #drives */
69 #define DKP_NUMWD       256                             /* words/sector */
70 #define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
71 #define UNIT_V_DTYPE    (UNIT_V_UF + 1)                 /* disk type */
72 #define UNIT_M_DTYPE    017
73 #define UNIT_V_AUTO     (UNIT_V_UF + 5)                 /* autosize */
74 #define UNIT_WLK        (1 << UNIT_V_WLK)
75 #define UNIT_DTYPE      (UNIT_M_DTYPE << UNIT_V_DTYPE)
76 #define UNIT_AUTO       (1 << UNIT_V_AUTO)
77 #define GET_DTYPE(x)    (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
78 #define FUNC            u3                              /* function */
79 #define CYL             u4                              /* on cylinder */
80 #define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protect */
81 
82 /* Unit, surface, sector, count register
83 
84    Original format: 2b, 6b, 4b, 4b
85    Revised format:  2b, 5b, 5b, 4b
86 */
87 
88 #define USSC_V_COUNT    0                               /* count */
89 #define USSC_M_COUNT    017
90 #define USSC_V_OSECTOR  4                               /* old: sector */
91 #define USSC_M_OSECTOR  017
92 #define USSC_V_OSURFACE 8                               /* old: surface */
93 #define USSC_M_OSURFACE 077
94 #define USSC_V_NSECTOR  4                               /* new: sector */
95 #define USSC_M_NSECTOR  037
96 #define USSC_V_NSURFACE 9                               /* new: surface */
97 #define USSC_M_NSURFACE 037
98 #define USSC_V_UNIT     14                              /* unit */
99 #define USSC_M_UNIT     03
100 #define USSC_UNIT       (USSC_M_UNIT << USSC_V_UNIT)
101 #define GET_COUNT(x)    (((x) >> USSC_V_COUNT) & USSC_M_COUNT)
102 #define GET_SECT(x,dt)  ((drv_tab[dt].newf)? \
103                         (((x) >> USSC_V_NSECTOR) & USSC_M_NSECTOR): \
104                         (((x) >> USSC_V_OSECTOR) & USSC_M_OSECTOR) )
105 #define GET_SURF(x,dt)  ((drv_tab[dt].newf)? \
106                         (((x) >> USSC_V_NSURFACE) & USSC_M_NSURFACE): \
107                         (((x) >> USSC_V_OSURFACE) & USSC_M_OSURFACE) )
108 #define GET_UNIT(x)     (((x) >> USSC_V_UNIT) & USSC_M_UNIT)
109 
110 /* Flags, command, cylinder register
111 
112    Original format: 5b, 2b, 1b + 8b (surrounding command)
113    Revised format:  5b, 2b, 9b
114 */
115 
116 #define FCCY_V_OCYL     0                               /* old: cylinder */
117 #define FCCY_M_OCYL     0377
118 #define FCCY_V_OCMD     8                               /* old: command */
119 #define FCCY_M_OCMD     3
120 #define FCCY_V_OCEX     10                              /* old: cyl extend */
121 #define FCCY_OCEX       (1 << FCCY_V_OCEX)
122 #define FCCY_V_NCYL     0                               /* new: cylinder */
123 #define FCCY_M_NCYL     0777
124 #define FCCY_V_NCMD     9                               /* new: command */
125 #define FCCY_M_NCMD     3
126 #define  FCCY_READ      0
127 #define  FCCY_WRITE     1
128 #define  FCCY_SEEK      2
129 #define  FCCY_RECAL     3
130 #define FCCY_FLAGS      0174000                         /* flags */
131 
132 #define GET_CMD(x,dt)   ((drv_tab[dt].newf)? \
133                         (((x) >> FCCY_V_NCMD) & FCCY_M_NCMD): \
134                         (((x) >> FCCY_V_OCMD) & FCCY_M_OCMD) )
135 
136 #define SET_CMD(x,dt)   dkp_fccy = (dkp_fccy & ((drv_tab[dt].newf)? \
137                             (FCCY_M_NCMD << FCCY_V_NCMD) : (FCCY_M_OCMD << FCCY_V_OCMD))) | \
138                         ((drv_tab[dt].newf)? \
139                         (((x) & FCCY_M_NCMD) << FCCY_V_NCMD): \
140                         (((x) & FCCY_M_OCMD) << FCCY_V_OCMD) )
141 
142 #define GET_CYL(x,dt)   ((drv_tab[dt].newf)? \
143                         (((x) >> FCCY_V_NCYL) & FCCY_M_NCYL): \
144                         ((((x) >> FCCY_V_OCYL) & FCCY_M_OCYL) | \
145                         ((dt != TYPE_D44)? 0: \
146                         (((x) & FCCY_OCEX) >> (FCCY_V_OCEX - FCCY_V_OCMD)))) )
147 
148 
149         /*  (Warning: no sector or surface masking is done!)  */
150 
151 #define	DKP_UPDATE_USSC( type, count, surf, sect )                                      \
152                 dkp_ussc = (dkp_ussc & USSC_UNIT)                                       \
153                         | ((dkp_ussc + count) & USSC_M_COUNT)                           \
154                         | ((drv_tab[dtype].newf)?                                       \
155                                 ((surf << USSC_V_NSURFACE) | (sect << USSC_V_NSECTOR)): \
156                                 ((surf << USSC_V_OSURFACE) | (sect << USSC_V_OSECTOR))  \
157                           );
158 
159 
160 /* Status */
161 
162 #define STA_ERR         0000001                         /* error */
163 #define STA_DLT         0000002                         /* data late */
164 #define STA_CRC         0000004                         /* crc error */
165 #define STA_UNS         0000010                         /* unsafe */
166 #define STA_XCY         0000020                         /* cross cylinder */
167 #define STA_CYL         0000040                         /* nx cylinder */
168 #define STA_DRDY        0000100                         /* drive ready */
169 #define STA_SEEK3       0000200                         /* seeking unit 3 */
170 #define STA_SEEK2       0000400                         /* seeking unit 2 */
171 #define STA_SEEK1       0001000                         /* seeking unit 1 */
172 #define STA_SEEK0       0002000                         /* seeking unit 0 */
173 #define STA_SKDN3       0004000                         /* seek done unit 3 */
174 #define STA_SKDN2       0010000                         /* seek done unit 2 */
175 #define STA_SKDN1       0020000                         /* seek done unit 1 */
176 #define STA_SKDN0       0040000                         /* seek done unit 0 */
177 #define STA_DONE        0100000                         /* operation done */
178 
179 #define STA_DYN         (STA_DRDY | STA_CYL)            /* set from unit */
180 #define STA_EFLGS       (STA_ERR | STA_DLT | STA_CRC | STA_UNS | \
181                          STA_XCY | STA_CYL)             /* error flags */
182 #define STA_DFLGS       (STA_DONE | STA_SKDN0 | STA_SKDN1 | \
183                          STA_SKDN2 | STA_SKDN3)         /* done flags */
184 
185 #define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \
186     drv_tab[t].sect)+(sc))
187 
188 /* This controller supports many different disk drive types:
189 
190    type         #sectors/       #surfaces/      #cylinders/     new format?
191                  surface         cylinder        drive
192 
193    floppy       8               1               77              no
194    DS/DD floppy 16              2               77              yes
195    (6097 "quad floppy")
196    Diablo 31    12              2               203             no
197    6225         20              2               245             yes
198    Century 111  6               10              203             no
199    4048 (same as Century 111)
200    Diablo 44    12              4               408             no
201    6099         32              4               192             yes
202    6227         20              6               245             yes
203    6070         24              4               408             yes
204    Century 114  12              20              203             no
205    4057 (same as Century 114)
206    6103         32              8               192             yes
207    4231         23              19              411             yes
208 
209    In theory, each drive can be a different type.  The size field in
210    each unit selects the drive capacity for each drive and thus the
211    drive type.  DISKS MUST BE DECLARED IN ASCENDING SIZE.
212 */
213 
214 #define TYPE_FLP        0
215 #define SECT_FLP        8
216 #define SURF_FLP        1
217 #define CYL_FLP         77
218 #define SIZE_FLP        (SECT_FLP * SURF_FLP * CYL_FLP * DKP_NUMWD)
219 #define NFMT_FLP        FALSE
220 
221 #define TYPE_DSDD       1
222 #define TYPE_6097       TYPE_DSDD
223 #define SECT_DSDD       16
224 #define SURF_DSDD       2
225 #define CYL_DSDD        77
226 #define SIZE_DSDD       (SECT_DSDD * SURF_DSDD * CYL_DSDD * DKP_NUMWD)
227 #define NFMT_DSDD       TRUE
228 
229 #define TYPE_D31        2
230 #define SECT_D31        12
231 #define SURF_D31        2
232 #define CYL_D31         203
233 #define SIZE_D31        (SECT_D31 * SURF_D31 * CYL_D31 * DKP_NUMWD)
234 #define NFMT_D31        FALSE
235 
236 #define TYPE_6225       3
237 #define SECT_6225       20
238 #define SURF_6225       2
239 #define CYL_6225        245
240 #define SIZE_6225       (SECT_6225 * SURF_6225 * CYL_6225 * DKP_NUMWD)
241 #define NFMT_6225       TRUE
242 
243 #define TYPE_C111       4
244 #define SECT_C111       6
245 #define SURF_C111       10
246 #define CYL_C111        203
247 #define SIZE_C111       (SECT_C111 * SURF_C111 * CYL_C111 * DKP_NUMWD)
248 #define NFMT_C111       FALSE
249 
250 #define TYPE_D44        5
251 #define SECT_D44        12
252 #define SURF_D44        4
253 #define CYL_D44         408
254 #define SIZE_D44        (SECT_D44 * SURF_D44 * CYL_D44 * DKP_NUMWD)
255 #define NFMT_D44        FALSE
256 
257 #define TYPE_6099       6
258 #define SECT_6099       32
259 #define SURF_6099       4
260 #define CYL_6099        192
261 #define SIZE_6099       (SECT_6099 * SURF_6099 * CYL_6099 * DKP_NUMWD)
262 #define NFMT_6099       TRUE
263 
264 #define TYPE_6227       7
265 #define SECT_6227       20
266 #define SURF_6227       6
267 #define CYL_6227        245
268 #define SIZE_6227       (SECT_6227 * SURF_6227 * CYL_6227 * DKP_NUMWD)
269 #define NFMT_6227       TRUE
270 
271 #define TYPE_6070       8
272 #define SECT_6070       24
273 #define SURF_6070       4
274 #define CYL_6070        408
275 #define SIZE_6070       (SECT_6070 * SURF_6070 * CYL_6070 * DKP_NUMWD)
276 #define NFMT_6070       TRUE
277 
278 #define TYPE_C114       9
279 #define SECT_C114       12
280 #define SURF_C114       20
281 #define CYL_C114        203
282 #define SIZE_C114       (SECT_C114 * SURF_C114 * CYL_C114 * DKP_NUMWD)
283 #define NFMT_C114       FALSE
284 
285 #define TYPE_6103       10
286 #define SECT_6103       32
287 #define SURF_6103       8
288 #define CYL_6103        192
289 #define SIZE_6103       (SECT_6103 * SURF_6103 * CYL_6103 * DKP_NUMWD)
290 #define NFMT_6103       TRUE
291 
292 #define TYPE_4231       11
293 #define SECT_4231       23
294 #define SURF_4231       19
295 #define CYL_4231        411
296 #define SIZE_4231       (SECT_4231 * SURF_4231 * CYL_4231 * DKP_NUMWD)
297 #define NFMT_4231       TRUE
298 
299 struct drvtyp {
300     int32       sect;                                   /* sectors */
301     int32       surf;                                   /* surfaces */
302     int32       cyl;                                    /* cylinders */
303     int32       size;                                   /* #blocks */
304     int32       newf;                                   /* new format flag */
305     };
306 
307 struct drvtyp drv_tab[] = {
308     { SECT_FLP,  SURF_FLP,  CYL_FLP,  SIZE_FLP,  NFMT_FLP },
309     { SECT_DSDD, SURF_DSDD, CYL_DSDD, SIZE_DSDD, NFMT_DSDD },
310     { SECT_D31,  SURF_D31,  CYL_D31,  SIZE_D31,  NFMT_D31 },
311     { SECT_6225, SURF_6225, CYL_6225, SIZE_6225, NFMT_6225 },
312     { SECT_C111, SURF_C111, CYL_C111, SIZE_C111, NFMT_C111 },
313     { SECT_D44,  SURF_D44,  CYL_D44,  SIZE_D44,  NFMT_D44 },
314     { SECT_6099, SURF_6099, CYL_6099, SIZE_6099, NFMT_6099 },
315     { SECT_6227, SURF_6227, CYL_6227, SIZE_6227, NFMT_6227 },
316     { SECT_6070, SURF_6070, CYL_6070, SIZE_6070, NFMT_6070 },
317     { SECT_C114, SURF_C114, CYL_C114, SIZE_C114, NFMT_C114 },
318     { SECT_6103, SURF_6103, CYL_6103, SIZE_6103, NFMT_6103 },
319     { SECT_4231, SURF_4231, CYL_4231, SIZE_4231, NFMT_4231 },
320     { 0 }
321     };
322 
323 #define DKP_TRACE(x)    (dkp_trace & (1<<(x)))
324 #define DKP_TRACE_FP    stderr
325 /*  current trace bit use (bit 0 = LSB)
326     0   I/O instructions
327     1   pre-seek/read/write event setup
328     2   seek events
329     3   read/write events
330     4   post read/write events
331  */
332 
333 extern uint16 M[];
334 extern UNIT cpu_unit;
335 extern int32 int_req, dev_busy, dev_done, dev_disable;
336 extern int32 saved_PC, SR, AMASK;
337 
338 int32 dkp_ma = 0;                                       /* memory address */
339 int32 dkp_map = 0;                                      /* DCH map 0=A 3=B */
340 int32 dkp_ussc = 0;                                     /* unit/sf/sc/cnt */
341 int32 dkp_fccy = 0;                                     /* flags/cylinder */
342 int32 dkp_sta = 0;                                      /* status register */
343 int32 dkp_swait = 100;                                  /* seek latency */
344 int32 dkp_rwait = 100;                                  /* rotate latency */
345 int32 dkp_diagmode = 0;                                 /* diagnostic mode */
346 
347 int32   dkp_trace	= 0 ;
348 
349 DEVICE dkp_dev;
350 int32 dkp (int32 pulse, int32 code, int32 AC);
351 t_stat dkp_svc (UNIT *uptr);
352 t_stat dkp_reset (DEVICE *dptr);
353 t_stat dkp_boot (int32 unitno, DEVICE *dptr);
354 t_stat dkp_attach (UNIT *uptr, char *cptr);
355 t_stat dkp_go ( int32 pulse );
356 t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
357 
358 /* DKP data structures
359 
360    dkp_dev      DKP device descriptor
361    dkp_unit     DKP unit list
362    dkp_reg      DKP register list
363    dkp_mod      DKP modifier list
364 */
365 
366 DIB dkp_dib = { DEV_DKP, INT_DKP, PI_DKP, &dkp };
367 
368 UNIT dkp_unit[] = {
369     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
370              UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
371     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
372              UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
373     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
374              UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
375     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
376              UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }
377     };
378 
379 REG dkp_reg[] = {
380     { ORDATA (FCCY, dkp_fccy, 16) },
381     { ORDATA (USSC, dkp_ussc, 16) },
382     { ORDATA (STA, dkp_sta, 16) },
383     { ORDATA (MA, dkp_ma, 16) },
384     { FLDATA (INT, int_req, INT_V_DKP) },
385     { FLDATA (BUSY, dev_busy, INT_V_DKP) },
386     { FLDATA (DONE, dev_done, INT_V_DKP) },
387     { FLDATA (DISABLE, dev_disable, INT_V_DKP) },
388     { FLDATA (DIAG,  dkp_diagmode, 0) },
389     { DRDATA (TRACE, dkp_trace,   32) },
390     { ORDATA (MAP, dkp_map, 2) },
391     { DRDATA (STIME, dkp_swait, 24), PV_LEFT },
392     { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT },
393     { URDATA (CAPAC, dkp_unit[0].capac, 10, T_ADDR_W, 0,
394               DKP_NUMDR, PV_LEFT | REG_HRO) },
395     { NULL }
396     };
397 
398 MTAB dkp_mod[] = {
399     { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
400     { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
401     { (UNIT_DTYPE+UNIT_ATT), (TYPE_FLP << UNIT_V_DTYPE) + UNIT_ATT,
402       "6030 (floppy)", NULL, NULL },
403     { (UNIT_DTYPE+UNIT_ATT), (TYPE_DSDD << UNIT_V_DTYPE) + UNIT_ATT,
404       "6097 (DS/DD floppy)", NULL, NULL },
405     { (UNIT_DTYPE+UNIT_ATT), (TYPE_D31 << UNIT_V_DTYPE) + UNIT_ATT,
406       "4047 (Diablo 31)", NULL, NULL },
407     { (UNIT_DTYPE+UNIT_ATT), (TYPE_D44 << UNIT_V_DTYPE) + UNIT_ATT,
408       "4234/6045 (Diablo 44)", NULL, NULL },
409     { (UNIT_DTYPE+UNIT_ATT), (TYPE_C111 << UNIT_V_DTYPE) + UNIT_ATT,
410       "4048 (Century 111)", NULL, NULL },
411     { (UNIT_DTYPE+UNIT_ATT), (TYPE_C114 << UNIT_V_DTYPE) + UNIT_ATT,
412       "2314/4057 (Century 114)", NULL, NULL },
413     { (UNIT_DTYPE+UNIT_ATT), (TYPE_6225 << UNIT_V_DTYPE) + UNIT_ATT,
414       "6225", NULL, NULL },
415     { (UNIT_DTYPE+UNIT_ATT), (TYPE_6227 << UNIT_V_DTYPE) + UNIT_ATT,
416       "6227", NULL, NULL },
417     { (UNIT_DTYPE+UNIT_ATT), (TYPE_6099 << UNIT_V_DTYPE) + UNIT_ATT,
418       "6099", NULL, NULL },
419     { (UNIT_DTYPE+UNIT_ATT), (TYPE_6103 << UNIT_V_DTYPE) + UNIT_ATT,
420       "6103", NULL, NULL },
421     { (UNIT_DTYPE+UNIT_ATT), (TYPE_6070 << UNIT_V_DTYPE) + UNIT_ATT,
422       "6070", NULL, NULL },
423     { (UNIT_DTYPE+UNIT_ATT), (TYPE_4231 << UNIT_V_DTYPE) + UNIT_ATT,
424       "4231/3330", NULL, NULL },
425     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_FLP << UNIT_V_DTYPE),
426       "6030 (floppy)", NULL, NULL },
427     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_DSDD << UNIT_V_DTYPE),
428       "6097 (DS/DD floppy)", NULL, NULL },
429     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_D31 << UNIT_V_DTYPE),
430       "4047 (Diablo 31)", NULL, NULL },
431     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_D44 << UNIT_V_DTYPE),
432       "4234/6045 (Diablo 44)", NULL, NULL },
433     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_C111 << UNIT_V_DTYPE),
434       "4048 (Century 111)", NULL, NULL },
435     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_C114 << UNIT_V_DTYPE),
436       "2314/4057 (Century 114)", NULL, NULL },
437     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6225 << UNIT_V_DTYPE),
438       "6225", NULL, NULL },
439     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6227 << UNIT_V_DTYPE),
440       "6227", NULL, NULL },
441     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6099 << UNIT_V_DTYPE),
442       "6099", NULL, NULL },
443     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6103 << UNIT_V_DTYPE),
444       "6103", NULL, NULL },
445     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6070 << UNIT_V_DTYPE),
446       "6070", NULL, NULL },
447     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_4231 << UNIT_V_DTYPE),
448       "4231/3330", NULL, NULL },
449     { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
450     { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
451     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_FLP << UNIT_V_DTYPE),
452       NULL, "FLOPPY", &dkp_set_size },
453     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_FLP << UNIT_V_DTYPE),
454       NULL, "6030", &dkp_set_size },
455     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_DSDD << UNIT_V_DTYPE),
456       NULL, "DSDDFLOPPY", &dkp_set_size },
457     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_DSDD << UNIT_V_DTYPE),
458       NULL, "6097", &dkp_set_size },
459     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D31 << UNIT_V_DTYPE),
460       NULL, "D31", &dkp_set_size },
461     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D31 << UNIT_V_DTYPE),
462       NULL, "4047", &dkp_set_size },
463     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE),
464       NULL, "D44", &dkp_set_size },
465     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE),
466       NULL, "4234", &dkp_set_size },
467     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE),
468       NULL, "6045", &dkp_set_size },
469     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C111 << UNIT_V_DTYPE),
470       NULL, "C111", &dkp_set_size },
471     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C111 << UNIT_V_DTYPE),
472       NULL, "4048", &dkp_set_size },
473     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE),
474       NULL, "C114", &dkp_set_size },
475     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE),
476       NULL, "2314", &dkp_set_size },
477     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE),
478       NULL, "4057", &dkp_set_size },
479     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6225 << UNIT_V_DTYPE),
480       NULL, "6225", &dkp_set_size },
481     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6227 << UNIT_V_DTYPE),
482       NULL, "6227", &dkp_set_size },
483     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6099 << UNIT_V_DTYPE),
484       NULL, "6099", &dkp_set_size },
485     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6103 << UNIT_V_DTYPE),
486       NULL, "6103", &dkp_set_size },
487     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6070 << UNIT_V_DTYPE),
488       NULL, "6070", &dkp_set_size },
489     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE),
490       NULL, "4231", &dkp_set_size },
491     { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE),
492       NULL, "3330", &dkp_set_size },
493     { 0 }
494     };
495 
496 DEVICE dkp_dev = {
497     "DKP", dkp_unit, dkp_reg, dkp_mod,
498     DKP_NUMDR, 8, 30, 1, 8, 16,
499     NULL, NULL, &dkp_reset,
500     &dkp_boot, &dkp_attach, NULL,
501     &dkp_dib, DEV_DISABLE
502     };
503 
504 
505 /* IOT routine */
506 
dkp(int32 pulse,int32 code,int32 AC)507 int32 dkp (int32 pulse, int32 code, int32 AC)
508 {
509 UNIT *uptr;
510 int32 u, rval, dtype;
511 
512 rval = 0;
513 uptr = dkp_dev.units + GET_UNIT (dkp_ussc);             /* select unit */
514 dtype = GET_DTYPE (uptr->flags);                        /* get drive type */
515 
516 if ( DKP_TRACE(0) )
517     {
518     static char * f[8] =
519         { "NIO", "DIA", "DOA", "DIB", "DOB", "DIC", "DOC", "SKP" } ;
520     static char * s[4] =
521         { " ", "S", "C", "P" } ;
522 
523         printf( "  [DKP  %s%s %06o ", f[code & 0x07], s[pulse & 0x03], (AC & 0xFFFF) ) ;
524         }
525 
526 switch (code) {                                         /* decode IR<5:7> */
527 
528     case ioDIA:                                         /* DIA */
529         dkp_sta = dkp_sta & (~STA_DRDY) ;		        /* keep error flags  */
530         if (uptr->flags & UNIT_ATT)                     /* update ready */
531             dkp_sta = dkp_sta | STA_DRDY;
532         if (uptr->CYL >= drv_tab[dtype].cyl)
533             dkp_sta = dkp_sta | STA_CYL;                /* bad cylinder? */
534         if (dkp_sta & STA_EFLGS)
535             dkp_sta = dkp_sta | STA_ERR;
536         rval = dkp_sta;
537         break;
538 
539     case ioDOA:                                         /* DOA */
540         if (AC & 0100000)                               /* clear rw done? */
541             dkp_sta = dkp_sta & ~(STA_CYL|STA_XCY|STA_UNS|STA_CRC);
542         if ((dev_busy & INT_DKP) == 0) {
543             dkp_fccy = AC;                              /* save cmd, cyl */
544             dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS);
545             }
546         DEV_CLR_DONE( INT_DKP )	;			            /* assume done flags 0 */
547         if ( dkp_sta & STA_DFLGS )		                /* done flags = 0? */
548             DEV_SET_DONE( INT_DKP )	;		            /* nope - set done  */
549         DEV_UPDATE_INTR	;				                /* update intr  */
550         break;
551 
552     case ioDIB:                                         /* DIB */
553         rval = dkp_ma & 077777 ;                        /* return buf addr */
554         /* with B0 clear (no DCH B map support) */
555         break;
556 
557     case ioDOB:                                         /* DOB */
558         if ((dev_busy & INT_DKP) == 0) {
559             dkp_ma = AC & (drv_tab[dtype].newf? DMASK: AMASK);
560             if (AC & 0100000)
561                 dkp_map = 3;                            /* high bit is map */
562             else
563                 dkp_map = 0;
564         }
565         break;
566 
567     case ioDIC:                                         /* DIC */
568         rval = dkp_ussc;                                /* return unit, sect */
569         break;
570 
571     case ioDOC:                                         /* DOC */
572         if ((dev_busy & INT_DKP) == 0)			        /* if device is not busy */
573         dkp_ussc = AC ;				                    /* save unit, sect */
574         if (((dtype == TYPE_6099) ||			        /* (BKR: don't forget 6097) */
575              (dtype == TYPE_6097) ||                    /* for 6099 and 6103 */
576              (dtype == TYPE_6103)) &&                   /* if data<0> set, */
577             (AC & 010000) )
578         dkp_diagmode = 1;			                    /* set diagnostic mode */
579         break;
580         }                                               /* end switch code */
581 
582 u = GET_UNIT(dkp_ussc);                                 /* update current unit */
583 uptr = dkp_dev.units + u ;				                /* select unit */
584 dtype = GET_DTYPE (uptr->flags);                        /* get drive type */
585 
586 if ( DKP_TRACE(0) )
587     {
588     if ( code & 1 )
589         printf( "  [%06o]  ", (rval & 0xFFFF) ) ;
590     printf( "]  \n" ) ;
591     }
592 
593 switch (pulse) {                                        /* decode IR<8:9> */
594 
595     case iopS:                                          /* start */
596         DEV_SET_BUSY( INT_DKP ) ;                       /*  set busy    */
597         DEV_CLR_DONE( INT_DKP ) ;                       /*  clear done  */
598         DEV_UPDATE_INTR ;                               /*  update ints */
599         if (dkp_diagmode) {                             /* in diagnostic mode? */
600             dkp_diagmode = 0;                           /* reset it     */
601             if (dtype == TYPE_6097)                     /* (BKR - quad floppy) */
602                 dkp_ussc = 010001;
603             if (dtype == TYPE_6099)                     /* return size bits */
604                 dkp_ussc = 010002;
605             if (dtype == TYPE_6103)                     /* for certain types */
606                 dkp_ussc = 010003;
607             }
608         else {                                          /* normal mode ... */
609             if (dkp_go (pulse))                         /* do command	*/
610                 break ;                                 /* break if no error  */
611             }
612         DEV_CLR_BUSY( INT_DKP ) ;                       /*  clear busy  */
613         DEV_SET_DONE( INT_DKP ) ;                       /*  set done    */
614         DEV_UPDATE_INTR ;                               /*  update ints */
615         dkp_sta = dkp_sta | STA_DONE;                   /*  set controller done  */
616         break;
617 
618     case iopC:                                          /* clear */
619         DEV_CLR_BUSY( INT_DKP ) ;                       /*  clear busy  */
620         DEV_CLR_DONE( INT_DKP ) ;                       /*  set done    */
621         DEV_UPDATE_INTR ;                               /*  update ints */
622         dkp_sta = dkp_sta & ~(STA_DFLGS + STA_EFLGS);   /*  clear controller flags  */
623         if (dkp_unit[u].FUNC != FCCY_SEEK)
624             sim_cancel (&dkp_unit[u]);                  /*  cancel any r/w op  */
625         break;
626 
627     case iopP:                                          /* pulse */
628         if ( dkp_diagmode )
629             {
630             dkp_diagmode = 0 ;                          /*  clear DG diagnostic mode  */
631             }
632         else
633             {
634             DEV_CLR_DONE( INT_DKP ) ;                   /*  clear done  */
635             DEV_UPDATE_INTR ;
636 
637             /*  DG "undocumented feature": 'P' pulse can not start a read/write operation!
638              *  Diagnostic routines will use this crock to do 'crazy things' to size a disk
639              *  and many assume that a recal is done, other assume that they can stop the
640              *  read operation before any damage is done.  Must also [re]calculate unit, function
641              *  and type because DOx instruction may have updated the controller info after
642              *  start of this procedure and before our 'P' handler.   BKR
643              */
644             if (dkp_go(pulse))
645                 break;                                  /* no error - do not set done and status  */
646             }
647 
648         DEV_SET_DONE( INT_DKP ) ;                       /*  set done	*/
649         DEV_UPDATE_INTR ;                               /*  update ints */
650         dkp_sta = dkp_sta | (STA_SKDN0 >> u);           /* set controller seek done */
651         break;
652     }                                                   /* end case pulse */
653 
654 return rval;
655 }
656 
657 
658 /* New command, start vs pulse handled externally
659    Returns true if command ok, false if error
660 */
661 
dkp_go(int32 pulse)662 t_stat dkp_go ( int32 pulse )
663 {
664 UNIT *	uptr;
665 int32	oldCyl, u, dtype;
666 
667 dkp_sta = dkp_sta & ~STA_EFLGS;                         /* clear errors */
668 u = GET_UNIT (dkp_ussc);                                /* get unit number */
669 uptr = dkp_dev.units + u;                               /* get unit */
670 if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) {
671     dkp_sta = dkp_sta | STA_ERR;                        /* attached or busy? */
672     return FALSE;
673     }
674 
675 if (dkp_diagmode) {                                     /* diagnostic mode? */
676     dkp_sta = (dkp_sta | STA_DONE);                     /* Set error bit only */
677     DEV_CLR_BUSY( INT_DKP ) ;                           /* clear busy  */
678     DEV_SET_DONE( INT_DKP ) ;                           /* set   done  */
679     DEV_UPDATE_INTR ;                                   /* update interrupts  */
680     return ( TRUE ) ;                                   /* do not do function */
681     }
682 
683 oldCyl = uptr->CYL ;                                    /* get old cylinder  */
684 dtype  = GET_DTYPE (uptr->flags);                       /* get drive type */
685 uptr->FUNC = GET_CMD (dkp_fccy, dtype) ;                /* save command */
686 uptr->CYL  = GET_CYL (dkp_fccy, dtype) ;
687 
688 if ( DKP_TRACE(1) )
689 	{
690 	int32		xSect ;
691 	int32		xSurf ;
692 	int32		xCyl ;
693 	int32		xCnt ;
694 
695 	xSect = GET_SECT(dkp_ussc, dtype) ;
696 	xSurf = GET_SURF(dkp_ussc, dtype) ;
697 	xCyl  = GET_CYL (dkp_fccy, dtype) ;
698 	xCnt  = 16 - (GET_COUNT(dkp_ussc)) ;
699 
700 	fprintf( DKP_TRACE_FP,
701 		"  [%s:%c  %-5s:  %3d / %2d / %2d   %2d   %06o ] \r\n",
702 		"DKP",
703 		(char) (u + '0'),
704 		((uptr->FUNC == FCCY_READ) ?
705 			  "read"
706 			: ((uptr->FUNC == FCCY_WRITE) ?
707 				  "write"
708 				: ((uptr->FUNC == FCCY_SEEK) ?
709 					  "seek"
710 					: "<?>"
711 				  )
712 			  )
713 		),
714 		(unsigned) xCyl,
715 		(unsigned) xSurf,
716 		(unsigned) xSect,
717 		(unsigned) (16 - xCnt),
718 		(unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */
719 		) ;
720 	}
721 
722 
723 switch (uptr->FUNC) {                                   /* decode command */
724 
725     case FCCY_READ:
726     case FCCY_WRITE:
727     if (((uptr->flags & UNIT_ATT) == 0) ||              /* not attached? */
728         ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE)))
729             {
730             dkp_sta = dkp_sta | STA_DONE | STA_ERR;		/* error */
731             }
732     else if ( uptr->CYL  >= drv_tab[dtype].cyl )        /* bad cylinder */
733         {
734         dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ;
735         }
736     else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */
737         {
738         dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;   /* older drives may not even do this... */
739         /*	dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ;  /-  newer disks give this error  */
740         }
741     else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */
742         {
743     /*  dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;   /- older drives may not even do this... */
744         dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ;  /*  newer disks give this error  */
745         }
746     if ( (pulse != iopS) || (dkp_sta & STA_ERR) )
747         {
748         return ( FALSE ) ;
749         }
750         sim_activate (uptr, dkp_rwait);                 /* schedule read or write request */
751         break;
752 
753     case FCCY_RECAL:                                    /* recalibrate */
754         uptr->FUNC = FCCY_SEEK ;                        /* save command */
755         uptr->CYL  = 0 ;
756 
757     case FCCY_SEEK:                                     /* seek */
758         if ( ! (uptr->flags & UNIT_ATT) )                /* not attached? */
759             {
760             dkp_sta = dkp_sta | STA_DONE | STA_ERR;     /* error */
761             }
762         else if ( uptr->CYL >= drv_tab[dtype].cyl )     /* bad cylinder? */
763             {
764             dkp_sta = dkp_sta | STA_ERR | STA_CYL;
765             }
766         if ( (pulse != iopP) || (dkp_sta & STA_ERR) )
767             {
768             return ( FALSE ) ;                          /* only 'P' pulse start seeks!  */
769             }
770 
771         /*  do the seek  */
772         /* must check for "do we support seeking bits" flag before setting SEEK0'ish bits!  */
773         dkp_sta = dkp_sta | (STA_SEEK0 >> u);           /* set seeking */
774         oldCyl = abs(oldCyl - uptr->CYL) ;
775         if ( (dkp_swait) && (! (oldCyl)) )              /* enforce minimum wait if req  */
776             oldCyl = 1 ;
777         sim_activate ( uptr, (dkp_swait * oldCyl) ) ;
778         break;
779         }                                               /* end case command */
780 
781 return ( TRUE ) ;                                       /* no error */
782 }
783 
784 
785 /* Unit service
786 
787    If seek done, put on cylinder;
788    else, do read or write
789    If controller was busy, clear busy, set done, interrupt
790 
791    Memory access: sectors are read into/written from an intermediate
792    buffer to allow word-by-word mapping of memory addresses on the
793    Eclipse.  This allows each word written to memory to be tested
794    for out of range.
795 */
796 
dkp_svc(UNIT * uptr)797 t_stat dkp_svc (UNIT *uptr)
798 {
799 int32 sa, bda;
800 int32 dx, pa, u;
801 int32 dtype, err, newsect, newsurf;
802 uint32 awc;
803 t_stat rval;
804 static uint16 tbuf[DKP_NUMWD];                          /* transfer buffer */
805 
806 
807 rval  = SCPE_OK;
808 dtype = GET_DTYPE (uptr->flags);                        /* get drive type */
809 u     = uptr - dkp_dev.units;                           /* get unit number */
810 
811 if (uptr->FUNC == FCCY_SEEK) {                          /* seek? */
812     if ( ! (uptr->flags & UNIT_ATT) )                   /* not attached? */
813         {
814         dkp_sta = dkp_sta | STA_DONE | STA_ERR;	        /* error (changed during queue time?) */
815         }
816     else if ( uptr->CYL >= drv_tab[dtype].cyl )         /* bad cylinder? */
817         {
818         dkp_sta = dkp_sta | STA_ERR | STA_CYL;
819         }
820     DEV_SET_DONE( INT_DKP ) ;
821     DEV_UPDATE_INTR ;
822     dkp_sta = (dkp_sta | (STA_SKDN0 >> u))              /* set seek done */
823                 & ~(STA_SEEK0 >> u);                    /* clear seeking */
824     if ( DKP_TRACE(2) )
825         {
826         fprintf( DKP_TRACE_FP,
827             "  [%s:%c  seek : %4d ] \r\n",
828             "DKP",
829             (char) (u + '0'),
830             (unsigned) (uptr->CYL)
831             ) ;
832         }
833     return SCPE_OK;
834     }
835 
836 /*  read or write  */
837 
838 if (((uptr->flags & UNIT_ATT) == 0) ||                  /* not attached? */
839     ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE)))
840     {
841     dkp_sta = dkp_sta | STA_DONE | STA_ERR;		/* error */
842     }
843 else if ( uptr->CYL >= drv_tab[dtype].cyl )             /* bad cylinder */
844     {
845     dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ;
846     dkp_sta  = dkp_sta | STA_ERR | STA_CYL;
847     DEV_SET_DONE( INT_DKP ) ;
848     DEV_UPDATE_INTR ;
849     return SCPE_OK ;
850     }
851 else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */
852     {
853     dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;   /* older drives may not even do this... */
854 /*  dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ;  /- newer disks give this error  */
855 /* set sector to some bad value and wait then exit?  */
856     }
857 else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect )   /* or bad sector? */
858     {
859 /*	dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;   /- older DG drives do not even give error(!), but we do */
860     dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ;  /* newer disks give this error  */
861     }
862 else {
863 err = 0 ;
864 do  {
865     if ( DKP_TRACE(3) )
866         {
867         fprintf( DKP_TRACE_FP,
868             "  [%s:%c  %-5s:  %3d / %2d / %2d   %06o ] \r\n",
869             "DKP",
870             (char) (u + '0'),
871             ((uptr->FUNC == FCCY_READ) ?
872                   "read"
873                 : ((uptr->FUNC == FCCY_WRITE) ?
874                       "write"
875                     : "<?>")
876             ),
877             (unsigned) (uptr->CYL),
878             (unsigned) (GET_SURF(dkp_ussc, dtype)),
879             (unsigned) (GET_SECT(dkp_ussc, dtype)),
880             (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */
881             ) ;
882         }
883 
884 
885     if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect )   /* or bad sector? */
886         {
887         /* sector overflows to 0 ;
888          * surface gets incremented
889          */
890         newsurf = GET_SURF(dkp_ussc, dtype) + 1 ;
891         newsurf = newsurf & ((drv_tab[dtype].newf) ? USSC_M_NSURFACE : USSC_M_OSURFACE) ;
892         DKP_UPDATE_USSC( type, 0, newsurf, 0 )
893 
894         if ( (GET_SURF(dkp_ussc, dtype)) >= drv_tab[dtype].surf )
895             {
896         /*  dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;   /- older drives may not even do this... */
897             dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ;  /*  newer disks give this error  */
898             /* DG retains overflowed surface number,
899              * other vendors have different/expanded options
900              */
901             break ;
902             }
903         }
904     sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype),
905          GET_SECT (dkp_ussc, dtype), dtype);            /* get disk block */
906     bda = sa * DKP_NUMWD * sizeof(uint16) ;             /* to words, bytes */
907     err = fseek (uptr->fileref, bda, SEEK_SET);         /* position drive */
908 
909     if (uptr->FUNC == FCCY_READ) {                      /* read? */
910             awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref);
911             for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0;
912             if ((err = ferror (uptr->fileref)))
913                 break;
914             for (dx = 0; dx < DKP_NUMWD; dx++) {            /* loop thru buffer */
915                 pa = MapAddr (dkp_map, (dkp_ma & AMASK));
916                 if (MEM_ADDR_OK (pa))
917                     M[pa] = tbuf[dx];
918                 dkp_ma = (dkp_ma + 1) & AMASK;
919                 }
920         }
921     else if (uptr->FUNC == FCCY_WRITE) {                /* write? */
922             for (dx = 0; dx < DKP_NUMWD; dx++) {        /* loop into buffer */
923                 pa = MapAddr (dkp_map, (dkp_ma & AMASK));
924                 tbuf[dx] = M[pa];
925                 dkp_ma = (dkp_ma + 1) & AMASK;
926                 }
927             fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref);
928             if ((err = ferror (uptr->fileref)))
929                 break;
930             }
931 
932     if (err != 0) {
933         perror ("DKP I/O error");
934         clearerr (uptr->fileref);
935         rval = SCPE_IOERR;
936         break ;
937         }
938 
939 newsect = GET_SECT (dkp_ussc, dtype) + 1 ;              /*  update next sector  */
940 newsurf = GET_SURF (dkp_ussc, dtype) ;                  /*  and next head	*/
941                                                         /*  (count set below)	*/
942 DKP_UPDATE_USSC( type, 1, newsurf, newsect )
943 }  /*  end read/write loop  */
944 
945     while ( (GET_COUNT(dkp_ussc)) ) ;
946     dkp_sta = dkp_sta | STA_DONE;                       /* set status */
947 
948     if ( DKP_TRACE(4) )
949            {
950            fprintf( DKP_TRACE_FP,
951                    "  [%s:%c  %-5s:  %3d / %2d / %2d   %06o ] \r\n",
952                    "DKP",
953                     (char) (u + '0'),
954                     "post",
955                     (unsigned) (uptr->CYL),
956                     (unsigned) (GET_SURF(dkp_ussc, dtype)),
957                     (unsigned) (GET_SECT(dkp_ussc, dtype)),
958                     (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */
959                     ) ;
960             }
961     }
962 
963 DEV_CLR_BUSY( INT_DKP ) ;
964 DEV_SET_DONE( INT_DKP ) ;
965 DEV_UPDATE_INTR ;
966 return rval;
967 }
968 
969 /* Reset routine */
970 
dkp_reset(DEVICE * dptr)971 t_stat dkp_reset (DEVICE *dptr)
972 {
973 int32 u;
974 UNIT *uptr;
975 
976 DEV_CLR_BUSY( INT_DKP ) ;                               /*  clear busy	*/
977 DEV_CLR_DONE( INT_DKP ) ;                               /*  clear done	*/
978 DEV_UPDATE_INTR ;                                       /*  update ints	*/
979 dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0;             /* clear registers */
980 dkp_diagmode = 0;                                       /* clear diagnostic mode */
981 dkp_map = 0;
982 for (u = 0; u < DKP_NUMDR; u++) {                       /* loop thru units */
983     uptr = dkp_dev.units + u;
984     sim_cancel (uptr);                                  /* cancel activity */
985     uptr->CYL = uptr->FUNC = 0;
986     }
987 return SCPE_OK;
988 }
989 
990 /* Attach routine (with optional autosizing) */
991 
dkp_attach(UNIT * uptr,char * cptr)992 t_stat dkp_attach (UNIT *uptr, char *cptr)
993 {
994 int32 i, p;
995 t_stat   r;
996 
997 uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;    /* restore capac */
998 r = attach_unit (uptr, cptr);                           /* attach */
999 if ((r != SCPE_OK) || !(uptr->flags & UNIT_AUTO))
1000     return r;
1001 if ((p = sim_fsize (uptr->fileref)) == 0)               /* get file size */
1002     return SCPE_OK;
1003 for (i = 0; drv_tab[i].sect != 0; i++) {
1004     if (p <= (drv_tab[i].size * (int32) sizeof (uint16))) {
1005         uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
1006         uptr->capac = drv_tab[i].size;
1007         return SCPE_OK;
1008         }
1009     }
1010 return SCPE_OK;
1011 }
1012 
1013 /* Set size command validation routine */
1014 
dkp_set_size(UNIT * uptr,int32 val,char * cptr,void * desc)1015 t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1016 {
1017 if (uptr->flags & UNIT_ATT)
1018     return SCPE_ALATT;
1019 uptr->capac = drv_tab[GET_DTYPE (val)].size;
1020 return SCPE_OK;
1021 }
1022 
1023 /* Bootstrap routine */
1024 
1025 #if defined(_OLD_CODE_)
1026 
1027 #define BOOT_START  02000
1028 #define BOOT_UNIT   02021
1029 #define BOOT_SEEK   02022
1030 #define BOOT_LEN    (sizeof(boot_rom) / sizeof(int32))
1031 
1032 static const int32 boot_rom[] = {
1033     0060233,                    /* NIOC 0,DKP           ; clear disk */
1034     0020420,                    /* LDA 0,USSC           ; unit, sfc, sec, cnt */
1035     0063033,                    /* DOC 0,DKP            ; select disk */
1036     0020417,                    /* LDA 0,SEKCMD         ; command, cylinder */
1037     0061333,                    /* DOAP 0,DKP           ; start seek */
1038     0024415,                    /* LDA 1,SEKDN */
1039     0060433,                    /* DIA 0,DKP            ; get status */
1040     0123415,                    /* AND# 1,0,SZR         ; skip if done */
1041     0000776,                    /* JMP .-2 */
1042     0102400,                    /* SUB 0,0              ; mem addr = 0 */
1043     0062033,                    /* DOB 0,DKP */
1044     0020411,                    /* LDA 0,REDCMD         ; command, cylinder */
1045     0061133,                    /* DOAS 0,DKP           ; start read */
1046     0060433,                    /* DIA 0, DKP           ; get status */
1047     0101113,                    /* MOVL# 0,0,SNC        ; skip if done */
1048     0000776,                    /* JMP .-2 */
1049     0000377,                    /* JMP 377 */
1050     0000016,                    /* USSC:   0.B1+0.B7+0.B11+16 */
1051     0175000,                    /* SEKCMD: 175000 */
1052     0074000,                    /* SEKDN:  074000 */
1053     0174000                     /* REDCMD: 174000 */
1054     };
1055 
1056 
dkp_boot(int32 unitno,DEVICE * dptr)1057 t_stat dkp_boot (int32 unitno, DEVICE *dptr)
1058 {
1059 int32 i, dtype;
1060 extern int32 saved_PC, SR;
1061 
1062 for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
1063 unitno = unitno & USSC_M_UNIT;
1064 dtype = GET_DTYPE (dkp_unit[unitno].flags);
1065 M[BOOT_UNIT] = M[BOOT_UNIT] | (unitno << USSC_V_UNIT);
1066 if (drv_tab[dtype].newf) M[BOOT_SEEK] = 0176000;
1067 saved_PC = BOOT_START;
1068 SR = 0100000 + DEV_DKP;
1069 return SCPE_OK;
1070 }
1071 
1072 #endif      /*  _OLD_CODE_  */
1073 
1074 
1075 
1076 #define BOOT_START  0375
1077 #define BOOT_LEN    (sizeof (boot_rom) / sizeof (int32))
1078 
1079 static const int32 boot_rom[] = {
1080       0062677                     /* IORST                ; reset the I/O system  */
1081     , 0060133                     /* NIOS DKP             ; start the disk        */
1082     , 0000377                     /* JMP 377              ; wait for the world    */
1083     } ;
1084 
1085 
dkp_boot(int32 unitno,DEVICE * dptr)1086 t_stat dkp_boot (int32 unitno, DEVICE *dptr)
1087 {
1088 int32   i;
1089 
1090 for (i = 0; i < BOOT_LEN; i++)
1091     M[BOOT_START + i] = (uint16) boot_rom[i];
1092 saved_PC = BOOT_START;
1093 SR = 0100000 + DEV_DKP;
1094 return SCPE_OK;
1095 }
1096