Added Asynch I/O and Disk Support for various Disk formats

I’ve always wanted to have the option to have simulated devices behave
more naturally with respect to I/O operations.  By more naturally I
mean that the current simulator model I/O is either polled (for asynchronous
things link Muxes and Network), or it is performed in the middle of some
instruction execution taking possibly many milliseconds (disk and/or tapes).
The existing model creates quite deterministic behavior which helps to debug
and understand issues, but it trades off potential instruction execution
while performing these I/O operations in between instruction execution.

To address this concept (while still retaining the potential advantages of
the original model), I’ve designed an Asynch I/O model extension for simh.
In order to flesh-out and debug this design, I’ve also refactored several
devices to utilize this capability.  Please read the attached
0readmeAsynchIO.txt file for concept details about the approach.

In order to make disk devices easy to implement (within or without the
AsynchIO framework), I’ve created a sim_disk.c  library which is modeled
on the sim_tape.c library to generalize disk I/O like tape I/O is
generalized in sim_tape.c.  This sim_disk.c library now provides that
natural place to implement support for various disk implementation formats
(just like sim_tape support several formats, and one day will be the place
to add direct physical tape access). The current sim_disk library provides
the framework for direct support of 3 different disk formats:
    1) standard simh disk format
    2) platform specific physical disk access
and 3) platform independent Virtual Disk format.
The Virtual Disk format is an implementation of the format described in
the ”Microsoft Virtual Hard Disk (VHD) Image Format Specification”.  The
VHD specification is available for anyone to implement under the "Microsoft
Open Specification Promise" described at
http://www.microsoft.com/interop/osp/default.mspx.
The VHD implementation includes support for:
    1) Fixed sized disks
    2) Dynamically expanding disks
and 3) Differencing Disks.
Dynamically expanding disks don’t change their “Virtual Size”, but they
don’t consume disk space on the containing storage until the virtual
sectors in the disk are actually written to (i.e. an RA81 or RA92 VHD
with a VMS installed on it may initially only contain 30+ MB of files,
and the resulting VHD will be 30+ MB).  The VHD format contains meta data
which describes the virtual device.  Amongst this meta data is the simh
device type which the VHD was originally created as.  This metadata is
therefore available whenever that VHD is attached to an emulated disk
device in the future so the device type & size can be automatically be
configured.

Sim_disk_attach is used by device emulations to attach a simh/vhd/raw
device to a simulated device.  The following simh command switches
are used by the sim_disk_attach API:

    -R          Attach Read Only.
    -E          Must Exist (if not specified an attempt to create the
                indicated virtual disk will be attempted).
    -F          Open the indicated disk container in a specific format
                (default is to autodetect VHD defaulting to simh if the
                indicated container is not a VHD).
    -X          When creating a VHD, create a fixed sized VHD (vs a
                Dynamically expanding one).
    -C          Create a VHD and copy its contents from another disk
                (simh, VHD, or RAW format).
    -D          Create a Differencing VHD (relative to an already
                existing VHD disk)

Examples:

    sim> show rq
    RQ, address=20001468-2000146B*, no vector, 4 units
      RQ0, 159MB, not attached, write enabled, RD54, autosize, SIMH format
      RQ1, 159MB, not attached, write enabled, RD54, autosize, SIMH format
      RQ2, 159MB, not attached, write enabled, RD54, autosize, SIMH format
      RQ3, 409KB, not attached, write enabled, RX50, autosize, SIMH format
    sim> atta rq0 RA81.vhd
    sim> show rq0
    RQ0, 456MB, attached to RA81.vhd, write enabled, RA81, autosize, VHD format
    sim> set rq2 ra92
    sim> att rq2 -f vhd RA92.vhd
    RQ2: creating new file
    sim> sho rq2
    RQ2, 1505MB, attached to RA92.vhd, write enabled, RA92, autosize, VHD format
    sim> ! dir RA92.vhd
     Volume in drive H is New Volume
     Volume Serial Number is F8DE-510C

     Directory of H:\Data

    04/14/2011  12:57 PM             5,120 RA92.vhd
                   1 File(s)          5,120 bytes
                   0 Dir(s)   3,074,412,544 bytes free
    sim> atta rq3 -c RA92-1.vhd RA92.vhd
    sim> atta rq3 -c RA92-1.vhd RA92.vhd
    RQ3: creating new virtual disk 'RA92-1.vhd'
    RQ3: Copied 1505MB.  99% complete.
    RQ3: Copied 1505MB. Done.
    sim> sh rq3
    RQ3, 1505MB, attached to RA92-1.vhd, write enabled, RA92, autosize, VHD format
    sim>  ! dir RA92*
     Volume in drive H is New Volume
     Volume Serial Number is F8DE-510C

     Directory of H:\Data

    04/14/2011  01:12 PM             5,120 RA92-1.vhd
    04/14/2011  12:58 PM             5,120 RA92.vhd
                   2 File(s)         10,240 bytes
                   0 Dir(s)   3,074,404,352 bytes free
    sim> sho rq2
    RQ2, 1505MB, not attached, write enabled, RA92, autosize, VHD format
    sim> set rq2 ra81
    sim> set rq2 noauto
    sim> sho rq2
    RQ2, 456MB, not attached, write enabled, RA81, noautosize, VHD format
    sim> set rq2 format=simh
    sim> sho rq2
    RQ2, 456MB, not attached, write enabled, RA81, noautosize, SIMH format
    sim> atta rq2 -c RA81-Copy.vhd VMS055.dsk
    RQ2: creating new virtual disk 'RA81-Copy.vhd'
    RQ2: Copied 456MB.  99% complete.
    RQ2: Copied 456MB. Done.
    sim> sho rq2
    RQ2, 456MB, attached to RA81-Copy.vhd, write enabled, RA81, noautosize, VHD format
    sim> det rq2
    sim> ! dir RA81-Copy.vhd
     Volume in drive H is New Volume
     Volume Serial Number is F8DE-510C

     Directory of H:\Data

    04/14/2011  01:22 PM       178,304,512 RA81-Copy.vhd
                   1 File(s)    178,304,512 bytes
                   0 Dir(s)   2,896,097,280 bytes free
    sim> ! dir VMS055.dsk
     Volume in drive H is New Volume
     Volume Serial Number is F8DE-510C

     Directory of H:\Data

    03/08/2011  01:42 PM       403,663,872 VMS055.dsk
                   1 File(s)    403,663,872 bytes
                   0 Dir(s)   2,896,097,280 bytes free
    sim>
This commit is contained in:
Mark Pizzolato 2011-04-15 08:49:18 -07:00
parent 35eac703c3
commit 87c3e3452f
19 changed files with 5695 additions and 504 deletions

161
0readmeAsynchIO.txt Normal file
View file

@ -0,0 +1,161 @@
SIM_ASYNCH_IO
Theory of operation.
Features.
- Optional Use. Build with or without SIM_ASYNCH_IO defined and
simulators will still build and perform correctly when run.
- Consistent Save/Restore state. The state of a simulator saved
on a simulator with (or without) Asynch support can be restored
on any simulator of the same version with or without Asynch
support.
- Optimal behavior/performance with simulator running with or
without CPU idling enabled.
- Consistent minimum instruction scheduling delays when operating
with or without SIM_ASYNCH_IO. When SIM_ASYNCH_IO is emabled,
any operation which would have been scheduled to occurr in 'n'
instructions will still occur (from the simulated computer's
point of view) at least 'n' instructions after it was initiated.
Benefits.
Allows a simulator to execute simulated instructions concurrently
with I/O operations which may take numerous milliseconds to perform.
Allows a simulated device to potentially avoid polling for the arrival
of data. Polling consumes host processor CPU cycles which may better
be spent executing simulated instructions or letting other host
processes run. Measurements made of available instruction execution
easily demonstrate the benefits of parallel instruction and I/O
activities. A VAX simulator with a process running a disk intensive
application in one process was able to process 11 X the number of
Dhrystone operations with Asynch I/O enabled.
Asynch I/O is provided through a callback model.
SimH Libraries which provide Asynch I/O support:
sim_disk
sim_tape
sim_ether
Requirements to use:
The Simulator's instruction loop needs to be modified to include a single
line which checks for asynchronouzly arrived events. The vax_cpu.c
module added the following line indicated by >>>:
/* Main instruction loop */
for ( ;; ) {
[...]
>>> AIO_CHECK_EVENT;
if (sim_interval <= 0) { /* chk clock queue */
temp = sim_process_event ();
if (temp)
ABORT (temp);
SET_IRQL; /* update interrupts */
}
A global variable (sim_asynch_latency) is used to indicate the "interrupt
dispatch latency". This variable is the number of nanoseconds between checks
for completed asynchronous I/O. The default value is 4000 (4 usec) which
corresponds reasonably with simulated hardware. This variable controls
the computation of sim_asynch_inst_latency which is the number of simulated
instructions in the sim_asynch_latency interval. We are trying to avoid
checking for completed asynchronous I/O after every instruction since the
actual checking every instruction can slow down execution. Periodic checks
provide a balance which allows response similar to real hardware while also
providing minimal impact on actual instruction execution. Meanwhile, if
maximal response is desired, then the value of sim_asynch_latency can be
set sufficiently low to assure that sim_asynch_inst_latency computes to 1.
The sim_asynch_inst_latency is dynamically updated once per second in the
sim_rtcn_calb routine where clock to instruction execution is dynamically
determined. A simulator would usually add register definitions
to enable viewing and setting of these variables via scp:
#if defined (SIM_ASYNCH_IO)
{ DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT },
{ DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT },
#endif
Naming conventions:
All of the routines implemented in sim_disk and sim_tape have been kept
in place. All routines which perform I/O have a variant routine available
with a "_a" appended to the the routine name with the addition of a single
parameter which indicates the asynch completion callback routine. For
example there now exists the routines:
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
The Purpose of the callback function is to record the I/O completion status
and then to schedule the activation of the unit.
Considerations:
Avoiding multiple concurrent users of the unit structure. While asynch
I/O is pending on a Unit, the unit should not otherwise be on the event
queue. The I/O completion will cause the Unit to be scheduled to run
immediately to actually dispatch control flow to the callback routine.
The callback routine is always called in the same thread which is
executing instructions. Since all simulator device data structures are
only referenced from this thread there are no host multi-processor cache
coherency issues to be concerned about.
Arguments to the callback routine:
UNIT *, and IO Status
Requirements of the Callback routine.
The callback routine must save the I/O completion status in a place
which the next invocation of the unit service routine will reference
and act on it. This allows device code to return error conditions
back to scp in a consistent way without regard to how the callback
routine (and the actual I/O) may have been executed.
Required change in device coding.
Devices which wish to leverage the benefits of asynch I/O must rearrange
the code which implements the unit service routine. This rearrangement
usually entails breaking the activities into two phases. The first phase
(I'll call the top half) involves performing whatever is needed to
initiate a call to perform an I/O operation with a callback argument.
Control is then immediately returned to the scp event dispatcher.
The callback routine needs to be coded to stash away the io completion
status and some indicator that an I/O has completed.
The top/bottom half separation of the unit service routine would be
coded to examine the I/O completion indicator and invoke the bottom half
code upon completion. The bottom half code should clear the I/O
completion indicator and then perform any activities which normally
need to occur after the I/O completes. Care should be taken while
performing these top/bottom half activities to return to the scp event
dispatcher with either SCPE_OK or an appropriate error code when needed.
The need to return error indications to the scp event dispatcher is why
the bottom half activities can't simply be performed in the
callback routine (the callback routine does not return a status).
Care should also be taken to realize that local variables in the
unit service routine will not directly survive between the separate
top and bottom half calls to the unit service routine. If any such
information must be referenced in both the top and bottom half code paths
then it must either be recomputed prior to the top/bottom half check
or not stored in local variables of the unit service routine.
Run time requirements to use SIM_ASYNCH_IO.
The Posix threads API (pthreads) is required for asynchronous execution.
Most *nix platforms have these APIs available and on these platforms
simh is typically built with these available since on these platforms,
pthreads is required for simh networking support. Windows can also
utilize the pthreads APIs if the compile and run time support for the
win32Pthreads package has been installed on the build system and the
run time dll is available in the execution environment.
Sample Asynch I/O device implementations.
The pdp11_rq.c module has been refactored to leverage the asynch I/O
features of the sim_disk library. The impact to this code to adopt the
asynch I/O paradigm was quite minimal.
The pdp11_rp.c module has also been refactored to leverage the asynch I/O
features of the sim_disk library.
The pdp11_tq.c module has been refactored to leverage the asynch I/O
features of the sim_tape library. The impact to this code to adopt the
asynch I/O paradigm was very significant. This was due to the two facts:
1) there are many different operations which can be requested of tape
devices and 2) some of the tmscp operations required many separate
operations on the physical device layer to perform a single tmscp request.
This issue was addressed by adding additional routines to the physical
device layer (in sim_tape.c) which combined these multiple operations.
This approach will dovetail well with a potential future addition of
operations on physical tapes as yet another supported tape format.

View file

@ -84,6 +84,7 @@
#define MD_ACL 0x0002 /* t avl: all class NI */ #define MD_ACL 0x0002 /* t avl: all class NI */
#define MD_NXU 0x0001 /* b gus: next unit */ #define MD_NXU 0x0001 /* b gus: next unit */
#define MD_RIP 0x0001 /* d onl: allow rip NI */ #define MD_RIP 0x0001 /* d onl: allow rip NI */
#define MD_SPD 0x0001 /* d avl: spin-down */
/* End flags */ /* End flags */

View file

@ -25,6 +25,10 @@
rp RH/RP/RM moving head disks rp RH/RP/RM moving head disks
06-Mar-11 MP Converted to using sim_disk library and refactored
for Asynch I/O.
Set STIME value to default of 26 which allows VMS V4.x
to boot.
17-May-07 RMS CS1 DVA resides in device, not MBA 17-May-07 RMS CS1 DVA resides in device, not MBA
21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter
12-Nov-05 RMS Fixed DriveClear, does not clear disk address 12-Nov-05 RMS Fixed DriveClear, does not clear disk address
@ -65,6 +69,7 @@
#endif #endif
#include "sim_disk.h"
#include <math.h> #include <math.h>
#define RP_CTRL 0 /* ctrl is RP */ #define RP_CTRL 0 /* ctrl is RP */
@ -93,6 +98,9 @@
/* Parameters in the unit descriptor */ /* Parameters in the unit descriptor */
#define CYL u3 /* current cylinder */ #define CYL u3 /* current cylinder */
#define sectsread u4 /* sectors read */
#define io_status u5 /* io status from callback */
#define io_complete u6 /* io completion flag */
/* RPCS1, RMCS1 - control/status 1 - offset 0 */ /* RPCS1, RMCS1 - control/status 1 - offset 0 */
@ -319,19 +327,20 @@ struct drvtyp {
int32 size; /* #blocks */ int32 size; /* #blocks */
int32 devtype; /* device type */ int32 devtype; /* device type */
int32 ctrl; /* ctrl type */ int32 ctrl; /* ctrl type */
char *name; /* device type name */
}; };
static struct drvtyp drv_tab[] = { static struct drvtyp drv_tab[] = {
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, RM_CTRL }, { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, RM_CTRL, "RM03" },
{ RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, RP_CTRL }, { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, RP_CTRL, "RP04" },
{ RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, RM_CTRL }, { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, RM_CTRL, "RM80" },
{ RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, RP_CTRL }, { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, RP_CTRL, "RP06" },
{ RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, RM_CTRL }, { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, RM_CTRL, "RM05" },
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, RM_CTRL }, { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, RM_CTRL, "RP07" },
{ 0 } { 0 }
}; };
uint16 *rpxb = NULL; /* xfer buffer */ uint16 *rpxb[RP_NUMDR] = { 0 }; /* xfer buffer */
uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */ uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */
uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */ uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */
uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */ uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */
@ -346,7 +355,7 @@ uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */
uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */ uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */
uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */ uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */
int32 rp_stopioe = 1; /* stop on error */ int32 rp_stopioe = 1; /* stop on error */
int32 rp_swait = 10; /* seek time */ int32 rp_swait = 26; /* seek time */
int32 rp_rwait = 10; /* rotate time */ int32 rp_rwait = 10; /* rotate time */
static const char *rp_fname[CS1_N_FNC] = { static const char *rp_fname[CS1_N_FNC] = {
"NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN", "NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN",
@ -767,6 +776,15 @@ int32 rp_abort (void)
return rp_reset (&rp_dev); return rp_reset (&rp_dev);
} }
/* I/O completion callback */
void rp_io_complete (UNIT *uptr, t_stat status)
{
uptr->io_status = status;
uptr->io_complete = 1;
sim_activate (uptr, 0);
}
/* Service unit timeout /* Service unit timeout
Complete movement or data transfer command Complete movement or data transfer command
@ -791,9 +809,9 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rp_update_ds (DS_ATA, drv); /* set attn */ rp_update_ds (DS_ATA, drv); /* set attn */
return (rp_stopioe? SCPE_UNATT: SCPE_OK); return (rp_stopioe? SCPE_UNATT: SCPE_OK);
} }
rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */
switch (fnc) { /* case on function */ if (!uptr->io_complete) { /* Top End (I/O Initiation) Processing */
switch (fnc) { /* case on function */
case FNC_OFFSET: /* offset */ case FNC_OFFSET: /* offset */
rp_update_ds (DS_OFM | DS_ATA, drv); rp_update_ds (DS_OFM | DS_ATA, drv);
@ -824,7 +842,6 @@ switch (fnc) { /* case on function */
case FNC_WCHK: /* write check */ case FNC_WCHK: /* write check */
case FNC_READ: /* read */ case FNC_READ: /* read */
case FNC_READH: /* read headers */ case FNC_READH: /* read headers */
err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);
mbc = mba_get_bc (rp_dib.ba); /* get byte count */ mbc = mba_get_bc (rp_dib.ba); /* get byte count */
wc = (mbc + 1) >> 1; /* convert to words */ wc = (mbc + 1) >> 1; /* convert to words */
if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */ if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */
@ -838,24 +855,56 @@ switch (fnc) { /* case on function */
} }
} }
if (fnc == FNC_WRITE) { /* write? */ if (fnc == FNC_WRITE) { /* write? */
abc = mba_rdbufW (rp_dib.ba, mbc, rpxb); /* get buffer */ abc = mba_rdbufW (rp_dib.ba, mbc, rpxb[drv]);/* get buffer */
wc = (abc + 1) >> 1; /* actual # wds */ wc = (abc + 1) >> 1; /* actual # wds */
awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1);
for (i = wc; i < awc; i++) /* fill buf */ for (i = wc; i < awc; i++) /* fill buf */
rpxb[i] = 0; rpxb[drv][i] = 0;
if (wc && !err) { /* write buf */ sim_disk_wrsect_a (uptr, da/RP_NUMWD, (void *)rpxb[drv], NULL, awc/RP_NUMWD, rp_io_complete);
fxwrite (rpxb, sizeof (uint16), awc, uptr->fileref); return SCPE_OK;
err = ferror (uptr->fileref);
}
} /* end if wr */ } /* end if wr */
else { /* read or wchk */ else { /* read or wchk */
awc = fxread (rpxb, sizeof (uint16), wc, uptr->fileref); awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1);
err = ferror (uptr->fileref); sim_disk_rdsect_a (uptr, da/RP_NUMWD, (void *)rpxb[drv], (t_seccnt*)&uptr->sectsread, awc/RP_NUMWD, rp_io_complete);
return SCPE_OK;
} /* end if read */
case FNC_WRITEH: /* write headers stub */
mba_set_don (rp_dib.ba); /* set done */
rp_update_ds (0, drv); /* update ds */
break;
} /* end case func */
}
else { /* Bottom End (After I/O processing) */
uptr->io_complete = 0;
err = uptr->io_status;
switch (fnc) { /* case on function */
case FNC_OFFSET: /* offset */
case FNC_RETURN: /* return to centerline */
case FNC_UNLOAD: /* unload */
case FNC_RECAL: /* recalibrate */
case FNC_SEARCH: /* search */
case FNC_SEEK: /* seek */
case FNC_WRITEH: /* write headers stub */
break;
case FNC_WRITE: /* write */
case FNC_WCHK: /* write check */
case FNC_READ: /* read */
case FNC_READH: /* read headers */
mbc = mba_get_bc (rp_dib.ba); /* get byte count */
wc = (mbc + 1) >> 1; /* convert to words */
if (fnc == FNC_WRITE) { /* write? */
} /* end if wr */
else { /* read or wchk */
awc = uptr->sectsread * RP_NUMWD;
for (i = awc; i < wc; i++) /* fill buf */ for (i = awc; i < wc; i++) /* fill buf */
rpxb[i] = 0; rpxb[drv][i] = 0;
if (fnc == FNC_WCHK) /* write check? */ if (fnc == FNC_WCHK) /* write check? */
mba_chbufW (rp_dib.ba, mbc, rpxb); /* check vs mem */ mba_chbufW (rp_dib.ba, mbc, rpxb[drv]); /* check vs mem */
else mba_wrbufW (rp_dib.ba, mbc, rpxb); /* store in mem */ else mba_wrbufW (rp_dib.ba, mbc, rpxb[drv]);/* store in mem */
} /* end if read */ } /* end if read */
da = da + wc + (RP_NUMWD - 1); da = da + wc + (RP_NUMWD - 1);
if (da >= drv_tab[dtype].size) if (da >= drv_tab[dtype].size)
@ -872,15 +921,15 @@ switch (fnc) { /* case on function */
mba_set_exc (rp_dib.ba); /* set exception */ mba_set_exc (rp_dib.ba); /* set exception */
rp_update_ds (DS_ATA, drv); rp_update_ds (DS_ATA, drv);
perror ("RP I/O error"); perror ("RP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; return SCPE_IOERR;
} }
case FNC_WRITEH: /* write headers stub */
mba_set_don (rp_dib.ba); /* set done */ mba_set_don (rp_dib.ba); /* set done */
rp_update_ds (0, drv); /* update ds */ rp_update_ds (0, drv); /* update ds */
break; break;
} /* end case func */ } /* end case func */
}
rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */
if (DEBUG_PRS (rp_dev)) if (DEBUG_PRS (rp_dev))
fprintf (sim_deb, ">>RP%d DONE: fnc=%s, ds=%o, cyl=%o, da=%o, er=%d\n", fprintf (sim_deb, ">>RP%d DONE: fnc=%s, ds=%o, cyl=%o, da=%o, er=%d\n",
@ -963,11 +1012,11 @@ for (i = 0; i < RP_NUMDR; i++) {
rpec2[i] = 0; rpec2[i] = 0;
rmmr2[i] = 0; rmmr2[i] = 0;
rmhr[i] = 0; rmhr[i] = 0;
} if (rpxb[i] == NULL)
if (rpxb == NULL) rpxb[i] = (uint16 *) calloc (RP_MAXFR, sizeof (uint16));
rpxb = (uint16 *) calloc (RP_MAXFR, sizeof (uint16)); if (rpxb[i] == NULL)
if (rpxb == NULL)
return SCPE_MEM; return SCPE_MEM;
}
return SCPE_OK; return SCPE_OK;
} }
@ -979,7 +1028,9 @@ int32 drv, i, p;
t_stat r; t_stat r;
uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
r = attach_unit (uptr, cptr); /* attach unit */ r = sim_disk_attach (uptr, cptr, RP_NUMWD * sizeof (uint16),
sizeof (uint16), TRUE, 0,
drv_tab[GET_DTYPE (uptr->flags)].name, drv_tab[GET_DTYPE (uptr->flags)].sect);
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
drv = (int32) (uptr - rp_dev.units); /* get drv number */ drv = (int32) (uptr - rp_dev.units); /* get drv number */
@ -988,14 +1039,9 @@ rpds[drv] = DS_MOL | DS_RDY | DS_DPR | /* upd drv status */
rper1[drv] = 0; rper1[drv] = 0;
rp_update_ds (DS_ATA, drv); /* upd ctlr status */ rp_update_ds (DS_ATA, drv); /* upd ctlr status */
if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
if (uptr->flags & UNIT_RO)
return SCPE_OK;
return pdp11_bad_block (uptr,
drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD);
}
if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */
return SCPE_OK; return SCPE_OK;
p = (int32)sim_disk_size (uptr);
for (i = 0; drv_tab[i].sect != 0; i++) { for (i = 0; drv_tab[i].sect != 0; i++) {
if (p <= (drv_tab[i].size * (int) sizeof (int16))) { if (p <= (drv_tab[i].size * (int) sizeof (int16))) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
@ -1017,7 +1063,7 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */
drv = (int32) (uptr - rp_dev.units); /* get drv number */ drv = (int32) (uptr - rp_dev.units); /* get drv number */
rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM); rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM);
rp_update_ds (DS_ATA, drv); /* request intr */ rp_update_ds (DS_ATA, drv); /* request intr */
return detach_unit (uptr); return sim_disk_detach (uptr);
} }
/* Set size command validation routine */ /* Set size command validation routine */

