1 /* ibm1130_disk.c: IBM 1130 disk IO simulator
3 NOTE - there is a problem with this code. The Device Status Word (DSW) is
4 computed from current conditions when requested by an XIO load status
5 command; the value of DSW available to the simulator's examine & save
6 commands may NOT be accurate. This should probably be fixed.
8 Based on the SIMH package written by Robert M Supnik
10 * (C) Copyright 2002, Brian Knittel.
11 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
12 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the
13 * usual yada-yada. Please keep this notice and the copyright in any distributions
17 * 05-dec-06 Added cgiwritable mode
19 * 19-Dec-05 We no longer issue an operation complete interrupt if an INITR, INITW
20 * or CONTROL operation is attemped on a drive that is not online. DATA_ERROR
21 * is now only indicated in the DSW when
23 * 02-Nov-04 Addes -s option to boot to leave switches alone.
24 * 15-jun-03 moved actual read on XIO read to end of time interval,
25 * as the APL boot card required 2 instructions to run between the
26 * time read was initiated and the time the data was read (a jump and a wait)
28 * 01-sep-02 corrected treatment of -m and -r flags in dsk_attach
29 * in cgi mode, so that file is opened readonly but emulated
32 * This is not a supported product, but I welcome bug reports and fixes.
33 * Mail to simh@ibm1130.org
36 #include "ibm1130_defs.h"
39 #define TRACE_DMS_IO /* define to enable debug of DMS phase IO */
42 extern int32 sim_switches
;
43 extern int32 sim_quiet
;
44 static int trace_dms
= 0;
45 static void tracesector (int iswrite
, int nwords
, int addr
, int sector
);
46 static t_stat
where_cmd (int flag
, char *ptr
);
47 static t_stat
phdebug_cmd (int flag
, char *ptr
);
48 static t_stat
fdump_cmd (int flags
, char *cptr
);
49 static void enable_dms_tracing (int newsetting
);
54 #define DSK_NUMWD 321 /* words/sector */
55 #define DSK_NUMSC 4 /* sectors/surface */
56 #define DSK_NUMSF 2 /* surfaces/cylinder */
57 #define DSK_NUMCY 203 /* cylinders/drive */
58 #define DSK_NUMTR (DSK_NUMCY * DSK_NUMSF) /* tracks/drive */
59 #define DSK_NUMDR 5 /* drives/controller */
60 #define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */
62 #define UNIT_V_RONLY (UNIT_V_UF + 0) /* hwre write lock */
63 #define UNIT_V_OPERR (UNIT_V_UF + 1) /* operation error flag */
64 #define UNIT_V_HARDERR (UNIT_V_UF + 2) /* hard error flag (reset on power down) */
65 #define UNIT_RONLY (1u << UNIT_V_RONLY)
66 #define UNIT_OPERR (1u << UNIT_V_OPERR)
67 #define UNIT_HARDERR (1u << UNIT_V_HARDERR)
69 #define MEM_MAPPED(uptr) (uptr->flags & UNIT_BUF) /* disk buffered in memory */
71 #define IO_NONE 0 /* last operation, used to ensure fseek between read and write */
75 #define DSK_DSW_DATA_ERROR 0x8000 /* device status word bits */
76 #define DSK_DSW_OP_COMPLETE 0x4000
77 #define DSK_DSW_NOT_READY 0x2000
78 #define DSK_DSW_DISK_BUSY 0x1000
79 #define DSK_DSW_CARRIAGE_HOME 0x0800
80 #define DSK_DSW_SECTOR_MASK 0x0003
82 /* device status words */
83 static int16 dsk_dsw
[DSK_NUMDR
] = {DSK_DSW_NOT_READY
, DSK_DSW_NOT_READY
, DSK_DSW_NOT_READY
, DSK_DSW_NOT_READY
, DSK_DSW_NOT_READY
};
84 static int16 dsk_sec
[DSK_NUMDR
] = {0}; /* next-sector-up */
85 static char dsk_lastio
[DSK_NUMDR
]; /* last stdio operation: IO_READ or IO_WRITE */
86 int32 dsk_swait
= 50; /* seek time -- see how short a delay we can get away with */
87 int32 dsk_rwait
= 50; /* rotate time */
88 static t_bool raw_disk_debug
= FALSE
;
90 static t_stat
dsk_svc (UNIT
*uptr
);
91 static t_stat
dsk_reset (DEVICE
*dptr
);
92 static t_stat
dsk_attach (UNIT
*uptr
, char *cptr
);
93 static t_stat
dsk_detach (UNIT
*uptr
);
94 static t_stat
dsk_boot (int unitno
, DEVICE
*dptr
);
96 static void diskfail (UNIT
*uptr
, int dswflag
, int unitflag
, t_bool do_interrupt
);
98 /* DSK data structures
100 dsk_dev disk device descriptor
101 dsk_unit unit descriptor
102 dsk_reg register list
106 { UDATA (&dsk_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
, DSK_SIZE
) },
107 { UDATA (&dsk_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
, DSK_SIZE
) },
108 { UDATA (&dsk_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
, DSK_SIZE
) },
109 { UDATA (&dsk_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
, DSK_SIZE
) },
110 { UDATA (&dsk_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_DISABLE
, DSK_SIZE
) }
113 #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
115 /* Parameters in the unit descriptor */
117 #define CYL u3 /* current cylinder */
118 #define FUNC u4 /* current function */
121 { HRDATA (DSKDSW0
, dsk_dsw
[0], 16) },
122 { HRDATA (DSKDSW1
, dsk_dsw
[1], 16) },
123 { HRDATA (DSKDSW2
, dsk_dsw
[2], 16) },
124 { HRDATA (DSKDSW3
, dsk_dsw
[3], 16) },
125 { HRDATA (DSKDSW4
, dsk_dsw
[4], 16) },
126 { DRDATA (STIME
, dsk_swait
, 24), PV_LEFT
},
127 { DRDATA (RTIME
, dsk_rwait
, 24), PV_LEFT
},
131 { UNIT_RONLY
, 0, "write enabled", "ENABLED", NULL
},
132 { UNIT_RONLY
, UNIT_RONLY
, "write locked", "LOCKED", NULL
},
136 "DSK", dsk_unit
, dsk_reg
, dsk_mod
,
137 DSK_NUMDR
, 16, 16, 1, 16, 16,
138 NULL
, NULL
, &dsk_reset
,
139 dsk_boot
, dsk_attach
, dsk_detach
};
141 static int32 dsk_ilswbit
[DSK_NUMDR
] = { /* interrupt level status word bits for the drives */
149 static int32 dsk_ilswlevel
[DSK_NUMDR
] =
151 2, /* interrupt levels for the drives */
155 typedef enum {DSK_FUNC_IDLE
, DSK_FUNC_READ
, DSK_FUNC_VERIFY
, DSK_FUNC_WRITE
, DSK_FUNC_SEEK
, DSK_FUNC_FAILED
} DSK_FUNC
;
157 static struct tag_dsk_action
{ /* stores data needed for pending IO activity */
162 } dsk_action
[DSK_NUMDR
];
164 /* xio_disk - XIO command interpreter for the disk drives */
166 * device status word:
168 * 0 data error, occurs when:
169 * 1. A modulo 4 error is detected during a read, read-check, or write operation.
170 * 2. The disk storage is in a read or write mode at the leading edge of a sector pulse.
171 * 3. A seek-incomplete signal is received from the 2311.
172 * 4. A write select error has occurred in the disk storage drive.
173 * 5. The power unsafe latch is set in the attachment.
174 * Conditions 1, 2, and 3 are turned off by a sense device command with modifier bit 15
175 * set to 1. Conditions 4 and 5 are turned off by powering the drive off and back on.
176 * 1 operation complete
177 * 2 not ready, occurs when disk not ready or busy or disabled or off-line or
178 * power unsafe latch set. Also included in the disk not ready is the write select error,
179 * which can be a result of power unsafe or write select.
181 * 4 carriage home (on cyl 0)
182 * 15-16: number of next sector spinning into position.
185 extern void void_backtrace (int afrom
, int ato
);
187 void xio_disk (int32 iocc_addr
, int32 func
, int32 modify
, int drv
)
189 int i
, rev
, nsteps
, newcyl
, sec
, nwords
;
190 uint32 newpos
; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
192 UNIT
*uptr
= dsk_unit
+drv
;
193 int16 buf
[DSK_NUMWD
];
195 if (! BETWEEN(drv
, 0, DSK_NUMDR
-1)) { /* hmmm, invalid drive */
196 if (func
!= XIO_SENSE_DEV
) { /* tried to use it, too */
197 /* just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
198 sprintf(msg, "Op %x on invalid drive number %d", func, drv);
205 CLRBIT(uptr
->flags
, UNIT_OPERR
); /* clear pending error flag from previous op, if any */
209 if (! IS_ONLINE(uptr
)) { /* disk is offline */
210 diskfail(uptr
, 0, 0, FALSE
);
214 sim_cancel(uptr
); /* cancel any pending ops */
215 dsk_dsw
[drv
] |= DSK_DSW_DISK_BUSY
; /* and mark the disk as busy */
217 nwords
= M
[iocc_addr
++ & mem_mask
]; /* get word count w/o upsetting SAR/SBR */
219 if (nwords
== 0) /* this is bad -- on real 1130, this locks up disk controller ! */
222 if (! BETWEEN(nwords
, 1, DSK_NUMWD
)) { /* count bad */
223 SETBIT(uptr
->flags
, UNIT_OPERR
); /* set data error DSW bit when op complete */
224 nwords
= DSK_NUMWD
; /* limit xfer to proper sector size */
227 sec
= modify
& 0x07; /* get sector on cylinder */
229 if ((modify
& 0x0080) == 0) { /* it's a real read if it's not a read check */
230 /* ah. We have a problem. The APL boot card counts on there being time for at least one
231 * more instruction to execute between the XIO read and the time the data starts loading
232 * into core. So, we have to defer the actual read operation a bit. Might as well wait
233 * until it's time to issue the operation complete interrupt. This means saving the
234 * IO information, then performing the actual read in dsk_svc.
237 newpos
= (uptr
->CYL
*DSK_NUMSC
*DSK_NUMSF
+ sec
)*2*DSK_NUMWD
;
239 dsk_action
[drv
].io_address
= iocc_addr
;
240 dsk_action
[drv
].io_nwords
= nwords
;
241 dsk_action
[drv
].io_sector
= sec
;
242 dsk_action
[drv
].io_filepos
= newpos
;
244 uptr
->FUNC
= DSK_FUNC_READ
;
247 trace_io("* DSK%d verify %d.%d (%x)", drv
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
);
250 printf("* DSK%d verify %d.%d (%x)", drv
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
);
252 uptr
->FUNC
= DSK_FUNC_VERIFY
;
255 sim_activate(uptr
, dsk_rwait
);
259 if (! IS_ONLINE(uptr
)) { /* disk is offline */
260 diskfail(uptr
, 0, 0, FALSE
);
264 if (uptr
->flags
& UNIT_RONLY
) { /* oops, write to RO disk? permanent error until disk is powered off/on */
265 diskfail(uptr
, DSK_DSW_DATA_ERROR
, UNIT_HARDERR
, FALSE
);
269 sim_cancel(uptr
); /* cancel any pending ops */
270 dsk_dsw
[drv
] |= DSK_DSW_DISK_BUSY
; /* and mark drive as busy */
272 nwords
= M
[iocc_addr
++ & mem_mask
]; /* get word count w/o upsetting SAR/SBR */
274 if (nwords
== 0) /* this is bad -- locks up disk controller ! */
277 if (! BETWEEN(nwords
, 1, DSK_NUMWD
)) { /* count bad */
278 SETBIT(uptr
->flags
, UNIT_OPERR
); /* set data error DSW bit when op complete */
279 nwords
= DSK_NUMWD
; /* limit xfer to proper sector size */
282 sec
= modify
& 0x07; /* get sector on cylinder */
283 newpos
= (uptr
->CYL
*DSK_NUMSC
*DSK_NUMSF
+ sec
)*2*DSK_NUMWD
;
285 trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)", drv
, nwords
, iocc_addr
& mem_mask
, (iocc_addr
+ nwords
- 1) & mem_mask
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
, newpos
);
288 printf("* DSK%d XIO @ %04x wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)\n", drv
, prev_IAR
, nwords
, iocc_addr
& mem_mask
, (iocc_addr
+ nwords
- 1) & mem_mask
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
, newpos
);
292 tracesector(1, nwords
, iocc_addr
& mem_mask
, uptr
->CYL
*8 + sec
);
294 for (i
= 0; i
< nwords
; i
++)
295 buf
[i
] = M
[iocc_addr
++ & mem_mask
];
297 for (; i
< DSK_NUMWD
; i
++) /* rest of sector gets zeroed */
300 i
= uptr
->CYL
*8 + sec
;
302 printf("*DSK writing bad sector#\n");
304 if (MEM_MAPPED(uptr
)) {
305 memcpy((char *) uptr
->filebuf
+ newpos
, buf
, 2*DSK_NUMWD
);
306 uptr
->hwmark
= newpos
+ 2*DSK_NUMWD
;
309 if (uptr
->pos
!= newpos
|| dsk_lastio
[drv
] != IO_WRITE
) {
310 fseek(uptr
->fileref
, newpos
, SEEK_SET
);
311 dsk_lastio
[drv
] = IO_WRITE
;
314 fxwrite(buf
, 2, DSK_NUMWD
, uptr
->fileref
);
315 uptr
->pos
= newpos
+ 2*DSK_NUMWD
;
318 uptr
->FUNC
= DSK_FUNC_WRITE
;
319 sim_activate(uptr
, dsk_rwait
);
322 case XIO_CONTROL
: /* step fwd/rev */
323 if (! IS_ONLINE(uptr
)) {
324 diskfail(uptr
, 0, 0, FALSE
);
331 nsteps
= iocc_addr
& 0x00FF;
332 if (nsteps
== 0) /* 0 steps does not cause op complete interrupt */
335 newcyl
= uptr
->CYL
+ (rev
? (-nsteps
) : nsteps
);
338 else if (newcyl
>= DSK_NUMCY
)
339 newcyl
= DSK_NUMCY
-1;
341 uptr
->FUNC
= DSK_FUNC_SEEK
;
343 sim_activate(uptr
, dsk_swait
); /* schedule interrupt */
345 dsk_dsw
[drv
] |= DSK_DSW_DISK_BUSY
;
346 trace_io("* DSK%d at cyl %d", drv
, newcyl
);
350 CLRBIT(dsk_dsw
[drv
], DSK_DSW_CARRIAGE_HOME
|DSK_DSW_NOT_READY
);
352 if ((uptr
->flags
& UNIT_HARDERR
) || (dsk_dsw
[drv
] & DSK_DSW_DISK_BUSY
) || ! IS_ONLINE(uptr
))
353 SETBIT(dsk_dsw
[drv
], DSK_DSW_NOT_READY
);
354 else if (uptr
->CYL
<= 0) {
355 SETBIT(dsk_dsw
[drv
], DSK_DSW_CARRIAGE_HOME
);
359 dsk_sec
[drv
] = (int16
) ((dsk_sec
[drv
] + 1) % 4); /* advance the "next sector" count every time */
360 ACC
= dsk_dsw
[drv
] | dsk_sec
[drv
];
362 if (modify
& 0x01) { /* reset interrupts */
363 CLRBIT(dsk_dsw
[drv
], DSK_DSW_OP_COMPLETE
|DSK_DSW_DATA_ERROR
);
364 CLRBIT(ILSW
[dsk_ilswlevel
[drv
]], dsk_ilswbit
[drv
]);
369 sprintf(msg
, "Invalid disk XIO function %x", func
);
374 /* diskfail - schedule an operation complete that sets the error bit */
376 static void diskfail (UNIT
*uptr
, int dswflag
, int unitflag
, t_bool do_interrupt
)
378 int drv
= uptr
- dsk_unit
;
380 sim_cancel(uptr
); /* cancel any pending ops */
381 SETBIT(dsk_dsw
[drv
], dswflag
); /* set any specified DSW bits */
382 SETBIT(uptr
->flags
, unitflag
); /* set any specified unit flag bits */
383 uptr
->FUNC
= DSK_FUNC_FAILED
; /* tell svc routine why it failed */
386 sim_activate(uptr
, 1); /* schedule an immediate op complete interrupt */
389 t_stat
dsk_svc (UNIT
*uptr
)
391 int drv
= uptr
- dsk_unit
, i
, nwords
, sec
;
392 int16 buf
[DSK_NUMWD
];
393 uint32 newpos
; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
396 if (uptr
->FUNC
== DSK_FUNC_IDLE
) /* service function called with no activity? not good, but ignore */
399 CLRBIT(dsk_dsw
[drv
], DSK_DSW_DISK_BUSY
); /* activate operation complete interrupt */
400 SETBIT(dsk_dsw
[drv
], DSK_DSW_OP_COMPLETE
);
402 if (uptr
->flags
& (UNIT_OPERR
|UNIT_HARDERR
)) { /* word count error or data error */
403 SETBIT(dsk_dsw
[drv
], DSK_DSW_DATA_ERROR
);
404 CLRBIT(uptr
->flags
, UNIT_OPERR
); /* soft error is one time occurrence; don't clear hard error */
406 /* schedule interrupt */
407 SETBIT(ILSW
[dsk_ilswlevel
[drv
]], dsk_ilswbit
[drv
]);
409 switch (uptr
->FUNC
) { /* take care of business */
411 case DSK_FUNC_VERIFY
:
414 case DSK_FUNC_FAILED
:
417 case DSK_FUNC_READ
: /* actually read the data into core */
418 iocc_addr
= dsk_action
[drv
].io_address
; /* recover saved parameters */
419 nwords
= dsk_action
[drv
].io_nwords
;
420 newpos
= dsk_action
[drv
].io_filepos
;
421 sec
= dsk_action
[drv
].io_sector
;
423 if (MEM_MAPPED(uptr
)) {
424 memcpy(buf
, (char *) uptr
->filebuf
+ newpos
, 2*DSK_NUMWD
);
427 if (uptr
->pos
!= newpos
|| dsk_lastio
[drv
] != IO_READ
) {
428 fseek(uptr
->fileref
, newpos
, SEEK_SET
);
429 dsk_lastio
[drv
] = IO_READ
;
432 fxread(buf
, 2, DSK_NUMWD
, uptr
->fileref
); /* read whole sector so we're in position for next read */
433 uptr
->pos
= newpos
+ 2*DSK_NUMWD
;
436 void_backtrace(iocc_addr
, iocc_addr
+ nwords
- 1); /* mark prev instruction as altered */
438 trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv
, nwords
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
, newpos
, iocc_addr
& mem_mask
,
439 (iocc_addr
+ nwords
- 1) & mem_mask
);
441 /* this will help debug the monitor by letting me watch phase loading */
443 printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv
, prev_IAR
, nwords
, uptr
->CYL
, sec
, uptr
->CYL
*8 + sec
, newpos
, iocc_addr
& mem_mask
,
444 (iocc_addr
+ nwords
- 1) & mem_mask
);
446 i
= uptr
->CYL
*8 + sec
;
448 printf("*DSK read bad sector #\n");
450 for (i
= 0; i
< nwords
; i
++)
451 M
[(iocc_addr
+i
) & mem_mask
] = buf
[i
];
455 tracesector(0, nwords
, iocc_addr
& mem_mask
, uptr
->CYL
*8 + sec
);
460 fprintf(stderr
, "Unexpected FUNC %x in dsk_svc(%d)\n", uptr
->FUNC
, drv
);
465 uptr
->FUNC
= DSK_FUNC_IDLE
; /* we're done with this operation */
470 t_stat
dsk_reset (DEVICE
*dptr
)
476 /* add the WHERE command. It finds the phase that was loaded at given address and indicates */
477 /* the offset in the phase */
478 register_cmd("WHERE", &where_cmd
, 0, "w{here} address find phase and offset of an address\n");
479 register_cmd("PHDEBUG", &phdebug_cmd
, 0, "ph{debug} off|phlo phhi break on phase load\n");
480 register_cmd("FDUMP", &fdump_cmd
, 0, NULL
);
483 for (drv
= 0, uptr
= dsk_dev
.units
; drv
< DSK_NUMDR
; drv
++, uptr
++) {
486 CLRBIT(ILSW
[2], dsk_ilswbit
[drv
]);
487 CLRBIT(uptr
->flags
, UNIT_OPERR
|UNIT_HARDERR
);
490 uptr
->FUNC
= DSK_FUNC_IDLE
;
491 dsk_dsw
[drv
] = (int16
) ((uptr
->flags
& UNIT_ATT
) ? DSK_DSW_CARRIAGE_HOME
: 0);
499 static t_stat
dsk_attach (UNIT
*uptr
, char *cptr
)
501 int drv
= uptr
- dsk_unit
;
504 sim_cancel(uptr
); /* cancel current IO */
505 dsk_lastio
[drv
] = IO_NONE
;
507 if (uptr
->flags
& UNIT_ATT
) /* dismount current disk */
508 if ((rval
= dsk_detach(uptr
)) != SCPE_OK
)
511 uptr
->CYL
= 0; /* reset the device */
512 uptr
->FUNC
= DSK_FUNC_IDLE
;
513 dsk_dsw
[drv
] = DSK_DSW_CARRIAGE_HOME
;
515 CLRBIT(uptr
->flags
, UNIT_RO
|UNIT_ROABLE
|UNIT_BUFABLE
|UNIT_BUF
|UNIT_RONLY
|UNIT_OPERR
|UNIT_HARDERR
);
516 CLRBIT(ILSW
[2], dsk_ilswbit
[drv
]);
519 if (sim_switches
& SWMASK('M')) /* if memory mode (e.g. for CGI), buffer the file */
520 SETBIT(uptr
->flags
, UNIT_BUFABLE
|UNIT_MUSTBUF
);
522 if (sim_switches
& SWMASK('R')) /* read lock mode */
523 SETBIT(uptr
->flags
, UNIT_RO
|UNIT_ROABLE
|UNIT_RONLY
);
525 if (cgi
&& (sim_switches
& SWMASK('M')) && ! cgiwritable
) { /* if cgi and memory mode, but writable option not specified */
526 sim_switches
|= SWMASK('R'); /* have attach_unit open file in readonly mode */
527 SETBIT(uptr
->flags
, UNIT_ROABLE
); /* but don't set the UNIT_RONLY flag so DMS can write to the buffered image */
530 if ((rval
= attach_unit(uptr
, quotefix(cptr
))) != SCPE_OK
) { /* mount new disk */
531 SETBIT(dsk_dsw
[drv
], DSK_DSW_NOT_READY
);
537 disk_unlocked(FALSE
);
540 enable_dms_tracing(sim_switches
& SWMASK('D'));
541 raw_disk_debug
= sim_switches
& SWMASK('G');
546 static t_stat
dsk_detach (UNIT
*uptr
)
549 int drv
= uptr
- dsk_unit
;
553 if ((rval
= detach_unit(uptr
)) != SCPE_OK
)
556 CLRBIT(ILSW
[2], dsk_ilswbit
[drv
]);
557 CLRBIT(uptr
->flags
, UNIT_OPERR
|UNIT_HARDERR
);
561 uptr
->FUNC
= DSK_FUNC_IDLE
;
562 dsk_dsw
[drv
] = DSK_DSW_NOT_READY
;
572 /* boot routine - if they type BOOT DSK, load the standard boot card. */
574 static t_stat
dsk_boot (int unitno
, DEVICE
*dptr
)
578 if ((rval
= reset_all(0)) != SCPE_OK
)
581 return load_cr_boot(unitno
, sim_switches
);
590 # include "dmsr2v12phases.h"
595 #define MAXSLET ((3*320)/4)
602 # include "dmsr2v12slet.h" /* without RPG, use this info until overwritten by actual data from disk */
610 int addr
, offset
, len
, phid
;
614 static void enable_dms_tracing (int newsetting
)
616 nseg
= 0; /* clear the segment map */
618 if ((newsetting
&& trace_dms
) || ! (newsetting
|| trace_dms
))
621 trace_dms
= newsetting
;
623 printf("DMS disk tracing is now %sabled\n", trace_dms
? "en" : "dis");
626 char * saywhere (int addr
)
629 static char buf
[150];
631 for (i
= 0; i
< nseg
; i
++) {
632 if (addr
>= mseg
[i
].addr
&& addr
< (mseg
[i
].addr
+mseg
[i
].len
)) {
633 sprintf(buf
, "/%04x = /%04x + /%x in ", addr
, mseg
[i
].addr
- mseg
[i
].offset
, addr
-mseg
[i
].addr
+ mseg
[i
].offset
);
634 if (mseg
[i
].phid
> 0)
635 sprintf(buf
+strlen(buf
), "phase %02x (%s)", mseg
[i
].phid
, mseg
[i
].name
);
637 sprintf(buf
+strlen(buf
), "%s", mseg
[i
].name
);
645 static int phdebug_lo
= -1, phdebug_hi
= -1;
647 static t_stat
phdebug_cmd (int flag
, char *ptr
)
651 if (strcmpi(ptr
, "off") == 0)
652 phdebug_lo
= phdebug_hi
= -1;
654 switch(sscanf(ptr
, "%x%x", &val1
, &val2
)) {
656 phdebug_lo
= phdebug_hi
= val1
;
657 enable_dms_tracing(TRUE
);
663 enable_dms_tracing(TRUE
);
667 printf("Usage: phdebug off | phdebug phfrom [phto]\n");
674 static t_stat
where_cmd (int flag
, char *ptr
)
680 printf("Tracing is disabled. To enable, attach disk with -d switch\n");
684 if (sscanf(ptr
, "%x", &addr
) != 1)
687 if ((where
= saywhere(addr
)) == NULL
)
688 printf("/%04x not found\n", addr
);
690 printf("%s\n", where
);
695 /* savesector - save info on a sector just read. THIS IS NOT YET TESTED */
697 static void addseg (int i
)
702 if (nseg
>= MAXMSEG
) {
703 printf("(Memory map full, disabling tracing)\n");
708 memcpy(mseg
+i
+1, mseg
+i
, (nseg
-i
)*sizeof(mseg
[0]));
712 static void delseg (int i
)
719 memcpy(mseg
+i
, mseg
+i
+1, (nseg
-i
)*sizeof(mseg
[0]));
723 static void savesector (int addr
, int offset
, int len
, int phid
, char *name
)
730 addr
++; /* first word is sector address, so account for that */
733 for (i
= 0; i
< nseg
; i
++) {
734 if (addr
>= (mseg
[i
].addr
+mseg
[i
].len
)) /* entirely after this entry */
737 if (mseg
[i
].addr
< addr
) { /* old one starts before this. split it */
739 mseg
[i
].len
= addr
-mseg
[i
].addr
;
742 mseg
[i
].len
-= mseg
[i
-1].len
;
748 addseg(i
); /* add new segment. Old one ends up after this */
754 mseg
[i
].offset
= offset
;
759 i
++; /* delete any segments completely covered */
761 while (i
< nseg
&& (mseg
[i
].addr
+mseg
[i
].len
) <= (addr
+len
))
764 if (i
< nseg
&& mseg
[i
].addr
< (addr
+len
)) { /* old one extends past this. Retain the end */
765 mseg
[i
].len
= (mseg
[i
].addr
+mseg
[i
].len
) - (addr
+len
);
766 mseg
[i
].addr
= addr
+len
;
770 static void tracesector (int iswrite
, int nwords
, int addr
, int sector
)
772 int i
, phid
= 0, offset
= 0;
775 if (nwords
< 3 || ! trace_dms
)
778 switch (sector
) { /* explicitly known sector name */
779 case 0: name
= "ID/COLD START"; break;
780 case 1: name
= "DCOM"; break;
781 case 2: name
= "RESIDENT IMAGE"; break;
784 case 5: name
= "SLET"; /* save just-read or written SLET info */
785 memmove(&slet
[(320/4)*(sector
-3)], &M
[addr
+1], nwords
*2);
787 case 6: name
= "RELOAD TABLE"; break;
788 case 7: name
= "PAGE HEADER"; break;
791 printf("* %04x: %3d /%04x %c %3d.%d ",
792 prev_IAR
, nwords
, addr
, iswrite
? 'W' : 'R', sector
/8, sector
%8);
794 if (name
== NULL
) { /* look up sector in SLET */
795 for (i
= 0; i
< MAXSLET
; i
++) {
796 if (slet
[i
].phid
== 0) /* not found */
798 else if (slet
[i
].sector
> sector
) {
800 if (sector
>= slet
[i
].sector
&& sector
<= (slet
[i
].sector
+ slet
[i
].nwords
/320)) {
802 offset
= (sector
-slet
[i
].sector
)*320;
808 if (slet
[i
].sector
== sector
) {
809 phid
= slet
[i
].phid
; /* we found the starting sector */
814 if (i
>= MAXSLET
) /* was not found */
818 for (i
= sizeof(phase
)/sizeof(phase
[0]); --i
>= 0; ) {
819 if (phase
[i
].phid
== phid
) { /* look up name */
820 name
= phase
[i
].name
;
824 printf("%02x %s", phid
, name
);
832 if (phid
>= phdebug_lo
&& phid
<= phdebug_hi
&& offset
== 0)
833 break_simulation(STOP_PHASE_BREAK
); /* break on read of first sector of indicated phases */
835 if (name
!= NULL
&& *name
!= '?' && ! iswrite
)
836 savesector(addr
, offset
, nwords
, phid
, name
);
839 static t_stat
fdump_cmd (int flags
, char *cptr
)
841 int addr
= 0x7a24; /* address of next statement */
842 int sofst
= 0x7a26, symaddr
;
843 int cword
, nwords
, stype
, has_stnum
, strel
= 1, laststno
= 0;
845 addr
= M
[addr
& mem_mask
] & mem_mask
; /* get address of first statement */
846 sofst
= M
[sofst
& mem_mask
] & mem_mask
; /* get address of symbol table */
850 nwords
= (cword
>> 2) & 0x01FF;
851 stype
= (cword
>> 1) & 0x7C00;
852 has_stnum
= (cword
& 1);
859 printf("/%04x [%4d +%3d] %3d - %04x", addr
, laststno
, strel
, nwords
, stype
);
864 symaddr
= sofst
- (M
[addr
] & 0x7FF)*3 + 3;
865 printf(" [%04x %04x %04x]", M
[symaddr
], M
[symaddr
+1], M
[symaddr
+2]);
868 if (stype
== 0x5000) { /* error record */
869 printf(" (err %d)", M
[addr
+1]);
879 printf("0 words?\n");
885 printf("\nEnd found at /%04x, EOFS = /%04x\n", addr
, M
[0x7a25 & mem_mask
]);
889 #endif /* TRACE_DMS_IO */