First Commit of my working state
[simh.git] / I7094 / i7094_dsk.c
1 /* i7094_dsk.c: 7631 file control (disk/drum) simulator
2
3 Copyright (c) 2005-2006, 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 dsk 7631 file control
27
28 The 7631 is a controller for multiple serial bit stream devices such as
29 disks or drums. It supports the
30
31 1301 fixed disk
32 1302 fixed disk
33 2302 fixed disk
34 7320 drum
35
36 The 7631 supports variable record formatting, user-specified record numbering,
37 and other complex features. Each track has
38
39 home address 1: the track number, 4 BCD digits (implicit)
40 home address 2: user-specified track identifier, 6 BCD chars
41 records 1..n: variably formatted records, each consisting of
42 record address: user-specified record identifier, 4 BCD digits
43 and 2 BCD characters
44 record data: 36b words
45
46 To deal with this, the simulator provides a container of 500 (7320/1301) or
47 1000 (1302/2302) words per track. Each track starts with home address 2
48 and then contains a variable number of records. Each record has a two-word
49 header followed by data:
50
51 word 0: record length without header
52 word 1: record address
53 word 2: start of data
54 word 2+n-1: end of data
55 word 2+n+2: start of next record
56
57 A record length of 0 indicates end of valid data on the track.
58
59 Orders to the 7631 are 10 BCD digits (60b), consisting of two words:
60
61 word 0: op-op-access-module-d1-d2
62 word 1: d3-d4-d5-d6-x-x
63
64 Depending on the opcode, d1:d6 can be a track number plus home address 2,
65 or a record number.
66
67 Status from the 7631 is also 10 BCD digits (60b), with 36b in the first
68 word, and 24b (plus 12b of zeroes) in the second.
69
70 Because modules can have two access arms that seek independently, each
71 module m is represented by two units: unit m for access 0 and unit m+10
72 for access 1. This requires tricky bookkeeping to be sure that the
73 service routine is using the 'right' unit.
74
75 Limitations of the simulation:
76
77 - HA2 and record address must be exactly 6 characters (one word)
78 - Record lengths must be exact multiples of 6 characters
79 - Seek timing is fixed rather than based on seek length
80 */
81
82 /* Definitions */
83
84 #include "i7094_defs.h"
85 #include <math.h>
86
87 #define DSK_NUMDR 10 /* modules/controller */
88 #define DSK_SNS (2 * DSK_NUMDR) /* dummy unit for sense */
89
90 /* Drive geometry */
91
92 #define DSK_WDSPT_7320 500 /* words/track */
93 #define DSK_WDSPT_1301 500
94 #define DSK_WDSPT_1302 1000
95 #define DSK_WDSPT_2302 1000
96 #define DSK_TRKPC_7320 400 /* tracks/cylinder */
97 #define DSK_TRKPC_1301 40
98 #define DSK_TRKPC_1302 40
99 #define DSK_TRKPC_2302 40
100 #define DSK_CYLPA_7320 1 /* cylinders/access */
101 #define DSK_CYLPA_1301 250
102 #define DSK_CYLPA_1302 250
103 #define DSK_CYLPA_2302 250
104 #define DSK_TRKPA_7320 (DSK_TRKPC_7320*DSK_CYLPA_7320) /* tracks/access */
105 #define DSK_TRKPA_1301 (DSK_TRKPC_1301*DSK_CYLPA_1301)
106 #define DSK_TRKPA_1302 (DSK_TRKPC_1302*DSK_CYLPA_1302)
107 #define DSK_TRKPA_2302 (DSK_TRKPC_2302*DSK_CYLPA_2302)
108 #define DSK_ACCPM_7320 1 /* access/module */
109 #define DSK_ACCPM_1301 1
110 #define DSK_ACCPM_1302 2
111 #define DSK_ACCPM_2302 2
112 #define DSK_FMCPT_7320 2868 /* format chars/track */
113 #define DSK_FMCPT_1301 2868
114 #define DSK_FMCPT_1302 5942
115 #define DSK_FMCPT_2302 5942
116 #define SIZE_7320 (DSK_WDSPT_7320*DSK_TRKPA_7320*DSK_ACCPM_7320)
117 #define SIZE_1301 (DSK_WDSPT_1301*DSK_TRKPA_1301*DSK_ACCPM_1301)
118 #define SIZE_1302 (DSK_WDSPT_1302*DSK_TRKPA_1302*DSK_ACCPM_1302)
119 #define SIZE_2302 (DSK_WDSPT_2302*DSK_TRKPA_2302*DSK_ACCPM_2302)
120 #define DSK_BUFSIZ (DSK_WDSPT_2302)
121 #define DSK_DA(a,t,d) (((((a) * dsk_tab[d].trkpa) + (t)) * dsk_tab[d].wdspt) *\
122 sizeof (t_uint64))
123
124 /* Unit flags */
125
126 #define UNIT_V_INOP0 (UNIT_V_UF + 0) /* acc 0 inoperative */
127 #define UNIT_V_INOP1 (UNIT_V_UF + 1) /* acc 1 inoperative */
128 #define UNIT_V_FMTE (UNIT_V_UF + 2) /* format enabled */
129 #define UNIT_V_TYPE (UNIT_V_UF + 3) /* drive type */
130 #define UNIT_M_TYPE 03
131 #define UNIT_INOP0 (1 << UNIT_V_INOP0)
132 #define UNIT_INOP1 (1 << UNIT_V_INOP1)
133 #define UNIT_FMTE (1 << UNIT_V_FMTE)
134 #define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE)
135 #define TYPE_7320 (0 << UNIT_V_TYPE)
136 #define TYPE_1301 (1 << UNIT_V_TYPE)
137 #define TYPE_1302 (2 << UNIT_V_TYPE)
138 #define TYPE_2302 (3 << UNIT_V_TYPE)
139 #define GET_DTYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE)
140 #define TRK u3 /* track */
141 #define SKF u4 /* seek in progress */
142
143 /* Track/record structure */
144
145 #define THA2 0 /* home address 2 */
146 #define HA2_MASK 0777700000000 /* two chars checked */
147 #define T1STREC 1 /* start of records */
148 #define RLNT 0 /* record length */
149 #define RADDR 1 /* record address */
150 #define RDATA 2 /* start of data */
151 #define REC_MASK 0171717177777 /* 4 digits, 2 chars */
152
153 /* Command word (60b) - 10 BCD digits */
154
155 #define OP1 0 /* opcode */
156 #define OP2 1
157 #define ACC 2 /* access */
158 #define MOD 3 /* module */
159 #define T1 4 /* track */
160 #define T2 5
161 #define T3 6
162 #define T4 7
163
164 /* Disk states */
165
166 #define DSK_IDLE 0
167
168 /* Status word (60b) */
169
170 #define DSKS_PCHK 004000000000000000000 /* prog check */
171 #define DSKS_DCHK 002000000000000000000 /* data check */
172 #define DSKS_EXCC 001000000000000000000 /* exc cond */
173 #define DSKS_INVS 000200000000000000000 /* invalid seq */
174 #define DSKS_INVC 000040000000000000000 /* invalid opcode */
175 #define DSKS_FMTC 000020000000000000000 /* format check */
176 #define DSKS_NRCF 000010000000000000000 /* no record found */
177 #define DSKS_INVA 000002000000000000000 /* invalid address */
178 #define DSKS_RSPC 000000400000000000000 /* response check */
179 #define DSKS_CMPC 000000200000000000000 /* compare check */
180 #define DSKS_PARC 000000100000000000000 /* parity check */
181 #define DSKS_ACCI 000000020000000000000 /* access inoperative */
182 #define DSKS_ACCN 000000004000000000000 /* access not ready */
183 #define DSKS_DSKE 000000002000000000000 /* disk error */
184 #define DSKS_FILE 000000001000000000000 /* file error */
185 #define DSKS_6B 000000000040000000000 /* six bit mode */
186 #define DSKS_ATN0 000000000002000000000 /* attention start */
187 #define DSKS_PALL 000777000000000000000
188 #define DSKS_DALL 000000740000000000000
189 #define DSKS_EALL 000000037000000000000
190 #define DSKS_ALLERR 007777777000000000000
191
192 /* Commands - opcode 0 */
193
194 #define DSKC_NOP 0x00
195 #define DSKC_RLS 0x04
196 #define DSKC_8B 0x08
197 #define DSKC_6B 0x09
198
199 /* Commands - opcode 8 */
200
201 #define DSKC_SEEK 0x0 /* seek */
202 #define DSKC_SREC 0x2 /* single record */
203 #define DSKC_WFMT 0x3 /* write format */
204 #define DSKC_TNOA 0x4 /* track no addr */
205 #define DSKC_CYL 0x5 /* cyl no addr */
206 #define DSKC_WCHK 0x6 /* write check */
207 #define DSKC_ACCI 0x7 /* set acc inoperative */
208 #define DSKC_TWIA 0x8 /* track with addr */
209 #define DSKC_THA 0x9 /* track home addr */
210
211 /* CTSS record structure */
212
213 #define CTSS_HA2 0676767676767 /* =HXXXXXX */
214 #define CTSS_RLNT 435 /* data record */
215 #define CTSS_D1LNT 31 /* padding */
216 #define CTSS_D2LNT 14
217 #define CTSS_D3LNT 16
218 #define CTSS_DLLNT 1
219 #define CTSS_RA1 2
220 #define CTSS_RA2 8
221
222 /* Data and declarations */
223
224 typedef struct {
225 char *name;
226 uint32 accpm; /* acc/module: 1 or 2 */
227 uint32 wdspt; /* wds/track: 500 or 1000 */
228 uint32 trkpc; /* trks/cyl: 1 or 40 */
229 uint32 trkpa; /* trks/acc: 400 or 10000 */
230 uint32 fchpt; /* format ch/track */
231 uint32 size;
232 } DISK_TYPE;
233
234 const DISK_TYPE dsk_tab[4] = {
235 { "7320", DSK_ACCPM_7320, DSK_WDSPT_7320,
236 DSK_TRKPC_7320, DSK_TRKPA_7320, DSK_FMCPT_7320, SIZE_7320 },
237 { "1301", DSK_ACCPM_1301, DSK_WDSPT_1301,
238 DSK_TRKPC_1301, DSK_TRKPA_1301, DSK_FMCPT_1301, SIZE_1301 },
239 { "1302", DSK_ACCPM_1302, DSK_WDSPT_1302,
240 DSK_TRKPC_1302, DSK_TRKPA_1302, DSK_FMCPT_1302, SIZE_1302 },
241 { "2302", DSK_ACCPM_2302, DSK_WDSPT_2302,
242 DSK_TRKPC_2302, DSK_TRKPA_2302, DSK_FMCPT_2302, SIZE_2302 }
243 };
244
245 /* 7320/1301 format track characters */
246
247 uint8 fmt_thdr_7320[] = {
248 4, 4, 4, /* gap 1 */
249 3, 3, 3, 3, 3, 3, 3, 3, 3, /* ha1 */
250 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, /* gap 2 */
251 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* ha2 */
252 };
253 uint8 fmt_rhdr_7320[] = {
254 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* x gap */
255 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* record addr */
256 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* y gap */
257 1, 1, 1, 1, 0 /* record ovhd */
258 };
259
260 /* 1302/2302 format track characters */
261
262 uint8 fmt_thdr_1302[] = {
263 4, 4, 4, 4, 4, 4, /* gap 1 */
264 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* ha1 */
265 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, /* gap 2 */
266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* ha2 */
267 };
268 uint8 fmt_rhdr_1302[] = {
269 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* x gap */
270 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* record addr */
271 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* y gap */
272 1, 1, 1, 1, 1, 1, 1, 0 /* record ovhd */
273 };
274
275 /* CTSS 7320/1301 track format table */
276
277 uint32 ctss_fmt_7320[] = {
278 CTSS_RLNT, CTSS_D3LNT, CTSS_DLLNT, 0
279 };
280
281 /* CTSS 1302/2302 track format table */
282
283 uint32 ctss_fmt_1302[] = {
284 CTSS_RLNT, CTSS_D1LNT, CTSS_D2LNT,
285 CTSS_RLNT, CTSS_D3LNT, CTSS_DLLNT, 0
286 };
287
288 uint32 dsk_ch = CH_C; /* disk channel */
289 uint32 dsk_acc = 0; /* access */
290 uint32 dsk_mod = 0; /* module */
291 uint32 dsk_sta = 0; /* disk state */
292 uint32 dsk_mode = 0; /* I/O mode */
293 uint32 dsk_wchk = 0; /* write check flag */
294 uint32 dsk_ctime = 10; /* command time */
295 uint32 dsk_stime = 1000; /* seek time */
296 uint32 dsk_rtime = 100; /* rotational latency */
297 uint32 dsk_wtime = 2; /* word time */
298 uint32 dsk_gtime = 5; /* gap time */
299 uint32 dsk_rbase = 0; /* record tracking */
300 uint32 dsk_rptr = 0;
301 uint32 dsk_rlim = 0;
302 uint32 dsk_stop = 0;
303 uint32 dsk_fmt_cntr = 0; /* format counter */
304 t_uint64 dsk_rec = 0; /* rec/home addr (36b) */
305 t_uint64 dsk_sns = 0; /* sense data (60b) */
306 t_uint64 dsk_cmd = 0; /* BCD command (60b) */
307 t_uint64 dsk_chob = 0; /* chan output buffer */
308 uint32 dsk_chob_v = 0; /* valid */
309 t_uint64 dsk_buf[DSK_BUFSIZ]; /* transfer buffer */
310
311 extern uint32 ch_req;
312
313 t_stat dsk_svc (UNIT *uptr);
314 t_stat dsk_svc_sns (UNIT *uptr);
315 t_stat dsk_reset (DEVICE *dptr);
316 t_stat dsk_attach (UNIT *uptr, char *cptr);
317 t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
318 t_stat dsk_chsel (uint32 ch, uint32 sel, uint32 unit);
319 t_stat dsk_chwr (uint32 ch, t_uint64 val, uint32 flags);
320 t_stat dsk_new_cmd (uint32 ch, t_uint64 cmd);
321 t_stat dsk_uend (uint32 ch, t_uint64 stat);
322 t_stat dsk_recad (uint32 trk, uint32 rec, uint32 acc, uint32 mod, t_uint64 *res);
323 t_uint64 dsk_acc_atn (uint32 u);
324 t_stat dsk_init_trk (UNIT *udptr, uint32 trk);
325 t_stat dsk_xfer_done (UNIT *uaptr, uint32 dtyp);
326 t_stat dsk_wr_trk (UNIT *uptr, uint32 trk);
327 t_bool dsk_get_fmtc (uint32 dtyp, uint8 *fc);
328 t_bool dsk_qdone (uint32 ch);
329 t_stat dsk_show_format (FILE *st, UNIT *uptr, int32 val, void *desc);
330
331 /* DSK data structures
332
333 dsk_dev DSK device descriptor
334 dsk_unit DSK unit descriptor
335 dsk_reg DSK register list
336 */
337
338 DIB dsk_dib = { &dsk_chsel, &dsk_chwr };
339
340 UNIT dsk_unit[] = {
341 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
342 TYPE_2302, SIZE_2302) },
343 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
344 TYPE_2302, SIZE_2302) },
345 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
346 TYPE_7320, SIZE_7320) },
347 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
348 UNIT_DIS+TYPE_2302, SIZE_2302) },
349 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
350 TYPE_2302, SIZE_2302) },
351 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
352 TYPE_2302, SIZE_2302) },
353 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
354 UNIT_DIS+TYPE_2302, SIZE_2302) },
355 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
356 UNIT_DIS+TYPE_2302, SIZE_2302) },
357 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
358 UNIT_DIS+TYPE_2302, SIZE_2302) },
359 { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
360 UNIT_DIS+TYPE_2302, SIZE_2302) },
361 { UDATA (&dsk_svc, UNIT_DIS, 0) },
362 { UDATA (&dsk_svc, UNIT_DIS, 0) },
363 { UDATA (&dsk_svc, UNIT_DIS, 0) },
364 { UDATA (&dsk_svc, UNIT_DIS, 0) },
365 { UDATA (&dsk_svc, UNIT_DIS, 0) },
366 { UDATA (&dsk_svc, UNIT_DIS, 0) },
367 { UDATA (&dsk_svc, UNIT_DIS, 0) },
368 { UDATA (&dsk_svc, UNIT_DIS, 0) },
369 { UDATA (&dsk_svc, UNIT_DIS, 0) },
370 { UDATA (&dsk_svc, UNIT_DIS, 0) },
371 { UDATA (&dsk_svc_sns, UNIT_DIS, 0) }
372 };
373
374 REG dsk_reg[] = {
375 { ORDATA (STATE, dsk_sta, 6) },
376 { ORDATA (ACCESS, dsk_acc, 1) },
377 { ORDATA (MODULE, dsk_mod, 4) },
378 { ORDATA (RECORD, dsk_rec, 36) },
379 { ORDATA (MODE, dsk_mode, 4) },
380 { ORDATA (SENSE, dsk_sns, 60) },
381 { ORDATA (BCDCMD, dsk_cmd, 60) },
382 { ORDATA (CHOB, dsk_chob, 36) },
383 { FLDATA (CHOBV, dsk_chob_v, 0) },
384 { FLDATA (STOP, dsk_stop, 0) },
385 { DRDATA (FCNTR, dsk_fmt_cntr, 13) },
386 { BRDATA (BUF, dsk_buf, 8, 36, DSK_BUFSIZ) },
387 { DRDATA (RBASE, dsk_rbase, 10), REG_RO },
388 { DRDATA (RPTR, dsk_rptr, 10), REG_RO },
389 { DRDATA (RLIM, dsk_rlim, 10), REG_RO },
390 { DRDATA (CHAN, dsk_ch, 3), REG_HRO },
391 { DRDATA (STIME, dsk_stime, 24), REG_NZ + PV_LEFT },
392 { DRDATA (RTIME, dsk_rtime, 24), REG_NZ + PV_LEFT },
393 { DRDATA (WTIME, dsk_wtime, 24), REG_NZ + PV_LEFT },
394 { DRDATA (GTIME, dsk_gtime, 24), REG_NZ + PV_LEFT },
395 { DRDATA (CTIME, dsk_ctime, 24), REG_NZ + PV_LEFT },
396 { URDATA (TRACK, dsk_unit[0].TRK, 10, 14, 0,
397 2 * DSK_NUMDR, PV_LEFT) },
398 { URDATA (SEEKF, dsk_unit[0].SKF, 10, 1, 0,
399 2 * DSK_NUMDR, PV_LEFT | REG_HRO) },
400 { URDATA (CAPAC, dsk_unit[0].capac, 10, T_ADDR_W, 0,
401 DSK_NUMDR, PV_LEFT | REG_HRO) },
402 { NULL }
403 };
404
405 MTAB dsk_mtab[] = {
406 { UNIT_INOP0 + UNIT_INOP1, 0, "operational", "OPERATIONAL" },
407 { UNIT_INOP0 + UNIT_INOP1, UNIT_INOP0, "access 0 inoperative", NULL },
408 { UNIT_INOP0 + UNIT_INOP1, UNIT_INOP1, "access 1 inoperative", NULL },
409 { UNIT_FMTE, UNIT_FMTE, "formating enabled", "FORMAT" },
410 { UNIT_FMTE, 0, "formating disabled", "NOFORMAT" },
411 { UNIT_TYPE, TYPE_7320, "7320", "7320", &dsk_set_size },
412 { UNIT_TYPE, TYPE_1301, "1301", "1301", &dsk_set_size },
413 { UNIT_TYPE, TYPE_1302, "1302", "1302", &dsk_set_size },
414 { UNIT_TYPE, TYPE_2302, "2302", "2302", &dsk_set_size },
415 { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,
416 NULL, &ch_show_chan, NULL },
417 { MTAB_XTD|MTAB_VUN|MTAB_NMO, 1, "FORMAT", NULL,
418 NULL, &dsk_show_format, NULL },
419 { 0 }
420 };
421
422 DEVICE dsk_dev = {
423 "DSK", dsk_unit, dsk_reg, dsk_mtab,
424 (DSK_NUMDR * 2) + 1, 10, 24, 1, 8, 36,
425 NULL, NULL, &dsk_reset,
426 NULL, &dsk_attach, NULL,
427 &dsk_dib, DEV_DIS
428 };
429
430 /* Disk channel select, from 7909 channel program */
431
432 t_stat dsk_chsel (uint32 ch, uint32 sel, uint32 unit)
433 {
434 uint32 u;
435
436 dsk_ch = ch;
437 if (dsk_sta != DSK_IDLE) dsk_uend (ch, DSKS_INVS); /* not idle? seq check */
438
439 switch (sel) {
440
441 case CHSL_CTL: /* control */
442 ch_req |= REQ_CH (ch); /* request channel */
443 break;
444
445 case CHSL_SNS: /* sense */
446 if (sim_is_active (&dsk_unit[DSK_SNS])) /* already sensing? */
447 return dsk_uend (ch, DSKS_INVS); /* sequence error */
448 sim_activate (&dsk_unit[DSK_SNS], dsk_ctime); /* set timer */
449 dsk_stop = 0;
450 break;
451
452 case CHSL_RDS: /* read */
453 if (dsk_mode == DSKC_WFMT) /* write format? */
454 return dsk_uend (ch, DSKS_INVS); /* sequence error */
455 case CHSL_WRS: /* write */
456 if (dsk_mode == 0) dsk_uend (ch, DSKS_INVS); /* no mode? seq check */
457 if (dsk_mode == DSKC_WFMT) sel = CHSL_FMT; /* format? fake sel */
458 u = (dsk_acc * DSK_NUMDR) + dsk_mod; /* access unit number */
459 if (sim_is_active (&dsk_unit[u])) /* access in use? */
460 return dsk_uend (ch, DSKS_ACCN); /* access not ready */
461 sim_activate (&dsk_unit[u], dsk_rtime); /* rotational time */
462 break;
463
464 default: /* other */
465 return STOP_ILLIOP;
466 }
467
468 dsk_sta = sel; /* set new state */
469 return SCPE_OK;
470 }
471
472 /* Disk channel write, from 7909 channel program */
473
474 t_stat dsk_chwr (uint32 ch, t_uint64 val, uint32 stopf)
475 {
476 if (stopf) dsk_stop = 1; /* stop? */
477
478 else {
479 val = val & DMASK;
480 switch (dsk_sta) { /* case on state */
481
482 case CHSL_CTL: /* control */
483 dsk_cmd = val << 24;
484 if (val & 0100000000000) { /* need 2nd word? */
485 ch_req |= REQ_CH (ch); /* req ch for 2nd */
486 dsk_sta = CHSL_CTL|CHSL_2ND; /* next state */
487 return SCPE_OK;
488 }
489 return dsk_new_cmd (ch, dsk_cmd); /* no, do cmd */
490
491 case CHSL_CTL|CHSL_2ND: /* 2nd control */
492 dsk_cmd |= (val >> 12);
493 return dsk_new_cmd (ch, dsk_cmd); /* do cmd */
494
495 default:
496 dsk_chob = val; /* store data */
497 dsk_chob_v = 1; /* set valid */
498 }
499 }
500
501 return SCPE_OK;
502 }
503
504 /* New command - end of CTL sequence */
505
506 t_stat dsk_new_cmd (uint32 ch, t_uint64 cmd)
507 {
508 uint32 i, d, a, m, u, trk, dtyp, bcd[8];
509
510 ch_req |= REQ_CH (ch); /* req ch for end */
511 ch9_set_end (ch, 0); /* set end flag */
512 dsk_sta = DSK_IDLE; /* ctrl is idle */
513
514 for (i = 0; i < 8; i++) { /* get chars from cmd */
515 d = (uint32) (cmd >> (6 * (9 - i))) & BCD_MASK;
516 if (d == BCD_ZERO) d = 0;
517 else if (d == 0) d = BCD_ZERO; /* BCD zero cvt */
518 bcd[i] = d;
519 }
520
521 if (bcd[OP1] == 0) { /* cmd = 0x? */
522
523 switch (bcd[OP2]) { /* case on x */
524
525 case DSKC_NOP: /* nop */
526 case DSKC_RLS: /* release */
527 break;
528
529 case DSKC_8B: /* 8b mode */
530 dsk_sns &= ~DSKS_6B;
531 break;
532
533 case DSKC_6B: /* 6b mode */
534 dsk_sns |= DSKS_6B;
535 break;
536
537 default: /* unknown */
538 return dsk_uend (ch, DSKS_INVC); /* invalid opcode */
539 } /* end case op2 */
540 return SCPE_OK;
541 } /* end if */
542
543 else if (bcd[OP1] == 8) { /* cmd = 8x? */
544
545 a = bcd[ACC]; /* get access, */
546 m = bcd[MOD]; /* module */
547 u = (a * DSK_NUMDR) + m; /* unit for access */
548 if ((m > DSK_NUMDR) || /* invalid module? */
549 (dsk_unit[m].flags & UNIT_DIS)) /* disabled module? */
550 return dsk_uend (ch, DSKS_ACCI);
551 dtyp = GET_DTYPE (dsk_unit[m].flags); /* get drive type */
552 if ((a >= dsk_tab[dtyp].accpm) || /* invalid access? */
553 (dsk_unit[m].flags & (UNIT_INOP0 << a))) /* access inop? */
554 return dsk_uend (ch, DSKS_ACCI);
555 if ((bcd[T1] > 9) || (bcd[T2] > 9) || (bcd[T3] > 9) || (bcd[T4] > 9))
556 trk = dsk_tab[dtyp].trkpa + 1; /* bad track */
557 else trk = (((((bcd[T1] * 10) + bcd[T2]) * 10) + bcd[T3]) * 10) + bcd[T4];
558
559 if (bcd[OP2] == DSKC_WCHK) { /* write check */
560 if (dsk_mode == 0) /* no prior operation? */
561 return dsk_uend (ch, DSKS_INVS);
562 bcd[OP2] = dsk_mode; /* use prior mode */
563 dsk_wchk = 1; /* set write check */
564 }
565 else dsk_wchk = 0;
566 dsk_sns &= ~(DSKS_ALLERR | dsk_acc_atn (u)); /* clear err, atn */
567 dsk_stop = 0; /* clear stop */
568
569 switch (bcd[OP2]) {
570
571 case DSKC_SEEK: /* seek */
572 if ((trk >= dsk_tab[dtyp].trkpa) && /* inv track? */
573 ((dtyp == TYPE_7320) || /* drum or not CE? */
574 (bcd[T1] > 9) || (bcd[T2] != BCD_AT) ||
575 (bcd[T3] > 9) || (bcd[T4] > 9)))
576 return dsk_uend (ch, DSKS_INVA);
577 if (sim_is_active (&dsk_unit[u])) /* selected acc busy? */
578 return dsk_uend (ch, DSKS_ACCN);
579 dsk_unit[u].SKF = 1; /* set seeking flag */
580 dsk_unit[u].TRK = trk; /* sel acc on cyl */
581 sim_activate (&dsk_unit[u], dsk_stime); /* seek */
582 dsk_mode = 0; /* clear I/O mode */
583 return SCPE_OK;
584
585 case DSKC_ACCI: /* access inoperative */
586 dsk_unit[m].flags |= (UNIT_INOP0 << a); /* set correct flag */
587 dsk_mode = 0; /* clear I/O mode */
588 return SCPE_OK;
589
590 case DSKC_SREC: /* single record */
591 break; /* no verification */
592
593 case DSKC_WFMT: /* format */
594 if (!(dsk_unit[m].flags & UNIT_FMTE)) /* format enabled? */
595 return dsk_uend (ch, DSKS_FMTC); /* no, error */
596 case DSKC_TNOA: /* track no addr */
597 case DSKC_CYL: /* cyl no addr */
598 case DSKC_TWIA: /* track with addr */
599 case DSKC_THA: /* track home addr */
600 if (trk != (uint32) dsk_unit[u].TRK) /* on track? */
601 return dsk_uend (ch, DSKS_NRCF);
602 break;
603
604 default:
605 return dsk_uend (ch, DSKS_INVC); /* invalid opcode */
606 }
607
608 dsk_acc = a; /* save access */
609 dsk_mod = m; /* save module */
610 dsk_rec = cmd & DMASK; /* save rec/home addr */
611 dsk_mode = bcd[OP2]; /* save mode */
612 return SCPE_OK;
613 }
614
615 return dsk_uend (ch, DSKS_INVC); /* invalid opcode */
616 }
617
618 /* Sense unit service */
619
620 t_stat dsk_svc_sns (UNIT *uptr)
621 {
622 t_uint64 dat;
623
624 switch (dsk_sta) { /* case on state */
625
626 case CHSL_SNS: /* prepare data */
627 dsk_buf[0] = (dsk_sns >> 24) & DMASK; /* buffer is 2 words */
628 dsk_buf[1] = (dsk_sns << 12) & DMASK;
629 dsk_rptr = 0;
630 dsk_rlim = 2;
631 dsk_sta = CHSL_SNS|CHSL_2ND; /* 2nd state */
632 break;
633
634 case CHSL_SNS|CHSL_2ND: /* second state */
635 if (dsk_rptr >= dsk_rlim) { /* end of buffer? */
636 ch9_set_end (dsk_ch, 0); /* set end */
637 ch_req |= REQ_CH (dsk_ch); /* request channel */
638 dsk_sta = CHSL_SNS|CHSL_3RD; /* 3rd state */
639 sim_activate (uptr, dsk_ctime); /* longer wait */
640 return SCPE_OK;
641 }
642 dat = dsk_buf[dsk_rptr++]; /* get word */
643 if (!dsk_stop) ch9_req_rd (dsk_ch, dat); /* send wd to chan */
644 break;
645
646 case CHSL_SNS|CHSL_3RD: /* 3rd state */
647 if (dsk_qdone (dsk_ch)) return SCPE_OK; /* done? exit */
648 dsk_sta = CHSL_SNS; /* repeat sequence */
649 break;
650 }
651
652 sim_activate (uptr, dsk_wtime); /* sched next */
653 return SCPE_OK;
654 }
655
656 /* Seek, read, write unit service */
657
658 t_stat dsk_svc (UNIT *uaptr)
659 {
660 uint32 i, dtyp, trk;
661 uint8 fc, *format;
662 t_uint64 rdat;
663 UNIT *udptr;
664 t_stat r;
665
666 if (uaptr->SKF) { /* seeking? */
667 uint32 u = uaptr - dsk_dev.units; /* get unit */
668 uaptr->SKF = 0; /* seek done */
669 dsk_sns |= dsk_acc_atn (u); /* set atn bit */
670 ch9_set_atn (dsk_ch); /* set atn flag */
671 return SCPE_OK;
672 }
673
674 udptr = dsk_dev.units + dsk_mod; /* data unit */
675 if (udptr->flags & (UNIT_INOP0 << dsk_acc)) /* acc inoperative? */
676 return dsk_uend (dsk_ch, DSKS_ACCI); /* error */
677 if ((udptr->flags & UNIT_ATT) == 0) { /* not attached? */
678 dsk_uend (dsk_ch, DSKS_ACCI); /* error */
679 return SCPE_UNATT;
680 }
681
682 dtyp = GET_DTYPE (udptr->flags); /* get data drive type */
683 trk = uaptr->TRK; /* get access track */
684
685 switch (dsk_sta) { /* case on state */
686
687 case CHSL_RDS: /* read start */
688 if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */
689 return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */
690 }
691 dsk_sta = CHSL_RDS|CHSL_2ND; /* next state */
692 break;
693
694 case CHSL_RDS|CHSL_2ND: /* read data transmit */
695 if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */
696 if (r != ERR_ENDRC) return r; /* error? */
697 dsk_sta = CHSL_RDS|CHSL_3RD; /* next state */
698 sim_activate (uaptr, dsk_gtime); /* gap time */
699 return SCPE_OK;
700 }
701 rdat = dsk_buf[dsk_rptr++]; /* get word */
702 if (dsk_rptr == T1STREC) dsk_rptr++; /* if THA, skip after HA */
703 if (!dsk_stop) ch9_req_rd (dsk_ch, rdat); /* give to channel */
704 break;
705
706 case CHSL_RDS|CHSL_3RD: /* read end rec/trk */
707 if (dsk_qdone (dsk_ch)) return SCPE_OK; /* done? exit */
708 dsk_sta = CHSL_RDS; /* repeat sequence */
709 break;
710
711 case CHSL_WRS: /* write start */
712 if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */
713 return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */
714 }
715 ch_req |= REQ_CH (dsk_ch); /* first request */
716 dsk_sta = CHSL_WRS|CHSL_2ND; /* next state */
717 dsk_chob = 0; /* clr, inval buffer */
718 dsk_chob_v = 0;
719 break;
720
721 case CHSL_WRS|CHSL_2ND: /* write data transmit */
722 if (dsk_chob_v) dsk_chob_v = 0; /* valid? clear */
723 else if (!dsk_stop) ch9_set_ioc (dsk_ch); /* no, no stop? io chk */
724 if (dsk_wchk) { /* write check? */
725 if (dsk_buf[dsk_rptr++] != dsk_chob) /* data mismatch? */
726 return dsk_uend (dsk_ch, DSKS_CMPC); /* error */
727 }
728 else dsk_buf[dsk_rptr++] = dsk_chob; /* write, store word */
729 if (dsk_rptr == T1STREC) dsk_rptr++; /* if THA, skip after HA */
730 if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */
731 if (r != ERR_ENDRC) return r; /* error? */
732 dsk_sta = CHSL_WRS|CHSL_3RD; /* next state */
733 sim_activate (uaptr, dsk_gtime); /* gap time */
734 return SCPE_OK;
735 }
736 if (!dsk_stop) ch_req |= REQ_CH (dsk_ch); /* more to do */
737 break;
738
739 case CHSL_WRS|CHSL_3RD: /* write done */
740 if (!dsk_wchk) { /* if write */
741 if (r = dsk_wr_trk (udptr, trk)) return r; /* write track; err? */
742 }
743 if (dsk_qdone (dsk_ch)) return SCPE_OK; /* done? exit */
744 dsk_sta = CHSL_WRS; /* repeat sequence */
745 break;
746
747 /* Formatting takes place in five stages
748
749 1. Clear the track buffer, request the first word from the channel
750 2. Match characters against the fixed overhead (HA1, HA2, and gaps)
751 3. Match characters against the per-record overhead (RA and gaps)
752 4. Count the characters defining the record length
753 5. See if the next character is end or gap; if gap, return to stage 3
754
755 This formating routine is not exact. It checks whether the format
756 will fit in the container, not whether the format would fit on a
757 real 7320, 1301, 1302, or 2302. */
758
759 case CHSL_FMT: /* initialization */
760 for (i = 0; i < DSK_BUFSIZ; i++) dsk_buf[i] = 0;/* clear track buf */
761 dsk_rbase = T1STREC; /* init record ptr */
762 dsk_rptr = 0; /* init format ptr */
763 dsk_fmt_cntr = 0; /* init counter */
764 ch_req |= REQ_CH (dsk_ch); /* request channel */
765 dsk_sta = CHSL_FMT|CHSL_2ND; /* next state */
766 dsk_chob = 0; /* clr, inval buffer */
767 dsk_chob_v = 0;
768 break;
769
770 case CHSL_FMT|CHSL_2ND: /* match track header */
771 if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301))
772 format = fmt_thdr_7320;
773 else format = fmt_thdr_1302;
774 if (!dsk_get_fmtc (dtyp, &fc)) return SCPE_OK; /* get fmt char; err? */
775 if (fc != format[dsk_rptr++]) /* mismatch? */
776 return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */
777 if (format[dsk_rptr] == 0) { /* end format? */
778 dsk_sta = CHSL_FMT|CHSL_3RD; /* next state */
779 dsk_rptr = 0; /* reset format ptr */
780 }
781 break;
782
783 case CHSL_FMT|CHSL_3RD: /* match record header */
784 if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301))
785 format = fmt_rhdr_7320;
786 else format = fmt_rhdr_1302;
787 if (!dsk_get_fmtc (dtyp, &fc)) return SCPE_OK; /* get fmt char; err? */
788 if (fc != format[dsk_rptr++]) /* mismatch? */
789 return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */
790 if (format[dsk_rptr] == 0) { /* end format? */
791 dsk_sta = CHSL_FMT|CHSL_4TH; /* next state */
792 dsk_rlim = 0; /* reset record ctr */
793 }
794 break;
795
796 case CHSL_FMT|CHSL_4TH: /* count record size */
797 if (!dsk_get_fmtc (dtyp, &fc)) return SCPE_OK; /* get fmt char; err? */
798 if (fc == BCD_ONE) dsk_rlim++; /* more record? */
799 else {
800 uint32 rsiz = dsk_rlim / 6; /* rec size words */
801 if ((fc != BCD_TWO) || /* improper end? */
802 (rsiz == 0) || /* smaller than min? */
803 ((dsk_rlim % 6) != 0) || /* not multiple of 6? */
804 ((dsk_rbase + rsiz + RDATA) >= dsk_tab[dtyp].wdspt))
805 return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */
806 dsk_buf[dsk_rbase + RLNT] = rsiz; /* record rec lnt */
807 dsk_rbase = dsk_rbase + rsiz + RDATA; /* new rec start */
808 dsk_sta = CHSL_FMT|CHSL_5TH; /* next state */
809 }
810 break;
811
812 case CHSL_FMT|CHSL_5TH: /* record or track end */
813 if (!dsk_get_fmtc (dtyp, &fc)) return SCPE_OK; /* get fmt char; err? */
814 if (fc == BCD_TWO) { /* back to record header? */
815 dsk_rptr = 2; /* already done 2 chars */
816 dsk_sta = CHSL_FMT|CHSL_3RD; /* record header state */
817 }
818 else if (fc != BCD_ONE) dsk_uend (dsk_ch, DSKS_FMTC); /* format check */
819 else {
820 if (!dsk_wchk) { /* actual write? */
821 trk = trk - (trk % dsk_tab[dtyp].trkpc); /* cyl start */
822 for (i = 0; i < dsk_tab[dtyp].trkpc; i++) { /* do all tracks */
823 if (r = dsk_wr_trk (udptr, trk + i)) /* wr track; err? */
824 return r;
825 }
826 }
827 ch9_set_end (dsk_ch, 0); /* set end */
828 ch_req |= REQ_CH (dsk_ch); /* request channel */
829 dsk_sta = DSK_IDLE; /* disk is idle */
830 return SCPE_OK; /* done */
831 }
832 break;
833
834 default:
835 return SCPE_IERR;
836 }
837
838 sim_activate (uaptr, dsk_wtime);
839 return SCPE_OK;
840 }
841
842 /* Initialize data transfer
843
844 Inputs:
845 udptr = pointer to data unit
846 trk = track to read
847 Outputs:
848 dsk_buf contains track specified by trk
849 dsk_rbase, dsk_rptr, dsk_rlim are initialized
850 Errors:
851 SCPE_IOERR = I/O error (fatal, uend)
852 ERR_NRCF = no record found (HA2 or record number mismatch, uend)
853 STOP_INVFMT = invalid format (fatal, uend)
854 */
855
856 t_stat dsk_init_trk (UNIT *udptr, uint32 trk)
857 {
858 uint32 k, da, dtyp, rlnt;
859
860 dtyp = GET_DTYPE (udptr->flags); /* get drive type */
861 da = DSK_DA (dsk_acc, trk, dtyp); /* get disk address */
862 sim_fseek (udptr->fileref, da, SEEK_SET); /* read track */
863 k = sim_fread (dsk_buf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, udptr->fileref);
864 if (ferror (udptr->fileref)) { /* error? */
865 perror ("DSK I/O error");
866 clearerr (udptr->fileref);
867 dsk_uend (dsk_ch, DSKS_DSKE);
868 return SCPE_IOERR;
869 }
870 for ( ; k < dsk_tab[dtyp].wdspt; k++) dsk_buf[k] = 0; /* zero fill */
871 dsk_rbase = T1STREC; /* record base */
872 rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */
873 dsk_rlim = dsk_rbase + rlnt + RDATA; /* end */
874 if ((rlnt == 0) || (dsk_rlim >= dsk_tab[dtyp].wdspt)) { /* invalid record? */
875 dsk_uend (dsk_ch, DSKS_FMTC);
876 return STOP_INVFMT;
877 }
878 if (dsk_mode != DSKC_SREC) { /* not single record? */
879 if (dsk_mode == DSKC_THA) dsk_rptr = 0; /* trk home addr? */
880 else {
881 if (((dsk_rec << 24) ^ dsk_buf[THA2]) & HA2_MASK) {
882 dsk_uend (dsk_ch, DSKS_NRCF); /* invalid HA2 */
883 return ERR_NRCF;
884 }
885 if (dsk_mode == DSKC_TWIA) /* track with addr? */
886 dsk_rptr = dsk_rbase + RADDR; /* start at addr */
887 else dsk_rptr = dsk_rbase + RDATA; /* else, at data */
888 }
889 return SCPE_OK;
890 }
891 while (rlnt != 0) { /* until end track */
892 dsk_rptr = dsk_rbase + RDATA;
893 if (((dsk_rec ^ dsk_buf[dsk_rbase + RADDR]) & REC_MASK) == 0)
894 return SCPE_OK; /* rec found? done */
895 dsk_rbase = dsk_rlim; /* next record */
896 rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */
897 dsk_rlim = dsk_rbase + rlnt + RDATA; /* limit */
898 if (dsk_rlim >= dsk_tab[dtyp].wdspt) { /* invalid format? */
899 dsk_uend (dsk_ch, DSKS_FMTC);
900 return STOP_INVFMT;
901 }
902 }
903 dsk_uend (dsk_ch, DSKS_NRCF); /* not found */
904 return ERR_NRCF;
905 }
906
907 /* Check end of transfer
908
909 Inputs:
910 uptr = pointer to access unit
911 dtyp = drive type
912 Outputs:
913 ERR_ENDRC = end of record/track/cylinder, end sent, ch req if required
914 SCPE_OK = more to do, dsk_rbase, dsk_rptr, dsk_rlim may be updated
915 STOP_INVFMT = invalid format (fatal, uend sent)
916 */
917
918 t_stat dsk_xfer_done (UNIT *uaptr, uint32 dtyp)
919 {
920 uint32 rlnt;
921
922 if (dsk_rptr < dsk_rlim) return SCPE_OK; /* record done? */
923 if (dsk_stop || !ch9_qconn (dsk_ch) || /* stop or err disc or */
924 (dsk_mode == DSKC_SREC)) { /* single record? */
925 ch9_set_end (dsk_ch, 0); /* set end */
926 ch_req |= REQ_CH (dsk_ch); /* request channel */
927 return ERR_ENDRC;
928 }
929 dsk_rbase = dsk_rlim; /* next record */
930 rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */
931 dsk_rlim = dsk_rbase + rlnt + RDATA; /* end */
932 if ((dsk_rbase >= dsk_tab[dtyp].wdspt) || /* invalid format? */
933 (dsk_rlim >= dsk_tab[dtyp].wdspt)) {
934 dsk_uend (dsk_ch, DSKS_FMTC);
935 return STOP_INVFMT;
936 }
937 if (rlnt) { /* more on track? */
938 if ((dsk_mode == DSKC_THA) || (dsk_mode == DSKC_TWIA))
939 dsk_rptr = dsk_rbase + RADDR; /* start with addr */
940 else dsk_rptr = dsk_rbase + RDATA; /* or data */
941 return SCPE_OK;
942 }
943 if (dsk_mode == DSKC_CYL) { /* cylinder mode? */
944 uaptr->TRK = (uaptr->TRK + 1) % dsk_tab[dtyp].trkpa; /* incr track */
945 if (uaptr->TRK % dsk_tab[dtyp].trkpc) /* not cyl end? */
946 return ERR_ENDRC; /* don't set end */
947 }
948 ch9_set_end (dsk_ch, 0); /* set end */
949 ch_req |= REQ_CH (dsk_ch); /* request channel */
950 return ERR_ENDRC;
951 }
952
953 /* Write track back to file */
954
955 t_stat dsk_wr_trk (UNIT *udptr, uint32 trk)
956 {
957 uint32 dtyp = GET_DTYPE (udptr->flags);
958 uint32 da = DSK_DA (dsk_acc, trk, dtyp);
959
960 sim_fseek (udptr->fileref, da, SEEK_SET);
961 sim_fwrite (dsk_buf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, udptr->fileref);
962 if (ferror (udptr->fileref)) {
963 perror ("DSK I/O error");
964 clearerr (udptr->fileref);
965 dsk_uend (dsk_ch, DSKS_DSKE);
966 return SCPE_IOERR;
967 }
968 return SCPE_OK;
969 }
970
971 /* Synthesize right attention bit from (access * 10 + module) */
972
973 t_uint64 dsk_acc_atn (uint32 u)
974 {
975 uint32 g, b;
976
977 g = u / 4; /* bit group */
978 b = u % 4; /* bit within group */
979 return (DSKS_ATN0 >> ((g * 6) + (b? b + 1: 0)));
980 }
981
982 /* Get next format character */
983
984 t_bool dsk_get_fmtc (uint32 dtyp, uint8 *fc)
985 {
986 uint32 cc = dsk_fmt_cntr % 6;
987
988 if (cc == 0) { /* start of word? */
989 if (dsk_chob_v) dsk_chob_v = 0; /* valid? clear */
990 else if (!dsk_stop) ch9_set_ioc (dsk_ch); /* no, no stop? io chk */
991 }
992 *fc = ((uint8) (dsk_chob >> ((5 - cc) * 6))) & 077; /* get character */
993 if ((cc == 5) && !dsk_stop) ch_req |= REQ_CH (dsk_ch); /* end of word? */
994 if (dsk_fmt_cntr++ >= dsk_tab[dtyp].fchpt) { /* track overflow? */
995 dsk_uend (dsk_ch, DSKS_FMTC); /* format check */
996 return FALSE;
997 }
998 return TRUE;
999 }
1000
1001 /* Unusual end (set status and stop) */
1002
1003 t_stat dsk_uend (uint32 ch, t_uint64 stat)
1004 {
1005 dsk_sns |= stat;
1006 dsk_sns &= ~(DSKS_PCHK|DSKS_DCHK|DSKS_EXCC);
1007 if (dsk_sns & DSKS_PALL) dsk_sns |= DSKS_PCHK;
1008 if (dsk_sns & DSKS_DALL) dsk_sns |= DSKS_DCHK;
1009 if (dsk_sns & DSKS_EALL) dsk_sns |= DSKS_EXCC;
1010 ch9_set_end (ch, CHINT_UEND);
1011 ch_req |= REQ_CH (ch);
1012 dsk_sta = DSK_IDLE;
1013 return SCPE_OK;
1014 }
1015
1016 /* Test for done */
1017
1018 t_bool dsk_qdone (uint32 ch)
1019 {
1020 if (dsk_stop || !ch9_qconn (ch)) { /* stop or err disc? */
1021 dsk_sta = DSK_IDLE; /* disk is idle */
1022 return TRUE;
1023 }
1024 return FALSE;
1025 }
1026
1027 /* Reset */
1028
1029 t_stat dsk_reset (DEVICE *dptr)
1030 {
1031 uint32 i;
1032 UNIT *uptr;
1033
1034 dsk_acc = 0;
1035 dsk_mod = 0;
1036 dsk_rec = 0;
1037 dsk_mode = 0;
1038 dsk_wchk = 0;
1039 dsk_sns = 0;
1040 dsk_cmd = 0;
1041 dsk_sta = DSK_IDLE;
1042 dsk_rbase = 0;
1043 dsk_rptr = 0;
1044 dsk_rlim = 0;
1045 dsk_stop = 0;
1046 dsk_fmt_cntr = 0;
1047 dsk_chob = 0;
1048 dsk_chob_v = 0;
1049 for (i = 0; i < DSK_BUFSIZ; i++) dsk_buf[i] = 0;
1050 for (i = 0; i <= (2 * DSK_NUMDR); i++) {
1051 uptr = dsk_dev.units + i;
1052 sim_cancel (uptr);
1053 uptr->TRK = 0;
1054 uptr->SKF = 0;
1055 }
1056 return SCPE_OK;
1057 }
1058
1059 /* Attach routine, test formating */
1060
1061 t_stat dsk_attach (UNIT *uptr, char *cptr)
1062 {
1063 uint32 dtyp = GET_DTYPE (uptr->flags);
1064 t_stat r;
1065
1066 uptr->capac = dsk_tab[dtyp].size;
1067 r = attach_unit (uptr, cptr);
1068 if (r != SCPE_OK) return r;
1069 uptr->TRK = 0;
1070 uptr->SKF = 0;
1071 uptr->flags &= ~(UNIT_INOP0|UNIT_INOP1);
1072 return dsk_show_format (stdout, uptr, 0, NULL);
1073 }
1074
1075 /* Set disk size */
1076
1077 t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1078 {
1079 uint32 dtyp = GET_DTYPE (val);
1080 uint32 u = uptr - dsk_dev.units;
1081 UNIT *u1;
1082
1083 if (u & 1) return SCPE_ARG;
1084 u1 = dsk_dev.units + u + 1;
1085 if ((uptr->flags & UNIT_ATT) || (u1->flags & UNIT_ATT))
1086 return SCPE_ALATT;
1087 if (val == TYPE_7320) u1->flags = (u1->flags & ~UNIT_DISABLE) | UNIT_DIS;
1088 else {
1089 u1->flags = (u1->flags & ~UNIT_TYPE) | val | UNIT_DISABLE;
1090 u1->capac = dsk_tab[dtyp].size;
1091 }
1092 uptr->capac = dsk_tab[dtyp].size;
1093 return SCPE_OK;
1094 }
1095
1096 /* Show format */
1097
1098 t_stat dsk_show_format (FILE *st, UNIT *uptr, int32 val, void *desc)
1099 {
1100 uint32 a, t, k, u, tlim, dtyp, da;
1101 uint32 rptr, rlnt, rlim, rec, ctptr, *format;
1102 uint32 minrsz = DSK_BUFSIZ;
1103 uint32 maxrsz = 0;
1104 uint32 minrno = DSK_BUFSIZ;
1105 uint32 maxrno = 0;
1106 t_bool ctss;
1107 t_uint64 dbuf[DSK_BUFSIZ];
1108 DEVICE *dptr;
1109
1110 if (uptr == NULL) return SCPE_IERR;
1111 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
1112 dptr = find_dev_from_unit (uptr);
1113 u = uptr - dptr->units;
1114 if (dptr == NULL) return SCPE_IERR;
1115
1116 dtyp = GET_DTYPE (uptr->flags);
1117 if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301))
1118 format = ctss_fmt_7320;
1119 else format = ctss_fmt_1302;
1120 for (a = 0, ctss = TRUE; a < dsk_tab[dtyp].accpm; a++) {
1121 if (val) tlim = dsk_tab[dtyp].trkpa;
1122 else tlim = 1;
1123 for (t = 0; t < tlim; t++) {
1124 da = DSK_DA (a, t, dtyp); /* get disk address */
1125 sim_fseek (uptr->fileref, da, SEEK_SET); /* read track */
1126 k = sim_fread (dbuf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, uptr->fileref);
1127 if (ferror (uptr->fileref)) return SCPE_IOERR; /* error? */
1128 for ( ; k < dsk_tab[dtyp].wdspt; k++) dbuf[k] = 0;
1129 rptr = T1STREC;
1130 rlnt = (uint32) dbuf[rptr + RLNT];
1131 if (dbuf[THA2] != CTSS_HA2) ctss = FALSE;
1132 if (rlnt == 0) {
1133 if (a || t) fprintf (st,
1134 "Unformatted track, unit = %d, access = %d, track = %d\n", u, a, t);
1135 else fprintf (st, "Unit %d is unformatted\n", u);
1136 return SCPE_OK;
1137 }
1138 for (rec = 0, ctptr = 0; rlnt != 0; rec++) {
1139 if ((format[ctptr] == 0) || format[ctptr++] != rlnt)
1140 ctss = FALSE;
1141 rlim = rptr + rlnt + RDATA;
1142 if (rlim >= dsk_tab[dtyp].wdspt) {
1143 fprintf (st, "Invalid record length %d, unit = %d, access = %d, track = %d, record = %d\n",
1144 rlnt, u, a, t, rec);
1145 return SCPE_OK;
1146 }
1147 if (rlnt > maxrsz) maxrsz = rlnt;
1148 if (rlnt < minrsz) minrsz = rlnt;
1149 rptr = rlim;
1150 rlnt = (uint32) dbuf[rptr + RLNT];
1151 }
1152 if (format[ctptr] != 0) ctss = FALSE;
1153 if (rec > maxrno) maxrno = rec;
1154 if (rec < minrno) minrno = rec;
1155 }
1156 }
1157 if (val == 0) return SCPE_OK;
1158 if (ctss) fprintf (st, "CTSS format\n");
1159 else if ((minrno == maxrno) && (minrsz == maxrsz)) fprintf (st,
1160 "Valid fixed format, records/track = %d, record size = %d\n",
1161 minrno, minrsz);
1162 else if (minrsz == maxrsz) fprintf (st,
1163 "Valid variable format, records/track = %d-%d, record size = %d\n",
1164 minrno, maxrno, minrsz);
1165 else if (minrno == maxrno) fprintf (st,
1166 "Valid variable format, records/track = %d, record sizes = %d-%d\n",
1167 minrno, minrsz, maxrsz);
1168 else fprintf (st,
1169 "Valid variable format, records/track = %d-%d, record sizes = %d-%d\n",
1170 minrno, maxrno, minrsz, maxrsz);
1171 return SCPE_OK;
1172 }