View file

@ -26,6 +26,19 @@
rq RQDX3 disk controller rq RQDX3 disk controller
07-Mar-11 MP Added working behaviors for removable device types.
This allows physical CDROM's to come online and be
ejected.
02-Mar-11 MP Fixed missing information from save/restore which
caused operations to not complete correctly after
a restore until the OS reset the controller.
02-Feb-11 MP Added Autosize support to rq_attach
28-Jan-11 MP Adopted use of sim_disk disk I/O library
- added support for the multiple formats sim_disk
provides (SimH, RAW, and VHD)
- adjusted to potentially leverage asynch I/O when
available
- Added differing detailed debug output via sim_debug
14-Jan-09 JH Added support for RD32 disc drive 14-Jan-09 JH Added support for RD32 disc drive
18-Jun-07 RMS Added UNIT_IDLE flag to timer thread 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
31-Oct-05 RMS Fixed address width for large files 31-Oct-05 RMS Fixed address width for large files
@ -97,6 +110,7 @@ extern int32 cpu_opt;
#include "pdp11_uqssp.h" #include "pdp11_uqssp.h"
#include "pdp11_mscp.h" #include "pdp11_mscp.h"
#include "sim_disk.h"
#define UF_MSK (UF_CMR|UF_CMW) /* settable flags */ #define UF_MSK (UF_CMR|UF_CMW) /* settable flags */
@ -129,20 +143,25 @@ extern int32 cpu_opt;
#define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */ #define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */
#define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */ #define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */
#define UNIT_M_DTYPE 0x1F #define UNIT_M_DTYPE 0x1F
#define UNIT_V_NOAUTO (UNIT_V_UF + 8) /* noautosize */
#define UNIT_ONL (1 << UNIT_V_ONL) #define UNIT_ONL (1 << UNIT_V_ONL)
#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_ATP (1 << UNIT_V_ATP) #define UNIT_ATP (1 << UNIT_V_ATP)
#define UNIT_NOAUTO (1 << UNIT_V_NOAUTO)
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define cpkt u3 /* current packet */ #define cpkt u3 /* current packet */
#define pktq u4 /* packet queue */ #define pktq u4 /* packet queue */
#define uf buf /* settable unit flags */ #define uf buf /* settable unit flags */
#define cnum wait /* controller index */ #define cnum wait /* controller index */
#define io_status u5 /* io status from callback */
#define io_complete u6 /* io completion flag */
#define rqxb filebuf /* xfer buffer */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
#define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \ #define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \
UF_RMV: 0) UF_RMV: 0)
#define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \ #define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \
(u->flags & UNIT_WPRT))? UF_WPH: 0) (u->flags & UNIT_WPRT) || sim_disk_wrp (u))? UF_WPH: 0)
#define CST_S1 0 /* init stage 1 */ #define CST_S1 0 /* init stage 1 */
#define CST_S1_WR 1 /* stage 1 wrap */ #define CST_S1_WR 1 /* stage 1 wrap */
@ -567,7 +586,6 @@ extern FILE *sim_deb;
extern uint32 sim_taddr_64; extern uint32 sim_taddr_64;
extern int32 sim_switches; extern int32 sim_switches;
uint16 *rqxb = NULL; /* xfer buffer */
int32 rq_itime = 200; /* init time, except */ int32 rq_itime = 200; /* init time, except */
int32 rq_itime4 = 10; /* stage 4 */ int32 rq_itime4 = 10; /* stage 4 */
int32 rq_qtime = RQ_QTIME; /* queue time */ int32 rq_qtime = RQ_QTIME; /* queue time */
@ -597,7 +615,56 @@ typedef struct {
struct rqpkt pak[RQ_NPKTS]; /* packet queue */ struct rqpkt pak[RQ_NPKTS]; /* packet queue */
} MSC; } MSC;
DEVICE rq_dev, rqb_dev, rqc_dev,rqd_dev; /* debugging bitmaps */
#define DBG_TRC 0x0001 /* trace routine calls */
#define DBG_INI 0x0002 /* display setup/init sequence info */
#define DBG_REG 0x0004 /* trace read/write registers */
#define DBG_REQ 0x0008 /* display transfer requests */
#define DBG_DSK 0x0010 /* display sim_disk activities */
#define DBG_DAT 0x0020 /* display transfer data */
DEBTAB rq_debug[] = {
{"TRACE", DBG_TRC},
{"INIT", DBG_INI},
{"REG", DBG_REG},
{"REQ", DBG_REQ},
{"DISK", DBG_DSK},
{"DATA", DBG_DAT},
{0}
};
static char *rq_cmdname[] = {
"", /* 0 */
"ABO", /* 1 b: abort */
"GCS", /* 2 b: get command status */
"GUS", /* 3 b: get unit status */
"SCC", /* 4 b: set controller char */
"","","", /* 5-7 */
"AVL", /* 8 b: available */
"ONL", /* 9 b: online */
"SUC", /* 10 b: set unit char */
"DAP", /* 11 b: det acc paths - nop */
"","","","", /* 12-15 */
"ACC", /* 16 b: access */
"CCD", /* 17 d: compare - nop */
"ERS", /* 18 b: erase */
"FLU", /* 19 d: flush - nop */
"","", /* 20-21 */
"ERG", /* 22 t: erase gap */
"","","","","","","","","", /* 23-31 */
"CMP", /* 32 b: compare */
"RD", /* 33 b: read */
"WR", /* 34 b: write */
"", /* 35 */
"WTM", /* 36 t: write tape mark */
"POS", /* 37 t: reposition */
"","","","","","","","","", /* 38-46 */
"FMT", /* 47 d: format */
"","","","","","","","","","","","","","","","", /* 48-63 */
"AVA", /* 64 b: unit now avail */
};
DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
t_stat rq_rd (int32 *data, int32 PA, int32 access); t_stat rq_rd (int32 *data, int32 PA, int32 access);
t_stat rq_wr (int32 data, int32 PA, int32 access); t_stat rq_wr (int32 data, int32 PA, int32 access);
@ -686,9 +753,11 @@ REG rq_reg[] = {
{ GRDATA (SAW, rq_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (SAW, rq_ctx.saw, DEV_RDX, 16, 0) },
{ GRDATA (S1DAT, rq_ctx.s1dat, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rq_ctx.s1dat, DEV_RDX, 16, 0) },
{ GRDATA (COMM, rq_ctx.comm, DEV_RDX, 22, 0) }, { GRDATA (COMM, rq_ctx.comm, DEV_RDX, 22, 0) },
{ GRDATA (CQIOFF, rq_ctx.cq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (CQBA, rq_ctx.cq.ba, DEV_RDX, 22, 0) }, { GRDATA (CQBA, rq_ctx.cq.ba, DEV_RDX, 22, 0) },
{ GRDATA (CQLNT, rq_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (CQLNT, rq_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (CQIDX, rq_ctx.cq.idx, DEV_RDX, 8, 2) }, { GRDATA (CQIDX, rq_ctx.cq.idx, DEV_RDX, 8, 2) },
{ GRDATA (RQIOFF, rq_ctx.rq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (RQBA, rq_ctx.rq.ba, DEV_RDX, 22, 0) }, { GRDATA (RQBA, rq_ctx.rq.ba, DEV_RDX, 22, 0) },
{ GRDATA (RQLNT, rq_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (RQLNT, rq_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (RQIDX, rq_ctx.rq.idx, DEV_RDX, 8, 2) }, { GRDATA (RQIDX, rq_ctx.rq.idx, DEV_RDX, 8, 2) },
@ -774,6 +843,10 @@ MTAB rq_mod[] = {
&rq_set_type, NULL, NULL }, &rq_set_type, NULL, NULL },
{ MTAB_XTD | MTAB_VUN, 0, "TYPE", NULL, { MTAB_XTD | MTAB_VUN, 0, "TYPE", NULL,
NULL, &rq_show_type, NULL }, NULL, &rq_show_type, NULL },
{ UNIT_NOAUTO, UNIT_NOAUTO, "noautosize", "NOAUTOSIZE", NULL },
{ UNIT_NOAUTO, 0, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_disk_set_fmt, &sim_disk_show_fmt, NULL },
#if defined (VM_PDP11) #if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL }, &set_addr, &show_addr, NULL },
@ -793,7 +866,8 @@ DEVICE rq_dev = {
RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
0, rq_debug
}; };
/* RQB data structures /* RQB data structures
@ -829,9 +903,11 @@ REG rqb_reg[] = {
{ GRDATA (SAW, rqb_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (SAW, rqb_ctx.saw, DEV_RDX, 16, 0) },
{ GRDATA (S1DAT, rqb_ctx.s1dat, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqb_ctx.s1dat, DEV_RDX, 16, 0) },
{ GRDATA (COMM, rqb_ctx.comm, DEV_RDX, 22, 0) }, { GRDATA (COMM, rqb_ctx.comm, DEV_RDX, 22, 0) },
{ GRDATA (CQIOFF, rqb_ctx.cq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (CQBA, rqb_ctx.cq.ba, DEV_RDX, 22, 0) }, { GRDATA (CQBA, rqb_ctx.cq.ba, DEV_RDX, 22, 0) },
{ GRDATA (CQLNT, rqb_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (CQLNT, rqb_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (CQIDX, rqb_ctx.cq.idx, DEV_RDX, 8, 2) }, { GRDATA (CQIDX, rqb_ctx.cq.idx, DEV_RDX, 8, 2) },
{ GRDATA (RQIOFF, rqb_ctx.rq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (RQBA, rqb_ctx.rq.ba, DEV_RDX, 22, 0) }, { GRDATA (RQBA, rqb_ctx.rq.ba, DEV_RDX, 22, 0) },
{ GRDATA (RQLNT, rqb_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (RQLNT, rqb_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (RQIDX, rqb_ctx.rq.idx, DEV_RDX, 8, 2) }, { GRDATA (RQIDX, rqb_ctx.rq.idx, DEV_RDX, 8, 2) },
@ -851,7 +927,7 @@ REG rqb_reg[] = {
{ URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (UFLG, rqb_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqb_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
{ URDATA (CAPAC, rqb_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, { URDATA (CAPAC, rqb_unit[0].capac, 10, T_ADDR_W, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
{ GRDATA (DEVADDR, rqb_dib.ba, DEV_RDX, 32, 0), REG_HRO }, { GRDATA (DEVADDR, rqb_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, rqb_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { GRDATA (DEVVEC, rqb_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL } { NULL }
@ -862,7 +938,8 @@ DEVICE rqb_dev = {
RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
0, rq_debug
}; };
/* RQC data structures /* RQC data structures
@ -898,9 +975,11 @@ REG rqc_reg[] = {
{ GRDATA (SAW, rqc_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (SAW, rqc_ctx.saw, DEV_RDX, 16, 0) },
{ GRDATA (S1DAT, rqc_ctx.s1dat, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqc_ctx.s1dat, DEV_RDX, 16, 0) },
{ GRDATA (COMM, rqc_ctx.comm, DEV_RDX, 22, 0) }, { GRDATA (COMM, rqc_ctx.comm, DEV_RDX, 22, 0) },
{ GRDATA (CQIOFF, rqc_ctx.cq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (CQBA, rqc_ctx.cq.ba, DEV_RDX, 22, 0) }, { GRDATA (CQBA, rqc_ctx.cq.ba, DEV_RDX, 22, 0) },
{ GRDATA (CQLNT, rqc_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (CQLNT, rqc_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (CQIDX, rqc_ctx.cq.idx, DEV_RDX, 8, 2) }, { GRDATA (CQIDX, rqc_ctx.cq.idx, DEV_RDX, 8, 2) },
{ GRDATA (RQIOFF, rqc_ctx.rq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (RQBA, rqc_ctx.rq.ba, DEV_RDX, 22, 0) }, { GRDATA (RQBA, rqc_ctx.rq.ba, DEV_RDX, 22, 0) },
{ GRDATA (RQLNT, rqc_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (RQLNT, rqc_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (RQIDX, rqc_ctx.rq.idx, DEV_RDX, 8, 2) }, { GRDATA (RQIDX, rqc_ctx.rq.idx, DEV_RDX, 8, 2) },
@ -920,7 +999,7 @@ REG rqc_reg[] = {
{ URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (UFLG, rqc_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqc_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
{ URDATA (CAPAC, rqc_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, { URDATA (CAPAC, rqc_unit[0].capac, 10, T_ADDR_W, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
{ GRDATA (DEVADDR, rqc_dib.ba, DEV_RDX, 32, 0), REG_HRO }, { GRDATA (DEVADDR, rqc_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, rqc_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { GRDATA (DEVVEC, rqc_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL } { NULL }
@ -931,7 +1010,8 @@ DEVICE rqc_dev = {
RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
0, rq_debug
}; };
/* RQD data structures /* RQD data structures
@ -967,9 +1047,11 @@ REG rqd_reg[] = {
{ GRDATA (SAW, rqd_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (SAW, rqd_ctx.saw, DEV_RDX, 16, 0) },
{ GRDATA (S1DAT, rqd_ctx.s1dat, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqd_ctx.s1dat, DEV_RDX, 16, 0) },
{ GRDATA (COMM, rqd_ctx.comm, DEV_RDX, 22, 0) }, { GRDATA (COMM, rqd_ctx.comm, DEV_RDX, 22, 0) },
{ GRDATA (CQIOFF, rqd_ctx.cq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (CQBA, rqd_ctx.cq.ba, DEV_RDX, 22, 0) }, { GRDATA (CQBA, rqd_ctx.cq.ba, DEV_RDX, 22, 0) },
{ GRDATA (CQLNT, rqd_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (CQLNT, rqd_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (CQIDX, rqd_ctx.cq.idx, DEV_RDX, 8, 2) }, { GRDATA (CQIDX, rqd_ctx.cq.idx, DEV_RDX, 8, 2) },
{ GRDATA (RQIOFF, rqd_ctx.rq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (RQBA, rqd_ctx.rq.ba, DEV_RDX, 22, 0) }, { GRDATA (RQBA, rqd_ctx.rq.ba, DEV_RDX, 22, 0) },
{ GRDATA (RQLNT, rqd_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (RQLNT, rqd_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (RQIDX, rqd_ctx.rq.idx, DEV_RDX, 8, 2) }, { GRDATA (RQIDX, rqd_ctx.rq.idx, DEV_RDX, 8, 2) },
@ -989,7 +1071,7 @@ REG rqd_reg[] = {
{ URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) },
{ URDATA (UFLG, rqd_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqd_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) },
{ URDATA (CAPAC, rqd_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, { URDATA (CAPAC, rqd_unit[0].capac, 10, T_ADDR_W, 0, RQ_NUMDR, PV_LEFT | REG_HRO) },
{ GRDATA (DEVADDR, rqd_dib.ba, DEV_RDX, 32, 0), REG_HRO }, { GRDATA (DEVADDR, rqd_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, rqd_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { GRDATA (DEVVEC, rqd_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL } { NULL }
@ -1000,7 +1082,8 @@ DEVICE rqd_dev = {
RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
0, rq_debug
}; };
static DEVICE *rq_devmap[RQ_NUMCT] = { static DEVICE *rq_devmap[RQ_NUMCT] = {
@ -1023,6 +1106,8 @@ int32 cidx = rq_map_pa ((uint32) PA);
MSC *cp = rq_ctxmap[cidx]; MSC *cp = rq_ctxmap[cidx];
DEVICE *dptr = rq_devmap[cidx]; DEVICE *dptr = rq_devmap[cidx];
sim_debug(DBG_REG, dptr, "rq_rd(PA=0x%08X [%s], access=%d)\n", PA, ((PA >> 1) & 01) ? "IP" : "SA", access);
if (cidx < 0) if (cidx < 0)
return SCPE_IERR; return SCPE_IERR;
switch ((PA >> 1) & 01) { /* decode PA<1> */ switch ((PA >> 1) & 01) { /* decode PA<1> */
@ -1032,9 +1117,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */
if (cp->csta == CST_S3_PPB) /* waiting for poll? */ if (cp->csta == CST_S3_PPB) /* waiting for poll? */
rq_step4 (cp); rq_step4 (cp);
else if (cp->csta == CST_UP) { /* if up */ else if (cp->csta == CST_UP) { /* if up */
if (DEBUG_PRD (dptr)) sim_debug (DBG_REQ, dptr, "poll started, PC=%X\n", OLDPC);
fprintf (sim_deb, ">>RQ%c: poll started, PC=%X\n",
'A' + cp->cnum, OLDPC);
cp->pip = 1; /* poll host */ cp->pip = 1; /* poll host */
sim_activate (dptr->units + RQ_QUEUE, rq_qtime); sim_activate (dptr->units + RQ_QUEUE, rq_qtime);
} }
@ -1044,7 +1127,6 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */
*data = cp->sa; *data = cp->sa;
break; break;
} }
return SCPE_OK; return SCPE_OK;
} }
@ -1056,13 +1138,14 @@ DEVICE *dptr = rq_devmap[cidx];
if (cidx < 0) if (cidx < 0)
return SCPE_IERR; return SCPE_IERR;
sim_debug(DBG_REG, dptr, "rq_wr(PA=0x%08X [%s], access=%d)\n", PA, ((PA >> 1) & 01) ? "IP" : "SA", access);
switch ((PA >> 1) & 01) { /* decode PA<1> */ switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* IP */ case 0: /* IP */
rq_reset (rq_devmap[cidx]); /* init device */ rq_reset (rq_devmap[cidx]); /* init device */
if (DEBUG_PRD (dptr)) sim_debug (DBG_REQ, dptr, "initialization started\n");
fprintf (sim_deb, ">>RQ%c: initialization started\n",
'A' + cp->cnum);
break; break;
case 1: /* SA */ case 1: /* SA */
@ -1147,7 +1230,12 @@ MSC *cp = rq_ctxmap[uptr->cnum];
DEVICE *dptr = rq_devmap[uptr->cnum]; DEVICE *dptr = rq_devmap[uptr->cnum];
DIB *dibp = (DIB *) dptr->ctxt; DIB *dibp = (DIB *) dptr->ctxt;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_quesvc\n");
if (cp->csta < CST_UP) { /* still init? */ if (cp->csta < CST_UP) { /* still init? */
sim_debug(DBG_INI, dptr, "CSTA=%d, SAW=0x%X\n", cp->csta, cp->saw);
switch (cp->csta) { /* controller state? */ switch (cp->csta) { /* controller state? */
case CST_S1: /* need S1 reply */ case CST_S1: /* need S1 reply */
@ -1197,8 +1285,7 @@ if (cp->csta < CST_UP) { /* still init? */
case CST_S4: /* need S4 reply */ case CST_S4: /* need S4 reply */
if (cp->saw & SA_S4H_GO) { /* go set? */ if (cp->saw & SA_S4H_GO) { /* go set? */
if (DEBUG_PRD (dptr)) sim_debug (DBG_REQ, dptr, "initialization complete\n");
fprintf (sim_deb, ">>RQ%c: initialization complete\n", 'A' + cp->cnum);
cp->csta = CST_UP; /* we're up */ cp->csta = CST_UP; /* we're up */
cp->sa = 0; /* clear SA */ cp->sa = 0; /* clear SA */
sim_activate (dptr->units + RQ_TIMER, tmr_poll * clk_tps); sim_activate (dptr->units + RQ_TIMER, tmr_poll * clk_tps);
@ -1224,15 +1311,12 @@ if ((pkt == 0) && cp->pip) { /* polling? */
if (!rq_getpkt (cp, &pkt)) /* get host pkt */ if (!rq_getpkt (cp, &pkt)) /* get host pkt */
return SCPE_OK; return SCPE_OK;
if (pkt) { /* got one? */ if (pkt) { /* got one? */
if (DEBUG_PRD (dptr)) { sim_debug (DBG_REQ, dptr, "cmd=%04X(%3s), mod=%04X, unit=%d, bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n",
fprintf (sim_deb, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", cp->pak[pkt].d[CMD_OPC], rq_cmdname[cp->pak[pkt].d[CMD_OPC]&0x3f],
'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC], cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN],
cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN]);
fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n",
cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL], cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL],
cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL], cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL],
cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]); cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]);
}
if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */
return rq_fatal (cp, PE_PIE); /* no, term thread */ return rq_fatal (cp, PE_PIE); /* no, term thread */
cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */
@ -1253,6 +1337,7 @@ if (cp->rspq) { /* resp q? */
pkt = rq_deqh (cp, &cp->rspq); /* get top of q */ pkt = rq_deqh (cp, &cp->rspq); /* get top of q */
if (!rq_putpkt (cp, pkt, FALSE)) /* send to host */ if (!rq_putpkt (cp, pkt, FALSE)) /* send to host */
return SCPE_OK; return SCPE_OK;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_quesvc - rq_putpkt failed - 1\n");
} /* end if resp q */ } /* end if resp q */
if (pkt) /* more to do? */ if (pkt) /* more to do? */
sim_activate (uptr, rq_qtime); sim_activate (uptr, rq_qtime);
@ -1268,6 +1353,7 @@ UNIT *nuptr;
MSC *cp = rq_ctxmap[uptr->cnum]; MSC *cp = rq_ctxmap[uptr->cnum];
DEVICE *dptr = rq_devmap[uptr->cnum]; DEVICE *dptr = rq_devmap[uptr->cnum];
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_tmrsvc\n");
sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */
for (i = 0; i < RQ_NUMDR; i++) { /* poll */ for (i = 0; i < RQ_NUMDR; i++) { /* poll */
nuptr = dptr->units + i; nuptr = dptr->units + i;
@ -1290,6 +1376,8 @@ t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q)
{ {
uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC); uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC);
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_mscp - %s\n", q? "Queue" : "No Queue");
switch (cmd) { switch (cmd) {
case OP_ABO: /* abort */ case OP_ABO: /* abort */
@ -1351,6 +1439,8 @@ int32 tpkt, prv;
UNIT *uptr; UNIT *uptr;
DEVICE *dptr = rq_devmap[cp->cnum]; DEVICE *dptr = rq_devmap[cp->cnum];
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_abo\n");
tpkt = 0; /* set no mtch */ tpkt = 0; /* set no mtch */
if (uptr = rq_getucb (cp, lu)) { /* get unit */ if (uptr = rq_getucb (cp, lu)) { /* get unit */
if (uptr->cpkt && /* curr pkt? */ if (uptr->cpkt && /* curr pkt? */
@ -1390,15 +1480,20 @@ t_bool rq_avl (MSC *cp, int32 pkt, t_bool q)
{ {
uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */
uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 mdf = cp->pak[pkt].d[CMD_MOD]; /* modifier */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_avl\n");
if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
if (q && uptr->cpkt) { /* need to queue? */ if (q && uptr->cpkt) { /* need to queue? */
rq_enqt (cp, &uptr->pktq, pkt); /* do later */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */
return OK; return OK;
} }
uptr->flags = uptr->flags & ~UNIT_ONL; /* not online */ uptr->flags = uptr->flags & ~UNIT_ONL; /* not online */
if ((mdf & MD_SPD) && RQ_RMV (uptr)) /* unload of removable device */
sim_disk_unload (uptr);
uptr->uf = 0; /* clr flags */ uptr->uf = 0; /* clr flags */
sts = ST_SUC; /* success */ sts = ST_SUC; /* success */
} }
@ -1417,6 +1512,8 @@ uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */
int32 tpkt; int32 tpkt;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_gcs\n");
if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */
(tpkt = uptr->cpkt) && /* queued pkt? */ (tpkt = uptr->cpkt) && /* queued pkt? */
(GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */
@ -1441,6 +1538,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 dtyp, sts, rbpar; uint32 dtyp, sts, rbpar;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_gus\n");
if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */
if (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */ if (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */
lu = 0; /* reset to 0 */ lu = 0; /* reset to 0 */
@ -1482,6 +1581,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_onl\n");
if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
if (q && uptr->cpkt) { /* need to queue? */ if (q && uptr->cpkt) { /* need to queue? */
rq_enqt (cp, &uptr->pktq, pkt); /* do later */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */
@ -1491,11 +1592,14 @@ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
sts = ST_OFL | SB_OFL_NV; /* offl no vol */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */
else if (uptr->flags & UNIT_ONL) /* already online? */ else if (uptr->flags & UNIT_ONL) /* already online? */
sts = ST_SUC | SB_SUC_ON; sts = ST_SUC | SB_SUC_ON;
else { /* mark online */ else if (sim_disk_isavailable (uptr))
{ /* mark online */
sts = ST_SUC; sts = ST_SUC;
uptr->flags = uptr->flags | UNIT_ONL; uptr->flags = uptr->flags | UNIT_ONL;
rq_setf_unit (cp, pkt, uptr); /* hack flags */ rq_setf_unit (cp, pkt, uptr); /* hack flags */
} }
else
sts = ST_OFL | SB_OFL_NV; /* offl no vol */
rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */ rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */
} }
else sts = ST_OFL; /* offline */ else sts = ST_OFL; /* offline */
@ -1511,6 +1615,8 @@ t_bool rq_scc (MSC *cp, int32 pkt, t_bool q)
{ {
int32 sts, cmd; int32 sts, cmd;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_scc\n");
if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */
sts = ST_CMD | I_VRSN; /* no, lose */ sts = ST_CMD | I_VRSN; /* no, lose */
cmd = 0; cmd = 0;
@ -1547,6 +1653,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_suc\n");
if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
if (q && uptr->cpkt) { /* need to queue? */ if (q && uptr->cpkt) { /* need to queue? */
rq_enqt (cp, &uptr->pktq, pkt); /* do later */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */
@ -1576,6 +1684,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_fmt\n");
if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
if (q && uptr->cpkt) { /* need to queue? */ if (q && uptr->cpkt) { /* need to queue? */
rq_enqt (cp, &uptr->pktq, pkt); /* do later */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */
@ -1610,8 +1720,11 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw(lu=%d, pkt=%d, queue=%s)\n", lu, pkt, q?"yes" : "no");
if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
if (q && uptr->cpkt) { /* need to queue? */ if (q && uptr->cpkt) { /* need to queue? */
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw - queued\n");
rq_enqt (cp, &uptr->pktq, pkt); /* do later */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */
return OK; return OK;
} }
@ -1624,7 +1737,9 @@ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
cp->pak[pkt].d[RW_WBCH] = cp->pak[pkt].d[RW_BCH]; cp->pak[pkt].d[RW_WBCH] = cp->pak[pkt].d[RW_BCH];
cp->pak[pkt].d[RW_WBLL] = cp->pak[pkt].d[RW_LBNL]; cp->pak[pkt].d[RW_WBLL] = cp->pak[pkt].d[RW_LBNL];
cp->pak[pkt].d[RW_WBLH] = cp->pak[pkt].d[RW_LBNH]; cp->pak[pkt].d[RW_WBLH] = cp->pak[pkt].d[RW_LBNH];
sim_activate (uptr, rq_xtime); /* activate */ uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* activate */
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw - started\n");
return OK; /* done */ return OK; /* done */
} }
} }
@ -1674,12 +1789,28 @@ if ((cmd == OP_WR) || (cmd == OP_ERS)) { /* write op? */
return 0; /* success! */ return 0; /* success! */
} }
/* I/O completion callback */
void rq_io_complete (UNIT *uptr, t_stat status)
{
MSC *cp = rq_ctxmap[uptr->cnum];
int32 elapsed = sim_grtime()-uptr->iostarttime;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_io_complete(status=%d)\n", status);
uptr->io_status = status;
uptr->io_complete = 1;
if (elapsed > rq_xtime)
sim_activate (uptr, 0);
else
sim_activate (uptr, rq_xtime-elapsed);
}
/* Unit service for data transfer commands */ /* Unit service for data transfer commands */
t_stat rq_svc (UNIT *uptr) t_stat rq_svc (UNIT *uptr)
{ {
MSC *cp = rq_ctxmap[uptr->cnum]; MSC *cp = rq_ctxmap[uptr->cnum];
uint32 i, t, tbc, abc, wwc; uint32 i, t, tbc, abc, wwc;
uint32 err = 0; uint32 err = 0;
int32 pkt = uptr->cpkt; /* get packet */ int32 pkt = uptr->cpkt; /* get packet */
@ -1687,7 +1818,10 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
uint32 ba = GETP32 (pkt, RW_WBAL); /* buf addr */ uint32 ba = GETP32 (pkt, RW_WBAL); /* buf addr */
uint32 bc = GETP32 (pkt, RW_WBCL); /* byte count */ uint32 bc = GETP32 (pkt, RW_WBCL); /* byte count */
uint32 bl = GETP32 (pkt, RW_WBLL); /* block addr */ uint32 bl = GETP32 (pkt, RW_WBLL); /* block addr */
t_addr da = ((t_addr) bl) * RQ_NUMBY; /* disk addr */
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_svc(unit=%d, pkt=%d, cmd=%s, lbn=%0X, bc=%0x, phase=%s)\n",
uptr-rq_devmap[cp->cnum]->units, pkt, rq_cmdname[cp->pak[pkt].d[CMD_OPC]&0x3f], bl, bc,
uptr->io_complete ? "bottom" : "top");
if ((cp == NULL) || (pkt == 0)) /* what??? */ if ((cp == NULL) || (pkt == 0)) /* what??? */
return STOP_RQ; return STOP_RQ;
@ -1713,27 +1847,39 @@ if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */
} }
} }
if (cmd == OP_ERS) { /* erase? */ if (!uptr->io_complete) { /* Top End (I/O Initiation) Processing */
if (cmd == OP_ERS) { /* erase? */
wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1;
for (i = 0; i < wwc; i++) /* clr buf */ memset (uptr->rqxb, 0, wwc * sizeof(uint16)); /* clr buf */
rqxb[i] = 0; sim_disk_data_trace(uptr, uptr->rqxb, bl, wwc << 1, "sim_disk_wrsect-ERS", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ);
err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ err = sim_disk_wrsect_a (uptr, bl, uptr->rqxb, NULL, (wwc << 1) / RQ_NUMBY, rq_io_complete);
if (!err)
sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref);
err = ferror (uptr->fileref); /* end if erase */
} }
else if (cmd == OP_WR) { /* write? */ else if (cmd == OP_WR) { /* write? */
t = Map_ReadW (ba, tbc, rqxb); /* fetch buffer */ t = Map_ReadW (ba, tbc, uptr->rqxb); /* fetch buffer */
if (abc = tbc - t) { /* any xfer? */ if (abc = tbc - t) { /* any xfer? */
wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1;
for (i = (abc >> 1); i < wwc; i++) for (i = (abc >> 1); i < wwc; i++)
rqxb[i] = 0; ((uint16 *)(uptr->rqxb))[i] = 0;
err = sim_fseek (uptr->fileref, da, SEEK_SET); sim_disk_data_trace(uptr, uptr->rqxb, bl, wwc << 1, "sim_disk_wrsect-WR", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ);
if (!err) err = sim_disk_wrsect_a (uptr, bl, uptr->rqxb, NULL, (wwc << 1) / RQ_NUMBY, rq_io_complete);
sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref);
err = ferror (uptr->fileref);
} }
}
else { /* OP_RD & OP_CMP */
err = sim_disk_rdsect_a (uptr, bl, uptr->rqxb, NULL, (tbc + RQ_NUMBY - 1) / RQ_NUMBY, rq_io_complete);
} /* end else read */
return SCPE_OK; /* done for now until callback */
}
else { /* Bottom End (After I/O processing) */
uptr->io_complete = 0;
err = uptr->io_status;
if (cmd == OP_ERS) { /* erase? */
}
else if (cmd == OP_WR) { /* write? */
t = Map_ReadW (ba, tbc, uptr->rqxb); /* fetch buffer */
abc = tbc - t; /* any xfer? */
if (t) { /* nxm? */ if (t) { /* nxm? */
PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */
PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */ PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */
@ -1743,16 +1889,10 @@ else if (cmd == OP_WR) { /* write? */
} }
} }
else { else {
err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ sim_disk_data_trace(uptr, uptr->rqxb, bl, tbc, "sim_disk_rdsect", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ);
if (!err) {
i = sim_fread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref);
for ( ; i < (tbc >> 1); i++) /* fill */
rqxb[i] = 0;
err = ferror (uptr->fileref);
}
if ((cmd == OP_RD) && !err) { /* read? */ if ((cmd == OP_RD) && !err) { /* read? */
if (t = Map_WriteW (ba, tbc, rqxb)) { /* store, nxm? */ if (t = Map_WriteW (ba, tbc, uptr->rqxb)) { /* store, nxm? */
PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */
PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */
if (rq_hbe (cp, uptr)) /* post err log */ if (rq_hbe (cp, uptr)) /* post err log */
@ -1770,7 +1910,7 @@ else {
rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM);
return SCPE_OK; return SCPE_OK;
} }
dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; dby = (((uint16 *)(uptr->rqxb))[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF;
if (mby != dby) { /* cmp err? */ if (mby != dby) { /* cmp err? */
PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */
rq_rw_end (cp, uptr, 0, ST_CMP); /* done */ rq_rw_end (cp, uptr, 0, ST_CMP); /* done */
@ -1779,10 +1919,12 @@ else {
} /* end for */ } /* end for */
} /* end else if */ } /* end else if */
} /* end else read */ } /* end else read */
} /* end else bottom end */
if (err != 0) { /* error? */ if (err != 0) { /* error? */
if (rq_dte (cp, uptr, ST_DRV)) /* post err log */ if (rq_dte (cp, uptr, ST_DRV)) /* post err log */
rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */ rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */
perror ("RQ I/O error"); perror ("RQ I/O error");
if (!(uptr->flags | UNIT_RAW))
clearerr (uptr->fileref); clearerr (uptr->fileref);
return SCPE_IOERR; return SCPE_IOERR;
} }
@ -1793,7 +1935,7 @@ PUTP32 (pkt, RW_WBAL, ba); /* update pkt */
PUTP32 (pkt, RW_WBCL, bc); PUTP32 (pkt, RW_WBCL, bc);
PUTP32 (pkt, RW_WBLL, bl); PUTP32 (pkt, RW_WBLL, bl);
if (bc) /* more? resched */ if (bc) /* more? resched */
sim_activate (uptr, rq_xtime); sim_activate (uptr, 0);
else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */ else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */
return SCPE_OK; return SCPE_OK;
} }
@ -1808,6 +1950,8 @@ uint32 bc = GETP32 (pkt, RW_BCL); /* init bc */
uint32 wbc = GETP32 (pkt, RW_WBCL); /* work bc */ uint32 wbc = GETP32 (pkt, RW_WBCL); /* work bc */
DEVICE *dptr = rq_devmap[uptr->cnum]; DEVICE *dptr = rq_devmap[uptr->cnum];
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw_end\n");
uptr->cpkt = 0; /* done */ uptr->cpkt = 0; /* done */
PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */ PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */
cp->pak[pkt].d[RW_WBAL] = 0; /* clear temps */ cp->pak[pkt].d[RW_WBAL] = 0; /* clear temps */
@ -1831,6 +1975,8 @@ t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err)
int32 pkt, tpkt; int32 pkt, tpkt;
uint32 lu, dtyp, lbn, ccyl, csurf, csect, t; uint32 lu, dtyp, lbn, ccyl, csurf, csect, t;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_dte\n");
if ((cp->cflgs & CF_THS) == 0) /* logging? */ if ((cp->cflgs & CF_THS) == 0) /* logging? */
return OK; return OK;
if (!rq_deqf (cp, &pkt)) /* get log pkt */ if (!rq_deqf (cp, &pkt)) /* get log pkt */
@ -1883,6 +2029,8 @@ t_bool rq_hbe (MSC *cp, UNIT *uptr)
{ {
int32 pkt, tpkt; int32 pkt, tpkt;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_hbe\n");
if ((cp->cflgs & CF_THS) == 0) /* logging? */ if ((cp->cflgs & CF_THS) == 0) /* logging? */
return OK; return OK;
if (!rq_deqf (cp, &pkt)) /* get log pkt */ if (!rq_deqf (cp, &pkt)) /* get log pkt */
@ -1912,6 +2060,8 @@ t_bool rq_plf (MSC *cp, uint32 err)
{ {
int32 pkt; int32 pkt;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_plf\n");
if (!rq_deqf (cp, &pkt)) /* get log pkt */ if (!rq_deqf (cp, &pkt)) /* get log pkt */
return ERR; return ERR;
cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */ cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */
@ -1933,12 +2083,13 @@ return rq_putpkt (cp, pkt, TRUE);
/* Unit now available attention packet */ /* Unit now available attention packet */
int32 rq_una (MSC *cp, int32 un) t_bool rq_una (MSC *cp, int32 un)
{ {
int32 pkt; int32 pkt;
uint32 lu = cp->ubase + un; uint32 lu = cp->ubase + un;
UNIT *uptr = rq_getucb (cp, lu); UNIT *uptr = rq_getucb (cp, lu);
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_una (Unit=%d)\n", lu);
if (uptr == NULL) /* huh? */ if (uptr == NULL) /* huh? */
return OK; return OK;
if (!rq_deqf (cp, &pkt)) /* get log pkt */ if (!rq_deqf (cp, &pkt)) /* get log pkt */
@ -2039,8 +2190,7 @@ DEVICE *dptr = rq_devmap[cp->cnum];
if (pkt == 0) /* any packet? */ if (pkt == 0) /* any packet? */
return OK; return OK;
if (DEBUG_PRD (dptr)) sim_debug (DBG_REQ, dptr, "rsp=%04X, sts=%04X\n",
fprintf (sim_deb, ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp->cnum,
cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]); cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]);
if (!rq_getdesc (cp, &cp->rq, &desc)) /* get rsp desc */ if (!rq_getdesc (cp, &cp->rq, &desc)) /* get rsp desc */
return ERR; return ERR;
@ -2146,6 +2296,8 @@ void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */ uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_putr_unit\n");
cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */ cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */
cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr);
cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */ cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */
@ -2205,6 +2357,8 @@ return;
void rq_setint (MSC *cp) void rq_setint (MSC *cp)
{ {
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_setint\n");
cp->irq = 1; /* set ctrl int */ cp->irq = 1; /* set ctrl int */
SET_INT (RQ); /* set master int */ SET_INT (RQ); /* set master int */
return; return;
@ -2217,6 +2371,8 @@ void rq_clrint (MSC *cp)
int32 i; int32 i;
MSC *ncp; MSC *ncp;
sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_clrint\n");
cp->irq = 0; /* clr ctrl int */ cp->irq = 0; /* clr ctrl int */
for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */
ncp = rq_ctxmap[i]; /* get context */ ncp = rq_ctxmap[i]; /* get context */
@ -2256,8 +2412,9 @@ t_bool rq_fatal (MSC *cp, uint32 err)
{ {
DEVICE *dptr = rq_devmap[cp->cnum]; DEVICE *dptr = rq_devmap[cp->cnum];
if (DEBUG_PRD (dptr)) sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_fatal\n");
fprintf (sim_deb, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err);
sim_debug (DBG_REQ, dptr, "fatal err=%X\n", err);
rq_reset (rq_devmap[cp->cnum]); /* reset device */ rq_reset (rq_devmap[cp->cnum]); /* reset device */
cp->sa = SA_ER | err; /* SA = dead code */ cp->sa = SA_ER | err; /* SA = dead code */
cp->csta = CST_DEAD; /* state = dead */ cp->csta = CST_DEAD; /* state = dead */
@ -2330,10 +2487,11 @@ t_stat rq_attach (UNIT *uptr, char *cptr)
MSC *cp = rq_ctxmap[uptr->cnum]; MSC *cp = rq_ctxmap[uptr->cnum];
t_stat r; t_stat r;
r = attach_unit (uptr, cptr); r = sim_disk_attach (uptr, cptr, RQ_NUMBY, sizeof (uint16), (uptr->flags & UNIT_NOAUTO), DBG_DSK, drv_tab[GET_DTYPE (uptr->flags)].name, 0);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
if (cp->csta == CST_UP)
if ((cp->csta == CST_UP) && sim_disk_isavailable (uptr))
uptr->flags = uptr->flags | UNIT_ATP; uptr->flags = uptr->flags | UNIT_ATP;
return SCPE_OK; return SCPE_OK;
} }
@ -2344,7 +2502,7 @@ t_stat rq_detach (UNIT *uptr)
{ {
t_stat r; t_stat r;
r = detach_unit (uptr); /* detach unit */ r = sim_disk_detach (uptr); /* detach unit */
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */ uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */
@ -2361,6 +2519,8 @@ UNIT *uptr;
MSC *cp; MSC *cp;
DIB *dibp = (DIB *) dptr->ctxt; DIB *dibp = (DIB *) dptr->ctxt;
sim_debug (DBG_TRC, dptr, "rq_reset\n");
for (i = 0, cidx = -1; i < RQ_NUMCT; i++) { /* find ctrl num */ for (i = 0, cidx = -1; i < RQ_NUMCT; i++) { /* find ctrl num */
if (rq_devmap[i] == dptr) if (rq_devmap[i] == dptr)
cidx = i; cidx = i;
@ -2408,11 +2568,10 @@ for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */
uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP);
uptr->uf = 0; /* clr unit flags */ uptr->uf = 0; /* clr unit flags */
uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */
} uptr->rqxb = (uint16 *) realloc (uptr->rqxb, (RQ_MAXFR >> 1) * sizeof (uint16));
if (rqxb == NULL) if (uptr->rqxb == NULL)
rqxb = (uint16 *) calloc (RQ_MAXFR >> 1, sizeof (uint16));
if (rqxb == NULL)
return SCPE_MEM; return SCPE_MEM;
}
return auto_config (0, 0); /* run autoconfig */ return auto_config (0, 0); /* run autoconfig */
} }

View file

@ -25,6 +25,23 @@
tq TQK50 tape controller tq TQK50 tape controller
05-Mar-11 MP Added missing state for proper save/restore
01-Mar-11 MP - Migrated complex physical tape activities to sim_tape
- adopted use of asynch I/O interfaces from sim_tape
- Added differing detailed debug output via sim_debug
14-Jan-11 MP Various fixes discovered while exploring Ultrix issue:
- Set UNIT_SXC flag when a tape mark is encountered
during forward motion read operations.
- Fixed logic which clears UNIT_SXC to check command
modifier.
- Added CMF_WR flag to tq_cmf entry for OP_WTM.
- Made Non-immediate rewind positioning operations
take 2 seconds.
- Added UNIT_IDLE flag to tq units.
- Fixed debug output of tape file positions when they
are 64b. Added more debug output after positioning
operations. Also, added textual display of the
command being performed (GUS,POS,RD,WR,etc)
18-Jun-07 RMS Added UNIT_IDLE flag to timer thread 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
16-Feb-06 RMS Revised for new magtape capacity checking 16-Feb-06 RMS Revised for new magtape capacity checking
31-Oct-05 RMS Fixed address width for large files 31-Oct-05 RMS Fixed address width for large files
@ -101,7 +118,10 @@ extern int32 cpu_opt;
#define pktq u4 /* packet queue */ #define pktq u4 /* packet queue */
#define uf buf /* settable unit flags */ #define uf buf /* settable unit flags */
#define objp wait /* object position */ #define objp wait /* object position */
#define io_status u5 /* io status from callback */
#define io_complete u6 /* io completion flag */
#define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0) #define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0)
#define results up7 /* xfer buffer & results */
#define CST_S1 0 /* init stage 1 */ #define CST_S1 0 /* init stage 1 */
#define CST_S1_WR 1 /* stage 1 wrap */ #define CST_S1_WR 1 /* stage 1 wrap */
@ -223,11 +243,9 @@ static struct drvtyp drv_tab[] = {
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 tmr_poll, clk_tps; extern int32 tmr_poll, clk_tps;
extern UNIT cpu_unit;
extern FILE *sim_deb; extern FILE *sim_deb;
extern uint32 sim_taddr_64; extern uint32 sim_taddr_64;
uint8 *tqxb = NULL; /* xfer buffer */
uint32 tq_sa = 0; /* status, addr */ uint32 tq_sa = 0; /* status, addr */
uint32 tq_saw = 0; /* written data */ uint32 tq_saw = 0; /* written data */
uint32 tq_s1dat = 0; /* S1 data */ uint32 tq_s1dat = 0; /* S1 data */
@ -249,6 +267,7 @@ int32 tq_itime = 200; /* init time, except */
int32 tq_itime4 = 10; /* stage 4 */ int32 tq_itime4 = 10; /* stage 4 */
int32 tq_qtime = 200; /* queue time */ int32 tq_qtime = 200; /* queue time */
int32 tq_xtime = 500; /* transfer time */ int32 tq_xtime = 500; /* transfer time */
int32 tq_rwtime = 2000000; /* rewind time 2 sec (adjusted later) */
int32 tq_typ = INIT_TYPE; /* device type */ int32 tq_typ = INIT_TYPE; /* device type */
/* Command table - legal modifiers (low 16b) and flags (high 16b) */ /* Command table - legal modifiers (low 16b) and flags (high 16b) */
@ -280,7 +299,7 @@ static uint32 tq_cmf[64] = {
CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */ CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */
MD_CMP|MD_ERW|MD_SEC|MD_SER, MD_CMP|MD_ERW|MD_SEC|MD_SER,
0, /* 35 */ 0, /* 35 */
CMF_SEQ|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */ CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */
CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */ CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */
MD_REV|MD_RWD|MD_DLE| MD_REV|MD_RWD|MD_DLE|
MD_SCH|MD_SEC|MD_SER, MD_SCH|MD_SEC|MD_SER,
@ -289,13 +308,44 @@ static uint32 tq_cmf[64] = {
0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0
}; };
static char *tq_cmdname[] = {
"", /* 0 */
"ABO", /* 1 b: abort */
"GCS", /* 2 b: get command status */
"GUS", /* 3 b: get unit status */
"SCC", /* 4 b: set controller char */
"","","", /* 5-7 */
"AVL", /* 8 b: available */
"ONL", /* 9 b: online */
"SUC", /* 10 b: set unit char */
"DAP", /* 11 b: det acc paths - nop */
"","","","", /* 12-15 */
"ACC", /* 16 b: access */
"CCD", /* 17 d: compare - nop */
"ERS", /* 18 b: erase */
"FLU", /* 19 d: flush - nop */
"","", /* 20-21 */
"ERG", /* 22 t: erase gap */
"","","","","","","","","", /* 23-31 */
"CMP", /* 32 b: compare */
"RD", /* 33 b: read */
"WR", /* 34 b: write */
"", /* 35 */
"WTM", /* 36 t: write tape mark */
"POS", /* 37 t: reposition */
"","","","","","","","","", /* 38-46 */
"FMT", /* 47 d: format */
"","","","","","","","","","","","","","","","", /* 48-63 */
"AVA", /* 64 b: unit now avail */
};
/* Forward references */ /* Forward references */
DEVICE tq_dev; DEVICE tq_dev;
t_stat tq_rd (int32 *data, int32 PA, int32 access); t_stat tq_rd (int32 *data, int32 PA, int32 access);
t_stat tq_wr (int32 data, int32 PA, int32 access); t_stat tq_wr (int32 data, int32 PA, int32 access);
t_stat tq_inta (void); int32 tq_inta (void);
t_stat tq_svc (UNIT *uptr); t_stat tq_svc (UNIT *uptr);
t_stat tq_tmrsvc (UNIT *uptr); t_stat tq_tmrsvc (UNIT *uptr);
t_stat tq_quesvc (UNIT *uptr); t_stat tq_quesvc (UNIT *uptr);
@ -329,12 +379,10 @@ t_bool tq_dte (UNIT *uptr, uint32 err);
t_bool tq_hbe (UNIT *uptr, uint32 ba); t_bool tq_hbe (UNIT *uptr, uint32 ba);
t_bool tq_una (UNIT *uptr); t_bool tq_una (UNIT *uptr);
uint32 tq_map_status (UNIT *uptr, t_stat st); uint32 tq_map_status (UNIT *uptr, t_stat st);
uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); void tq_rdbuff_top (UNIT *uptr, t_mtrlnt *tbc);
uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped); uint32 tq_rdbuff_bottom (UNIT *uptr, t_mtrlnt *tbc);
uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc); void tq_rdbufr_top (UNIT *uptr, t_mtrlnt *tbc);
uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); uint32 tq_rdbufr_bottom (UNIT *uptr, t_mtrlnt *tbc);
uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped);
uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc);
t_bool tq_deqf (int32 *pkt); t_bool tq_deqf (int32 *pkt);
int32 tq_deqh (int32 *lh); int32 tq_deqh (int32 *lh);
void tq_enqh (int32 *lh, int32 pkt); void tq_enqh (int32 *lh, int32 pkt);
@ -369,12 +417,12 @@ DIB tq_dib = {
}; };
UNIT tq_unit[] = { UNIT tq_unit[] = {
{ UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP }, { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP }, { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP }, { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP }, { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },
{ UDATA (&tq_tmrsvc, UNIT_DIS, 0) }, { UDATA (&tq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) },
{ UDATA (&tq_quesvc, UNIT_DIS, 0) } { UDATA (&tq_quesvc, UNIT_IDLE|UNIT_DIS, 0) }
}; };
#define TQ_TIMER (TQ_NUMDR) #define TQ_TIMER (TQ_NUMDR)
@ -384,9 +432,11 @@ REG tq_reg[] = {
{ GRDATA (SA, tq_sa, DEV_RDX, 16, 0) }, { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) },
{ GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) }, { GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) },
{ GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) },
{ GRDATA (CQIOFF, tq_cq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) }, { GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) },
{ GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) }, { GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) },
{ GRDATA (TQIOFF, tq_rq.ioff, DEV_RDX, 32, 0) },
{ GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) }, { GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) },
{ GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ },
{ GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) }, { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) },
@ -411,6 +461,7 @@ REG tq_reg[] = {
{ DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ }, { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ },
{ DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ }, { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ },
{ DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ }, { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ },
{ DRDATA (RWTIME, tq_rwtime, 32), PV_LEFT + REG_NZ },
{ BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) }, { BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) },
{ DRDATA (DEVTYPE, tq_typ, 2), REG_HRO }, { DRDATA (DEVTYPE, tq_typ, 2), REG_HRO },
{ DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO }, { DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO },
@ -458,12 +509,44 @@ MTAB tq_mod[] = {
{ 0 } { 0 }
}; };
/* debugging bitmaps */
#define DBG_TRC 0x0001 /* trace routine calls */
#define DBG_INI 0x0002 /* display setup/init sequence info */
#define DBG_REG 0x0004 /* trace read/write registers */
#define DBG_REQ 0x0008 /* display transfer requests */
#define DBG_TAP 0x0010 /* display sim_tape activities */
#define DBG_DAT 0x0020 /* display transfer data */
DEBTAB tq_debug[] = {
{"TRACE", DBG_TRC},
{"INIT", DBG_INI},
{"REG", DBG_REG},
{"REQ", DBG_REQ},
{"TAPE", DBG_TAP},
{"DATA", DBG_DAT},
{0}
};
DEVICE tq_dev = { DEVICE tq_dev = {
"TQ", tq_unit, tq_reg, tq_mod, "TQ", tq_unit, tq_reg, tq_mod,
TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8, TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8,
NULL, NULL, &tq_reset, NULL, NULL, &tq_reset,
&tq_boot, &tq_attach, &tq_detach, &tq_boot, &tq_attach, &tq_detach,
&tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
0, tq_debug
};
struct tq_req_results { /* intermediate State during tape motion commands */
t_stat io_status;
int32 io_complete;
int rewind_done;
uint32 sts;
uint32 sktmk;
uint32 skrec;
t_mtrlnt tbc;
int32 objupd;
uint8 tqxb[TQ_MAXFR];
}; };
/* I/O dispatch routines, I/O addresses 17772150 - 17772152 /* I/O dispatch routines, I/O addresses 17772150 - 17772152
@ -474,6 +557,8 @@ DEVICE tq_dev = {
t_stat tq_rd (int32 *data, int32 PA, int32 access) t_stat tq_rd (int32 *data, int32 PA, int32 access)
{ {
sim_debug(DBG_REG, &tq_dev, "tq_rd(PA=0x%08X [%s], access=%d)\n", PA, ((PA >> 1) & 01) ? "IP" : "SA", access);
switch ((PA >> 1) & 01) { /* decode PA<1> */ switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* IP */ case 0: /* IP */
*data = 0; /* reads zero */ *data = 0; /* reads zero */
@ -495,13 +580,13 @@ return SCPE_OK;
t_stat tq_wr (int32 data, int32 PA, int32 access) t_stat tq_wr (int32 data, int32 PA, int32 access)
{ {
sim_debug(DBG_REG, &tq_dev, "tq_wr(PA=0x%08X [%s], access=%d)\n", PA, ((PA >> 1) & 01) ? "IP" : "SA", access);
switch ((PA >> 1) & 01) { /* decode PA<1> */ switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* IP */ case 0: /* IP */
tq_reset (&tq_dev); /* init device */ tq_reset (&tq_dev); /* init device */
if (DEBUG_PRS (tq_dev)) sim_debug (DBG_REQ, &tq_dev, "initialization started\n");
fprintf (sim_deb, ">>TQ: initialization started, time=%.0f\n",
sim_gtime ());
break; break;
case 1: /* SA */ case 1: /* SA */
@ -565,9 +650,12 @@ int32 i, cnid;
int32 pkt = 0; int32 pkt = 0;
UNIT *nuptr; UNIT *nuptr;
if (tq_csta < CST_UP) { /* still init? */ sim_debug(DBG_TRC, &tq_dev, "tq_quesvc\n");
switch (tq_csta) { /* controller state? */
if (tq_csta < CST_UP) { /* still init? */
sim_debug(DBG_INI, &tq_dev, "CSTA=%d, SAW=0x%X\n", tq_csta, tq_saw);
switch (tq_csta) { /* controller state? */
case CST_S1: /* need S1 reply */ case CST_S1: /* need S1 reply */
if (tq_saw & SA_S1H_VL) { /* valid? */ if (tq_saw & SA_S1H_VL) { /* valid? */
if (tq_saw & SA_S1H_WR) { /* wrap? */ if (tq_saw & SA_S1H_WR) { /* wrap? */
@ -615,8 +703,7 @@ if (tq_csta < CST_UP) { /* still init? */
case CST_S4: /* need S4 reply */ case CST_S4: /* need S4 reply */
if (tq_saw & SA_S4H_GO) { /* go set? */ if (tq_saw & SA_S4H_GO) { /* go set? */
if (DEBUG_PRS (tq_dev)) sim_debug (DBG_REQ, &tq_dev, "initialization complete\n");
fprintf (sim_deb, ">>TQ: initialization complete\n");
tq_csta = CST_UP; /* we're up */ tq_csta = CST_UP; /* we're up */
tq_sa = 0; /* clear SA */ tq_sa = 0; /* clear SA */
sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps); sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps);
@ -641,18 +728,21 @@ if ((pkt == 0) && tq_pip) { /* polling? */
if (!tq_getpkt (&pkt)) /* get host pkt */ if (!tq_getpkt (&pkt)) /* get host pkt */
return SCPE_OK; return SCPE_OK;
if (pkt) { /* got one? */ if (pkt) { /* got one? */
if (DEBUG_PRS (tq_dev)) {
UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);
fprintf (sim_deb, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ",
tq_pkt[pkt].d[CMD_OPC], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]); if (up)
fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X", sim_debug (DBG_REQ, &tq_dev, "cmd=%04X(%3s), mod=%04X, unit=%d, bc=%04X%04X, ma=%04X%04X, obj=%d, pos=0x%X\n",
tq_pkt[pkt].d[CMD_OPC], tq_cmdname[tq_pkt[pkt].d[CMD_OPC]&0x3f],
tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN],
tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],
tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL],
up->objp, up->pos);
else
sim_debug (DBG_REQ, &tq_dev, "cmd=%04X(%3s), mod=%04X, unit=%d, bc=%04X%04X, ma=%04X%04X\n",
tq_pkt[pkt].d[CMD_OPC], tq_cmdname[tq_pkt[pkt].d[CMD_OPC]&0x3f],
tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN],
tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL], tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],
tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]); tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]);
if (up)
fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);
else fprintf (sim_deb, "\n");
fflush (sim_deb);
}
if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */
return tq_fatal (PE_PIE); /* no, term thread */ return tq_fatal (PE_PIE); /* no, term thread */
cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */
@ -686,6 +776,8 @@ t_stat tq_tmrsvc (UNIT *uptr)
int32 i; int32 i;
UNIT *nuptr; UNIT *nuptr;
sim_debug(DBG_TRC, &tq_dev, "tq_tmrsvc\n");
sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */
for (i = 0; i < TQ_NUMDR; i++) { /* poll */ for (i = 0; i < TQ_NUMDR; i++) { /* poll */
nuptr = tq_dev.units + i; nuptr = tq_dev.units + i;
@ -713,6 +805,8 @@ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */
uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_mscp\n");
if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */ if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */
cmd = OP_END; /* set end op */ cmd = OP_END; /* set end op */
sts = ST_CMD | I_OPCD; /* ill op */ sts = ST_CMD | I_OPCD; /* ill op */
@ -734,8 +828,9 @@ else { /* valid cmd */
} }
/* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */ /* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */
/* uptr->flags = uptr->flags & ~UNIT_CDL; */ /* uptr->flags = uptr->flags & ~UNIT_CDL; */
if (tq_cmf[cmd] & MD_CSE) /* clr ser exc? */ if ((mdf & MD_CSE) && (uptr->flags & UNIT_SXC)) /* clr ser exc? */
uptr->flags = uptr->flags & ~UNIT_SXC; uptr->flags = uptr->flags & ~UNIT_SXC;
memset (uptr->results, 0, sizeof (struct tq_req_results)); /* init request state */
} }
switch (cmd) { switch (cmd) {
@ -803,6 +898,8 @@ uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */
int32 tpkt, prv; int32 tpkt, prv;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_abo\n");
tpkt = 0; /* set no mtch */ tpkt = 0; /* set no mtch */
if (uptr = tq_getucb (lu)) { /* get unit */ if (uptr = tq_getucb (lu)) { /* get unit */
if (uptr->cpkt && /* curr pkt? */ if (uptr->cpkt && /* curr pkt? */
@ -846,6 +943,8 @@ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_avl\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
if (uptr->flags & UNIT_SXC) /* ser exc pending? */ if (uptr->flags & UNIT_SXC) /* ser exc pending? */
sts = ST_SXC; sts = ST_SXC;
@ -875,6 +974,8 @@ uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */
int32 tpkt; int32 tpkt;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_gcs\n");
if ((uptr = tq_getucb (lu)) && /* valid lu? */ if ((uptr = tq_getucb (lu)) && /* valid lu? */
(tpkt = uptr->cpkt) && /* queued pkt? */ (tpkt = uptr->cpkt) && /* queued pkt? */
(GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */
@ -895,6 +996,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_gus\n");
if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */
if (lu >= TQ_NUMDR) { /* end of range? */ if (lu >= TQ_NUMDR) { /* end of range? */
lu = 0; /* reset to 0 */ lu = 0; /* reset to 0 */
@ -926,6 +1029,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_onl\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
sts = ST_OFL | SB_OFL_NV; /* offl no vol */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */
@ -950,6 +1055,8 @@ return tq_putpkt (pkt, TRUE);
t_bool tq_scc (int32 pkt) t_bool tq_scc (int32 pkt)
{ {
sim_debug(DBG_TRC, &tq_dev, "tq_scc\n");
if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */ if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */
tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ); tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ);
else { else {
@ -979,6 +1086,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_suc\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
sts = ST_OFL | SB_OFL_NV; /* offl no vol */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */
@ -1001,6 +1110,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_flu\n");
if (uptr = tq_getucb (lu)) /* unit exist? */ if (uptr = tq_getucb (lu)) /* unit exist? */
sts = tq_mot_valid (uptr, OP_FLU); /* validate req */ sts = tq_mot_valid (uptr, OP_FLU); /* validate req */
else sts = ST_OFL; /* offline */ else sts = ST_OFL; /* offline */
@ -1017,11 +1128,14 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */
uint32 sts; uint32 sts;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_erase\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
sts = tq_mot_valid (uptr, cmd); /* validity checks */ sts = tq_mot_valid (uptr, cmd); /* validity checks */
if (sts == ST_SUC) { /* ok? */ if (sts == ST_SUC) { /* ok? */
uptr->cpkt = pkt; /* op in progress */ uptr->cpkt = pkt; /* op in progress */
sim_activate (uptr, tq_xtime); /* activate */ uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* activate */
return OK; /* done */ return OK; /* done */
} }
} }
@ -1038,12 +1152,15 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts, objp = 0; uint32 sts, objp = 0;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_wtm\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
objp = uptr->objp; /* position op */ objp = uptr->objp; /* position op */
sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */ sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */
if (sts == ST_SUC) { /* ok? */ if (sts == ST_SUC) { /* ok? */
uptr->cpkt = pkt; /* op in progress */ uptr->cpkt = pkt; /* op in progress */
sim_activate (uptr, tq_xtime); /* activate */ uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* activate */
return OK; /* done */ return OK; /* done */
} }
} }
@ -1061,12 +1178,21 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */
uint32 sts, objp = 0; uint32 sts, objp = 0;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_pos\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
objp = uptr->objp; /* position op */ objp = uptr->objp; /* position op */
sts = tq_mot_valid (uptr, OP_POS); /* validity checks */ sts = tq_mot_valid (uptr, OP_POS); /* validity checks */
if (sts == ST_SUC) { /* ok? */ if (sts == ST_SUC) { /* ok? */
uptr->cpkt = pkt; /* op in progress */ uptr->cpkt = pkt; /* op in progress */
sim_activate (uptr, tq_xtime); /* activate */ tq_rwtime = 2 * tmr_poll * clk_tps; /* 2 second rewind time */
if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) && /* rewind? */
(!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) /* !immediate? */
sim_activate (uptr, tq_rwtime); /* use 2 sec rewind execute time */
else { /* otherwise */
uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* use normal execute time */
}
return OK; /* done */ return OK; /* done */
} }
} }
@ -1088,6 +1214,8 @@ uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */
uint32 sts, objp = 0; uint32 sts, objp = 0;
UNIT *uptr; UNIT *uptr;
sim_debug(DBG_TRC, &tq_dev, "tq_rw\n");
if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr = tq_getucb (lu)) { /* unit exist? */
objp = uptr->objp; /* position op */ objp = uptr->objp; /* position op */
sts = tq_mot_valid (uptr, cmd); /* validity checks */ sts = tq_mot_valid (uptr, cmd); /* validity checks */
@ -1098,7 +1226,8 @@ if (uptr = tq_getucb (lu)) { /* unit exist? */
} }
else { else {
uptr->cpkt = pkt; /* op in progress */ uptr->cpkt = pkt; /* op in progress */
sim_activate (uptr, tq_xtime); /* activate */ uptr->iostarttime = sim_grtime();
sim_activate (uptr, 0); /* activate */
return OK; /* done */ return OK; /* done */
} }
} }
@ -1115,6 +1244,8 @@ return tq_putpkt (pkt, TRUE);
int32 tq_mot_valid (UNIT *uptr, uint32 cmd) int32 tq_mot_valid (UNIT *uptr, uint32 cmd)
{ {
sim_debug(DBG_TRC, &tq_dev, "tq_mot_valid\n");
if (uptr->flags & UNIT_SXC) /* ser exc pend? */ if (uptr->flags & UNIT_SXC) /* ser exc pend? */
return ST_SXC; return ST_SXC;
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
@ -1136,10 +1267,28 @@ return ST_SUC; /* success! */
/* Unit service for motion commands */ /* Unit service for motion commands */
/* I/O completion callback */
void tq_io_complete (UNIT *uptr, t_stat status)
{
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
int32 elapsed = sim_grtime()-uptr->iostarttime;
sim_debug(DBG_TRC, &tq_dev, "tq_io_complete(status=%d)\n", status);
res->io_status = status;
res->io_complete = 1;
if (elapsed > tq_xtime)
sim_activate (uptr, 0);
else
sim_activate (uptr, tq_xtime-elapsed);
}
t_stat tq_svc (UNIT *uptr) t_stat tq_svc (UNIT *uptr)
{ {
uint32 t, sts, sktmk, skrec; uint32 t;
t_mtrlnt i, tbc, wbc; t_mtrlnt wbc;
int32 pkt = uptr->cpkt; /* get packet */ int32 pkt = uptr->cpkt; /* get packet */
uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */
@ -1147,7 +1296,14 @@ uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */
t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */ t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */
uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */ uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */
uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */ uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
int32 io_complete = res->io_complete;
sim_debug (DBG_TRC, &tq_dev, "tq_svc(unit=%d, pkt=%d, cmd=%s, mdf=0x%0X, bc=0x%0x, phase=%s)\n",
uptr-tq_dev.units, pkt, tq_cmdname[tq_pkt[pkt].d[CMD_OPC]&0x3f], mdf, bc,
uptr->io_complete ? "bottom" : "top");
res->io_complete = 0;
if (pkt == 0) /* what??? */ if (pkt == 0) /* what??? */
return SCPE_IERR; return SCPE_IERR;
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
@ -1167,58 +1323,71 @@ if (tq_cmf[cmd] & CMF_WR) { /* write op? */
return SCPE_OK; return SCPE_OK;
} }
} }
sts = ST_SUC; /* assume success */ if (!io_complete) {
tbc = 0; /* assume zero rec */ res->sts = ST_SUC; /* assume success */
res->tbc = 0; /* assume zero rec */
}
switch (cmd) { /* case on command */ switch (cmd) { /* case on command */
case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */ case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */
if (!io_complete) {
if (mdf & MD_REV) /* read record */ if (mdf & MD_REV) /* read record */
sts = tq_rdbufr (uptr, &tbc); tq_rdbufr_top (uptr, &res->tbc);
else sts = tq_rdbuff (uptr, &tbc); else
if (sts == ST_DRV) { /* read error? */ tq_rdbuff_top (uptr, &res->tbc);
PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ return SCPE_OK;
return tq_mot_err (uptr, tbc); /* log, done */
} }
if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */ if (mdf & MD_REV) /* read record */
res->sts = tq_rdbufr_bottom (uptr, &res->tbc);
else
res->sts = tq_rdbuff_bottom (uptr, &res->tbc);
if (res->sts == ST_DRV) { /* read error? */
PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */
return tq_mot_err (uptr, res->tbc); /* log, done */
}
if ((res->sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */
if (res->sts == ST_TMK)
uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */
PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */
break; break;
} }
if (tbc > bc) { /* tape rec > buf? */ if (res->tbc > bc) { /* tape rec > buf? */
uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */
sts = ST_RDT; /* data truncated */ res->sts = ST_RDT; /* data truncated */
wbc = bc; /* set working bc */ wbc = bc; /* set working bc */
} }
else wbc = tbc; else wbc = res->tbc;
if (cmd == OP_RD) { /* read? */ if (cmd == OP_RD) { /* read? */
if (t = Map_WriteB (ba, wbc, tqxb)) { /* store, nxm? */ if (t = Map_WriteB (ba, wbc, res->tqxb)) { /* store, nxm? */
PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */ PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */
if (tq_hbe (uptr, ba + wbc - t)) /* post err log */ if (tq_hbe (uptr, ba + wbc - t)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, res->tbc);
return SCPE_OK; /* end if nxm */ return SCPE_OK; /* end if nxm */
} }
} /* end if read */ } /* end if read */
else { /* compare */ else { /* compare */
uint8 mby, dby; uint8 mby, dby;
uint32 mba; uint32 mba;
t_mtrlnt i;
for (i = 0; i < wbc; i++) { /* loop */ for (i = 0; i < wbc; i++) { /* loop */
if (mdf & MD_REV) { /* reverse? */ if (mdf & MD_REV) { /* reverse? */
mba = ba + bc - 1 - i; /* mem addr */ mba = ba + bc - 1 - i; /* mem addr */
dby = tqxb[tbc - 1 - i]; /* byte */ dby = ((uint8 *)res->tqxb)[res->tbc - 1 - i]; /* byte */
} }
else { else {
mba = ba + i; mba = ba + i;
dby = tqxb[i]; dby = ((uint8 *)res->tqxb)[i];
} }
if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */ if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */
PUTP32 (pkt, RW_BCL, i); /* adj bc */ PUTP32 (pkt, RW_BCL, i); /* adj bc */
if (tq_hbe (uptr, mba)) /* post err log */ if (tq_hbe (uptr, mba)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, res->tbc);
return SCPE_OK; return SCPE_OK;
} }
if (mby != dby) { /* cmp err? */ if (mby != dby) { /* cmp err? */
uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */ uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */
PUTP32 (pkt, RW_BCL, i); /* adj bc */ PUTP32 (pkt, RW_BCL, i); /* adj bc */
tq_mot_end (uptr, 0, ST_CMP, tbc); tq_mot_end (uptr, 0, ST_CMP, res->tbc);
return SCPE_OK; /* exit */ return SCPE_OK; /* exit */
} }
} /* end for */ } /* end for */
@ -1227,23 +1396,31 @@ switch (cmd) { /* case on command */
break; break;
case OP_WR: /* write */ case OP_WR: /* write */
if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */ if (!io_complete) { /* Top half processing */
if (t = Map_ReadB (ba, bc, res->tqxb)) { /* fetch buf, nxm? */
PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */
if (tq_hbe (uptr, ba + bc - t)) /* post err log */ if (tq_hbe (uptr, ba + bc - t)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc);
return SCPE_OK; /* end else wr */ return SCPE_OK; /* end else wr */
} }
if (sim_tape_wrrecf (uptr, tqxb, bc)) /* write rec fwd, err? */ sim_tape_wrrecf_a (uptr, res->tqxb, bc, tq_io_complete); /* write rec fwd */
return SCPE_OK;
}
if (res->io_status)
return tq_mot_err (uptr, bc); /* log, end */ return tq_mot_err (uptr, bc); /* log, end */
uptr->objp = uptr->objp + 1; /* upd obj pos */ uptr->objp = uptr->objp + 1; /* upd obj pos */
if (TEST_EOT (uptr)) /* EOT on write? */ if (TEST_EOT (uptr)) /* EOT on write? */
uptr->flags = uptr->flags | UNIT_SXC; uptr->flags = uptr->flags | UNIT_SXC;
uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */
tbc = bc; /* RW_BC is ok */ res->tbc = bc; /* RW_BC is ok */
break; break;
case OP_WTM: /* write tape mark */ case OP_WTM: /* write tape mark */
if (sim_tape_wrtmk (uptr)) /* write tmk, err? */ if (!io_complete) { /* Top half processing */
sim_tape_wrtmk_a (uptr, tq_io_complete); /* write tmk, err? */
return SCPE_OK;
}
if (res->io_status)
return tq_mot_err (uptr, 0); /* log, end */ return tq_mot_err (uptr, 0); /* log, end */
uptr->objp = uptr->objp + 1; /* incr obj cnt */ uptr->objp = uptr->objp + 1; /* incr obj cnt */
case OP_ERG: /* erase gap */ case OP_ERG: /* erase gap */
@ -1253,46 +1430,47 @@ switch (cmd) { /* case on command */
break; break;
case OP_ERS: /* erase */ case OP_ERS: /* erase */
if (sim_tape_wreom (uptr)) /* write eom, err? */ if (!io_complete) { /* Top half processing */
sim_tape_wreomrw_a (uptr, tq_io_complete); /* write eom, err? */
return SCPE_OK;
}
if (res->io_status)
return tq_mot_err (uptr, 0); /* log, end */ return tq_mot_err (uptr, 0); /* log, end */
sim_tape_rewind (uptr); /* rewind */
uptr->objp = 0; uptr->objp = 0;
uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);
break; break;
case OP_POS: /* position */ case OP_POS: /* position */
sktmk = skrec = 0; /* clr skipped */ if (!io_complete) { /* Top half processing */
res->sktmk = res->skrec = 0; /* clr skipped */
if (mdf & MD_RWD) { /* rewind? */ if (mdf & MD_RWD) { /* rewind? */
sim_tape_rewind (uptr);
uptr->objp = 0; /* clr flags */ uptr->objp = 0; /* clr flags */
uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);
} }
if (mdf & MD_OBC) { /* skip obj? */ sim_tape_position_a (uptr,
if (mdf & MD_REV) /* reverse? */ ((mdf & MD_RWD) ? MTPOS_M_REW : 0) |
sts = tq_spacer (uptr, nrec, &skrec, FALSE); ((mdf & MD_REV) ? MTPOS_M_REV : 0) |
else sts = tq_spacef (uptr, nrec, &skrec, FALSE); ((mdf & MD_OBC) ? MTPOS_M_OBJ : 0) ,
nrec, &res->skrec, ntmk, &res->sktmk, (uint32 *)&res->objupd, tq_io_complete);
return SCPE_OK;
} }
else { /* skip tmk, rec */ if (res->io_status)
return tq_mot_err (uptr, 0); /* log, end */
sim_debug (DBG_REQ, &tq_dev, "Position Done: mdf=0x%04X, nrec=%d, ntmk=%d, skrec=%d, sktmk=%d, skobj=%d\n",
mdf, nrec, ntmk, res->skrec, res->sktmk, res->objupd);
if (mdf & MD_REV) if (mdf & MD_REV)
sts = tq_skipfr (uptr, ntmk, &sktmk); uptr->objp = uptr->objp - res->objupd;
else sts = tq_skipff (uptr, ntmk, &sktmk); else
if (sts == ST_SUC) { /* tmk succeed? */ uptr->objp = uptr->objp + res->objupd;
if (mdf & MD_REV) /* reverse? */ PUTP32 (pkt, POS_RCL, res->skrec); /* #rec skipped */
sts = tq_spacer (uptr, nrec, &skrec, TRUE); PUTP32 (pkt, POS_TMCL, res->sktmk); /* #tmk skipped */
else sts = tq_spacef (uptr, nrec, &skrec, TRUE);
if (sts == ST_TMK)
sktmk = sktmk + 1;
}
}
PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */
PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */
break; break;
default: default:
return SCPE_IERR; return SCPE_IERR;
} }
tq_mot_end (uptr, 0, sts, tbc); /* done */ tq_mot_end (uptr, 0, res->sts, res->tbc); /* done */
return SCPE_OK; return SCPE_OK;
} }
@ -1384,90 +1562,21 @@ switch (st) {
return ST_SUC; return ST_SUC;
} }
uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
{
t_stat st;
t_mtrlnt tbc;
*skipped = 0;
while (*skipped < cnt) { /* loop */
st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */
if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */
return tq_map_status (uptr, st); /* map status */
uptr->objp = uptr->objp + 1; /* upd obj cnt */
if (st == MTSE_TMK) { /* tape mark? */
int32 pkt = uptr->cpkt; /* get pkt */
if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) && /* LEOT? */
(uptr->flags & UNIT_TMK)) {
sim_tape_sprecr (uptr, &tbc); /* rev over tmk */
uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */
return ST_LED;
}
uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */
if (qrec) /* rec spc? stop */
return ST_TMK;
}
else uptr->flags = uptr->flags & ~UNIT_TMK; /* clr TM seen */
*skipped = *skipped + 1; /* # obj skipped */
}
return ST_SUC;
}
uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped)
{
uint32 st, skrec;
*skipped = 0;
while (*skipped < cnt) { /* loop */
st = tq_spacef (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc fwd */
if (st == ST_TMK) /* count files */
*skipped = *skipped + 1;
else if (st != ST_SUC)
return st;
}
return ST_SUC;
}
uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)
{
t_stat st;
t_mtrlnt tbc;
*skipped = 0;
while (*skipped < cnt) { /* loop */
st = sim_tape_sprecr (uptr, &tbc); /* spc rec rev */
if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */
return tq_map_status (uptr, st); /* map status */
uptr->objp = uptr->objp - 1; /* upd obj cnt */
if ((st == MTSE_TMK) && qrec) /* tape mark, stop? */
return ST_TMK;
*skipped = *skipped + 1; /* # obj skipped */
}
return ST_SUC;
}
uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped)
{
uint32 st, skrec;
*skipped = 0;
while (*skipped < cnt) { /* loopo */
st = tq_spacer (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc rev */
if (st == ST_TMK) /* tape mark? */
*skipped = *skipped + 1;
else if (st != 0) /* error? */
return st;
}
return ST_SUC;
}
/* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */ /* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */
uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc) void tq_rdbuff_top (UNIT *uptr, t_mtrlnt *tbc)
{
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
sim_tape_rdrecf_a (uptr, res->tqxb, tbc, MT_MAXFR, tq_io_complete);/* read rec fwd */
}
uint32 tq_rdbuff_bottom (UNIT *uptr, t_mtrlnt *tbc)
{ {
t_stat st; t_stat st;
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
st = sim_tape_rdrecf (uptr, tqxb, tbc, MT_MAXFR); /* read rec fwd */ st = res->io_status; /* read rec fwd io status */
if (st == MTSE_TMK) { /* tape mark? */ if (st == MTSE_TMK) { /* tape mark? */
uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */ uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */
uptr->objp = uptr->objp + 1; /* update obj cnt */ uptr->objp = uptr->objp + 1; /* update obj cnt */
@ -1480,11 +1589,19 @@ uptr->objp = uptr->objp + 1; /* upd obj cnt */
return ST_SUC; return ST_SUC;
} }
uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc) void tq_rdbufr_top (UNIT *uptr, t_mtrlnt *tbc)
{
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
sim_tape_rdrecr_a (uptr, res->tqxb, tbc, MT_MAXFR, tq_io_complete); /* read rec rev */
}
uint32 tq_rdbufr_bottom (UNIT *uptr, t_mtrlnt *tbc)
{ {
t_stat st; t_stat st;
struct tq_req_results *res = (struct tq_req_results *)uptr->results;
st = sim_tape_rdrecr (uptr, tqxb, tbc, MT_MAXFR); /* read rec rev */ st = res->io_status; /* read rec rev io status */
if (st == MTSE_TMK) { /* tape mark? */ if (st == MTSE_TMK) { /* tape mark? */
uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */
uptr->objp = uptr->objp - 1; /* update obj cnt */ uptr->objp = uptr->objp - 1; /* update obj cnt */
@ -1584,7 +1701,7 @@ return tq_putpkt (pkt, TRUE);
/* Unit now available attention packet */ /* Unit now available attention packet */
int32 tq_una (UNIT *uptr) t_bool tq_una (UNIT *uptr)
{ {
int32 pkt; int32 pkt;
uint32 lu; uint32 lu;
@ -1683,18 +1800,17 @@ return tq_putdesc (&tq_cq, desc); /* release desc */
t_bool tq_putpkt (int32 pkt, t_bool qt) t_bool tq_putpkt (int32 pkt, t_bool qt)
{ {
uint32 addr, desc, lnt, cr; uint32 addr, desc, lnt, cr;
UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);
if (pkt == 0) /* any packet? */ if (pkt == 0) /* any packet? */
return OK; return OK;
if (DEBUG_PRS (tq_dev)) { if (up)
UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); sim_debug (DBG_REQ, &tq_dev, "rsp=%04X, sts=%04X, rszl=%04X, obj=%d, pos=%d\n",
fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X", tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS], tq_pkt[pkt].d[RW_RSZL],
up->objp, up->pos);
else
sim_debug (DBG_REQ, &tq_dev, "rsp=%04X, sts=%04X\n",
tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]); tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]);
if (up)
fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);
else fprintf (sim_deb, "\n");
fflush (sim_deb);
}
if (!tq_getdesc (&tq_rq, &desc)) /* get rsp desc */ if (!tq_getdesc (&tq_rq, &desc)) /* get rsp desc */
return ERR; return ERR;
if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */
@ -1816,6 +1932,7 @@ void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
{ {
tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */ tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */
tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */ tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */
tq_pkt[pkt].d[ONL_UFL] |= tq_efl (uptr); /* end flags accordingly */
tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */ tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */
tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */ tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */
tq_pkt[pkt].d[ONL_UIDB] = 0; tq_pkt[pkt].d[ONL_UIDB] = 0;
@ -1879,8 +1996,9 @@ return tq_dib.vec; /* prog vector */
t_bool tq_fatal (uint32 err) t_bool tq_fatal (uint32 err)
{ {
if (DEBUG_PRS (tq_dev)) sim_debug (DBG_TRC, &tq_dev, "tq_fatal\n");
fprintf (sim_deb, ">>TQ: fatal err=%X\n", err);
sim_debug (DBG_REQ, &tq_dev, "fatal err=%X\n", err);
tq_reset (&tq_dev); /* reset device */ tq_reset (&tq_dev); /* reset device */
tq_sa = SA_ER | err; /* SA = dead code */ tq_sa = SA_ER | err; /* SA = dead code */
tq_csta = CST_DEAD; /* state = dead */ tq_csta = CST_DEAD; /* state = dead */
@ -1894,7 +2012,7 @@ t_stat tq_attach (UNIT *uptr, char *cptr)
{ {
t_stat r; t_stat r;
r = sim_tape_attach (uptr, cptr); r = sim_tape_attach_ex (uptr, cptr, DBG_TAP);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
if (tq_csta == CST_UP) if (tq_csta == CST_UP)
@ -1955,11 +2073,11 @@ for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */
~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK); ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK);
uptr->uf = 0; /* clr unit flags */ uptr->uf = 0; /* clr unit flags */
uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */
} if (uptr->results == NULL)
if (tqxb == NULL) uptr->results = calloc (1, sizeof (struct tq_req_results));
tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8)); if (uptr->results == NULL)
if (tqxb == NULL)
return SCPE_MEM; return SCPE_MEM;
}
return SCPE_OK; return SCPE_OK;
} }

View file

@ -27,6 +27,8 @@
sbi bus controller sbi bus controller
04-Feb-2011 MP Added RQB, RQC and RQD as bootable controllers
07-Jan-2011 MP Implemented reboot functionality in the console emulator
31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn) 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn)
03-May-2006 RMS Fixed writes to ACCS 03-May-2006 RMS Fixed writes to ACCS
28-May-08 RMS Inlined physical memory routines 28-May-08 RMS Inlined physical memory routines
@ -109,6 +111,9 @@ static struct boot_dev boot_tab[] = {
{ "HK", BOOT_HK, 0 }, { "HK", BOOT_HK, 0 },
{ "RL", BOOT_RL, 0 }, { "RL", BOOT_RL, 0 },
{ "RQ", BOOT_UDA, 1 << 24 }, { "RQ", BOOT_UDA, 1 << 24 },
{ "RQB", BOOT_UDA, 1 << 24 },
{ "RQC", BOOT_UDA, 1 << 24 },
{ "RQD", BOOT_UDA, 1 << 24 },
{ "TQ", BOOT_TK, 1 << 24 }, { "TQ", BOOT_TK, 1 << 24 },
{ NULL } { NULL }
}; };
@ -152,6 +157,7 @@ extern void init_mbus_tab (void);
extern void init_ubus_tab (void); extern void init_ubus_tab (void);
extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp); extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp);
extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp); extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp);
extern DEVICE cpu_dev;
/* SBI data structures /* SBI data structures
@ -162,6 +168,8 @@ extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp);
UNIT sbi_unit = { UDATA (NULL, 0, 0) }; UNIT sbi_unit = { UDATA (NULL, 0, 0) };
char cpu_boot_command[64];
REG sbi_reg[] = { REG sbi_reg[] = {
{ HRDATA (NREQ14, nexus_req[0], 16) }, { HRDATA (NREQ14, nexus_req[0], 16) },
{ HRDATA (NREQ15, nexus_req[1], 16) }, { HRDATA (NREQ15, nexus_req[1], 16) },
@ -175,6 +183,7 @@ REG sbi_reg[] = {
{ HRDATA (SBIMT, sbi_mt, 32) }, { HRDATA (SBIMT, sbi_mt, 32) },
{ HRDATA (SBIER, sbi_er, 32) }, { HRDATA (SBIER, sbi_er, 32) },
{ HRDATA (SBITMO, sbi_tmo, 32) }, { HRDATA (SBITMO, sbi_tmo, 32) },
{ BRDATA (BOOTCMD, cpu_boot_command, 16, 8, sizeof(cpu_boot_command)), REG_HRO },
{ NULL } { NULL }
}; };
@ -587,14 +596,6 @@ sbi_er = sbi_er & ~SBIER_TMOW1C; /* clr SBIER<tmo> etc */
return cc; return cc;
} }
/* Console entry */
int32 con_halt (int32 code, int32 cc)
{
ABORT (STOP_HALT);
return cc;
}
/* Special boot command - linked into SCP by initial reset /* Special boot command - linked into SCP by initial reset
Syntax: BOOT <device>{/R5:val} Syntax: BOOT <device>{/R5:val}
@ -602,7 +603,7 @@ return cc;
Sets up R0-R5, calls SCP boot processor with effective BOOT CPU Sets up R0-R5, calls SCP boot processor with effective BOOT CPU
*/ */
t_stat vax780_boot (int32 flag, char *ptr) t_stat vax780_boot_parse (int32 flag, char *ptr)
{ {
char gbuf[CBUFSIZE]; char gbuf[CBUFSIZE];
char *slptr, *regptr; char *slptr, *regptr;
@ -649,12 +650,23 @@ for (i = 0; boot_tab[i].name != NULL; i++) {
R[3] = unitno; R[3] = unitno;
R[4] = 0; R[4] = 0;
R[5] = r5v; R[5] = r5v;
return run_cmd (flag, "CPU"); strncpy(cpu_boot_command, ptr, sizeof(cpu_boot_command)-1);
return SCPE_OK;
} }
} }
return SCPE_NOFNC; return SCPE_NOFNC;
} }
t_stat vax780_boot (int32 flag, char *ptr)
{
t_stat r;
r = vax780_boot_parse (flag, ptr);
if (r == SCPE_OK)
return run_cmd (flag, "CPU");
return r;
}
/* Bootstrap - finish up bootstrap process */ /* Bootstrap - finish up bootstrap process */
t_stat cpu_boot (int32 unitno, DEVICE *dptr) t_stat cpu_boot (int32 unitno, DEVICE *dptr)
@ -671,6 +683,21 @@ SP = PC = 512;
return SCPE_OK; return SCPE_OK;
} }
/* Console entry/Reboot */
int32 con_halt (int32 code, int32 cc)
{
t_stat r;
printf ("Reboot Requested ... Rebooting\n");
if (sim_log) fprintf (sim_log,
"Reboot Requested ... Rebooting\n");
reset_all (0);
r = vax780_boot_parse (4, cpu_boot_command);
if (r == SCPE_OK) r = cpu_boot (0, &cpu_dev);
return r;
}
/* SBI reset */ /* SBI reset */
t_stat sbi_reset (DEVICE *dptr) t_stat sbi_reset (DEVICE *dptr)

View file

@ -284,6 +284,10 @@ REG clk_reg[] = {
{ DRDATA (TODR, todr_reg, 32), PV_LEFT }, { DRDATA (TODR, todr_reg, 32), PV_LEFT },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_HIDDEN + REG_NZ + PV_LEFT }, { DRDATA (TPS, clk_tps, 8), REG_HIDDEN + REG_NZ + PV_LEFT },
#if defined (SIM_ASYNCH_IO)
{ DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT },
{ DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT },
#endif
{ NULL } { NULL }
}; };
@ -570,6 +574,7 @@ t_stat clk_svc (UNIT *uptr)
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ sim_activate (&clk_unit, tmr_poll); /* reactivate unit */
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
todr_reg = todr_reg + 1; /* incr TODR */ todr_reg = todr_reg + 1; /* incr TODR */
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
tmr_incr (TMR_INC); /* do timer service */ tmr_incr (TMR_INC); /* do timer service */

View file

@ -25,6 +25,7 @@
cpu VAX central processor cpu VAX central processor
05-Jan-11 MP Added Asynch I/O support
24-Apr-10 RMS Added OLDVMS idle timer option 24-Apr-10 RMS Added OLDVMS idle timer option
Fixed bug in SET CPU IDLE Fixed bug in SET CPU IDLE
21-May-08 RMS Removed inline support 21-May-08 RMS Removed inline support
@ -612,6 +613,7 @@ for ( ;; ) {
} }
fault_PC = PC; fault_PC = PC;
recqptr = 0; /* clr recovery q */ recqptr = 0; /* clr recovery q */
AIO_CHECK_EVENT;
if (sim_interval <= 0) { /* chk clock queue */ if (sim_interval <= 0) { /* chk clock queue */
temp = sim_process_event (); temp = sim_process_event ();
if (temp) if (temp)
@ -3108,6 +3110,7 @@ PSL = PSL_IS | PSL_IPL1F;
SISR = 0; SISR = 0;
ASTLVL = 4; ASTLVL = 4;
mapen = 0; mapen = 0;
FLUSH_ISTR;
if (M == NULL) if (M == NULL)
M = (uint32 *) calloc (((uint32) MEMSIZE) >> 2, sizeof (uint32)); M = (uint32 *) calloc (((uint32) MEMSIZE) >> 2, sizeof (uint32));
if (M == NULL) if (M == NULL)

View file

@ -27,6 +27,7 @@
tto terminal output tto terminal output
clk 100Hz and TODR clock clk 100Hz and TODR clock
05-Jan-11 MP Added Asynch I/O support
17-Aug-08 RMS Resync TODR on any clock reset 17-Aug-08 RMS Resync TODR on any clock reset
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
17-Oct-06 RMS Synced keyboard poll to real-time clock for idling 17-Oct-06 RMS Synced keyboard poll to real-time clock for idling
@ -178,6 +179,10 @@ REG clk_reg[] = {
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO }, { DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
#if defined (SIM_ASYNCH_IO)
{ DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT },
{ DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT },
#endif
{ NULL } { NULL }
}; };

98
scp.c
View file

@ -23,6 +23,11 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
29-Jan-11 MP Adjusted sim_debug to:
- include the simulator timestamp (sim_time)
as part of the prefix for each line of output
- write complete lines at a time (avoid asynch I/O issues).
05-Jan-11 MP Added Asynch I/O support
08-Feb-09 RMS Fixed warnings in help printouts 08-Feb-09 RMS Fixed warnings in help printouts
29-Dec-08 RMS Fixed implementation of MTAB_NC 29-Dec-08 RMS Fixed implementation of MTAB_NC
24-Nov-08 RMS Revised RESTORE unit logic for consistency 24-Nov-08 RMS Revised RESTORE unit logic for consistency
@ -241,6 +246,17 @@
else if (sim_switches & SWMASK ('H')) val = 16; \ else if (sim_switches & SWMASK ('H')) val = 16; \
else val = dft; else val = dft;
/* Asynch I/O support */
#if defined (SIM_ASYNCH_IO)
pthread_mutex_t sim_asynch_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t sim_asynch_wake = PTHREAD_COND_INITIALIZER;
pthread_t sim_asynch_main_threadid;
struct sim_unit *sim_asynch_queue = NULL;
int32 sim_asynch_check;
int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */
int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */
#endif
/* VM interface */ /* VM interface */
extern char sim_name[]; extern char sim_name[];
@ -393,7 +409,7 @@ static const char *sim_sa64 = "64b addresses";
#else #else
static const char *sim_sa64 = "32b addresses"; static const char *sim_sa64 = "32b addresses";
#endif #endif
#if defined USE_NETWORK #if defined (USE_NETWORK) || defined (USE_SHARED)
static const char *sim_snet = "Ethernet support"; static const char *sim_snet = "Ethernet support";
#else #else
static const char *sim_snet = "no Ethernet"; static const char *sim_snet = "no Ethernet";
@ -616,6 +632,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */
} /* end for */ } /* end for */
sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */
AIO_INIT; /* init Asynch I/O */
if (sim_vm_init != NULL) /* call once only */ if (sim_vm_init != NULL) /* call once only */
(*sim_vm_init)(); (*sim_vm_init)();
sim_finit (); /* init fio package */ sim_finit (); /* init fio package */
@ -700,6 +717,7 @@ sim_set_deboff (0, NULL); /* close debug */
sim_set_logoff (0, NULL); /* close log */ sim_set_logoff (0, NULL); /* close log */
sim_set_notelnet (0, NULL); /* close Telnet */ sim_set_notelnet (0, NULL); /* close Telnet */
sim_ttclose (); /* close console */ sim_ttclose (); /* close console */
AIO_CLEANUP; /* Asynch I/O */
return 0; return 0;
} }
@ -1564,6 +1582,26 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) {
fprintf (st, " at %d\n", accum + uptr->time); fprintf (st, " at %d\n", accum + uptr->time);
accum = accum + uptr->time; accum = accum + uptr->time;
} }
#if defined (SIM_ASYNCH_IO)
pthread_mutex_lock (&sim_asynch_lock);
fprintf (st, "asynchronous pending event queue\n");
if (sim_asynch_queue == (void *)-1)
fprintf (st, "Empty\n");
else {
for (uptr = sim_asynch_queue; uptr != (void *)-1; uptr = uptr->a_next) {
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
fprintf (st, " %s", sim_dname (dptr));
if (dptr->numunits > 1) fprintf (st, " unit %d",
(int32) (uptr - dptr->units));
}
else fprintf (st, " Unknown");
fprintf (st, " event delay %d, queue time %d\n", uptr->a_event_time, uptr->a_sim_interval);
}
}
fprintf (st, "asynch latency: %d microseconds\n", sim_asynch_latency);
fprintf (st, "asynch instruction latency: %d instructions\n", sim_asynch_inst_latency);
pthread_mutex_unlock (&sim_asynch_lock);
#endif
return SCPE_OK; return SCPE_OK;
} }
@ -2633,14 +2671,6 @@ r = sim_instr();
sim_is_running = 0; /* flag idle */ sim_is_running = 0; /* flag idle */
sim_ttcmd (); /* restore console */ sim_ttcmd (); /* restore console */
signal (SIGINT, SIG_DFL); /* cancel WRU */ signal (SIGINT, SIG_DFL); /* cancel WRU */
sim_cancel (&sim_step_unit); /* cancel step timer */
sim_throt_cancel (); /* cancel throttle */
if (sim_clock_queue != NULL) { /* update sim time */
UPDATE_SIM_TIME (sim_clock_queue->time);
}
else {
UPDATE_SIM_TIME (noqueue_time);
}
if (sim_log) /* flush console log */ if (sim_log) /* flush console log */
fflush (sim_log); fflush (sim_log);
if (sim_deb) /* flush debug log */ if (sim_deb) /* flush debug log */
@ -2650,12 +2680,24 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files
uptr = dptr->units + j; uptr = dptr->units + j;
if ((uptr->flags & UNIT_ATT) && /* attached, */ if ((uptr->flags & UNIT_ATT) && /* attached, */
!(uptr->flags & UNIT_BUF) && /* not buffered, */ !(uptr->flags & UNIT_BUF) && /* not buffered, */
(uptr->fileref) && /* real file, */ (uptr->fileref)) /* real file, */
!(uptr->flags & UNIT_RAW) && /* not raw, */ if (uptr->io_flush) /* unit specific flush routine */
uptr->io_flush (uptr);
else
if (!(uptr->flags & UNIT_RAW) && /* not raw, */
!(uptr->flags & UNIT_RO)) /* not read only? */ !(uptr->flags & UNIT_RO)) /* not read only? */
fflush (uptr->fileref); fflush (uptr->fileref);
} }
} }
sim_cancel (&sim_step_unit); /* cancel step timer */
sim_throt_cancel (); /* cancel throttle */
AIO_UPDATE_QUEUE;
if (sim_clock_queue != NULL) { /* update sim time */
UPDATE_SIM_TIME (sim_clock_queue->time);
}
else {
UPDATE_SIM_TIME (noqueue_time);
}
#if defined (VMS) #if defined (VMS)
printf ("\n"); printf ("\n");
#endif #endif
@ -4159,6 +4201,7 @@ t_stat reason;
if (stop_cpu) /* stop CPU? */ if (stop_cpu) /* stop CPU? */
return SCPE_STOP; return SCPE_STOP;
AIO_UPDATE_QUEUE;
if (sim_clock_queue == NULL) { /* queue empty? */ if (sim_clock_queue == NULL) { /* queue empty? */
UPDATE_SIM_TIME (noqueue_time); /* update sim time */ UPDATE_SIM_TIME (noqueue_time); /* update sim time */
sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */
@ -4197,8 +4240,7 @@ t_stat sim_activate (UNIT *uptr, int32 event_time)
UNIT *cptr, *prvptr; UNIT *cptr, *prvptr;
int32 accum; int32 accum;
if (event_time < 0) AIO_ACTIVATE (sim_activate, uptr, event_time);
return SCPE_IERR;
if (sim_is_active (uptr)) /* already active? */ if (sim_is_active (uptr)) /* already active? */
return SCPE_OK; return SCPE_OK;
if (sim_clock_queue == NULL) { if (sim_clock_queue == NULL) {
@ -4242,6 +4284,7 @@ return SCPE_OK;
t_stat sim_activate_abs (UNIT *uptr, int32 event_time) t_stat sim_activate_abs (UNIT *uptr, int32 event_time)
{ {
AIO_ACTIVATE (sim_activate_abs, uptr, event_time);
sim_cancel (uptr); sim_cancel (uptr);
return sim_activate (uptr, event_time); return sim_activate (uptr, event_time);
} }
@ -4259,6 +4302,7 @@ t_stat sim_cancel (UNIT *uptr)
{ {
UNIT *cptr, *nptr; UNIT *cptr, *nptr;
AIO_VALIDATE;
if (sim_clock_queue == NULL) if (sim_clock_queue == NULL)
return SCPE_OK; return SCPE_OK;
UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */
@ -4296,6 +4340,7 @@ int32 sim_is_active (UNIT *uptr)
UNIT *cptr; UNIT *cptr;
int32 accum; int32 accum;
AIO_VALIDATE;
accum = 0; accum = 0;
for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {
if (cptr == sim_clock_queue) { if (cptr == sim_clock_queue) {
@ -4667,7 +4712,7 @@ return;
/* Debug printout routines, from Dave Hittner */ /* Debug printout routines, from Dave Hittner */
const char* debug_bstates = "01_^"; const char* debug_bstates = "01_^";
const char* debug_fmt = "DBG> %s %s: "; const char* debug_fmt = "DBG(%.0f)> %s %s: ";
int32 debug_unterm = 0; int32 debug_unterm = 0;
/* Finds debug phrase matching bitmask from from device DEBTAB table */ /* Finds debug phrase matching bitmask from from device DEBTAB table */
@ -4697,7 +4742,7 @@ static void sim_debug_prefix (uint32 dbits, DEVICE* dptr)
{ {
if (!debug_unterm) { if (!debug_unterm) {
char* debug_type = get_dbg_verb (dbits, dptr); char* debug_type = get_dbg_verb (dbits, dptr);
fprintf(sim_deb, debug_fmt, dptr->name, debug_type); fprintf(sim_deb, debug_fmt, sim_time, dptr->name, debug_type);
} }
} }
@ -4725,7 +4770,7 @@ if (sim_deb && (dptr->dctrl & dbits)) {
#if defined (_WIN32) #if defined (_WIN32)
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#endif #endif
#if defined (__DECC) && defined (__VMS) #if defined (__DECC) && defined (__VMS) && defined (__VAX)
#define NO_vsnprintf #define NO_vsnprintf
#endif #endif
#if defined( NO_vsnprintf) #if defined( NO_vsnprintf)
@ -4738,9 +4783,12 @@ if (sim_deb && (dptr->dctrl & dbits)) {
set and the bitmask matches the current device debug options. set and the bitmask matches the current device debug options.
Extra returns are added for un*x systems, since the output Extra returns are added for un*x systems, since the output
device is set into 'raw' mode when the cpu is booted, device is set into 'raw' mode when the cpu is booted,
and the extra returns don't hurt any other systems. */ and the extra returns don't hurt any other systems.
Callers should be calling sim_debug() which is a macro
defined in scp.h which evaluates the action condition before
incurring call overhead. */
void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...) void _sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...)
{ {
if (sim_deb && (dptr->dctrl & dbits)) { if (sim_deb && (dptr->dctrl & dbits)) {
@ -4749,9 +4797,9 @@ if (sim_deb && (dptr->dctrl & dbits)) {
char *buf = stackbuf; char *buf = stackbuf;
va_list arglist; va_list arglist;
int32 i, j, len; int32 i, j, len;
char* debug_type = get_dbg_verb (dbits, dptr);
buf[bufsize-1] = '\0'; buf[bufsize-1] = '\0';
sim_debug_prefix(dbits, dptr); /* print prefix if required */
while (1) { /* format passed string, args */ while (1) { /* format passed string, args */
va_start (arglist, fmt); va_start (arglist, fmt);
@ -4797,10 +4845,14 @@ if (sim_deb && (dptr->dctrl & dbits)) {
for (i = j = 0; i < len; ++i) { for (i = j = 0; i < len; ++i) {
if ('\n' == buf[i]) { if ('\n' == buf[i]) {
if (i > j) if (i > j) {
fwrite (&buf[j], 1, i-j, sim_deb); if (debug_unterm)
j = i; fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]);
fputc('\r', sim_deb); else /* print prefix when required */
fprintf (sim_deb, "DBG(%.0f)> %s %s: %.*s\r\n", sim_time, dptr->name, debug_type, i-j, &buf[j]);
debug_unterm = 0;
}
j = i + 1;
} }
} }
if (i > j) if (i > j)

8
scp.h
View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
05-Dec-10 MP Added macro invocation of sim_debug
09-Aug-06 JDB Added assign_device and deassign_device 09-Aug-06 JDB Added assign_device and deassign_device
14-Jul-06 RMS Added sim_activate_abs 14-Jul-06 RMS Added sim_activate_abs
06-Jan-06 RMS Added fprint_stopped_gen 06-Jan-06 RMS Added fprint_stopped_gen
@ -116,7 +117,14 @@ char *match_ext (char *fnam, char *ext);
t_stat sim_cancel_step (void); t_stat sim_cancel_step (void);
void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs, void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs,
uint16 before, uint16 after, int terminate); uint16 before, uint16 after, int terminate);
#ifdef CANT_USE_MACRO_VA_ARGS
#define _sim_debug sim_debug
void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...); void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...);
#else
void _sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...);
extern FILE *sim_deb; /* debug file */
#define sim_debug(dbits, dptr, ...) if (sim_deb && ((dptr)->dctrl & dbits)) _sim_debug (dbits, dptr, __VA_ARGS__)
#endif
void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr); void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr);
#endif #endif

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
05-Jan-11 MP Added Asynch I/O support
21-Jul-08 RMS Removed inlining support 21-Jul-08 RMS Removed inlining support
28-May-08 RMS Added inlining support 28-May-08 RMS Added inlining support
28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica) 28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica)
@ -118,12 +119,16 @@
/* Length specific integer declarations */ /* Length specific integer declarations */
#if defined (VMS)
#include <ints.h>
#else
typedef signed char int8; typedef signed char int8;
typedef signed short int16; typedef signed short int16;
typedef signed int int32; typedef signed int int32;
typedef unsigned char uint8; typedef unsigned char uint8;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef unsigned int uint32; typedef unsigned int uint32;
#endif
typedef int t_stat; /* status */ typedef int t_stat; /* status */
typedef int t_bool; /* boolean */ typedef int t_bool; /* boolean */
@ -346,12 +351,23 @@ struct sim_unit {
uint32 flags; /* flags */ uint32 flags; /* flags */
t_addr capac; /* capacity */ t_addr capac; /* capacity */
t_addr pos; /* file position */ t_addr pos; /* file position */
void (*io_flush)(struct sim_unit *up);/* io flush routine */
uint32 iostarttime; /* I/O start time */
int32 buf; /* buffer */ int32 buf; /* buffer */
int32 wait; /* wait */ int32 wait; /* wait */
int32 u3; /* device specific */ int32 u3; /* device specific */
int32 u4; /* device specific */ int32 u4; /* device specific */
int32 u5; /* device specific */ int32 u5; /* device specific */
int32 u6; /* device specific */ int32 u6; /* device specific */
void *up7; /* device specific */
void *up8; /* device specific */
#ifdef SIM_ASYNCH_IO
void (*a_check_completion)(struct sim_unit *);
struct sim_unit *a_next; /* next asynch active */
int32 a_event_time;
int32 a_sim_interval;
t_stat (*a_activate_call)(struct sim_unit *, int32);
#endif
}; };
/* Unit flags */ /* Unit flags */
@ -528,4 +544,157 @@ typedef struct sim_debtab DEBTAB;
#include "sim_timer.h" #include "sim_timer.h"
#include "sim_fio.h" #include "sim_fio.h"
/* Asynch/Threaded I/O support */
#if defined (SIM_ASYNCH_IO)
#include <pthread.h>
extern pthread_mutex_t sim_asynch_lock;
extern pthread_cond_t sim_asynch_wake;
extern pthread_t sim_asynch_main_threadid;
extern struct sim_unit *sim_asynch_queue;
extern t_bool sim_idle_wait;
extern int32 sim_asynch_check;
extern int32 sim_asynch_latency;
extern int32 sim_asynch_inst_latency;
#define AIO_INIT \
if (1) { \
sim_asynch_main_threadid = pthread_self(); \
/* Empty list/list end uses the point value (void *)-1. \
This allows NULL in an entry's a_next pointer to \
indicate that the entry is not currently in any list */ \
sim_asynch_queue = (void *)-1; \
}
#define AIO_CLEANUP \
if (1) { \
pthread_mutex_destroy(&sim_asynch_lock); \
pthread_cond_destroy(&sim_asynch_wake); \
}
#if defined(_WIN32) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define USE_AIO_INTRINSICS 1
#endif
#ifdef USE_AIO_INTRINSICS
/* This approach uses intrinsics to manage access to the link list head */
/* sim_asynch_queue. However, once the list head state has been determined */
/* a lock is used to manage the list update and entry removal. */
/* This approach avoids the ABA issues with a completly lock free approach */
/* since the ABA problem is very likely to happen with this use model, and */
/* it avoids the lock overhead for the simple list head checking. */
#ifdef _WIN32
#include <winsock2.h>
#ifdef ERROR
#undef ERROR
#endif /* ERROR */
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) __sync_val_compare_and_swap(Destination, Comparand, Exchange)
#define InterlockedExchangePointer(Destination, value) __sync_lock_test_and_set(Destination, value)
#else
#error "Implementation of functions InterlockedCompareExchangePointer() and InterlockedExchangePointer() are needed to build with USE_AIO_INTRINSICS"
#endif
#define AIO_QUEUE_VAL InterlockedCompareExchangePointer(&sim_asynch_queue, sim_asynch_queue, NULL)
#define AIO_QUEUE_SET(val) InterlockedExchangePointer(&sim_asynch_queue, val)
#define AIO_UPDATE_QUEUE \
if (1) { \
UNIT *uptr; \
if (AIO_QUEUE_VAL != (void *)-1) { \
pthread_mutex_lock (&sim_asynch_lock); \
while ((uptr = AIO_QUEUE_VAL) != (void *)-1) { \
int32 a_event_time; \
AIO_QUEUE_SET(uptr->a_next); \
uptr->a_next = NULL; /* hygiene */ \
a_event_time = uptr->a_event_time-(uptr->a_sim_interval-sim_interval); \
if (a_event_time < 0) a_event_time = 0; \
uptr->a_activate_call (uptr, a_event_time); \
if (uptr->a_check_completion) { \
pthread_mutex_unlock (&sim_asynch_lock); \
uptr->a_check_completion (uptr); \
pthread_mutex_lock (&sim_asynch_lock); \
} \
} \
pthread_mutex_unlock (&sim_asynch_lock); \
} \
sim_asynch_check = sim_asynch_inst_latency; \
}
#define AIO_ACTIVATE(caller, uptr, event_time) \
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
pthread_mutex_lock (&sim_asynch_lock); \
if (uptr->a_next) { \
uptr->a_activate_call = sim_activate_abs; \
} else { \
uptr->a_next = AIO_QUEUE_VAL; \
uptr->a_event_time = event_time; \
uptr->a_sim_interval = sim_interval; \
uptr->a_activate_call = caller; \
AIO_QUEUE_SET(uptr); \
} \
if (sim_idle_wait) \
pthread_cond_signal (&sim_asynch_wake); \
pthread_mutex_unlock (&sim_asynch_lock); \
return SCPE_OK; \
}
#else /* !USE_AIO_INTRINSICS */
/* This approach uses a pthread mutex to manage access to the link list */
/* head sim_asynch_queue. It will always work, but may be slower than the */
/* partially lock free approach when using USE_AIO_INTRINSICS */
#define AIO_UPDATE_QUEUE \
if (1) { \
UNIT *uptr; \
pthread_mutex_lock (&sim_asynch_lock); \
while (sim_asynch_queue != (void *)-1) { /* List !Empty */ \
int32 a_event_time; \
uptr = sim_asynch_queue; \
sim_asynch_queue = uptr->a_next; \
uptr->a_next = NULL; \
a_event_time = uptr->a_event_time-(uptr->a_sim_interval-sim_interval); \
if (a_event_time < 0) a_event_time = 0; \
uptr->a_activate_call (uptr, a_event_time); \
if (uptr->a_check_completion) { \
pthread_mutex_unlock (&sim_asynch_lock); \
uptr->a_check_completion (uptr); \
pthread_mutex_lock (&sim_asynch_lock); \
} \
} \
pthread_mutex_unlock (&sim_asynch_lock); \
sim_asynch_check = sim_asynch_inst_latency; \
}
#define AIO_ACTIVATE(caller, uptr, event_time) \
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
pthread_mutex_lock (&sim_asynch_lock); \
if (uptr->a_next) { \
uptr->a_activate_call = sim_activate_abs; \
} else { \
uptr->a_next = sim_asynch_queue; \
uptr->a_event_time = event_time; \
uptr->a_sim_interval = sim_interval; \
uptr->a_activate_call = caller; \
sim_asynch_queue = uptr; \
} \
if (sim_idle_wait) \
pthread_cond_signal (&sim_asynch_wake); \
pthread_mutex_unlock (&sim_asynch_lock); \
return SCPE_OK; \
}
#endif /* USE_AIO_INTRINSICS */
#define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) abort()
#define AIO_CHECK_EVENT \
if (0 > --sim_asynch_check) { \
AIO_UPDATE_QUEUE; \
}
#define AIO_SET_INTERRUPT_LATENCY(instpersec) \
if (1) { \
sim_asynch_inst_latency = (int32)((((double)(instpersec))*sim_asynch_latency)/1000000000);\
if (sim_asynch_inst_latency == 0) \
sim_asynch_inst_latency = 1; \
}
#else /* !SIM_ASYNCH_IO */
#define AIO_UPDATE_QUEUE
#define AIO_ACTIVATE(caller, uptr, event_time)
#define AIO_VALIDATE
#define AIO_CHECK_EVENT
#define AIO_INIT
#define AIO_CLEANUP
#define AIO_SET_INTERRUPT_LATENCY(instpersec)
#endif /* SIM_ASYNCH_IO */
#endif #endif

3272
sim_disk.c Normal file

File diff suppressed because it is too large Load diff

86
sim_disk.h Normal file
View file

@ -0,0 +1,86 @@
/* sim_disk.h: simulator disk support library definitions
Copyright (c) 2011, Mark Pizzolato
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of Robert M Supnik and
Mark Pizzolato shall not be used in advertising or otherwise to promote
the sale, use or other dealings in this Software without prior written
authorization from Robert M Supnik and Mark Pizzolato.
25-Jan-11 MP Initial Implemementation
*/
#ifndef _SIM_DISK_H_
#define _SIM_DISK_H_ 0
/* SIMH/Disk format */
typedef uint32 t_seccnt; /* disk sector count */
typedef uint32 t_lba; /* disk logical block address */
/* Unit flags */
#define DKUF_V_WLK (UNIT_V_UF + 12) /* write locked */
#define DKUF_V_FMT (UNIT_V_UF + 13) /* disk file format */
#define DKUF_W_FMT 3 /* 3b of formats */
#define DKUF_N_FMT (1u << DKUF_W_FMT) /* number of formats */
#define DKUF_M_FMT ((1u << DKUF_W_FMT) - 1)
#define DKUF_F_STD 0 /* SIMH format */
#define DKUF_F_RAW 1 /* Raw Physical Disk Access */
#define DKUF_F_VHD 2 /* VHD format */
#define DKUF_V_UF (DKUF_V_FMT + DKUF_W_FMT)
#define DKUF_WLK (1u << DKUF_V_WLK)
#define DKUF_FMT (DKUF_M_FMT << DKUF_V_FMT)
#define DKUF_WRP (DKUF_WLK | UNIT_RO)
#define DK_F_STD (DKUF_F_STD << DKUF_V_FMT)
#define DK_F_RAW (DKUF_F_RAW << DKUF_V_FMT)
#define DK_F_VHD (DKUF_F_VHD << DKUF_V_FMT)
#define DK_GET_FMT(u) (((u)->flags >> DKUF_V_FMT) & DKUF_M_FMT)
/* Return status codes */
#define DKSE_OK 0 /* no error */
typedef void (*DISK_PCALLBACK)(UNIT *unit, t_stat status);
/* Prototypes */
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize);
t_stat sim_disk_detach (UNIT *uptr);
t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback);
t_stat sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
t_stat sim_disk_wrsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects, DISK_PCALLBACK callback);
t_stat sim_disk_unload (UNIT *uptr);
t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat sim_disk_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat sim_disk_set_asynch (UNIT *uptr, int latency);
t_stat sim_disk_clr_asynch (UNIT *uptr);
t_bool sim_disk_isavailable (UNIT *uptr);
t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback);
t_bool sim_disk_wrp (UNIT *uptr);
t_addr sim_disk_size (UNIT *uptr);
void sim_disk_data_trace (UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason);
#endif

148
sim_fio.c
View file

@ -23,6 +23,8 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
02-Feb-11 MP Added sim_fsize_ex and sim_fsize_name_ex returning t_addr
Added export of sim_buf_copy_swapped and sim_buf_swap_data
28-Jun-07 RMS Added VMS IA64 support (from Norm Lastovica) 28-Jun-07 RMS Added VMS IA64 support (from Norm Lastovica)
10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman)
15-May-06 RMS Added sim_fsize_name 15-May-06 RMS Added sim_fsize_name
@ -41,6 +43,11 @@
sim_write - endian independent write (formerly fxwrite) sim_write - endian independent write (formerly fxwrite)
sim_fseek - extended (>32b) seek (formerly fseek_ext) sim_fseek - extended (>32b) seek (formerly fseek_ext)
sim_fsize - get file size sim_fsize - get file size
sim_fsize_name - get file size of named file
sim_fsize_ex - get file size as a t_addr
sim_fsize_name_ex - get file size as a t_addr of named file
sim_buf_copy_swapped - copy data swapping elements along the way
sim_buf_swap_data - swap data elements inplace in buffer
sim_fopen and sim_fseek are OS-dependent. The other routines are not. sim_fopen and sim_fseek are OS-dependent. The other routines are not.
sim_fsize is always a 32b routine (it is used only with small capacity random sim_fsize is always a 32b routine (it is used only with small capacity random
@ -78,18 +85,16 @@ sim_end = end_test.c[0];
return sim_end; return sim_end;
} }
size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr) void sim_buf_swap_data (void *bptr, size_t size, size_t count)
{ {
size_t c, j; uint32 j;
int32 k; int32 k;
unsigned char by, *sptr, *dptr; unsigned char by, *sptr, *dptr;
if ((size == 0) || (count == 0)) /* check arguments */ if (sim_end || (count == 0) || (size == sizeof (char)))
return 0; return;
c = fread (bptr, size, count, fptr); /* read buffer */ for (j = 0, dptr = sptr = (unsigned char *) bptr; /* loop on items */
if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */ j < count; j++) {
return c; /* done */
for (j = 0, dptr = sptr = (unsigned char *) bptr; j < c; j++) { /* loop on items */
for (k = size - 1; k >= (((int32) size + 1) / 2); k--) { for (k = size - 1; k >= (((int32) size + 1) / 2); k--) {
by = *sptr; /* swap end-for-end */ by = *sptr; /* swap end-for-end */
*sptr++ = *(dptr + k); *sptr++ = *(dptr + k);
@ -97,14 +102,44 @@ for (j = 0, dptr = sptr = (unsigned char *) bptr; j < c; j++) { /* loop on items
} }
sptr = dptr = dptr + size; /* next item */ sptr = dptr = dptr + size; /* next item */
} }
}
size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)
{
size_t c;
if ((size == 0) || (count == 0)) /* check arguments */
return 0;
c = fread (bptr, size, count, fptr); /* read buffer */
if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */
return c; /* done */
sim_buf_swap_data (bptr, size, count);
return c; return c;
} }
void sim_buf_copy_swapped (void *dbuf, void *sbuf, size_t size, size_t count)
{
size_t j;
int32 k;
unsigned char *sptr = (unsigned char *)sbuf;
unsigned char *dptr = (unsigned char *)dbuf;
if (sim_end || (size == sizeof (char))) {
memcpy (dptr, sptr, size * count);
return;
}
for (j = 0; j < count; j++) { /* loop on items */
for (k = size - 1; k >= 0; k--)
*(dptr + k) = *sptr++;
dptr = dptr + size;
}
}
size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr) size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr)
{ {
size_t c, j, nelem, nbuf, lcnt, total; size_t c, nelem, nbuf, lcnt, total;
int32 i, k; int32 i;
unsigned char *sptr, *dptr; unsigned char *sptr;
if ((size == 0) || (count == 0)) /* check arguments */ if ((size == 0) || (count == 0)) /* check arguments */
return 0; return 0;
@ -119,11 +154,8 @@ total = 0;
sptr = (unsigned char *) bptr; /* init input ptr */ sptr = (unsigned char *) bptr; /* init input ptr */
for (i = nbuf; i > 0; i--) { /* loop on buffers */ for (i = nbuf; i > 0; i--) { /* loop on buffers */
c = (i == 1)? lcnt: nelem; c = (i == 1)? lcnt: nelem;
for (j = 0, dptr = sim_flip; j < c; j++) { /* loop on items */ sim_buf_copy_swapped (sim_flip, sptr, size, c);
for (k = size - 1; k >= 0; k--) sptr = sptr + size * count;
*(dptr + k) = *sptr++;
dptr = dptr + size;
}
c = fwrite (sim_flip, size, c, fptr); c = fwrite (sim_flip, size, c, fptr);
if (c == 0) if (c == 0)
return total; return total;
@ -132,31 +164,45 @@ for (i = nbuf; i > 0; i--) { /* loop on buffers */
return total; return total;
} }
/* Forward Declaration */
static t_addr _sim_ftell (FILE *st);
/* Get file size */ /* Get file size */
uint32 sim_fsize_name (char *fname) t_addr sim_fsize_ex (FILE *fp)
{
t_addr pos, sz;
if (fp == NULL)
return 0;
pos = _sim_ftell (fp);
sim_fseek (fp, 0, SEEK_END);
sz = _sim_ftell (fp);
sim_fseek (fp, pos, SEEK_SET);
return sz;
}
t_addr sim_fsize_name_ex (char *fname)
{ {
FILE *fp; FILE *fp;
uint32 sz; t_addr sz;
if ((fp = sim_fopen (fname, "rb")) == NULL) if ((fp = sim_fopen (fname, "rb")) == NULL)
return 0; return 0;
sz = sim_fsize (fp); sz = sim_fsize_ex (fp);
fclose (fp); fclose (fp);
return sz; return sz;
} }
uint32 sim_fsize_name (char *fname)
{
return (uint32)(sim_fsize_name_ex (fname));
}
uint32 sim_fsize (FILE *fp) uint32 sim_fsize (FILE *fp)
{ {
uint32 pos, sz; return (uint32)(sim_fsize_ex (fp));
if (fp == NULL)
return 0;
pos = ftell (fp);
fseek (fp, 0, SEEK_END);
sz = ftell (fp);
fseek (fp, pos, SEEK_SET);
return sz;
} }
/* OS-dependent routines */ /* OS-dependent routines */
@ -227,6 +273,9 @@ switch (whence) {
fileaddr = offset; fileaddr = offset;
break; break;
case SEEK_END:
if (_fseeki64 (st, 0, SEEK_END))
return (-1);
case SEEK_CUR: case SEEK_CUR:
if (fgetpos (st, &filepos)) if (fgetpos (st, &filepos))
return (-1); return (-1);
@ -243,6 +292,14 @@ int64_to_fpos_t (fileaddr, &filepos, 127);
return fsetpos (st, &filepos); return fsetpos (st, &filepos);
} }
static t_addr _sim_ftell (FILE *st)
{
fpos_t fileaddr;
if (fgetpos (st, &fileaddr))
return (-1);
return (t_addr)fpos_t_to_int64 (&fileaddr);
}
#endif #endif
/* Alpha UNIX - natively 64b */ /* Alpha UNIX - natively 64b */
@ -255,16 +312,23 @@ int sim_fseek (FILE *st, t_addr offset, int whence)
return fseek (st, offset, whence); return fseek (st, offset, whence);
} }
static t_addr _sim_ftell (FILE *st)
{
return (t_addr)(ftell (st));
}
#endif #endif
/* Windows */ /* Windows */
#if defined (_WIN32) #if defined (_WIN32)
#define _SIM_IO_FSEEK_EXT_ 1 #define _SIM_IO_FSEEK_EXT_ 1
#include <sys/stat.h>
int sim_fseek (FILE *st, t_addr offset, int whence) int sim_fseek (FILE *st, t_addr offset, int whence)
{ {
fpos_t fileaddr; fpos_t fileaddr;
struct _stati64 statb;
switch (whence) { switch (whence) {
@ -272,6 +336,11 @@ switch (whence) {
fileaddr = offset; fileaddr = offset;
break; break;
case SEEK_END:
if (_fstati64 (_fileno (st), &statb))
return (-1);
fileaddr = statb.st_size + offset;
break;
case SEEK_CUR: case SEEK_CUR:
if (fgetpos (st, &fileaddr)) if (fgetpos (st, &fileaddr))
return (-1); return (-1);
@ -286,6 +355,14 @@ switch (whence) {
return fsetpos (st, &fileaddr); return fsetpos (st, &fileaddr);
} }
static t_addr _sim_ftell (FILE *st)
{
fpos_t fileaddr;
if (fgetpos (st, &fileaddr))
return (-1);
return (t_addr)fileaddr;
}
#endif /* end Windows */ #endif /* end Windows */
/* Linux */ /* Linux */
@ -298,6 +375,11 @@ int sim_fseek (FILE *st, t_addr xpos, int origin)
return fseeko64 (st, xpos, origin); return fseeko64 (st, xpos, origin);
} }
static t_addr _sim_ftell (FILE *st)
{
return (t_addr)(ftello64 (st));
}
#endif /* end Linux with LFS */ #endif /* end Linux with LFS */
/* Apple OS/X */ /* Apple OS/X */
@ -310,6 +392,11 @@ int sim_fseek (FILE *st, t_addr xpos, int origin)
return fseeko (st, xpos, origin); return fseeko (st, xpos, origin);
} }
static t_addr _sim_ftell (FILE *st)
{
return (t_addr)(ftello (st));
}
#endif /* end Apple OS/X */ #endif /* end Apple OS/X */
#endif /* end 64b seek defs */ #endif /* end 64b seek defs */
@ -324,6 +411,11 @@ int sim_fseek (FILE *st, t_addr xpos, int origin)
return fseek (st, (int32) xpos, origin); return fseek (st, (int32) xpos, origin);
} }
static t_addr _sim_ftell (FILE *st)
{
return (t_addr)(ftell (st));
}
#endif #endif
uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_; uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_;

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
02-Feb-11 MP Added sim_fsize_ex and sim_fsize_name_ex returning t_addr
Added export of sim_buf_copy_swapped and sim_buf_swap_data
15-May-06 RMS Added sim_fsize_name 15-May-06 RMS Added sim_fsize_name
16-Aug-05 RMS Fixed C++ declaration and cast problems 16-Aug-05 RMS Fixed C++ declaration and cast problems
02-Jan-04 RMS Split out from SCP 02-Jan-04 RMS Split out from SCP
@ -42,5 +44,10 @@ size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr);
size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr); size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr);
uint32 sim_fsize (FILE *fptr); uint32 sim_fsize (FILE *fptr);
uint32 sim_fsize_name (char *fname); uint32 sim_fsize_name (char *fname);
t_addr sim_fsize_ex (FILE *fptr);
t_addr sim_fsize_name_ex (char *fname);
void sim_buf_swap_data (void *bptr, size_t size, size_t count);
void sim_buf_copy_swapped (void *dptr, void *bptr, size_t size, size_t count);
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
05-Feb-11 MP Add Asynch I/O support
30-Aug-06 JDB Added erase gap support 30-Aug-06 JDB Added erase gap support
14-Feb-06 RMS Added variable tape capacity 14-Feb-06 RMS Added variable tape capacity
17-Dec-05 RMS Added write support for Paul Pierce 7b format 17-Dec-05 RMS Added write support for Paul Pierce 7b format
@ -91,6 +92,14 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */
#define MT_TST_PNU(u) ((u)->flags & MTUF_PNU) #define MT_TST_PNU(u) ((u)->flags & MTUF_PNU)
#define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT) #define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT)
/* sim_tape_position Position Flags */
#define MTPOS_V_REW 3
#define MTPOS_M_REW (1u << MTPOS_V_REW) /* Rewind First */
#define MTPOS_V_REV 2
#define MTPOS_M_REV (1u << MTPOS_V_REV) /* Reverse Direction */
#define MTPOS_V_OBJ 1
#define MTPOS_M_OBJ (1u << MTPOS_V_OBJ) /* Objects vs Records/Files */
/* Return status codes */ /* Return status codes */
#define MTSE_OK 0 /* no error */ #define MTSE_OK 0 /* no error */
@ -104,19 +113,47 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */
#define MTSE_RECE 8 /* error in record */ #define MTSE_RECE 8 /* error in record */
#define MTSE_WRP 9 /* write protected */ #define MTSE_WRP 9 /* write protected */
typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status);
/* Prototypes */ /* Prototypes */
t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit);
t_stat sim_tape_attach (UNIT *uptr, char *cptr); t_stat sim_tape_attach (UNIT *uptr, char *cptr);
t_stat sim_tape_detach (UNIT *uptr); t_stat sim_tape_detach (UNIT *uptr);
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max); t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max); t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc); t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc);
t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback);
t_stat sim_tape_wrtmk (UNIT *uptr); t_stat sim_tape_wrtmk (UNIT *uptr);
t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wreom (UNIT *uptr); t_stat sim_tape_wreom (UNIT *uptr);
t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wreomrw (UNIT *uptr);
t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi); t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi);
t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, uint32 bpi, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc);
t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped);
t_stat sim_tape_spfilebyrecf_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc);
t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped);
t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback);
t_stat sim_tape_rewind (UNIT *uptr); t_stat sim_tape_rewind (UNIT *uptr);
t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_position (UNIT *uptr, uint8 flags, uint32 recs, uint32 *recskipped, uint32 files, uint32 *fileskipped, uint32 *objectsskipped);
t_stat sim_tape_position_a (UNIT *uptr, uint8 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped, TAPE_PCALLBACK callback);
t_stat sim_tape_reset (UNIT *uptr); t_stat sim_tape_reset (UNIT *uptr);
t_bool sim_tape_bot (UNIT *uptr); t_bool sim_tape_bot (UNIT *uptr);
t_bool sim_tape_wrp (UNIT *uptr); t_bool sim_tape_wrp (UNIT *uptr);
@ -125,5 +162,8 @@ t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat sim_tape_set_asynch (UNIT *uptr, int latency);
t_stat sim_tape_clr_asynch (UNIT *uptr);
void sim_tape_data_trace (UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason);
#endif #endif

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
05-Jan-11 MP Added Asynch I/O support
22-Sep-08 RMS Added "stability threshold" for idle routine 22-Sep-08 RMS Added "stability threshold" for idle routine
27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller) 27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller)
18-Jun-07 RMS Modified idle to exclude counted delays 18-Jun-07 RMS Modified idle to exclude counted delays
@ -51,6 +52,7 @@
#include <ctype.h> #include <ctype.h>
t_bool sim_idle_enab = FALSE; /* global flag */ t_bool sim_idle_enab = FALSE; /* global flag */
t_bool sim_idle_wait = FALSE; /* global flag */
static uint32 sim_idle_rate_ms = 0; static uint32 sim_idle_rate_ms = 0;
static uint32 sim_idle_stable = SIM_IDLE_STDFLT; static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
@ -76,6 +78,11 @@ UNIT sim_throt_unit = { UDATA (&sim_throt_svc, 0, 0) };
#if defined (__VAX) #if defined (__VAX)
#define sys$gettim SYS$GETTIM #define sys$gettim SYS$GETTIM
#define sys$setimr SYS$SETIMR
#define lib$emul LIB$EMUL
#define sys$waitfr SYS$WAITFR
#define lib$subx LIB$SUBX
#define lib$ediv LIB$EDIV
#endif #endif
#include <starlet.h> #include <starlet.h>
@ -138,10 +145,30 @@ sys$waitfr (2);
return sim_os_msec () - stime; return sim_os_msec () - stime;
} }
/* Win32 routines */ #if defined(SIM_ASYNCH_IO)
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1
int clock_gettime(int clk_id, struct timespec *tp)
{
uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de};
if (clk_id != CLOCK_REALTIME)
return -1;
sys$gettim (tod); /* time 0.1usec */
lib$subx(tod, unixbase, tod); /* convert to unix base */
lib$ediv(&10000000, tod, &secs, &ns); /* isolate seconds & 100ns parts */
tp->tv_sec = secs;
tp->tv_nsec = ns*100;
return 0;
}
#endif /* CLOCK_REALTIME */
#endif /* SIM_ASYNCH_IO */
#elif defined (_WIN32) #elif defined (_WIN32)
/* Win32 routines */
#include <windows.h> #include <windows.h>
const t_bool rtc_avail = TRUE; const t_bool rtc_avail = TRUE;
@ -192,10 +219,26 @@ Sleep (msec);
return sim_os_msec () - stime; return sim_os_msec () - stime;
} }
/* OS/2 routines, from Bruce Ray */ #if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO)
#define CLOCK_REALTIME 1
int clock_gettime(int clk_id, struct timespec *tp)
{
t_uint64 now, unixbase;
unixbase = 116444736;
unixbase *= 1000000000;
GetSystemTimeAsFileTime((FILETIME*)&now);
now -= unixbase;
tp->tv_sec = (long)(now/10000000);
tp->tv_nsec = (now%10000000)*100;
return 0;
}
#endif
#elif defined (__OS2__) #elif defined (__OS2__)
/* OS/2 routines, from Bruce Ray */
const t_bool rtc_avail = FALSE; const t_bool rtc_avail = FALSE;
uint32 sim_os_msec () uint32 sim_os_msec ()
@ -266,6 +309,22 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
return sim_os_msec () - stime; return sim_os_msec () - stime;
} }
#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO)
#define CLOCK_REALTIME 1
int clock_gettime(int clk_id, struct timespec *tp)
{
struct timeval cur;
struct timezone foo;
if (clk_id != CLOCK_REALTIME)
return -1;
gettimeofday (&cur, &foo);
tp->tv_sec = cur.tv_sec;
tp->tv_nsec = cur.tv_usec*1000;
return 0;
}
#endif
#else #else
/* UNIX routines */ /* UNIX routines */
@ -298,19 +357,6 @@ return;
uint32 sim_os_ms_sleep_init (void) uint32 sim_os_ms_sleep_init (void)
{ {
#if defined (_POSIX_SOURCE) /* POSIX-compliant */
struct timespec treq;
uint32 msec;
if (clock_getres (CLOCK_REALTIME, &treq) != 0)
return 0;
msec = (treq.tv_nsec + (NANOS_PER_MILLI - 1)) / NANOS_PER_MILLI;
if (msec > SIM_IDLE_MAX) return 0;
return msec;
#else /* others */
uint32 i, t1, t2, tot, tim; uint32 i, t1, t2, tot, tim;
for (i = 0, tot = 0; i < sleep1Samples; i++) { for (i = 0, tot = 0; i < sleep1Samples; i++) {
@ -320,15 +366,30 @@ for (i = 0, tot = 0; i < sleep1Samples; i++) {
tot += (t2 - t1); tot += (t2 - t1);
} }
tim = (tot + (sleep1Samples - 1)) / sleep1Samples; tim = (tot + (sleep1Samples - 1)) / sleep1Samples;
if (tim == 0) if (tim > SIM_IDLE_MAX)
tim = 1;
else if (tim > SIM_IDLE_MAX)
tim = 0; tim = 0;
return tim; return tim;
#endif
} }
#if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO)
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 1
typedef int clockid_t;
#endif
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
struct timeval cur;
struct timezone foo;
if (clk_id != CLOCK_REALTIME)
return -1;
gettimeofday (&cur, &foo);
tp->tv_sec = cur.tv_sec;
tp->tv_nsec = cur.tv_usec*1000;
return 0;
}
#endif
uint32 sim_os_ms_sleep (unsigned int milliseconds) uint32 sim_os_ms_sleep (unsigned int milliseconds)
{ {
uint32 stime = sim_os_msec (); uint32 stime = sim_os_msec ();
@ -342,6 +403,31 @@ return sim_os_msec () - stime;
#endif #endif
#if defined(SIM_ASYNCH_IO)
uint32 sim_idle_ms_sleep (unsigned int msec)
{
uint32 start_time = sim_os_msec();
struct timespec done_time;
clock_gettime(CLOCK_REALTIME, &done_time);
done_time.tv_sec += (msec/1000);
done_time.tv_nsec += 1000000*(msec%1000);
if (done_time.tv_nsec > 1000000000) {
done_time.tv_sec += 1;
done_time.tv_nsec = done_time.tv_nsec%1000000000;
}
pthread_mutex_lock (&sim_asynch_lock);
sim_idle_wait = TRUE;
pthread_cond_timedwait (&sim_asynch_wake, &sim_asynch_lock, &done_time);
sim_idle_wait = FALSE;
pthread_mutex_unlock (&sim_asynch_lock);
return sim_os_msec() - start_time;
}
#define SIM_IDLE_MS_SLEEP sim_idle_ms_sleep
#else
#define SIM_IDLE_MS_SLEEP sim_os_ms_sleep
#endif
/* OS independent clock calibration package */ /* OS independent clock calibration package */
static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */
@ -423,6 +509,7 @@ if (rtc_based[tmr] <= 0) /* never negative or zer
rtc_based[tmr] = 1; rtc_based[tmr] = 1;
if (rtc_currd[tmr] <= 0) /* never negative or zero! */ if (rtc_currd[tmr] <= 0) /* never negative or zero! */
rtc_currd[tmr] = 1; rtc_currd[tmr] = 1;
AIO_SET_INTERRUPT_LATENCY(rtc_currd[tmr]*ticksper); /* set interrrupt latency */
return rtc_currd[tmr]; return rtc_currd[tmr];
} }
@ -462,7 +549,8 @@ return (sim_idle_rate_ms != 0);
t_bool sim_idle (uint32 tmr, t_bool sin_cyc) t_bool sim_idle (uint32 tmr, t_bool sin_cyc)
{ {
uint32 cyc_ms, w_ms, w_idle, act_ms; static uint32 cyc_ms;
uint32 w_ms, w_idle, act_ms;
int32 act_cyc; int32 act_cyc;
if ((sim_clock_queue == NULL) || /* clock queue empty? */ if ((sim_clock_queue == NULL) || /* clock queue empty? */
@ -472,7 +560,8 @@ if ((sim_clock_queue == NULL) || /* clock queue empty? */
sim_interval = sim_interval - 1; sim_interval = sim_interval - 1;
return FALSE; return FALSE;
} }
cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */ if (!cyc_ms)
cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */
if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */ if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */
if (sin_cyc) if (sin_cyc)
sim_interval = sim_interval - 1; sim_interval = sim_interval - 1;
@ -485,11 +574,11 @@ if (w_idle == 0) { /* none? */
sim_interval = sim_interval - 1; sim_interval = sim_interval - 1;
return FALSE; return FALSE;
} }
act_ms = sim_os_ms_sleep (w_idle); /* wait */ act_ms = SIM_IDLE_MS_SLEEP (w_ms); /* wait */
act_cyc = act_ms * cyc_ms; act_cyc = act_ms * cyc_ms;
if (sim_interval > act_cyc) if (sim_interval > act_cyc)
sim_interval = sim_interval - act_cyc; sim_interval = sim_interval - act_cyc;
else sim_interval = 1; else sim_interval = 0;
return TRUE; return TRUE;
} }